tls: handle read write ssl errors
[vpp.git] / src / plugins / tlsopenssl / tls_openssl.c
index 05cd13c..74b8142 100644 (file)
@@ -155,6 +155,10 @@ openssl_lctx_get (u32 lctx_index)
   return pool_elt_at_index (openssl_main.lctx_pool, lctx_index);
 }
 
+#define ossl_check_err_is_fatal(_ssl, _rv)                                    \
+  if (PREDICT_FALSE (_rv < 0 && SSL_get_error (_ssl, _rv) == SSL_ERROR_SSL))  \
+    return -1;
+
 static int
 openssl_read_from_ssl_into_fifo (svm_fifo_t * f, SSL * ssl)
 {
@@ -174,7 +178,10 @@ openssl_read_from_ssl_into_fifo (svm_fifo_t * f, SSL * ssl)
   /* Return early if we can't read anything */
   read = SSL_read (ssl, fs[0].data, fs[0].len);
   if (read <= 0)
-    return 0;
+    {
+      ossl_check_err_is_fatal (ssl, read);
+      return 0;
+    }
 
   for (i = 1; i < n_fs; i++)
     {
@@ -182,7 +189,10 @@ openssl_read_from_ssl_into_fifo (svm_fifo_t * f, SSL * ssl)
       read += rv > 0 ? rv : 0;
 
       if (rv < (int) fs[i].len)
-       break;
+       {
+         ossl_check_err_is_fatal (ssl, rv);
+         break;
+       }
     }
 
   svm_fifo_enqueue_nocopy (f, read);
@@ -194,10 +204,10 @@ static int
 openssl_write_from_fifo_into_ssl (svm_fifo_t *f, SSL *ssl, u32 max_len)
 {
   int wrote = 0, rv, i = 0, len;
-  const int n_segs = 2;
+  u32 n_segs = 2;
   svm_fifo_seg_t fs[n_segs];
 
-  len = svm_fifo_segments (f, 0, fs, n_segs, max_len);
+  len = svm_fifo_segments (f, 0, fs, &n_segs, max_len);
   if (len <= 0)
     return 0;
 
@@ -206,7 +216,10 @@ openssl_write_from_fifo_into_ssl (svm_fifo_t *f, SSL *ssl, u32 max_len)
       rv = SSL_write (ssl, fs[i].data, fs[i].len);
       wrote += (rv > 0) ? rv : 0;
       if (rv < (int) fs[i].len)
-       break;
+       {
+         ossl_check_err_is_fatal (ssl, rv);
+         break;
+       }
       i++;
     }
 
@@ -266,6 +279,7 @@ openssl_handle_handshake_failure (tls_ctx_t * ctx)
        * Also handles cleanup of the pre-allocated session
        */
       tls_notify_app_connected (ctx, SESSION_E_TLS_HANDSHAKE);
+      tls_disconnect_transport (ctx);
     }
 }
 
@@ -331,7 +345,7 @@ openssl_ctx_handshake_rx (tls_ctx_t * ctx, session_t * tls_session)
           */
          if (ctx->srv_hostname)
            {
-             tls_notify_app_connected (ctx, SESSION_E_TLS_HANDSHAKE);
+             openssl_handle_handshake_failure (ctx);
              return -1;
            }
        }
@@ -363,6 +377,8 @@ openssl_ctx_handshake_rx (tls_ctx_t * ctx, session_t * tls_session)
 static void
 openssl_confirm_app_close (tls_ctx_t * ctx)
 {
+  openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
+  SSL_shutdown (oc->ssl);
   tls_disconnect_transport (ctx);
   session_transport_closed_notify (&ctx->connection);
 }
@@ -399,6 +415,14 @@ openssl_ctx_write_tls (tls_ctx_t *ctx, session_t *app_session,
     goto check_tls_fifo;
 
   wrote = openssl_write_from_fifo_into_ssl (f, oc->ssl, deq_max);
+
+  /* Unrecoverable protocol error. Reset connection */
+  if (PREDICT_FALSE (wrote < 0))
+    {
+      tls_notify_app_io_error (ctx);
+      return 0;
+    }
+
   if (!wrote)
     goto check_tls_fifo;
 
@@ -515,6 +539,13 @@ openssl_ctx_read_tls (tls_ctx_t *ctx, session_t *tls_session)
 
   read = openssl_read_from_ssl_into_fifo (f, oc->ssl);
 
+  /* Unrecoverable protocol error. Reset connection */
+  if (PREDICT_FALSE (read < 0))
+    {
+      tls_notify_app_io_error (ctx);
+      return 0;
+    }
+
   /* If handshake just completed, session may still be in accepting state */
   if (read && app_session->session_state >= SESSION_STATE_READY)
     tls_notify_app_enqueue (ctx, app_session);
@@ -749,29 +780,59 @@ openssl_start_listen (tls_ctx_t * lctx)
       return -1;
     }
 
+  /* use the default OpenSSL built-in DH parameters */
+  rv = SSL_CTX_set_dh_auto (ssl_ctx, 1);
+  if (rv != 1)
+    {
+      TLS_DBG (1, "Couldn't set temp DH parameters");
+      return -1;
+    }
+
   /*
    * Set the key and cert
    */
   cert_bio = BIO_new (BIO_s_mem ());
+  if (!cert_bio)
+    {
+      clib_warning ("unable to allocate memory");
+      return -1;
+    }
   BIO_write (cert_bio, ckpair->cert, vec_len (ckpair->cert));
   srvcert = PEM_read_bio_X509 (cert_bio, NULL, NULL, NULL);
   if (!srvcert)
     {
       clib_warning ("unable to parse certificate");
-      return -1;
+      goto err;
     }
-  SSL_CTX_use_certificate (ssl_ctx, srvcert);
+  rv = SSL_CTX_use_certificate (ssl_ctx, srvcert);
+  if (rv != 1)
+    {
+      clib_warning ("unable to use SSL certificate");
+      goto err;
+    }
+
   BIO_free (cert_bio);
 
   cert_bio = BIO_new (BIO_s_mem ());
+  if (!cert_bio)
+    {
+      clib_warning ("unable to allocate memory");
+      return -1;
+    }
   BIO_write (cert_bio, ckpair->key, vec_len (ckpair->key));
   pkey = PEM_read_bio_PrivateKey (cert_bio, NULL, NULL, NULL);
   if (!pkey)
     {
       clib_warning ("unable to parse pkey");
-      return -1;
+      goto err;
     }
-  SSL_CTX_use_PrivateKey (ssl_ctx, pkey);
+  rv = SSL_CTX_use_PrivateKey (ssl_ctx, pkey);
+  if (rv != 1)
+    {
+      clib_warning ("unable to use SSL PrivateKey");
+      goto err;
+    }
+
   BIO_free (cert_bio);
 
   olc_index = openssl_listen_ctx_alloc ();
@@ -785,6 +846,10 @@ openssl_start_listen (tls_ctx_t * lctx)
 
   return 0;
 
+err:
+  if (cert_bio)
+    BIO_free (cert_bio);
+  return -1;
 }
 
 static int