From: Daniel Lowrey Date: Fri, 21 Feb 2014 00:46:54 +0000 (-0700) Subject: Merge branch 'PHP-5.6' X-Git-Tag: PRE_PHPNG_MERGE~504^2~46 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86d9235de5b0fd5576e01c601f1bd04333d13ba3;p=php Merge branch 'PHP-5.6' * 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 --- 86d9235de5b0fd5576e01c601f1bd04333d13ba3 diff --cc ext/openssl/xp_ssl.c index 6f4b6303ad,7104cb07b6..538a9d68e3 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@@ -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); } @@@ -416,17 -430,36 +430,36 @@@ #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 + 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) ++ 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"); @@@ -435,6 -468,18 +468,18 @@@ return -1; } + 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); + } + + #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); } @@@ -451,8 -496,193 +496,195 @@@ 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; @@@ -576,6 -796,18 +798,18 @@@ if (stream->context) { zval **val, *zcert; + if (SUCCESS == php_stream_context_get_option( + stream->context, "ssl", + "capture_session_meta", &val) && - zend_is_true(*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) &&