Skip to content

Commit

Permalink
Merge branch 'PHP-5.6'
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
rdlowrey committed Feb 21, 2014
2 parents 0140e83 + dcf27a1 commit 86d9235
Show file tree
Hide file tree
Showing 15 changed files with 920 additions and 191 deletions.
44 changes: 43 additions & 1 deletion ext/openssl/openssl.c
Expand Up @@ -83,6 +83,15 @@
#define HAVE_EVP_PKEY_EC 1 #define HAVE_EVP_PKEY_EC 1
#endif #endif


#define PHP_OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH 9
#define PHP_OPENSSL_DEFAULT_STREAM_CIPHERS "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:" \
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
"DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:" \
"ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:" \
"ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:" \
"DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:" \
"AES256-GCM-SHA384:AES128:AES256:HIGH:!SSLv2:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!RC4:!ADH"

/* FIXME: Use the openssl constants instead of /* FIXME: Use the openssl constants instead of
* enum. It is now impossible to match real values * enum. It is now impossible to match real values
* against php constants. Also sorry to break the * against php constants. Also sorry to break the
Expand Down Expand Up @@ -424,11 +433,16 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0) ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0)
ZEND_ARG_INFO(0, spki) ZEND_ARG_INFO(0, spki)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_openssl_get_cert_locations, 0)
ZEND_END_ARG_INFO()
/* }}} */ /* }}} */


/* {{{ openssl_functions[] /* {{{ openssl_functions[]
*/ */
const zend_function_entry openssl_functions[] = { const zend_function_entry openssl_functions[] = {
PHP_FE(openssl_get_cert_locations, arginfo_openssl_get_cert_locations)

/* spki functions */ /* spki functions */
PHP_FE(openssl_spki_new, arginfo_openssl_spki_new) PHP_FE(openssl_spki_new, arginfo_openssl_spki_new)
PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify) PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify)
Expand Down Expand Up @@ -1151,6 +1165,10 @@ PHP_MINIT_FUNCTION(openssl)
REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);


/* Informational stream wrapper constants */
REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", PHP_OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH", PHP_OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH, CONST_CS|CONST_PERSISTENT);

/* Ciphers */ /* Ciphers */
#ifndef OPENSSL_NO_RC2 #ifndef OPENSSL_NO_RC2
REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
Expand Down Expand Up @@ -1206,6 +1224,7 @@ PHP_MINIT_FUNCTION(openssl)
php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC); php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
#endif #endif
php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC); 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 #if OPENSSL_VERSION_NUMBER >= 0x10001001L
php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory TSRMLS_CC); 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); php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory TSRMLS_CC);
Expand Down Expand Up @@ -1251,6 +1270,7 @@ PHP_MSHUTDOWN_FUNCTION(openssl)
#endif #endif
php_stream_xport_unregister("sslv3" TSRMLS_CC); php_stream_xport_unregister("sslv3" TSRMLS_CC);
php_stream_xport_unregister("tls" TSRMLS_CC); php_stream_xport_unregister("tls" TSRMLS_CC);
php_stream_xport_unregister("tlsv1.0" TSRMLS_CC);
#if OPENSSL_VERSION_NUMBER >= 0x10001001L #if OPENSSL_VERSION_NUMBER >= 0x10001001L
php_stream_xport_unregister("tlsv1.1" TSRMLS_CC); php_stream_xport_unregister("tlsv1.1" TSRMLS_CC);
php_stream_xport_unregister("tlsv1.2" TSRMLS_CC); php_stream_xport_unregister("tlsv1.2" TSRMLS_CC);
Expand All @@ -1267,6 +1287,26 @@ PHP_MSHUTDOWN_FUNCTION(openssl)


/* {{{ x509 cert functions */ /* {{{ x509 cert functions */


/* {{{ proto array openssl_get_cert_locations(void)
Retrieve an array mapping available certificate locations */
PHP_FUNCTION(openssl_get_cert_locations)
{
array_init(return_value);

add_assoc_string(return_value, "default_cert_file", (char *) X509_get_default_cert_file(), 1);
add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env(), 1);
add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir(), 1);
add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env(), 1);
add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir(), 1);
add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area(), 1);
add_assoc_string(return_value, "ini_cafile",
zend_ini_string("openssl.cafile", sizeof("openssl.cafile"), 0), 1);
add_assoc_string(return_value, "ini_capath",
zend_ini_string("openssl.capath", sizeof("openssl.capath"), 0), 1);
}
/* }}} */


