Update for OpenSSL 1.0.2 compatibility
authorDaniel Lowrey <rdlowrey@php.net>
Sat, 28 Feb 2015 20:23:59 +0000 (15:23 -0500)
committerDaniel Lowrey <rdlowrey@php.net>
Sat, 28 Feb 2015 22:41:29 +0000 (17:41 -0500)
ext/openssl/openssl.c
ext/openssl/xp_ssl.c

index 1cb69585aeb19470c9e16d346b18f77b421eaff6..2c7aecf4330c640c9363e5b5ade4386b21ce027f 100644 (file)
 
 /* OpenSSL includes */
 #include <openssl/evp.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/dh.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/crypto.h>
@@ -3350,22 +3354,46 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
        if ((req->priv_key = EVP_PKEY_new()) != NULL) {
                switch(req->priv_key_type) {
                        case OPENSSL_KEYTYPE_RSA:
-                               if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) {
-                                       return_val = req->priv_key;
+                               {
+                                       RSA* rsaparam;
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+                                       /* OpenSSL 1.0.2 deprecates RSA_generate_key */
+                                       rsaparam = (RSA*)RSA_generate_key(req->priv_key_bits, RSA_F4, NULL, NULL);
+#else
+                                       {
+                                               BIGNUM *bne = (BIGNUM *)BN_new();
+                                               if (BN_set_word(bne, RSA_F4) != 1) {
+                                                       BN_free(bne);
+                                                       php_error_docref(NULL, E_WARNING, "failed setting exponent");
+                                                       return NULL;
+                                               }
+                                               rsaparam = RSA_new();
+                                               RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL);
+                                               BN_free(bne);
+                                       }
+#endif
+                                       if (rsaparam && EVP_PKEY_assign_RSA(req->priv_key, rsaparam)) {
+                                               return_val = req->priv_key;
+                                       }
                                }
                                break;
 #if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD)
                        case OPENSSL_KEYTYPE_DSA:
                                {
-                                       DSA *dsapar = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
-                                       if (dsapar) {
-                                               DSA_set_method(dsapar, DSA_get_default_method());
-                                               if (DSA_generate_key(dsapar)) {
-                                                       if (EVP_PKEY_assign_DSA(req->priv_key, dsapar)) {
+                                       DSA* dsaparam;
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+                                       dsaparam = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
+#else
+                                       DSA_generate_parameters_ex(dsaparam, req->priv_key_bits, NULL, 0, NULL, NULL, NULL);
+#endif
+                                       if (dsaparam) {
+                                               DSA_set_method(dsaparam, DSA_get_default_method());
+                                               if (DSA_generate_key(dsaparam)) {
+                                                       if (EVP_PKEY_assign_DSA(req->priv_key, dsaparam)) {
                                                                return_val = req->priv_key;
                                                        }
                                                } else {
-                                                       DSA_free(dsapar);
+                                                       DSA_free(dsaparam);
                                                }
                                        }
                                }
@@ -3374,17 +3402,21 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
 #if !defined(NO_DH)
                        case OPENSSL_KEYTYPE_DH:
                                {
-                                       DH *dhpar = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
                                        int codes = 0;
-
-                                       if (dhpar) {
-                                               DH_set_method(dhpar, DH_get_default_method());
-                                               if (DH_check(dhpar, &codes) && codes == 0 && DH_generate_key(dhpar)) {
-                                                       if (EVP_PKEY_assign_DH(req->priv_key, dhpar)) {
+                                       DH *dhparam;
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+                                       dhparam = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
+#else
+                                       DH_generate_parameters_ex(dhparam, req->priv_key_bits, 2, NULL);
+#endif
+                                       if (dhparam) {
+                                               DH_set_method(dhparam, DH_get_default_method());
+                                               if (DH_check(dhparam, &codes) && codes == 0 && DH_generate_key(dhparam)) {
+                                                       if (EVP_PKEY_assign_DH(req->priv_key, dhparam)) {
                                                                return_val = req->priv_key;
                                                        }
                                                } else {
-                                                       DH_free(dhpar);
+                                                       DH_free(dhparam);
                                                }
                                        }
                                }
index 216509169509376912ad0f896ffe44eac16e4ae1..539a0429679d8eac053311060d051ce877264b75 100644 (file)
@@ -32,6 +32,7 @@
 #include "php_openssl.h"
 #include "php_network.h"
 #include <openssl/ssl.h>
+#include <openssl/rsa.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/err.h>
 #include <sys/select.h>
 #endif
 
+/* OpenSSL 1.0.2 removes SSLv2 support entirely*/
+#if OPENSSL_VERSION_NUMBER < 0x10002000L && !defined(OPENSSL_NO_SSL2)
+#define HAVE_SSL2 1
+#endif
+
+#ifndef OPENSSL_NO_SSL3
+#define HAVE_SSL3 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+#define HAVE_TLS11 1
+#define HAVE_TLS12 1
+#endif
+
 #if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
 #define HAVE_ECDH 1
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x00908070L && !defined(OPENSSL_NO_TLSEXT)
-#define HAVE_SNI 1
+#if !defined(OPENSSL_NO_TLSEXT)
+#if OPENSSL_VERSION_NUMBER >= 0x00908070L
+#define HAVE_TLS_SNI 1
 #endif
+#endif
+
 
 /* Flags for determining allowed stream crypto methods */
 #define STREAM_CRYPTO_IS_CLIENT            (1<<0)
@@ -885,37 +903,37 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */
 static const SSL_METHOD *php_select_crypto_method(zend_long method_value, int is_client) /* {{{ */
 {
        if (method_value == STREAM_CRYPTO_METHOD_SSLv2) {
-#ifndef OPENSSL_NO_SSL2
-               return is_client ? SSLv2_client_method() : SSLv2_server_method();
+#ifdef HAVE_SSL2
+               return is_client ? (SSL_METHOD *)SSLv2_client_method() : (SSL_METHOD *)SSLv2_server_method();
 #else
                php_error_docref(NULL, E_WARNING,
-                               "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
+                               "SSLv2 unavailable in the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        } else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) {
-#ifndef OPENSSL_NO_SSL3
+#ifdef HAVE_SSL3
                return is_client ? SSLv3_client_method() : SSLv3_server_method();
 #else
                php_error_docref(NULL, E_WARNING,
-                               "SSLv3 support is not compiled into the OpenSSL library PHP is linked against");
+                               "SSLv3 unavailable in the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_0) {
                return is_client ? TLSv1_client_method() : TLSv1_server_method();
        } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_1) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+#ifdef HAVE_TLS11
                return is_client ? TLSv1_1_client_method() : TLSv1_1_server_method();
 #else
                php_error_docref(NULL, E_WARNING,
-                               "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against");
+                               "TLSv1.1 unavailable in the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+#ifdef HAVE_TLS12
                return is_client ? TLSv1_2_client_method() : TLSv1_2_server_method();
 #else
                php_error_docref(NULL, E_WARNING,
-                               "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against");
+                               "TLSv1.2 unavailable in the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        } else {
@@ -1086,7 +1104,21 @@ static int set_server_rsa_key(php_stream *stream, SSL_CTX *ctx) /* {{{ */
                rsa_key_size = 2048;
        }
 
-       rsa = RSA_generate_key(rsa_key_size, RSA_F4, NULL, NULL);
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+       /* OpenSSL 1.0.2 deprecates RSA_generate_key */
+       rsa = (RSA*)RSA_generate_key(rsa_key_size, RSA_F4, NULL, NULL);
+#else
+       {
+               BIGNUM *bne = (BIGNUM *)BN_new();
+               if (BN_set_word(bne, RSA_F4) != 1) {
+                       BN_free(bne);
+                       return FAILURE;
+               }
+               rsa = RSA_new();
+               RSA_generate_key_ex(rsa, rsa_key_size, bne, NULL);
+               BN_free(bne);
+       }
+#endif
 
        if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) {
                php_error_docref(NULL, E_WARNING, "Failed setting RSA key");
@@ -1226,7 +1258,7 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */
 }
 /* }}} */
 
-#ifdef HAVE_SNI
+#ifdef HAVE_TLS_SNI
 static int server_sni_callback(SSL *ssl_handle, int *al, void *arg) /* {{{ */
 {
        php_stream *stream;
@@ -1466,6 +1498,7 @@ int php_openssl_setup_crypto(php_stream *stream,
                        return FAILURE;
                }
        }
+
        if (FAILURE == set_local_cert(sslsock->ctx, stream)) {
                return FAILURE;
        }
@@ -1493,7 +1526,7 @@ int php_openssl_setup_crypto(php_stream *stream,
                handle_ssl_error(stream, 0, 1);
        }
 
-#ifdef HAVE_SNI
+#ifdef HAVE_TLS_SNI
        /* Enable server-side SNI */
        if (sslsock->is_client == 0 && enable_server_sni(stream, sslsock) == FAILURE) {
                return FAILURE;
@@ -1534,13 +1567,29 @@ static zend_array *capture_session_meta(SSL *ssl_handle) /* {{{ */
        const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl_handle);
 
        switch (proto) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001001L
-               case TLS1_2_VERSION: proto_str = "TLSv1.2"; break;
-               case TLS1_1_VERSION: proto_str = "TLSv1.1"; break;
+#ifdef HAVE_TLS12
+               case TLS1_2_VERSION:
+                       proto_str = "TLSv1.2";
+                       break;
+#endif
+#ifdef HAVE_TLS11
+               case TLS1_1_VERSION:
+                       proto_str = "TLSv1.1";
+                       break;
+#endif
+               case TLS1_VERSION:
+                       proto_str = "TLSv1";
+                       break;
+#ifdef HAVE_SSL3
+               case SSL3_VERSION:
+                       proto_str = "SSLv3";
+                       break;
+#endif
+#ifdef HAVE_SSL2
+               case SSL2_VERSION:
+                       proto_str = "SSLv2";
+                       break;
 #endif
-               case TLS1_VERSION: proto_str = "TLSv1"; break;
-               case SSL3_VERSION: proto_str = "SSLv3"; break;
-               case SSL2_VERSION: proto_str = "SSLv2"; break;
                default: proto_str = "UNKNOWN";
        }
 
@@ -1615,7 +1664,7 @@ static int php_openssl_enable_crypto(php_stream *stream,
                int                             blocked         = sslsock->s.is_blocked,
                                                has_timeout = 0;
 
-#ifdef HAVE_SNI
+#ifdef HAVE_TLS_SNI
                if (sslsock->is_client) {
                        enable_client_sni(stream, sslsock);
                }
@@ -1699,10 +1748,8 @@ static int php_openssl_enable_crypto(php_stream *stream,
 
                                if (PHP_STREAM_CONTEXT(stream)) {
                                        zval *val;
-
                                        if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream),
-                                                       "ssl", "capture_session_meta")) &&
-                                               zend_is_true(val)
+                                               "ssl", "capture_session_meta")) && zend_is_true(val)
                                        ) {
                                                zval meta_arr;
                                                ZVAL_ARR(&meta_arr, capture_session_meta(sslsock->ssl_handle));
@@ -1715,6 +1762,7 @@ static int php_openssl_enable_crypto(php_stream *stream,
                        n = 0;
                } else {
                        n = -1;
+                       /* We want to capture the peer cert even if verification fails*/
                        peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle);
                        if (peer_cert && PHP_STREAM_CONTEXT(stream)) {
                                cert_captured = capture_peer_certs(stream, sslsock, peer_cert);
@@ -2344,20 +2392,20 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen,
                sslsock->enable_on_connect = 1;
                sslsock->method = get_crypto_method(context, STREAM_CRYPTO_METHOD_ANY_CLIENT);
        } else if (strncmp(proto, "sslv2", protolen) == 0) {
-#ifdef OPENSSL_NO_SSL2
-               php_error_docref(NULL, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
-               return NULL;
-#else
+#ifdef HAVE_SSL2
                sslsock->enable_on_connect = 1;
                sslsock->method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT;
+#else
+               php_error_docref(NULL, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library against which PHP is linked");
+               return NULL;
 #endif
        } else if (strncmp(proto, "sslv3", protolen) == 0) {
-#ifdef OPENSSL_NO_SSL3
-               php_error_docref(NULL, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library PHP is linked against");
-               return NULL;
-#else
+#ifdef HAVE_SSL3
                sslsock->enable_on_connect = 1;
                sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
+#else
+               php_error_docref(NULL, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library against which PHP is linked");
+               return NULL;
 #endif
        } else if (strncmp(proto, "tls", protolen) == 0) {
                sslsock->enable_on_connect = 1;
@@ -2366,19 +2414,19 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen,
                sslsock->enable_on_connect = 1;
                sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
        } else if (strncmp(proto, "tlsv1.1", protolen) == 0) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+#ifdef HAVE_TLS11
                sslsock->enable_on_connect = 1;
                sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
 #else
-               php_error_docref(NULL, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against");
+               php_error_docref(NULL, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        } else if (strncmp(proto, "tlsv1.2", protolen) == 0) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+#ifdef HAVE_TLS12
                sslsock->enable_on_connect = 1;
                sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
 #else
-               php_error_docref(NULL, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against");
+               php_error_docref(NULL, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked");
                return NULL;
 #endif
        }