]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-5.6'
authorDaniel Lowrey <rdlowrey@php.net>
Fri, 21 Feb 2014 00:46:54 +0000 (17:46 -0700)
committerDaniel Lowrey <rdlowrey@php.net>
Fri, 21 Feb 2014 00:46:54 +0000 (17:46 -0700)
* PHP-5.6:
  Improve OpenSSL compile flag compatibility, minor updates
  Use crypto method flags; add tlsv1.0 wrapper; add wrapper tests
  Improve server forward secrecy, refactor client SNI
  Add 'honor_cipher_order' server context option
  Add 'capture_session_meta' context option
  Disable TLS compression by default in both clients and servers
  Release ssl buffers
  Add openssl_get_cert_locations() function
  Explicitly set cert verify depth if not specified
  Strengthen default cipher list

1  2 
ext/openssl/openssl.c
ext/openssl/xp_ssl.c

Simple merge
index 6f4b6303ad2fcf11bbf0f3a5c4d3d9aba5aa353d,7104cb07b6f7a1d6b534dbc1a385d324337a042c..538a9d68e30690e2d5ab9183aae6d0d86e83da67
@@@ -403,11 -419,9 +419,9 @@@ static inline int php_openssl_setup_cry
  
  #if OPENSSL_VERSION_NUMBER >= 0x0090806fL
        {
-               zval **val;
                if (stream->context && SUCCESS == php_stream_context_get_option(
                                        stream->context, "ssl", "no_ticket", &val) && 
 -                              zend_is_true(*val)
 +                              zend_is_true(*val TSRMLS_CC)
                ) {
                        SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_TICKET);
                }
  
  #if OPENSSL_VERSION_NUMBER >= 0x10000000L
        {
-               zval **val;
-               if (stream->context && SUCCESS == php_stream_context_get_option(
-                                       stream->context, "ssl", "disable_compression", &val) &&
-                               zend_is_true(*val TSRMLS_CC)
+               if (stream->context && (FAILURE == php_stream_context_get_option(
+                                       stream->context, "ssl", "disable_compression", &val) ||
 -                              zend_is_true(*val))
++                              zend_is_true(*val TSRMLS_CC))
                ) {
                        SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_COMPRESSION);
                }
        }
  #endif
  
 -                      zend_is_true(*val)
+       if (!sslsock->is_client && stream->context && SUCCESS == php_stream_context_get_option(
+                               stream->context, "ssl", "honor_cipher_order", &val) &&
 -                      zend_is_true(*val)
++                      zend_is_true(*val TSRMLS_CC)
+       ) {
+               SSL_CTX_set_options(sslsock->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+       }
+       if (!sslsock->is_client && stream->context && SUCCESS == php_stream_context_get_option(
+                               stream->context, "ssl", "single_dh_use", &val) &&
 -                      zend_is_true(*val)
++                      zend_is_true(*val TSRMLS_CC)
+       ) {
+               SSL_CTX_set_options(sslsock->ctx, SSL_OP_SINGLE_DH_USE);
+       }
+       if (!sslsock->is_client && stream->context && SUCCESS == php_stream_context_get_option(
+                               stream->context, "ssl", "single_ecdh_use", &val) &&
++                      zend_is_true(*val TSRMLS_CC)
+       ) {
+               SSL_CTX_set_options(sslsock->ctx, SSL_OP_SINGLE_ECDH_USE);
+       }
        sslsock->ssl_handle = php_SSL_new_from_context(sslsock->ctx, stream TSRMLS_CC);
        if (sslsock->ssl_handle == NULL) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create an SSL handle");
                return -1;
        }
  
 -                      zend_is_true(*val)
+       if (!sslsock->is_client && stream->context && SUCCESS == php_stream_context_get_option(
+                               stream->context, "ssl", "honor_cipher_order", &val) &&
++                      zend_is_true(*val TSRMLS_CC)
+       ) {
+               SSL_CTX_set_options(sslsock->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+       }
+ #ifdef SSL_MODE_RELEASE_BUFFERS
+       long mode = SSL_get_mode(sslsock->ssl_handle);
+       SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_RELEASE_BUFFERS);
+ #endif
        if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) {
                handle_ssl_error(stream, 0, 1 TSRMLS_CC);
        }
        return 0;
  }
  
+ static zval *php_capture_ssl_session_meta(SSL *ssl_handle)
+ {
+       zval *meta_arr;
+       char *proto_str;
+       long proto = SSL_version(ssl_handle);
+       const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl_handle);
+       switch (proto) {
+               case TLS1_2_VERSION: proto_str = "TLSv1.2"; break;
+               case TLS1_1_VERSION: proto_str = "TLSv1.1"; break;
+               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";
+       }
+       MAKE_STD_ZVAL(meta_arr);
+       array_init(meta_arr);
+       add_assoc_string(meta_arr, "protocol", proto_str, 1);
+       add_assoc_string(meta_arr, "cipher_name", (char *) SSL_CIPHER_get_name(cipher), 1);
+       add_assoc_long(meta_arr, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL));
+       add_assoc_string(meta_arr, "cipher_version", SSL_CIPHER_get_version(cipher), 1);
  
