com php-src: Capture peer cert even if verify fails: NEWS ext/openssl/tests/capture_peer_cert_001.phpt ex t/openssl/xp_ssl.c

From: Date: Sun, 02 Mar 2014 17:35:52 +0000
Subject: com php-src: Capture peer cert even if verify fails: NEWS ext/openssl/tests/capture_peer_cert_001.phpt ex t/openssl/xp_ssl.c
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-76306@lists.php.net to get a copy of this message
Commit: c126c16479c13e5fcbb57e6fe2341736c37edf36 Author: Daniel Lowrey <rdlowrey@php.net> Sun, 2 Mar 2014 07:03:39 -0700 Parents: e8995c8cb064d36396c4570135815827aa991058 Branches: PHP-5.6 Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=c126c16479c13e5fcbb57e6fe2341736c37edf36 Log: Capture peer cert even if verify fails Previously the "capture_peer_cert" SSL context option only captured the peer's certificate if the verification routine succeeded. By also capturing the on verify failure applications have the ability to parse the cert and ask users whether they wish to proceed given the information presented by the peer. Changed paths: M NEWS A ext/openssl/tests/capture_peer_cert_001.phpt M ext/openssl/xp_ssl.c Diff: diff --git a/NEWS b/NEWS index 1adb05e..3ba4a1c 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,12 @@ PHP NEWS - Core: . Allow zero length comparison in substr_compare() (Tjerk) +- Openssl: + . Fixed memory leak in windows cert verification on verify failure. + (Chris Wright) + . Peer certificate capturing via SSL context options now functions even if + peer verification fails. (Daniel Lowrey) + ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 27 Feb 2014, PHP 5.6.0 Alpha 3 diff --git a/ext/openssl/tests/capture_peer_cert_001.phpt b/ext/openssl/tests/capture_peer_cert_001.phpt new file mode 100644 index 0000000..2cec06a --- /dev/null +++ b/ext/openssl/tests/capture_peer_cert_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +capture_peer_cert context captures on verify failure +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip openssl not loaded"); +if (!function_exists("proc_open")) die("skip no proc_open"); +--FILE-- +<?php +$serverCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; + $serverCtx = stream_context_create(['ssl' => [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'capture_peer_cert' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem' + ]]); + + phpt_wait(); + $client = @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + $cert = stream_context_get_options($clientCtx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(%d) "bug54992.local" diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 7424cd8..d63519e 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -822,12 +822,67 @@ static inline void enable_client_sni(php_stream *stream, php_openssl_netstream_d /* }}} */ #endif +static int capture_peer_certs(php_stream *stream, + php_openssl_netstream_data_t *sslsock, + X509 *peer_cert + TSRMLS_DC) +{ + zval **val, *zcert; + int cert_captured = 0; + + if (SUCCESS == php_stream_context_get_option(stream->context, + "ssl", "capture_peer_cert", &val) && + zend_is_true(*val) + ) { + MAKE_STD_ZVAL(zcert); + ZVAL_RESOURCE(zcert, zend_list_insert(peer_cert, php_openssl_get_x509_list_id() TSRMLS_CC)); + php_stream_context_set_option(stream->context, "ssl", "peer_certificate", zcert); + cert_captured = 1; + FREE_ZVAL(zcert); + } + + if (SUCCESS == php_stream_context_get_option(stream->context, + "ssl", "capture_peer_cert_chain", &val) && + zend_is_true(*val) + ) { + zval *arr; + STACK_OF(X509) *chain; + + MAKE_STD_ZVAL(arr); + chain = SSL_get_peer_cert_chain(sslsock->ssl_handle); + + if (chain && sk_X509_num(chain) > 0) { + int i; + array_init(arr); + + for (i = 0; i < sk_X509_num(chain); i++) { + X509 *mycert = X509_dup(sk_X509_value(chain, i)); + MAKE_STD_ZVAL(zcert); + ZVAL_RESOURCE(zcert, zend_list_insert(mycert, php_openssl_get_x509_list_id() TSRMLS_CC)); + add_next_index_zval(arr, zcert); + } + + } else { + ZVAL_NULL(arr); + } + + php_stream_context_set_option(stream->context, "ssl", "peer_certificate_chain", arr); + zval_dtor(arr); + efree(arr); + } + + return cert_captured; +} + 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; + int n; + int retry = 1; + int cert_captured; + X509 *peer_cert; if (cparam->inputs.activate && !sslsock->ssl_active) { struct timeval start_time, @@ -924,9 +979,10 @@ static inline int php_openssl_enable_crypto(php_stream *stream, } if (n == 1) { - X509 *peer_cert; - peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); + if (peer_cert && stream->context) { + cert_captured = capture_peer_certs(stream, sslsock, peer_cert TSRMLS_CC); + } if (FAILURE == php_openssl_apply_verification_policy(sslsock->ssl_handle, peer_cert, stream TSRMLS_CC)) { SSL_shutdown(sslsock->ssl_handle); @@ -934,80 +990,32 @@ static inline int php_openssl_enable_crypto(php_stream *stream, } else { sslsock->ssl_active = 1; - /* allow the script to capture the peer cert - * and/or the certificate chain */ if (stream->context) { - zval **val, *zcert; + zval **val; - if (SUCCESS == php_stream_context_get_option( - stream->context, "ssl", - "capture_session_meta", &val) && - zend_is_true(*val)) { + if (SUCCESS == php_stream_context_get_option(stream->context, + "ssl", "capture_session_meta", &val) && + zend_is_true(*val) + ) { zval *meta_arr = php_capture_ssl_session_meta(sslsock->ssl_handle); - php_stream_context_set_option(stream->context, - "ssl", "session_meta", - meta_arr); + 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) && - zend_is_true(*val)) { - MAKE_STD_ZVAL(zcert); - ZVAL_RESOURCE(zcert, zend_list_insert(peer_cert, - php_openssl_get_x509_list_id() TSRMLS_CC)); - php_stream_context_set_option(stream->context, - "ssl", "peer_certificate", - zcert); - peer_cert = NULL; - FREE_ZVAL(zcert); - } - - if (SUCCESS == php_stream_context_get_option( - stream->context, "ssl", - "capture_peer_cert_chain", &val) && - zend_is_true(*val)) { - zval *arr; - STACK_OF(X509) *chain; - - MAKE_STD_ZVAL(arr); - chain = SSL_get_peer_cert_chain( - sslsock->ssl_handle); - - if (chain && sk_X509_num(chain) > 0) { - int i; - array_init(arr); - - for (i = 0; i < sk_X509_num(chain); i++) { - X509 *mycert = X509_dup( - sk_X509_value(chain, i)); - MAKE_STD_ZVAL(zcert); - ZVAL_RESOURCE(zcert, - zend_list_insert(mycert, - php_openssl_get_x509_list_id() TSRMLS_CC)); - add_next_index_zval(arr, zcert); - } - - } else { - ZVAL_NULL(arr); - } - - php_stream_context_set_option(stream->context, - "ssl", "peer_certificate_chain", - arr); - zval_dtor(arr); - efree(arr); - } } } - - if (peer_cert) { - X509_free(peer_cert); + } else if (errno == EAGAIN) { + n = 0; + } else { + n = -1; + peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); + if (peer_cert && stream->context) { + cert_captured = capture_peer_certs(stream, sslsock, peer_cert TSRMLS_CC); } - } else { - n = errno == EAGAIN ? 0 : -1; + } + + if (n && peer_cert && cert_captured == 0) { + X509_free(peer_cert); } return n; @@ -1017,6 +1025,7 @@ static inline int php_openssl_enable_crypto(php_stream *stream, SSL_shutdown(sslsock->ssl_handle); sslsock->ssl_active = 0; } + return -1; }

« previous php.cvs (#76306) next »