From: Daniel Lowrey Date: Tue, 11 Feb 2014 15:12:01 +0000 (-0700) Subject: Use crypto method flags; add tlsv1.0 wrapper; add wrapper tests X-Git-Tag: php-5.6.0alpha3~1^2~43^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a9829af2062527fb4e5cb11eb4ac3e045d0b370;p=php Use crypto method flags; add tlsv1.0 wrapper; add wrapper tests --- diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 8d8871b9ff..8b77d28ad1 100755 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1224,6 +1224,7 @@ PHP_MINIT_FUNCTION(openssl) php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC); #endif php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC); + php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory TSRMLS_CC); #if OPENSSL_VERSION_NUMBER >= 0x10001001L php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory TSRMLS_CC); php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory TSRMLS_CC); @@ -1269,6 +1270,7 @@ PHP_MSHUTDOWN_FUNCTION(openssl) #endif php_stream_xport_unregister("sslv3" TSRMLS_CC); php_stream_xport_unregister("tls" TSRMLS_CC); + php_stream_xport_unregister("tlsv1.0" TSRMLS_CC); #if OPENSSL_VERSION_NUMBER >= 0x10001001L php_stream_xport_unregister("tlsv1.1" TSRMLS_CC); php_stream_xport_unregister("tlsv1.2" TSRMLS_CC); diff --git a/ext/openssl/tests/stream_crypto_flags_001.phpt b/ext/openssl/tests/stream_crypto_flags_001.phpt new file mode 100644 index 0000000000..6e3c69b401 --- /dev/null +++ b/ext/openssl/tests/stream_crypto_flags_001.phpt @@ -0,0 +1,58 @@ +--TEST-- +Basic bitwise stream crypto context flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'allow_self_signed' => true +]]); +$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} else if ($pid) { + + // Base SSL context values + $sslCtxVars = array( + 'verify_peer' => TRUE, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local', // common name from the server's "local_cert" PEM file + ); + + // SSLv3 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLSv1 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLS (any) + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLS_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + +} else { + @pcntl_wait($status); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) + diff --git a/ext/openssl/tests/stream_crypto_flags_002.phpt b/ext/openssl/tests/stream_crypto_flags_002.phpt new file mode 100644 index 0000000000..c1d181bc76 --- /dev/null +++ b/ext/openssl/tests/stream_crypto_flags_002.phpt @@ -0,0 +1,67 @@ +--TEST-- +TLSv1.1 and TLSv1.2 bitwise stream crypto flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'allow_self_signed' => true +]]); +$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} else if ($pid) { + + // Base SSL context values + $sslCtxVars = array( + 'verify_peer' => TRUE, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local', // common name from the server's "local_cert" PEM file + ); + + // TLSv1 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLSv1.1 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLSv1.2 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLS (any) + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLS_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + +} else { + @pcntl_wait($status); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) + diff --git a/ext/openssl/tests/stream_crypto_flags_003.phpt b/ext/openssl/tests/stream_crypto_flags_003.phpt new file mode 100644 index 0000000000..8c4dadba0d --- /dev/null +++ b/ext/openssl/tests/stream_crypto_flags_003.phpt @@ -0,0 +1,68 @@ +--TEST-- +Server bitwise stream crypto flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'allow_self_signed' => true, + + // Only accept SSLv3 and TLSv1.2 connections + 'crypto_method' => STREAM_CRYPTO_METHOD_SSLv3_SERVER | STREAM_CRYPTO_METHOD_TLSv1_2_SERVER +]]); +$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} else if ($pid) { + + // Base SSL context values + $sslCtxVars = array( + 'verify_peer' => TRUE, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local', // common name from the server's "local_cert" PEM file + ); + + // TLSv1.2 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // SSLv3 + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLSv1 (should fail) + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + + // TLSv1.1 (should fail) + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx)); + +} else { + @pcntl_wait($status); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +bool(false) +bool(false) + diff --git a/ext/openssl/tests/stream_crypto_flags_005.phpt b/ext/openssl/tests/stream_crypto_flags_005.phpt new file mode 100644 index 0000000000..965471f075 --- /dev/null +++ b/ext/openssl/tests/stream_crypto_flags_005.phpt @@ -0,0 +1,67 @@ +--TEST-- +Specific protocol method specification +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'allow_self_signed' => true, + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_SERVER +]]); + +$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} else if ($pid) { + + // Base SSL context values + $sslCtxVars = array( + 'verify_peer' => FALSE, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'CN_match' => 'bug54992.local', // common name from the server's "local_cert" PEM file + ); + + // Should fail because the SSLv23 hello method is not supported + $ctxCopy = $sslCtxVars; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321")); + + // Should fail because the TLSv1.1 hello method is not supported + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321")); + + // Should fail because the TLSv1.2 hello method is not supported + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(@stream_socket_client("ssl://127.0.0.1:64321")); + + // Should succeed because we use the same TLSv1 hello + $ctxCopy = $sslCtxVars; + $ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; + $ctx = stream_context_create(array('ssl' => $ctxCopy)); + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $ctx)); + +} else { + @pcntl_wait($status); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +} +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) +bool(false) +resource(%d) of type (stream) + diff --git a/ext/openssl/tests/streams_crypto_method.phpt b/ext/openssl/tests/streams_crypto_method.phpt index 6f6bedd633..6eee8df5f4 100644 --- a/ext/openssl/tests/streams_crypto_method.phpt +++ b/ext/openssl/tests/streams_crypto_method.phpt @@ -56,4 +56,3 @@ EOS; ?> --EXPECTF-- Hello World! - diff --git a/ext/openssl/tests/tlsv1.0_wrapper.phpt b/ext/openssl/tests/tlsv1.0_wrapper.phpt new file mode 100644 index 0000000000..5366830187 --- /dev/null +++ b/ext/openssl/tests/tlsv1.0_wrapper.phpt @@ -0,0 +1,47 @@ +--TEST-- +tlsv1.0 stream wrapper +--SKIPIF-- + array( + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', +))); + +$server = stream_socket_server('tlsv1.0://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} elseif ($pid) { + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(array('ssl' => array( + 'verify_peer' => false, + 'verify_host' => false + ))); + + $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + +} else { + @pcntl_wait($status); + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 1); + } +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/ext/openssl/tests/tlsv1.1_wrapper.phpt b/ext/openssl/tests/tlsv1.1_wrapper.phpt new file mode 100644 index 0000000000..82048e525d --- /dev/null +++ b/ext/openssl/tests/tlsv1.1_wrapper.phpt @@ -0,0 +1,47 @@ +--TEST-- +tlsv1.1 stream wrapper +--SKIPIF-- + array( + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', +))); + +$server = stream_socket_server('tlsv1.1://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} elseif ($pid) { + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(array('ssl' => array( + 'verify_peer' => false, + 'verify_host' => false + ))); + + $client = stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + +} else { + @pcntl_wait($status); + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 1); + } +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/ext/openssl/tests/tlsv1.2_wrapper.phpt b/ext/openssl/tests/tlsv1.2_wrapper.phpt new file mode 100644 index 0000000000..d58d1a1262 --- /dev/null +++ b/ext/openssl/tests/tlsv1.2_wrapper.phpt @@ -0,0 +1,47 @@ +--TEST-- +tlsv1.2 stream wrapper +--SKIPIF-- + array( + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', +))); + +$server = stream_socket_server('tlsv1.2://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); +var_dump($server); + +$pid = pcntl_fork(); +if ($pid == -1) { + die('could not fork'); +} elseif ($pid) { + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(array('ssl' => array( + 'verify_peer' => false, + 'verify_host' => false + ))); + + $client = stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + var_dump($client); + +} else { + @pcntl_wait($status); + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 1); + } +} +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 1b2271b128..39e9577641 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -41,6 +41,14 @@ #define HAVE_ECDH #endif +/* Flags for determining allowed stream crypto methods */ +#define STREAM_CRYPTO_IS_CLIENT (1<<0) +#define STREAM_CRYPTO_METHOD_SSLv2 (1<<1) +#define STREAM_CRYPTO_METHOD_SSLv3 (1<<2) +#define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3) +#define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4) +#define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5) + int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC); SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC); int php_openssl_get_x509_list_id(void); @@ -290,14 +298,97 @@ static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb T } +static const SSL_METHOD *php_select_crypto_method(long method_value, int is_client TSRMLS_DC) +{ + if (method_value == STREAM_CRYPTO_METHOD_SSLv2) { +#ifndef OPENSSL_NO_SSL2 + return is_client ? SSLv2_client_method() : SSLv2_server_method(); +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); + return NULL; +#endif + } else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) { + return is_client ? SSLv3_client_method() : SSLv3_server_method(); + } 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 + return is_client ? TLSv1_1_client_method() : TLSv1_1_server_method(); +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); + return NULL; +#endif + } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2) { +#if OPENSSL_VERSION_NUMBER >= 0x10001001L + return is_client ? TLSv1_2_client_method() : TLSv1_2_server_method(); +#else + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); + return NULL; +#endif + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "Invalid crypto method"); + return NULL; + } +} + +static long php_get_crypto_method_ctx_flags(long method_flags TSRMLS_DC) +{ + long ssl_ctx_options = SSL_OP_ALL; + +#ifndef OPENSSL_NO_SSL2 + if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv2)) { + ssl_ctx_options |= SSL_OP_NO_SSLv2; + } +#endif + + if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) { + ssl_ctx_options |= SSL_OP_NO_SSLv3; + } + + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_0)) { + ssl_ctx_options |= SSL_OP_NO_TLSv1; + } + + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_1)) { +#if OPENSSL_VERSION_NUMBER >= 0x10001001L + ssl_ctx_options |= SSL_OP_NO_TLSv1_1; +#endif + } else { +#if OPENSSL_VERSION_NUMBER < 0x10001001L + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); + return -1; +#endif + } + + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_2)) { +#if OPENSSL_VERSION_NUMBER >= 0x10001001L + ssl_ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + } else { +#if OPENSSL_VERSION_NUMBER < 0x10001001L + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against"); + return -1; +#endif + } + + return ssl_ctx_options; +} + static inline int php_openssl_setup_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam TSRMLS_DC) { const SSL_METHOD *method; - long ssl_ctx_options = SSL_OP_ALL; - + long ssl_ctx_options; + long method_flags; + if (sslsock->ssl_handle) { if (sslsock->s.is_blocked) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); @@ -309,89 +400,22 @@ static inline int php_openssl_setup_crypto(php_stream *stream, /* need to do slightly different things, based on client/server method, * so lets remember which method was selected */ - - switch (cparam->inputs.method) { - case STREAM_CRYPTO_METHOD_SSLv23_CLIENT: - sslsock->is_client = 1; - method = SSLv23_client_method(); - break; - case STREAM_CRYPTO_METHOD_SSLv2_CLIENT: -#ifdef OPENSSL_NO_SSL2 - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); + sslsock->is_client = cparam->inputs.method & STREAM_CRYPTO_IS_CLIENT; + method_flags = ((cparam->inputs.method >> 1) << 1); + + /* Should we use a specific crypto method or is generic SSLv23 okay? */ + if ((method_flags & (method_flags-1)) == 0) { + ssl_ctx_options = SSL_OP_ALL; + method = php_select_crypto_method(method_flags, sslsock->is_client TSRMLS_CC); + if (method == NULL) { return -1; -#else - sslsock->is_client = 1; - method = SSLv2_client_method(); - break; -#endif - case STREAM_CRYPTO_METHOD_SSLv3_CLIENT: - sslsock->is_client = 1; - method = SSLv3_client_method(); - break; - case STREAM_CRYPTO_METHOD_TLS_CLIENT: - sslsock->is_client = 1; - method = TLSv1_client_method(); - break; - case STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT: -#if OPENSSL_VERSION_NUMBER >= 0x10001001L - sslsock->is_client = 1; - method = TLSv1_1_client_method(); - break; -#else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); - return -1; -#endif - case STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT: -#if OPENSSL_VERSION_NUMBER >= 0x10001001L - sslsock->is_client = 1; - method = TLSv1_2_client_method(); - break; -#else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against"); - return -1; -#endif - case STREAM_CRYPTO_METHOD_SSLv23_SERVER: - sslsock->is_client = 0; - method = SSLv23_server_method(); - break; - case STREAM_CRYPTO_METHOD_SSLv3_SERVER: - sslsock->is_client = 0; - method = SSLv3_server_method(); - break; - case STREAM_CRYPTO_METHOD_SSLv2_SERVER: -#ifdef OPENSSL_NO_SSL2 - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); - return -1; -#else - sslsock->is_client = 0; - method = SSLv2_server_method(); - break; -#endif - case STREAM_CRYPTO_METHOD_TLS_SERVER: - sslsock->is_client = 0; - method = TLSv1_server_method(); - break; - case STREAM_CRYPTO_METHOD_TLSv1_1_SERVER: -#if OPENSSL_VERSION_NUMBER >= 0x10001001L - sslsock->is_client = 0; - method = TLSv1_1_server_method(); - break; -#else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); - return -1; -#endif - case STREAM_CRYPTO_METHOD_TLSv1_2_SERVER: -#if OPENSSL_VERSION_NUMBER >= 0x10001001L - sslsock->is_client = 0; - method = TLSv1_2_server_method(); - break; -#else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against"); - return -1; -#endif - default: + } + } else { + method = sslsock->is_client ? SSLv23_client_method() : SSLv23_server_method(); + ssl_ctx_options = php_get_crypto_method_ctx_flags(method_flags TSRMLS_CC); + if (ssl_ctx_options == -1) { return -1; - + } } sslsock->ctx = SSL_CTX_new(method); @@ -911,28 +935,9 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ } if (xparam->outputs.client && sock->enable_on_connect) { - /* apply crypto */ - switch (sock->method) { - case STREAM_CRYPTO_METHOD_SSLv23_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_SSLv23_SERVER; - break; - case STREAM_CRYPTO_METHOD_SSLv2_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_SSLv2_SERVER; - break; - case STREAM_CRYPTO_METHOD_SSLv3_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_SSLv3_SERVER; - break; - case STREAM_CRYPTO_METHOD_TLS_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_TLS_SERVER; - break; - case STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_TLSv1_1_SERVER; - break; - case STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT: - sock->method = STREAM_CRYPTO_METHOD_TLSv1_2_SERVER; - break; - default: - break; + /* remove the client bit */ + if (sock->method & STREAM_CRYPTO_IS_CLIENT) { + sock->method = ((sock->method >> 1) << 1); } clisockdata->method = sock->method; @@ -1117,32 +1122,21 @@ php_stream_ops php_openssl_socket_ops = { php_openssl_sockop_set_option, }; -static int get_crypto_method(php_stream_context *ctx) { - if (ctx) { - zval **val = NULL; - long crypto_method; - - if (php_stream_context_get_option(ctx, "ssl", "crypto_method", &val) == SUCCESS) { - convert_to_long_ex(val); - crypto_method = (long)Z_LVAL_PP(val); - - switch (crypto_method) { - case STREAM_CRYPTO_METHOD_SSLv2_CLIENT: - case STREAM_CRYPTO_METHOD_SSLv3_CLIENT: - case STREAM_CRYPTO_METHOD_SSLv23_CLIENT: - case STREAM_CRYPTO_METHOD_TLS_CLIENT: - case STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT: - case STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT: - return crypto_method; - } - - } - } - - return STREAM_CRYPTO_METHOD_SSLv23_CLIENT; +static long get_crypto_method(php_stream_context *ctx, long crypto_method) +{ + zval **val; + + if (ctx && php_stream_context_get_option(ctx, "ssl", "crypto_method", &val) == SUCCESS) { + convert_to_long_ex(val); + crypto_method = (long)Z_LVAL_PP(val); + crypto_method |= STREAM_CRYPTO_IS_CLIENT; + } + + return crypto_method; } -static char * get_url_name(const char *resourcename, size_t resourcenamelen, int is_persistent TSRMLS_DC) { +static char *get_url_name(const char *resourcename, size_t resourcenamelen, int is_persistent TSRMLS_DC) +{ php_url *url; if (!resourcename) { @@ -1184,7 +1178,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, { php_stream *stream = NULL; php_openssl_netstream_data_t *sslsock = NULL; - + sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0); memset(sslsock, 0, sizeof(*sslsock)); @@ -1200,10 +1194,10 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, /* we don't know the socket until we have determined if we are binding or * connecting */ sslsock->s.socket = -1; - + /* Initialize context as NULL */ sslsock->ctx = NULL; - + stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+"); if (stream == NULL) { @@ -1213,12 +1207,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, if (strncmp(proto, "ssl", protolen) == 0) { sslsock->enable_on_connect = 1; - - /* General ssl:// transports can use a number - * of crypto methods. The actual methhod can be - * provided in the streams context options. - */ - sslsock->method = get_crypto_method(context); + 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 TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); @@ -1232,7 +1221,10 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; } else if (strncmp(proto, "tls", protolen) == 0) { sslsock->enable_on_connect = 1; - sslsock->method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + sslsock->method = get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_CLIENT); + } else if (strncmp(proto, "tlsv1.0", protolen) == 0) { + 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 sslsock->enable_on_connect = 1; diff --git a/ext/standard/file.c b/ext/standard/file.c index 0dab6f284a..74df6dc759 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -219,18 +219,22 @@ PHP_MINIT_FUNCTION(file) REGISTER_LONG_CONSTANT("STREAM_CLIENT_ASYNC_CONNECT", PHP_STREAM_CLIENT_ASYNC_CONNECT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CLIENT_CONNECT", PHP_STREAM_CLIENT_CONNECT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv2_CLIENT", STREAM_CRYPTO_METHOD_SSLv2_CLIENT, CONST_CS|CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv3_CLIENT", STREAM_CRYPTO_METHOD_SSLv3_CLIENT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_ANY_CLIENT", STREAM_CRYPTO_METHOD_ANY_CLIENT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv2_CLIENT", STREAM_CRYPTO_METHOD_SSLv2_CLIENT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv3_CLIENT", STREAM_CRYPTO_METHOD_SSLv3_CLIENT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv23_CLIENT", STREAM_CRYPTO_METHOD_SSLv23_CLIENT, CONST_CS|CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLS_CLIENT", STREAM_CRYPTO_METHOD_TLS_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_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); + REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLS_CLIENT", STREAM_CRYPTO_METHOD_TLS_CLIENT, CONST_CS|CONST_PERSISTENT); + 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_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); REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv23_SERVER", STREAM_CRYPTO_METHOD_SSLv23_SERVER, CONST_CS|CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLS_SERVER", STREAM_CRYPTO_METHOD_TLS_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_TLS_SERVER", STREAM_CRYPTO_METHOD_TLS_SERVER, CONST_CS|CONST_PERSISTENT); + 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_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 c599a65d0f..dc10eb4e92 100644 --- a/main/streams/php_stream_transport.h +++ b/main/streams/php_stream_transport.h @@ -163,23 +163,30 @@ typedef struct _php_stream_xport_param { } outputs; } php_stream_xport_param; - -/* These functions provide crypto support on the underlying transport */ +/* Because both client and server streams use the same mechanisms + for encryption we use the LSB to denote clients. +*/ typedef enum { - STREAM_CRYPTO_METHOD_SSLv2_CLIENT, - STREAM_CRYPTO_METHOD_SSLv3_CLIENT, - STREAM_CRYPTO_METHOD_SSLv23_CLIENT, - STREAM_CRYPTO_METHOD_TLS_CLIENT, - STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT, - STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, - STREAM_CRYPTO_METHOD_SSLv2_SERVER, - STREAM_CRYPTO_METHOD_SSLv3_SERVER, - STREAM_CRYPTO_METHOD_SSLv23_SERVER, - STREAM_CRYPTO_METHOD_TLS_SERVER, - STREAM_CRYPTO_METHOD_TLSv1_1_SERVER, - STREAM_CRYPTO_METHOD_TLSv1_2_SERVER + STREAM_CRYPTO_METHOD_SSLv2_CLIENT = (1 << 1 | 1), + STREAM_CRYPTO_METHOD_SSLv3_CLIENT = (1 << 2 | 1), + STREAM_CRYPTO_METHOD_SSLv23_CLIENT = ((1 << 1) | (1 << 2) | 1), + 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_TLS_CLIENT = ((1 << 3) | (1 << 4) | (1 << 5) | 1), + STREAM_CRYPTO_METHOD_ANY_CLIENT = ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | 1), + STREAM_CRYPTO_METHOD_SSLv2_SERVER = (1 << 1), + STREAM_CRYPTO_METHOD_SSLv3_SERVER = (1 << 2), + STREAM_CRYPTO_METHOD_SSLv23_SERVER = ((1 << 1) | (1 << 2)), + 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_TLS_SERVER = ((1 << 3) | (1 << 4) | (1 << 5)), + STREAM_CRYPTO_METHOD_ANY_SERVER = ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5)) } php_stream_xport_crypt_method_t; +/* These functions provide crypto support on the underlying transport */ + BEGIN_EXTERN_C() PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC); PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC);