diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 7fcab17ed66b5..a654fb97d2a77 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1559,6 +1559,9 @@ PHP_MINIT_FUNCTION(openssl) php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory); php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory); php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory); +#if OPENSSL_VERSION_NUMBER >= 0x10101000 + php_stream_xport_register("tlsv1.3", php_openssl_ssl_socket_factory); +#endif /* override the default tcp socket provider */ php_stream_xport_register("tcp", php_openssl_ssl_socket_factory); @@ -1632,6 +1635,9 @@ PHP_MSHUTDOWN_FUNCTION(openssl) php_stream_xport_unregister("tlsv1.0"); php_stream_xport_unregister("tlsv1.1"); php_stream_xport_unregister("tlsv1.2"); +#if OPENSSL_VERSION_NUMBER >= 0x10101000 + php_stream_xport_unregister("tlsv1.3"); +#endif /* reinstate the default tcp handler */ php_stream_xport_register("tcp", php_stream_generic_socket_factory); diff --git a/ext/openssl/tests/session_meta_capture_tlsv13.phpt b/ext/openssl/tests/session_meta_capture_tlsv13.phpt new file mode 100644 index 0000000000000..bb3ac3f71bacd --- /dev/null +++ b/ext/openssl/tests/session_meta_capture_tlsv13.phpt @@ -0,0 +1,50 @@ +--TEST-- +Capture SSL session meta array in stream context for TLSv1.3 +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_SERVER, + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + 'capture_session_meta' => true, + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT); + @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; + var_dump($meta['protocol']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECT-- +string(7) "TLSv1.3" diff --git a/ext/openssl/tests/tlsv1.3_wrapper.phpt b/ext/openssl/tests/tlsv1.3_wrapper.phpt new file mode 100644 index 0000000000000..cc73f7d22d39f --- /dev/null +++ b/ext/openssl/tests/tlsv1.3_wrapper.phpt @@ -0,0 +1,50 @@ +--TEST-- +tlsv1.3 stream wrapper +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server('tlsv1.3://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + + phpt_wait(); + + $client = stream_socket_client("tlsv1.3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 4c4bfaddd3ef9..2a6b693c04769 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -58,6 +58,7 @@ #define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3) #define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4) #define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5) +#define STREAM_CRYPTO_METHOD_TLSv1_3 (1<<6) #ifndef OPENSSL_NO_SSL3 #define HAVE_SSL3 1 @@ -65,11 +66,14 @@ #else #define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_0 #endif -#define PHP_OPENSSL_MAX_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_2 +#define PHP_OPENSSL_MAX_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_3 #define HAVE_TLS11 1 #define HAVE_TLS12 1 +#if OPENSSL_VERSION_NUMBER >= 0x10101000 +#define HAVE_TLS13 1 +#endif #ifndef OPENSSL_NO_ECDH #define HAVE_ECDH 1 @@ -998,6 +1002,11 @@ static int php_openssl_get_crypto_method_ctx_flags(int method_flags) /* {{{ */ ssl_ctx_options |= SSL_OP_NO_TLSv1_2; } #endif +#ifdef HAVE_TLS13 + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_3)) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_3; + } +#endif return ssl_ctx_options; } @@ -1012,7 +1021,7 @@ static inline int php_openssl_get_min_proto_version_flag(int flags) /* {{{ */ return ver; } } - return STREAM_CRYPTO_METHOD_TLSv1_2; + return STREAM_CRYPTO_METHOD_TLSv1_3; } /* }}} */ @@ -1024,7 +1033,7 @@ static inline int php_openssl_get_max_proto_version_flag(int flags) /* {{{ */ return ver; } } - return STREAM_CRYPTO_METHOD_TLSv1_2; + return STREAM_CRYPTO_METHOD_TLSv1_3; } /* }}} */ @@ -1040,9 +1049,13 @@ static inline int php_openssl_map_proto_version(int flag) /* {{{ */ return TLS1_VERSION; case STREAM_CRYPTO_METHOD_TLSv1_1: return TLS1_1_VERSION; - /* case STREAM_CRYPTO_METHOD_TLSv1_2: */ + case STREAM_CRYPTO_METHOD_TLSv1_2: + return TLS1_2_VERSION; + /* case STREAM_CRYPTO_METHOD_TLSv1_3: */ +#ifdef HAVE_TLS13 default: - return TLS1_2_VERSION; + return TLS1_3_VERSION; +#endif } } @@ -1788,6 +1801,11 @@ static zend_array *php_openssl_capture_session_meta(SSL *ssl_handle) /* {{{ */ char version_str[PHP_SSL_MAX_VERSION_LEN]; switch (proto) { +#ifdef HAVE_TLS13 + case TLS1_3_VERSION: + proto_str = "TLSv1.3"; + break; +#endif #ifdef HAVE_TLS12 case TLS1_2_VERSION: proto_str = "TLSv1.2"; @@ -2392,6 +2410,9 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val array_init(&tmp); switch (SSL_version(sslsock->ssl_handle)) { +#ifdef HAVE_TLS13 + case TLS1_3_VERSION: proto_str = "TLSv1.3"; break; +#endif #ifdef HAVE_TLS12 case TLS1_2_VERSION: proto_str = "TLSv1.2"; break; #endif @@ -2739,6 +2760,16 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked"); php_stream_close(stream); return NULL; +#endif + } else if (strncmp(proto, "tlsv1.3", protolen) == 0) { +#ifdef HAVE_TLS13 + sslsock->enable_on_connect = 1; + sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT; +#else + php_error_docref(NULL, E_WARNING, + "TLSv1.3 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; #endif } diff --git a/ext/standard/file.c b/ext/standard/file.c index 2eed1562b9323..fc1b55ab4e877 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -217,6 +217,7 @@ PHP_MINIT_FUNCTION(file) REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT", STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT", STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT", STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT", STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_ANY_SERVER", STREAM_CRYPTO_METHOD_ANY_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv2_SERVER", STREAM_CRYPTO_METHOD_SSLv2_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv3_SERVER", STREAM_CRYPTO_METHOD_SSLv3_SERVER, CONST_CS|CONST_PERSISTENT); @@ -225,11 +226,13 @@ PHP_MINIT_FUNCTION(file) REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_0_SERVER", STREAM_CRYPTO_METHOD_TLSv1_0_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_1_SERVER", STREAM_CRYPTO_METHOD_TLSv1_1_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_2_SERVER", STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLSv1_3_SERVER", STREAM_CRYPTO_METHOD_TLSv1_3_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_PROTO_SSLv3", STREAM_CRYPTO_METHOD_SSLv3_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_PROTO_TLSv1_0", STREAM_CRYPTO_METHOD_TLSv1_0_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_PROTO_TLSv1_1", STREAM_CRYPTO_METHOD_TLSv1_1_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_PROTO_TLSv1_2", STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_PROTO_TLSv1_3", STREAM_CRYPTO_METHOD_TLSv1_3_SERVER, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_SHUT_RD", STREAM_SHUT_RD, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_SHUT_WR", STREAM_SHUT_WR, CONST_CS|CONST_PERSISTENT); diff --git a/main/streams/php_stream_transport.h b/main/streams/php_stream_transport.h index a4a851b399967..9ae5d13d422e2 100644 --- a/main/streams/php_stream_transport.h +++ b/main/streams/php_stream_transport.h @@ -171,6 +171,7 @@ typedef enum { STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT = (1 << 3 | 1), STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT = (1 << 4 | 1), STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT = (1 << 5 | 1), + STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT = (1 << 6 | 1), /* TLS equates to TLS_ANY as of PHP 7.2 */ STREAM_CRYPTO_METHOD_TLS_CLIENT = ((1 << 3) | (1 << 4) | (1 << 5) | 1), STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT = ((1 << 3) | (1 << 4) | (1 << 5) | 1), @@ -182,6 +183,7 @@ typedef enum { STREAM_CRYPTO_METHOD_TLSv1_0_SERVER = (1 << 3), STREAM_CRYPTO_METHOD_TLSv1_1_SERVER = (1 << 4), STREAM_CRYPTO_METHOD_TLSv1_2_SERVER = (1 << 5), + STREAM_CRYPTO_METHOD_TLSv1_3_SERVER = (1 << 6), /* TLS equates to TLS_ANY as of PHP 7.2 */ STREAM_CRYPTO_METHOD_TLS_SERVER = ((1 << 3) | (1 << 4) | (1 << 5)), STREAM_CRYPTO_METHOD_TLS_ANY_SERVER = ((1 << 3) | (1 << 4) | (1 << 5)),