- static inline int php_openssl_enable_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam TSRMLS_DC)
+       return meta_arr;
+ }
+ static int php_set_server_rsa_key(php_stream *stream,
+       php_openssl_netstream_data_t *sslsock
+       TSRMLS_DC)
+ {
+       zval ** val;
+       int rsa_key_size;
+       RSA* rsa;
+       int retval = 1;
+       if (php_stream_context_get_option(stream->context, "ssl", "rsa_key_size", &val) == SUCCESS) {
+               rsa_key_size = (int) Z_LVAL_PP(val);
+               if ((rsa_key_size != 1) && (rsa_key_size & (rsa_key_size - 1))) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                               "RSA key size requires a power of 2: %d",
+                               rsa_key_size);
+                       rsa_key_size = 2048;
+               }
+       } else {
+               rsa_key_size = 2048;
+       }
+       rsa = RSA_generate_key(rsa_key_size, RSA_F4, NULL, NULL);
+       if (!SSL_set_tmp_rsa(sslsock->ssl_handle, rsa)) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Failed setting RSA key");
+               retval = 0;
+       }
+       RSA_free(rsa);
+       return retval;
+ }
+ static int php_set_server_dh_param(php_openssl_netstream_data_t *sslsock,
+       char *dh_path
+       TSRMLS_DC)
+ {
+       DH *dh;
+       BIO* bio;
+       bio = BIO_new_file(dh_path, "r");
+       if (bio == NULL) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Invalid dh_param file: %s",
+                       dh_path);
+               return 0;
+       }
+       dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+       BIO_free(bio);
+       if (dh == NULL) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Failed reading DH params from file: %s",
+                       dh_path);
+               return 0;
+       }
+       if (SSL_set_tmp_dh(sslsock->ssl_handle, dh) < 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "DH param assignment failed");
+               DH_free(dh);
+               return 0;
+       }
+       DH_free(dh);
+       return 1;
+ }
+ static int php_enable_server_crypto_opts(php_stream *stream,
+       php_openssl_netstream_data_t *sslsock
+       TSRMLS_DC)
+ {
+       zval **val;
+       if (php_stream_context_get_option(stream->context, "ssl", "dh_param", &val) == SUCCESS) {
+               convert_to_string_ex(val);
+               if (!php_set_server_dh_param(sslsock,  Z_STRVAL_PP(val) TSRMLS_CC)) {
+                       return 0;
+               }
+       }
+ #ifdef HAVE_ECDH
+       int curve_nid;
+       EC_KEY *ecdh;
+       if (php_stream_context_get_option(stream->context, "ssl", "ecdh_curve", &val) == SUCCESS) {
+               char *curve_str;
+               convert_to_string_ex(val);
+               curve_str = Z_STRVAL_PP(val);
+               curve_nid = OBJ_sn2nid(curve_str);
+               if (curve_nid == NID_undef) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                               "Invalid ECDH curve: %s",
+                               curve_str);
+                       return 0;
+               }
+       } else {
+               curve_nid = NID_X9_62_prime256v1;
+       }
+       ecdh = EC_KEY_new_by_curve_name(curve_nid);
+       if (ecdh == NULL) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Failed generating ECDH curve");
+               return 0;
+       }
+       SSL_set_tmp_ecdh(sslsock->ssl_handle, ecdh);
+       EC_KEY_free(ecdh);
+ #else
+       if (php_stream_context_get_option(stream->context, "ssl", "ecdh_curve", &val) == SUCCESS) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "ECDH curve support not compiled into the OpenSSL lib against which PHP is linked");
+       }
+ #endif
+       if (!php_set_server_rsa_key(stream, sslsock TSRMLS_CC)) {
+               return 0;
+       }
+       return 1;
+ }
+ static inline void enable_client_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */
+ {
+       zval **val;
++      TSRMLS_FETCH();
++
+       if (stream->context &&
+             (php_stream_context_get_option(stream->context, "ssl", "SNI_enabled", &val) == FAILURE
 -                || zend_is_true(*val))
++                || zend_is_true(*val TSRMLS_CC))
+       ) {
+               if (php_stream_context_get_option(stream->context, "ssl", "SNI_server_name", &val) == SUCCESS) {
+                       convert_to_string_ex(val);
+                       SSL_set_tlsext_host_name(sslsock->ssl_handle, Z_STRVAL_PP(val));
+               } else if (sslsock->url_name) {
+                       SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->url_name);
+               }
+       } else if (!stream->context && sslsock->url_name) {
+               SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->url_name);
+       }
+ }
+ /* }}} */
+ static inline int php_openssl_enable_crypto(php_stream *stream,
+               php_openssl_netstream_data_t *sslsock,
+               php_stream_xport_crypto_param *cparam
+               TSRMLS_DC)
  {
        int n, retry = 1;
  
                                if (stream->context) {
                                        zval **val, *zcert;
  
 -                                                      zend_is_true(*val)) {
+                                       if (SUCCESS == php_stream_context_get_option(
+                                                               stream->context, "ssl",
+                                                               "capture_session_meta", &val) &&
++                                                      zend_is_true(*val TSRMLS_CC)) {
+                                               zval *meta_arr = php_capture_ssl_session_meta(sslsock->ssl_handle);
+                                               php_stream_context_set_option(stream->context,
+                                                               "ssl", "session_meta",
+                                                               meta_arr);
+                                               zval_dtor(meta_arr);
+                                               efree(meta_arr);
+                                       }
                                        if (SUCCESS == php_stream_context_get_option(
                                                                stream->context, "ssl",
                                                                "capture_peer_cert", &val) &&