On 09/08/17 15:51, Mark Thomas wrote: > I'll take a look at this. I think the hint about the statistics hack > will help me get further than I have so far. Whether it is far enough, > we'll see.
As it happened, the statistics weren't the fix I needed but they got me looking in the right direction where I found SSL_renegotiate_pending() - thanks for the hint. I have attached my proposed patch for review. It seems to be moving back towards an a previous approach. The commit history suggests this approach should not be necessary. I have tested both 7.0.x and 9.0.x and both versions need the additional reads. I'm not 100% sure what is going on. If there aren't any objections, I plan to apply this patch roll 1.2.13 in time for it to be included in the September round of Tomcat releases. Mark
Index: native/src/sslnetwork.c =================================================================== --- native/src/sslnetwork.c (revision 1804444) +++ native/src/sslnetwork.c (working copy) @@ -365,7 +365,7 @@ * Check for failed client authentication */ if (con->ctx->verify_mode != SSL_VERIFY_NONE && - (vr = SSL_get_verify_result(con->ssl)) != X509_V_OK) { + (vr = SSL_get_verify_result(con->ssl)) != X509_V_OK) { if (SSL_VERIFY_ERROR_IS_OPTIONAL(vr) && con->ctx->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) { @@ -622,8 +622,9 @@ { tcn_socket_t *s = J2P(sock, tcn_socket_t *); tcn_ssl_conn_t *con; - int retVal; + int retVal, error; char peekbuf[1]; + apr_interval_time_t timeout; UNREFERENCED_STDARGS; TCN_ASSERT(sock != 0); @@ -633,28 +634,59 @@ * handshake to proceed. */ con->reneg_state = RENEG_ALLOW; + + // Schedule a renegotiation request retVal = SSL_renegotiate(con->ssl); if (retVal <= 0) return APR_EGENERAL; - retVal = SSL_do_handshake(con->ssl); - if (retVal <= 0) - return APR_EGENERAL; - if (!SSL_is_init_finished(con->ssl)) { - return APR_EGENERAL; - } - - /* Need to trigger renegotiation handshake by reading. + /* 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. */ - SSL_peek(con->ssl, peekbuf, 0); + retVal = SSL_peek(con->ssl, peekbuf, 0); + if (retVal < 1) { + error = SSL_get_error(con->ssl, retVal); + } - con->reneg_state = RENEG_REJECT; + 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)) { + 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 { + // SSL_ERROR_WANT_READ is expected. Anything else is an error. + return APR_EGENERAL; + } - if (!SSL_is_init_finished(con->ssl)) { - 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; return APR_SUCCESS; }
--------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org