X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Fplugins%2Ftlsopenssl%2Ftls_openssl.c;h=74b8142a68d2d4ab907b0b4400cefa4f8d2823f2;hb=8c5e5f64023146a20e1a9e774b76d6bf713b622b;hp=a10372d1c9c857ae4831bb557c5d5f08dfaa5975;hpb=04161c8f201f95c8354fc583d67e808440d33b9d;p=vpp.git diff --git a/src/plugins/tlsopenssl/tls_openssl.c b/src/plugins/tlsopenssl/tls_openssl.c index a10372d1c9c..74b8142a68d 100644 --- a/src/plugins/tlsopenssl/tls_openssl.c +++ b/src/plugins/tlsopenssl/tls_openssl.c @@ -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); } @@ -150,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) { @@ -169,15 +178,21 @@ 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++) { rv = SSL_read (ssl, fs[i].data, fs[i].len); read += rv > 0 ? rv : 0; - if (rv < fs[i].len) - break; + if (rv < (int) fs[i].len) + { + ossl_check_err_is_fatal (ssl, rv); + break; + } } svm_fifo_enqueue_nocopy (f, read); @@ -189,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; @@ -200,8 +215,11 @@ 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) - break; + if (rv < (int) fs[i].len) + { + ossl_check_err_is_fatal (ssl, rv); + break; + } i++; } @@ -261,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); } } @@ -326,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; } } @@ -336,9 +355,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 +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); } @@ -377,7 +407,22 @@ 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); + + /* Unrecoverable protocol error. Reset connection */ + if (PREDICT_FALSE (wrote < 0)) + { + tls_notify_app_io_error (ctx); + return 0; + } + if (!wrote) goto check_tls_fifo; @@ -386,6 +431,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 +455,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 +473,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); @@ -489,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); @@ -723,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 (); @@ -759,6 +846,10 @@ openssl_start_listen (tls_ctx_t * lctx) return 0; +err: + if (cert_bio) + BIO_free (cert_bio); + return -1; } static int