From: Rainer Jung Date: Wed, 10 Aug 2016 19:57:14 +0000 (+0000) Subject: Support for OpenSSL 1.1.0: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cab6568df8cb5661fdbbf8cec308971ab713c0dd;p=thirdparty%2Fapache%2Fhttpd.git Support for OpenSSL 1.1.0: - partial support for renegotiations. - Not a good design, need to poll until renegotitation has finished. - Loop criterion not right, if no client certs will be send. - Also doesn't work for EC or DH ciphers. Unclear how to fix with current 1.1.0 API. - Details see http://marc.info/?t=145493359200002&r=1&w=2 Backport of r1729341 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat@1755821 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 1ed8b3d23bc..442ad377a0b 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -32,6 +32,9 @@ #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 @@ -42,6 +45,11 @@ 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) { @@ -1011,16 +1019,49 @@ int ssl_hook_Access(request_rec *r) * However, this causes failures in perl-framework currently, * perhaps pre-test if we have already negotiated? */ - /* XXX: OpenSSL 1.1.0: SSL_set_state() no longer available. - * Would SSL_renegotiate(ssl) work? */ #if OPENSSL_VERSION_NUMBER < 0x10100000L + #ifdef OPENSSL_NO_SSL_INTERN SSL_set_state(ssl, SSL_ST_ACCEPT); #else ssl->state = SSL_ST_ACCEPT; -#endif -#endif SSL_do_handshake(ssl); +#endif + +#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 + * https://github.com/openssl/openssl/commit/311f27852a18fb9c10f0c1283b639f12eea06de2 + * It does not work for EC and DH. For details see: + * See: http://marc.info/?t=145493359200002&r=1&w=2 + */ + /* XXX: Polling is bad, alternatives? */ + /* XXX: What about renegotiations which do not need to + * send client certs, e.g. if only the cipher needs + * to switch? We need a better success criterion here + * or the loop will poll until SSL_HANDSHAKE_MAX_POLLS + * is reached. + */ + for (i = 0; i < SSL_HANDSHAKE_MAX_POLLS; i++) { + has_buffered_data(r); + cert = SSL_get_peer_certificate(ssl); + if (cert != NULL) { + break; + } + apr_sleep(SSL_HANDSHAKE_POLL_MS); + } + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO() + "Renegotiation loop %d iterations, " + "in_init=%d, init_finished=%d, " + "state=%s, peer_certs=%s", + i, SSL_in_init(ssl), SSL_is_init_finished(ssl), + SSL_state_string_long(ssl), + cert != NULL ? "yes" : "no"); + +#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */ sslconn->reneg_state = RENEG_REJECT;