Author: markt Date: Wed Oct 10 21:49:55 2018 New Revision: 1843514 URL: http://svn.apache.org/viewvc?rev=1843514&view=rev Log: Implement TLS 1.3 support for CLIENT-CERT when the APR/native connector is not configured with certificateVerification="required" (i.e. the equivalent of server initiated renegotiation to obtain a client cert)
Modified: tomcat/native/trunk/native/include/ssl_private.h tomcat/native/trunk/native/src/sslnetwork.c tomcat/native/trunk/native/src/sslutils.c Modified: tomcat/native/trunk/native/include/ssl_private.h URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/include/ssl_private.h?rev=1843514&r1=1843513&r2=1843514&view=diff ============================================================================== --- tomcat/native/trunk/native/include/ssl_private.h (original) +++ tomcat/native/trunk/native/include/ssl_private.h Wed Oct 10 21:49:55 2018 @@ -324,7 +324,7 @@ struct tcn_ssl_conf_ctxt_t { SSL_CONF_CTX *cctx; }; #endif - + typedef struct { apr_pool_t *pool; tcn_ssl_ctxt_t *ctx; @@ -335,7 +335,7 @@ typedef struct { * that all client-initiated renegotiations can be rejected, as a * partial fix for CVE-2009-3555. */ - enum { + enum { RENEG_INIT = 0, /* Before initial handshake */ RENEG_REJECT, /* After initial handshake; any client-initiated * renegotiation should be rejected @@ -347,6 +347,13 @@ typedef struct { * connection */ } reneg_state; +#if defined(SSL_OP_NO_TLSv1_3) + enum { + PHA_NONE = 0, /* Before PHA */ + PHA_STARTED, /* PHA req sent to client but no response */ + PHA_COMPLETE /* Client has returned cert */ + } pha_state; +#endif apr_socket_t *sock; apr_pollset_t *pollset; } tcn_ssl_conn_t; @@ -356,7 +363,7 @@ typedef struct { * Additional Functions */ void SSL_init_app_data2_3_idx(void); -/* The app_data2 is used to store the tcn_ssl_ctxt_t pointer for the SSL instance. */ +/* The app_data2 is used to store the tcn_ssl_ctxt_t pointer for the SSL instance. */ void *SSL_get_app_data2(SSL *); void SSL_set_app_data2(SSL *, void *); /* The app_data3 is used to store the handshakeCount pointer for the SSL instance. */ Modified: tomcat/native/trunk/native/src/sslnetwork.c URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslnetwork.c?rev=1843514&r1=1843513&r2=1843514&view=diff ============================================================================== --- tomcat/native/trunk/native/src/sslnetwork.c (original) +++ tomcat/native/trunk/native/src/sslnetwork.c Wed Oct 10 21:49:55 2018 @@ -625,69 +625,130 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene int error = 0; char peekbuf[1]; apr_interval_time_t timeout; + const SSL_SESSION *session; UNREFERENCED_STDARGS; TCN_ASSERT(sock != 0); con = (tcn_ssl_conn_t *)s->opaque; + session = SSL_get_session(con->ssl); + apr_socket_timeout_get(con->sock, &timeout); - /* Toggle the renegotiation state to allow the new - * handshake to proceed. - */ - con->reneg_state = RENEG_ALLOW; - - // Schedule a renegotiation request - retVal = SSL_renegotiate(con->ssl); - if (retVal <= 0) - return APR_EGENERAL; - - /* Need to trigger the renegotiation handshake by reading. - * Peeking 0 bytes actually works. - * See: http://marc.info/?t=145493359200002&r=1&w=2 - * - * This will normally return SSL_ERROR_WANT_READ whether the renegotiation - * has been completed or not. Afterwards, need to determine if I/O needs to - * be triggered or not. - */ - retVal = SSL_peek(con->ssl, peekbuf, 0); - if (retVal < 1) { - error = SSL_get_error(con->ssl, retVal); - } +#if defined(SSL_OP_NO_TLSv1_3) + if (SSL_SESSION_get_protocol_version(session) == TLS1_3_VERSION) { + // TLS 1.3 renegotiation + retVal = SSL_verify_client_post_handshake(con->ssl); + if (retVal <= 0) { + return APR_EGENERAL; + } + + con->pha_state = PHA_STARTED; + + // Need to trigger a write operation to sent the cert request to the + // client. As per OpenSSL docs, use SSL_do_handshake() for this. + retVal = SSL_do_handshake(con->ssl); + if (retVal <= 0) { + return APR_EGENERAL; + } + + // Trigger reading of the certs from the client + retVal = SSL_peek(con->ssl, peekbuf, 0); + if (retVal < 1) { + error = SSL_get_error(con->ssl, retVal); + } + + // If the certs have not been received, then need to wait for I/O + while (con->pha_state == PHA_STARTED) { + // SSL_ERROR_WANT_READ is expected. Anything else is an error. + if (error == SSL_ERROR_WANT_READ) { + retVal = wait_for_io_or_timeout(con, error, timeout); + /* + * Since this is blocking I/O, anything other than APR_SUCCESS is an + * error. + */ + if (retVal != APR_SUCCESS) { + con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN; + return retVal; + } + } else { + return APR_EGENERAL; + } + + // Re-try SSL_peek after I/O + retVal = SSL_peek(con->ssl, peekbuf, 0); + if (retVal < 1) { + error = SSL_get_error(con->ssl, retVal); + } else { + /* + * Reset error to handle case where SSL_Peek returns 0 but + * con->pha_state has not changed. This will trigger an error + * to be returned. + */ + error = 0; + } + } + } else { +#endif + // TLS 1.2 and earlier renegotiation + + /* Toggle the renegotiation state to allow the new + * handshake to proceed. + */ + con->reneg_state = RENEG_ALLOW; + + // Schedule a renegotiation request + retVal = SSL_renegotiate(con->ssl); + if (retVal <= 0) { + return APR_EGENERAL; + } + + /* Need to trigger the renegotiation handshake by reading. + * Peeking 0 bytes actually works. + * See: http://marc.info/?t=145493359200002&r=1&w=2 + * + * This will normally return SSL_ERROR_WANT_READ whether the renegotiation + * has been completed or not. Afterwards, need to determine if I/O needs to + * be triggered or not. + */ + retVal = SSL_peek(con->ssl, peekbuf, 0); + if (retVal < 1) { + error = SSL_get_error(con->ssl, retVal); + } + + // If the renegotiation is still pending, then I/O needs to be triggered + while (SSL_renegotiate_pending(con->ssl)) { + // SSL_ERROR_WANT_READ is expected. Anything else is an error. + if (error == SSL_ERROR_WANT_READ) { + retVal = wait_for_io_or_timeout(con, error, timeout); + /* + * Since this is blocking I/O, anything other than APR_SUCCESS is an + * error. + */ + if (retVal != APR_SUCCESS) { + con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN; + return retVal; + } + } else { + return APR_EGENERAL; + } + + // Re-try SSL_peek after I/O + retVal = SSL_peek(con->ssl, peekbuf, 0); + if (retVal < 1) { + error = SSL_get_error(con->ssl, retVal); + } else { + /* + * Reset error to handle case where SSL_Peek returns 0 but + * SSL_renegotiate_pending returns true. This will trigger an error + * to be returned. + */ + error = 0; + } + } - apr_socket_timeout_get(con->sock, &timeout); - // If the renegotiation is still pending, then I/O needs to be triggered - while (SSL_renegotiate_pending(con->ssl)) { - // SSL_ERROR_WANT_READ is expected. Anything else is an error. - if (error == SSL_ERROR_WANT_READ) { - retVal = wait_for_io_or_timeout(con, error, timeout); - /* - * Since this is blocking I/O, anything other than APR_SUCCESS is an - * error. - */ - if (retVal != APR_SUCCESS) { - printf("ERROR\n"); - con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN; - return retVal; - } - } else { - return APR_EGENERAL; - } - - // Re-try SSL_peek after I/O - retVal = SSL_peek(con->ssl, peekbuf, 0); - if (retVal < 1) { - error = SSL_get_error(con->ssl, retVal); - } else { - /* - * Reset error to handle case where SSL_Peek returns 0 but - * SSL_renegotiate_pending returns true. This will trigger an error - * to be returned. - */ - error = 0; - } + con->reneg_state = RENEG_REJECT; +#if defined(SSL_OP_NO_TLSv1_3) } - - con->reneg_state = RENEG_REJECT; - +#endif return APR_SUCCESS; } Modified: tomcat/native/trunk/native/src/sslutils.c URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslutils.c?rev=1843514&r1=1843513&r2=1843514&view=diff ============================================================================== --- tomcat/native/trunk/native/src/sslutils.c (original) +++ tomcat/native/trunk/native/src/sslutils.c Wed Oct 10 21:49:55 2018 @@ -305,6 +305,10 @@ int SSL_callback_SSL_verify(int ok, X509 int verify = con->ctx->verify_mode; int depth = con->ctx->verify_depth; +#if defined(SSL_OP_NO_TLSv1_3) + con->pha_state = PHA_COMPLETE; +#endif + if (verify == SSL_CVERIFY_UNSET || verify == SSL_CVERIFY_NONE) return 1; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org