/* {{{ php_openssl_x509_from_zval /* {{{ php_openssl_x509_from_zval
Given a zval, coerce it into an X509 object. Given a zval, coerce it into an X509 object.
The zval can be: The zval can be:
Expand Down Expand Up @@ -5328,6 +5368,8 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
if (GET_VER_OPT("verify_depth")) { if (GET_VER_OPT("verify_depth")) {
convert_to_long_ex(val); convert_to_long_ex(val);
SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val)); SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val));
} else {
SSL_CTX_set_verify_depth(ctx, PHP_OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH);
} }
} }


Expand All @@ -5339,7 +5381,7 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{


GET_VER_OPT_STRING("ciphers", cipherlist); GET_VER_OPT_STRING("ciphers", cipherlist);
if (!cipherlist) { if (!cipherlist) {
cipherlist = "DEFAULT"; cipherlist = PHP_OPENSSL_DEFAULT_STREAM_CIPHERS;
} }
if (SSL_CTX_set_cipher_list(ctx, cipherlist) != 1) { if (SSL_CTX_set_cipher_list(ctx, cipherlist) != 1) {
return NULL; return NULL;
Expand Down
2 changes: 2 additions & 0 deletions ext/openssl/php_openssl.h
Expand Up @@ -85,6 +85,8 @@ PHP_FUNCTION(openssl_spki_new);
PHP_FUNCTION(openssl_spki_verify); PHP_FUNCTION(openssl_spki_verify);
PHP_FUNCTION(openssl_spki_export); PHP_FUNCTION(openssl_spki_export);
PHP_FUNCTION(openssl_spki_export_challenge); PHP_FUNCTION(openssl_spki_export_challenge);

PHP_FUNCTION(openssl_get_cert_locations);
#else #else


#define phpext_openssl_ptr NULL #define phpext_openssl_ptr NULL
Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/tests/bug66501.phpt
Expand Up @@ -3,7 +3,7 @@ Bug #66501: EC private key support in openssl_sign
--SKIPIF-- --SKIPIF--
<?php <?php
if (!extension_loaded("openssl")) die("skip"); if (!extension_loaded("openssl")) die("skip");
if (!defined(OPENSSL_KEYTYPE_EC)) die("skip no EC available); if (!defined('OPENSSL_KEYTYPE_EC')) die("skip no EC available");
--FILE-- --FILE--
<?php <?php
$pkey = 'ASN1 OID: prime256v1 $pkey = 'ASN1 OID: prime256v1
Expand Down
73 changes: 73 additions & 0 deletions ext/openssl/tests/session_meta_capture.phpt
@@ -0,0 +1,73 @@
--TEST--
Capture SSL session meta array in stream context
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip");
if (!function_exists('pcntl_fork')) die("skip no fork");
if (OPENSSL_VERSION_NUMBER < 0x10001001) die("skip OpenSSLv1.0.1 required");
--FILE--
<?php
$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'local_cert' => __DIR__ . '/bug54992.pem',
'allow_self_signed' => true
]]);
$server = stream_socket_server('ssl://127.0.0.1:64321', $errno, $errstr, $flags, $ctx);

$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
'capture_session_meta' => TRUE
);

// SSLv3
$ctxCopy = $sslCtxVars;
$ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
$ctx = stream_context_create(array('ssl' => $ctxCopy));
stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx);
$meta = stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta['protocol']);

// TLSv1
$ctxCopy = $sslCtxVars;
$ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
$ctx = stream_context_create(array('ssl' => $ctxCopy));
stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx);
$meta = stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta['protocol']);

// TLSv1.1
$ctxCopy = $sslCtxVars;
$ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
$ctx = stream_context_create(array('ssl' => $ctxCopy));
stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx);
$meta = stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta['protocol']);

// TLSv1.2
$ctxCopy = $sslCtxVars;
$ctxCopy['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
$ctx = stream_context_create(array('ssl' => $ctxCopy));
stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $ctx);
$meta = stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta['protocol']);

} 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--
string(5) "SSLv3"
string(5) "TLSv1"
string(7) "TLSv1.1"
string(7) "TLSv1.2"
58 changes: 58 additions & 0 deletions ext/openssl/tests/stream_crypto_flags_001.phpt
@@ -0,0 +1,58 @@
--TEST--
Basic bitwise stream crypto context flag assignment
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip");
if (!function_exists('pcntl_fork')) die("skip no fork");
--FILE--
<?php
$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'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)

67 changes: 67 additions & 0 deletions ext/openssl/tests/stream_crypto_flags_002.phpt
@@ -0,0 +1,67 @@
--TEST--
TLSv1.1 and TLSv1.2 bitwise stream crypto flag assignment
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip");
if (!function_exists('pcntl_fork')) die("skip no fork");
if (OPENSSL_VERSION_NUMBER < 0x10001001) die("skip OpenSSLv1.0.1 required");
--FILE--
<?php
$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'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)

68 changes: 68 additions & 0 deletions ext/openssl/tests/stream_crypto_flags_003.phpt
@@ -0,0 +1,68 @@
--TEST--
Server bitwise stream crypto flag assignment
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip");
if (!function_exists('pcntl_fork')) die("skip no fork");
if (OPENSSL_VERSION_NUMBER < 0x10001001) die("skip OpenSSLv1.0.1 required");
--FILE--
<?php
$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'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)

0 comments on commit 86d9235

Please sign in to comment.