]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Support for OpenSSL 1.1.0:
authorRainer Jung <rjung@apache.org>
Wed, 10 Aug 2016 20:14:58 +0000 (20:14 +0000)
committerRainer Jung <rjung@apache.org>
Wed, 10 Aug 2016 20:14:58 +0000 (20:14 +0000)
- 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

modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_private.h

index e58f79829a68216ee093b63d0020ed8ff0110894..17ccb9b97982c7fb4646eb3d777f6b38023e5584 100644 (file)
@@ -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) {
index decda3784856c0474b2f0b668fe93b007c64947f..04a723ea6c296e63272a058e13ea41068528d371 100644 (file)
@@ -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;