From: Rainer Jung Date: Wed, 10 Aug 2016 20:14:58 +0000 (+0000) Subject: Support for OpenSSL 1.1.0: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15f5ad54f645c8dd6115608ab7abca4a967c8139;p=thirdparty%2Fapache%2Fhttpd.git Support for OpenSSL 1.1.0: - use SSL_peek instead of looping with has_buffered_data(). This fixes t/security/CVE-2009-3555.t where has_buffered_data() doesn't help, because it finds the buffered data and doesn't call SSL_read(), so the reneg handshake isn't triggered. SSL_peek() for 0 bytes seems to reliably trigger the reneg in every case. No more polling/sleeping. The code for the OpenSSL 1.1.0 case is now again very close to the pre 1.1.0 case. Still need to run the full test suite with a clean build. Backport of r1730316 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat@1755838 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index e58f79829a6..17ccb9b9798 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -32,9 +32,6 @@ #include "mod_ssl.h" #include "util_md5.h" #include "scoreboard.h" -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -#include "apr_time.h" -#endif static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); #ifdef HAVE_TLSEXT @@ -45,11 +42,6 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s); #define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1" #define CONNECTION_HEADER "Connection: Upgrade" -#if OPENSSL_VERSION_NUMBER >= 0x10100000L -#define SSL_HANDSHAKE_POLL_MS 10 -#define SSL_HANDSHAKE_MAX_POLLS 500 -#endif - /* Perform an upgrade-to-TLS for the given request, per RFC 2817. */ static apr_status_t upgrade_connection(request_rec *r) { @@ -956,6 +948,10 @@ int ssl_hook_Access(request_rec *r) } } else { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + int rc; + char peekbuf[1]; +#endif const char *reneg_support; request_rec *id = r->main ? r->main : r; @@ -1030,30 +1026,21 @@ int ssl_hook_Access(request_rec *r) #else /* if OPENSSL_VERSION_NUMBER < 0x10100000L */ - /* XXX: OpenSSL 1.1.0: SSL_set_state() no longer available. - * Need to trigger renegotiation handshake by reading, - * until handshake has finished. - * The code works for some ciphers with 1.1.0pre2 plus the patch + /* Need to trigger renegotiation handshake by reading. + * Peeking 0 bytes actually works. + * The code needs the following patches on top of OpenSSL 1.1.0pre2: * https://github.com/openssl/openssl/commit/311f27852a18fb9c10f0c1283b639f12eea06de2 - * It does not work for EC and DH. For details see: + * https://github.com/openssl/openssl/commit/5b326dc529e19194feaef9a65fa37efbe11eaa7e + * It is expected to work without changes with the forthcoming 1.1.0pre3. * See: http://marc.info/?t=145493359200002&r=1&w=2 */ - /* XXX: Polling is bad, alternatives? */ - for (i = 0; i < SSL_HANDSHAKE_MAX_POLLS; i++) { - has_buffered_data(r); - if (sslconn->ssl == NULL || - sslconn->reneg_state == RENEG_DONE || - sslconn->reneg_state == RENEG_ALERT) { - break; - } - apr_sleep(SSL_HANDSHAKE_POLL_MS); - } + rc = SSL_peek(ssl, peekbuf, 0); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO() - "Renegotiation loop %d iterations, " + "Renegotiation peek result=%d, " "reneg_state=%d, " "in_init=%d, init_finished=%d, " "state=%s, sslconn->ssl=%s, peer_certs=%s", - i, sslconn->reneg_state, + rc, sslconn->reneg_state, SSL_in_init(ssl), SSL_is_init_finished(ssl), SSL_state_string_long(ssl), sslconn->ssl != NULL ? "yes" : "no", @@ -2152,23 +2139,6 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) } #endif } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - else if (!scr->is_proxy && - (where & SSL_CB_HANDSHAKE_START) && - scr->reneg_state == RENEG_ALLOW) { - scr->reneg_state = RENEG_STARTED; - } - else if (!scr->is_proxy && - (where & SSL_CB_HANDSHAKE_DONE) && - scr->reneg_state == RENEG_STARTED) { - scr->reneg_state = RENEG_DONE; - } - else if (!scr->is_proxy && - (where & SSL_CB_ALERT) && - (scr->reneg_state == RENEG_ALLOW || scr->reneg_state == RENEG_STARTED)) { - scr->reneg_state = RENEG_ALERT; - } -#endif /* If the first handshake is complete, change state to reject any * subsequent client-initiated renegotiation. */ else if ((where & SSL_CB_HANDSHAKE_DONE) && scr->reneg_state == RENEG_INIT) { diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index decda378485..04a723ea6c2 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -460,11 +460,6 @@ typedef struct { * renegotiation should be rejected */ RENEG_ALLOW, /* A server-initiated renegotiation is taking * place (as dictated by configuration) */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - RENEG_STARTED, /* A renegotiation has started after RENEG_ALLOW */ - RENEG_DONE, /* A renegotiation has finished after RENEG_STARTED */ - RENEG_ALERT, /* A renegotiation has finished with an SSL Alert */ -#endif RENEG_ABORT /* Renegotiation initiated by client, abort the * connection */ } reneg_state;