Commit: edd93f34520b550c4c42877fe9e03112cad005ba Author: datibbaw <datib...@php.net> Fri, 27 Sep 2013 14:13:11 +0800 Parents: 69bdc5aca8f14515556bb6fc8f86becf55ef30bf Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=edd93f34520b550c4c42877fe9e03112cad005ba Log: Support string and array for peer fingerprint matching Changed paths: M ext/openssl/openssl.c M ext/openssl/tests/openssl_peer_fingerprint.phpt Diff: diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index a6ddd14..c0d1b0b 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1672,7 +1672,7 @@ PHP_FUNCTION(openssl_x509_export) } /* }}} */ -int php_openssl_x509_fingerprint(X509 *peer, const char *method, int raw, char **out, int *out_len) +static int php_openssl_x509_fingerprint(X509 *peer, const char *method, int raw, char **out, int *out_len) { unsigned char md[EVP_MAX_MD_SIZE]; const EVP_MD *mdtype; @@ -1699,6 +1699,61 @@ int php_openssl_x509_fingerprint(X509 *peer, const char *method, int raw, char * return 1; } +static int php_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected) +{ + char *fingerprint; + int fingerprint_len; + int result = -1; + + if (php_openssl_x509_fingerprint(peer, method, 0, &fingerprint, &fingerprint_len)) { + result = strcmp(expected, fingerprint); + efree(fingerprint); + } + + return result; +} + +static int php_x509_fingerprint_match(X509 *peer, zval **val) +{ + if (Z_TYPE_PP(val) == IS_STRING) { + const char *method = NULL; + + switch (Z_STRLEN_PP(val)) { + case 32: + method = "md5"; + break; + + case 40: + method = "sha1"; + break; + } + + return method && php_x509_fingerprint_cmp(peer, method, Z_STRVAL_PP(val)) == 0; + } else if (Z_TYPE_PP(val) == IS_ARRAY) { + HashPosition pos; + zval **current; + char *key; + uint key_len; + ulong key_index; + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(val), &pos); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(val), (void **)¤t, &pos) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(val), &pos) + ) { + int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_PP(val), &key, &key_len, &key_index, 0, &pos); + + if (key_type == HASH_KEY_IS_STRING + && Z_TYPE_PP(current) == IS_STRING + && php_x509_fingerprint_cmp(peer, key, Z_STRVAL_PP(current)) != 0 + ) { + return 0; + } + } + return 1; + } + return 0; +} + PHP_FUNCTION(openssl_x509_fingerprint) { X509 *cert; @@ -1709,7 +1764,7 @@ PHP_FUNCTION(openssl_x509_fingerprint) int method_len; char *fingerprint; - char *fingerprint_len; + int fingerprint_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) { return; @@ -4932,30 +4987,14 @@ int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stre /* if the cert passed the usual checks, apply our own local policies now */ - if (GET_VER_OPT("peer_fingerprint") && Z_TYPE_PP(val) == IS_STRING) { - char *fingerprint; - int fingerprint_len; - const char *method = NULL; - - switch (Z_STRLEN_PP(val)) { - case 32: - method = "md5"; - break; - - case 40: - method = "sha1"; - break; - } - - if (method && php_openssl_x509_fingerprint(peer, method, 0, &fingerprint, &fingerprint_len)) { - int match = strcmp(Z_STRVAL_PP(val), fingerprint) == 0; - - efree(fingerprint); - - if (!match) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer fingerprint `%s` not matched", Z_STRVAL_PP(val)); + if (GET_VER_OPT("peer_fingerprint")) { + if (Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_ARRAY) { + if (!php_x509_fingerprint_match(peer, val)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer fingerprint doesn't match"); return FAILURE; } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected peer fingerprint must be a string or an array"); } } diff --git a/ext/openssl/tests/openssl_peer_fingerprint.phpt b/ext/openssl/tests/openssl_peer_fingerprint.phpt index a6be676..2960dff 100644 --- a/ext/openssl/tests/openssl_peer_fingerprint.phpt +++ b/ext/openssl/tests/openssl_peer_fingerprint.phpt @@ -31,14 +31,32 @@ if ($pid == -1) { // should be: 81cafc260aa8d82956ebc6212a362ecc var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $contextC)); + + $contextC = stream_context_create( + array( + 'ssl' => array( + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'capture_peer_cert' => true, + 'peer_fingerprint' => array( + 'sha256' => '78ea579f2c3b439359dec5dac9d445108772927427c4780037e87df3799a0aa0', + ), + ) + ) + ); + + var_dump(stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 1, + STREAM_CLIENT_CONNECT, $contextC)); } else { @pcntl_wait($status); @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); } --EXPECTF-- -Warning: stream_socket_client(): Peer fingerprint `81cafc260aa8d82956ebc6212a362ece` not matched in %s on line %d +Warning: stream_socket_client(): Peer fingerprint doesn't match in %s on line %d Warning: stream_socket_client(): Failed to enable crypto in %s on line %d Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d bool(false) +resource(9) of type (stream) -- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php