mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
merge from trunk: openssl sni support (rev 289831)
This commit is contained in:
parent
832e181304
commit
7c0803a8ca
@ -1041,6 +1041,11 @@ PHP_MINIT_FUNCTION(openssl)
|
||||
REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
|
||||
/* SNI support included in OpenSSL >= 0.9.8j */
|
||||
REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
|
||||
#endif
|
||||
|
||||
/* Determine default SSL configuration file */
|
||||
config_filename = getenv("OPENSSL_CONF");
|
||||
if (config_filename == NULL) {
|
||||
|
178
ext/openssl/tests/sni_001.phpt
Normal file
178
ext/openssl/tests/sni_001.phpt
Normal file
@ -0,0 +1,178 @@
|
||||
--TEST--
|
||||
SNI 001
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('openssl')) die("skip openssl extension not available");
|
||||
if (!getenv('SNI_TESTS')) die("skip Set SNI_TESTS to enable this test (uses remote resources)");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
/* Server Name Indication (SNI) tests
|
||||
*
|
||||
* This test relies on https://sni.velox.ch/ and thus is disabled by default.
|
||||
*
|
||||
* sni.velox.ch uses 3 certificates :
|
||||
* - CN=alice.sni.velox.ch (sent in response to server_name = alice.sni.velox.ch or not set)
|
||||
* - CN=bob.sni.velox.ch (sent in response to server_name = bob.sni.velox.ch)
|
||||
* - CN=*.sni.velox.ch (sent in response to server_name = mallory.sni.velox.ch or *.sni.velox.ch or sni.velox.ch)
|
||||
*
|
||||
* The test sends requests to the server, sending different names, and checks which certificate
|
||||
* the server returned.
|
||||
*/
|
||||
|
||||
function context() {
|
||||
return stream_context_create(array(
|
||||
'ssl' => array(
|
||||
'capture_peer_cert' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
function get_CN($context) {
|
||||
|
||||
$ary = stream_context_get_options($context);
|
||||
assert($ary);
|
||||
|
||||
$cert = $ary['ssl']['peer_certificate'];
|
||||
assert($cert);
|
||||
|
||||
$cert_ary = openssl_x509_parse($cert);
|
||||
return $cert_ary['subject']['CN'];
|
||||
}
|
||||
|
||||
function do_http_test($url, $context) {
|
||||
|
||||
$fh = fopen($url, 'r', false, $context);
|
||||
assert($fh);
|
||||
|
||||
var_dump(get_CN($context));
|
||||
}
|
||||
|
||||
function do_ssl_test($url, $context) {
|
||||
|
||||
$fh = stream_socket_client($url, $errno, $errstr,
|
||||
ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $context);
|
||||
assert($fh);
|
||||
|
||||
var_dump(get_CN($context));
|
||||
}
|
||||
|
||||
function do_enable_crypto_test($url, $context) {
|
||||
|
||||
$fh = stream_socket_client($url, $errno, $errstr,
|
||||
ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $context);
|
||||
assert($fh);
|
||||
|
||||
$r = stream_socket_enable_crypto($fh, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
|
||||
assert($r);
|
||||
|
||||
var_dump(get_CN($context));
|
||||
}
|
||||
|
||||
/* Test https:// streams */
|
||||
|
||||
echo "-- auto host name (1) --\n";
|
||||
do_http_test('https://alice.sni.velox.ch/', context());
|
||||
|
||||
echo "-- auto host name (2) --\n";
|
||||
do_http_test('https://bob.sni.velox.ch/', context());
|
||||
|
||||
echo "-- auto host name (3) --\n";
|
||||
do_http_test('https://bob.sni.velox.ch./', context());
|
||||
|
||||
echo "-- user supplied server name --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_server_name', 'bob.sni.velox.ch');
|
||||
stream_context_set_option($context, 'http', 'header', b'Host: bob.sni.velox.ch');
|
||||
do_http_test('https://alice.sni.velox.ch/', $context);
|
||||
|
||||
echo "-- sni disabled --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_enabled', false);
|
||||
do_http_test('https://bob.sni.velox.ch/', $context);
|
||||
|
||||
/* Test ssl:// socket streams */
|
||||
|
||||
echo "-- raw SSL stream (1) --\n";
|
||||
do_ssl_test('ssl://bob.sni.velox.ch:443', context());
|
||||
|
||||
echo "-- raw SSL stream (2) --\n";
|
||||
do_ssl_test('ssl://mallory.sni.velox.ch:443', context());
|
||||
|
||||
echo "-- raw SSL stream with user supplied sni --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_server_name', 'bob.sni.velox.ch');
|
||||
|
||||
do_ssl_test('ssl://mallory.sni.velox.ch:443', $context);
|
||||
|
||||
echo "-- raw SSL stream with sni disabled --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_enabled', false);
|
||||
|
||||
do_ssl_test('ssl://mallory.sni.velox.ch:443', $context);
|
||||
|
||||
/* Test tcp:// socket streams with SSL enabled */
|
||||
|
||||
echo "-- stream_socket_enable_crypto (1) --\n";
|
||||
|
||||
do_enable_crypto_test('tcp://bob.sni.velox.ch:443', context());
|
||||
|
||||
echo "-- stream_socket_enable_crypto (2) --\n";
|
||||
|
||||
do_enable_crypto_test('tcp://mallory.sni.velox.ch:443', context());
|
||||
|
||||
echo "-- stream_socket_enable_crypto with user supplied sni --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_server_name', 'bob.sni.velox.ch');
|
||||
|
||||
do_enable_crypto_test('tcp://mallory.sni.velox.ch:443', $context);
|
||||
|
||||
echo "-- stream_socket_enable_crypto with sni disabled --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_enabled', false);
|
||||
|
||||
do_enable_crypto_test('tcp://mallory.sni.velox.ch:443', $context);
|
||||
|
||||
echo "-- stream_socket_enable_crypto with long name --\n";
|
||||
|
||||
$context = context();
|
||||
stream_context_set_option($context, 'ssl', 'SNI_server_name', str_repeat('a.', 500) . '.sni.velox.ch');
|
||||
|
||||
do_enable_crypto_test('tcp://mallory.sni.velox.ch:443', $context);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
-- auto host name (1) --
|
||||
%unicode|string%(18) "alice.sni.velox.ch"
|
||||
-- auto host name (2) --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- auto host name (3) --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- user supplied server name --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- sni disabled --
|
||||
%unicode|string%(18) "alice.sni.velox.ch"
|
||||
-- raw SSL stream (1) --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- raw SSL stream (2) --
|
||||
%unicode|string%(14) "*.sni.velox.ch"
|
||||
-- raw SSL stream with user supplied sni --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- raw SSL stream with sni disabled --
|
||||
%unicode|string%(18) "alice.sni.velox.ch"
|
||||
-- stream_socket_enable_crypto (1) --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- stream_socket_enable_crypto (2) --
|
||||
%unicode|string%(14) "*.sni.velox.ch"
|
||||
-- stream_socket_enable_crypto with user supplied sni --
|
||||
%unicode|string%(16) "bob.sni.velox.ch"
|
||||
-- stream_socket_enable_crypto with sni disabled --
|
||||
%unicode|string%(18) "alice.sni.velox.ch"
|
||||
-- stream_socket_enable_crypto with long name --
|
||||
%unicode|string%(18) "alice.sni.velox.ch"
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "php.h"
|
||||
#include "ext/standard/file.h"
|
||||
#include "ext/standard/url.h"
|
||||
#include "streams/php_streams_int.h"
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "php_network.h"
|
||||
@ -54,6 +55,7 @@ typedef struct _php_openssl_netstream_data_t {
|
||||
int is_client;
|
||||
int ssl_active;
|
||||
php_stream_xport_crypt_method_t method;
|
||||
char *sni;
|
||||
unsigned state_set:1;
|
||||
unsigned _spare:31;
|
||||
} php_openssl_netstream_data_t;
|
||||
@ -283,6 +285,9 @@ static int php_openssl_sockop_close(php_stream *stream, int close_handle TSRMLS_
|
||||
}
|
||||
}
|
||||
|
||||
if (sslsock->sni) {
|
||||
pefree(sslsock->sni, php_stream_is_persistent(stream));
|
||||
}
|
||||
pefree(sslsock, php_stream_is_persistent(stream));
|
||||
|
||||
return 0;
|
||||
@ -393,6 +398,12 @@ static inline int php_openssl_enable_crypto(php_stream *stream,
|
||||
float timeout = sslsock->connect_timeout.tv_sec + sslsock->connect_timeout.tv_usec / 1000000;
|
||||
int blocked = sslsock->s.is_blocked;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
|
||||
if (sslsock->is_client && sslsock->sni) {
|
||||
SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->sni);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sslsock->state_set) {
|
||||
if (sslsock->is_client) {
|
||||
SSL_set_connect_state(sslsock->ssl_handle);
|
||||
@ -759,6 +770,52 @@ php_stream_ops php_openssl_socket_ops = {
|
||||
php_openssl_sockop_set_option,
|
||||
};
|
||||
|
||||
static char * get_sni(php_stream_context *ctx, char *resourcename, long resourcenamelen, int is_persistent TSRMLS_DC) {
|
||||
|
||||
php_url *url;
|
||||
|
||||
if (ctx) {
|
||||
zval **val = NULL;
|
||||
|
||||
if (php_stream_context_get_option(ctx, "ssl", "SNI_enabled", &val) == SUCCESS && !zend_is_true(*val)) {
|
||||
return NULL;
|
||||
}
|
||||
if (php_stream_context_get_option(ctx, "ssl", "SNI_server_name", &val) == SUCCESS) {
|
||||
convert_to_string_ex(val);
|
||||
return pestrdup(Z_STRVAL_PP(val), is_persistent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!resourcename) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
url = php_url_parse_ex(resourcename, resourcenamelen);
|
||||
if (!url) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (url->host) {
|
||||
const char * host = url->host;
|
||||
char * sni = NULL;
|
||||
size_t len = strlen(host);
|
||||
|
||||
/* skip trailing dots */
|
||||
while (len && host[len-1] == '.') {
|
||||
--len;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
sni = pestrndup(host, len, is_persistent);
|
||||
}
|
||||
|
||||
php_url_free(url);
|
||||
return sni;
|
||||
}
|
||||
|
||||
php_url_free(url);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
php_stream *php_openssl_ssl_socket_factory(const char *proto, long protolen,
|
||||
char *resourcename, long resourcenamelen,
|
||||
@ -795,6 +852,8 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, long protolen,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sslsock->sni = get_sni(context, resourcename, resourcenamelen, !!persistent_id TSRMLS_CC);
|
||||
|
||||
if (strncmp(proto, "ssl", protolen) == 0) {
|
||||
sslsock->enable_on_connect = 1;
|
||||
sslsock->method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
|
||||
|
Loading…
Reference in New Issue
Block a user