svm: update number of segments in svm_fifo_segments
[vpp.git] / src / plugins / tlsopenssl / tls_openssl.c
index a10372d..964230f 100644 (file)
@@ -61,15 +61,20 @@ openssl_ctx_free (tls_ctx_t * ctx)
 {
   openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
 
-  if (SSL_is_init_finished (oc->ssl) && !ctx->is_passive_close)
-    SSL_shutdown (oc->ssl);
+  /* Cleanup ssl ctx unless migrated */
+  if (!ctx->is_migrated)
+    {
+      if (SSL_is_init_finished (oc->ssl) && !ctx->is_passive_close)
+       SSL_shutdown (oc->ssl);
 
-  SSL_free (oc->ssl);
+      SSL_free (oc->ssl);
+      vec_free (ctx->srv_hostname);
 
 #ifdef HAVE_OPENSSL_ASYNC
   openssl_evt_free (ctx->evt_index, ctx->c_thread_index);
 #endif
-  vec_free (ctx->srv_hostname);
+    }
+
   pool_put_index (openssl_main.ctx_pool[ctx->c_thread_index],
                  oc->openssl_ctx_index);
 }
@@ -176,7 +181,7 @@ openssl_read_from_ssl_into_fifo (svm_fifo_t * f, SSL * ssl)
       rv = SSL_read (ssl, fs[i].data, fs[i].len);
       read += rv > 0 ? rv : 0;
 
-      if (rv < fs[i].len)
+      if (rv < (int) fs[i].len)
        break;
     }
 
@@ -189,10 +194,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;
 
@@ -200,7 +205,7 @@ 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 < fs[i].len)
+      if (rv < (int) fs[i].len)
        break;
       i++;
     }
@@ -336,9 +341,18 @@ openssl_ctx_handshake_rx (tls_ctx_t * ctx, session_t * tls_session)
     {
       /* Need to check transport status */
       if (ctx->is_passive_close)
-       openssl_handle_handshake_failure (ctx);
-      else
-       tls_notify_app_accept (ctx);
+       {
+         openssl_handle_handshake_failure (ctx);
+         return -1;
+       }
+
+      /* Accept failed, cleanup */
+      if (tls_notify_app_accept (ctx))
+       {
+         ctx->c_s_index = SESSION_INVALID_INDEX;
+         tls_disconnect_transport (ctx);
+         return -1;
+       }
     }
 
   TLS_DBG (1, "Handshake for %u complete. TLS cipher is %s",
@@ -349,6 +363,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);
 }
@@ -377,6 +393,13 @@ openssl_ctx_write_tls (tls_ctx_t *ctx, session_t *app_session,
 
   deq_max = clib_min (deq_max, sp->max_burst_size);
 
+  /* Make sure tcp's tx fifo can actually buffer all bytes to be dequeued.
+   * If under memory pressure, tls's fifo segment might not be able to
+   * allocate the chunks needed. This also avoids errors from the underlying
+   * custom bio to the ssl infra which at times can get stuck. */
+  if (svm_fifo_provision_chunks (ts->tx_fifo, 0, 0, deq_max + TLSO_CTRL_BYTES))
+    goto check_tls_fifo;
+
   wrote = openssl_write_from_fifo_into_ssl (f, oc->ssl, deq_max);
   if (!wrote)
     goto check_tls_fifo;
@@ -386,6 +409,9 @@ openssl_ctx_write_tls (tls_ctx_t *ctx, session_t *app_session,
 
 check_tls_fifo:
 
+  if (PREDICT_FALSE (ctx->app_closed && BIO_ctrl_pending (oc->rbio) <= 0))
+    openssl_confirm_app_close (ctx);
+
   /* Deschedule and wait for deq notification if fifo is almost full */
   enq_buf = clib_min (svm_fifo_size (ts->tx_fifo) / 2, TLSO_MIN_ENQ_SPACE);
   if (space < wrote + enq_buf)
@@ -407,10 +433,10 @@ openssl_ctx_write_dtls (tls_ctx_t *ctx, session_t *app_session,
 {
   openssl_main_t *om = &openssl_main;
   openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
+  u32 read = 0, to_deq, dgram_sz, enq_max;
   session_dgram_pre_hdr_t hdr;
   session_t *us;
   int wrote, rv;
-  u32 read = 0, to_deq, dgram_sz;
   u8 *buf;
 
   us = session_get_from_handle (ctx->tls_session_handle);
@@ -425,7 +451,9 @@ openssl_ctx_write_dtls (tls_ctx_t *ctx, session_t *app_session,
       ASSERT (to_deq >= hdr.data_length + SESSION_CONN_HDR_LEN);
 
       dgram_sz = hdr.data_length + SESSION_CONN_HDR_LEN;
-      if (svm_fifo_max_enqueue_prod (us->tx_fifo) < dgram_sz + TLSO_CTRL_BYTES)
+      enq_max = dgram_sz + TLSO_CTRL_BYTES;
+      if (svm_fifo_max_enqueue_prod (us->tx_fifo) < enq_max ||
+         svm_fifo_provision_chunks (us->tx_fifo, 0, 0, enq_max))
        {
          svm_fifo_add_want_deq_ntf (us->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
          transport_connection_deschedule (&ctx->connection);
@@ -723,29 +751,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;
+    }
+  rv = SSL_CTX_use_certificate (ssl_ctx, srvcert);
+  if (rv != 1)
+    {
+      clib_warning ("unable to use SSL certificate");
+      goto err;
     }
-  SSL_CTX_use_certificate (ssl_ctx, srvcert);
+
   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 ();
@@ -759,6 +817,10 @@ openssl_start_listen (tls_ctx_t * lctx)
 
   return 0;
 
+err:
+  if (cert_bio)
+    BIO_free (cert_bio);
+  return -1;
 }
 
 static int