summaryrefslogtreecommitdiff
path: root/ext/openssl/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/openssl/openssl.c')
-rw-r--r--ext/openssl/openssl.c558
1 files changed, 526 insertions, 32 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 4e659a10db..8d033035e2 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2014 The PHP Group |
+ | Copyright (c) 1997-2013 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -129,6 +129,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
ZEND_ARG_INFO(0, notext)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_fingerprint, 0, 0, 1)
+ ZEND_ARG_INFO(0, x509)
+ ZEND_ARG_INFO(0, method)
+ ZEND_ARG_INFO(0, raw_output)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
ZEND_ARG_INFO(0, cert)
ZEND_ARG_INFO(0, key)
@@ -394,11 +400,35 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
ZEND_ARG_INFO(0, length)
ZEND_ARG_INFO(1, result_is_strong)
ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 2)
+ ZEND_ARG_INFO(0, privkey)
+ ZEND_ARG_INFO(0, challenge)
+ ZEND_ARG_INFO(0, algo)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0)
+ ZEND_ARG_INFO(0, spki)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0)
+ ZEND_ARG_INFO(0, spki)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0)
+ ZEND_ARG_INFO(0, spki)
+ZEND_END_ARG_INFO()
/* }}} */
/* {{{ openssl_functions[]
*/
const zend_function_entry openssl_functions[] = {
+/* spki functions */
+ PHP_FE(openssl_spki_new, arginfo_openssl_spki_new)
+ PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify)
+ PHP_FE(openssl_spki_export, arginfo_openssl_spki_export)
+ PHP_FE(openssl_spki_export_challenge, arginfo_openssl_spki_export_challenge)
+
/* public/private key functions */
PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free)
PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new)
@@ -419,6 +449,7 @@ const zend_function_entry openssl_functions[] = {
PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose)
PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key)
PHP_FE(openssl_x509_export, arginfo_openssl_x509_export)
+ PHP_FE(openssl_x509_fingerprint, arginfo_openssl_x509_fingerprint)
PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file)
/* PKCS12 funcs */
@@ -791,6 +822,7 @@ static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo);
+int openssl_spki_cleanup(const char *src, char *dest);
static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */
{
@@ -1161,6 +1193,10 @@ 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);
+#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);
+#endif
/* override the default tcp socket provider */
php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
@@ -1199,6 +1235,10 @@ PHP_MSHUTDOWN_FUNCTION(openssl)
#endif
php_stream_xport_unregister("sslv3" TSRMLS_CC);
php_stream_xport_unregister("tls" TSRMLS_CC);
+#if OPENSSL_VERSION_NUMBER >= 0x10001001L
+ php_stream_xport_unregister("tlsv1.1" TSRMLS_CC);
+ php_stream_xport_unregister("tlsv1.2" TSRMLS_CC);
+#endif
/* reinstate the default tcp handler */
php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
@@ -1335,6 +1375,279 @@ PHP_FUNCTION(openssl_x509_export_to_file)
}
/* }}} */
+/* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method])
+ Creates new private key (or uses existing) and creates a new spki cert
+ outputting results to var */
+PHP_FUNCTION(openssl_spki_new)
+{
+ int challenge_len;
+ char * challenge = NULL, * spkstr = NULL, * s = NULL;
+ long keyresource = -1;
+ const char *spkac = "SPKAC=";
+ long algo = OPENSSL_ALGO_MD5;
+
+ zval *method = NULL;
+ zval * zpkey = NULL;
+ EVP_PKEY * pkey = NULL;
+ NETSCAPE_SPKI *spki=NULL;
+ const EVP_MD *mdtype;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) {
+ return;
+ }
+ RETVAL_FALSE;
+
+ pkey = php_openssl_evp_from_zval(&zpkey, 0, challenge, 1, &keyresource TSRMLS_CC);
+
+ if (pkey == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied private key");
+ goto cleanup;
+ }
+
+ if (method != NULL) {
+ if (Z_TYPE_P(method) == IS_LONG) {
+ algo = Z_LVAL_P(method);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Algorithm must be of supported type");
+ goto cleanup;
+ }
+ }
+ mdtype = php_openssl_get_evp_md_from_algo(algo);
+
+ if (!mdtype) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
+ goto cleanup;
+ }
+
+ if ((spki = NETSCAPE_SPKI_new()) == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create new SPKAC");
+ goto cleanup;
+ }
+
+ if (challenge) {
+ ASN1_STRING_set(spki->spkac->challenge, challenge, challenge_len);
+ }
+
+ if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to embed public key");
+ goto cleanup;
+ }
+
+ if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to sign with specified algorithm");
+ goto cleanup;
+ }
+
+ spkstr = NETSCAPE_SPKI_b64_encode(spki);
+ if (!spkstr){
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to encode SPKAC");
+ goto cleanup;
+ }
+
+ s = emalloc(strlen(spkac) + strlen(spkstr) + 1);
+ sprintf(s, "%s%s", spkac, spkstr);
+
+ RETVAL_STRINGL(s, strlen(s), 0);
+ goto cleanup;
+
+cleanup:
+
+ if (keyresource == -1 && spki != NULL) {
+ NETSCAPE_SPKI_free(spki);
+ }
+ if (keyresource == -1 && pkey != NULL) {
+ EVP_PKEY_free(pkey);
+ }
+ if (keyresource == -1 && spkstr != NULL) {
+ efree(spkstr);
+ }
+
+ if (strlen(s) <= 0) {
+ RETVAL_FALSE;
+ }
+
+ if (keyresource == -1 && s != NULL) {
+ efree(s);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_spki_verify(string spki)
+ Verifies spki returns boolean */
+PHP_FUNCTION(openssl_spki_verify)
+{
+ int spkstr_len, i = 0;
+ char *spkstr = NULL, * spkstr_cleaned = NULL;
+
+ EVP_PKEY *pkey = NULL;
+ NETSCAPE_SPKI *spki = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) {
+ return;
+ }
+ RETVAL_FALSE;
+
+ if (spkstr == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC");
+ goto cleanup;
+ }
+
+ spkstr_cleaned = emalloc(spkstr_len + 1);
+ openssl_spki_cleanup(spkstr, spkstr_cleaned);
+
+ if (strlen(spkstr_cleaned)<=0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SPKAC");
+ goto cleanup;
+ }
+
+ spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned));
+ if (spki == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC");
+ goto cleanup;
+ }
+
+ pkey = X509_PUBKEY_get(spki->spkac->pubkey);
+ if (pkey == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to acquire signed public key");
+ goto cleanup;
+ }
+
+ i = NETSCAPE_SPKI_verify(spki, pkey);
+ goto cleanup;
+
+cleanup:
+ if (spki != NULL) {
+ NETSCAPE_SPKI_free(spki);
+ }
+ if (pkey != NULL) {
+ EVP_PKEY_free(pkey);
+ }
+ if (spkstr_cleaned != NULL) {
+ efree(spkstr_cleaned);
+ }
+
+ if (i > 0) {
+ RETVAL_TRUE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string openssl_spki_export(string spki)
+ Exports public key from existing spki to var */
+PHP_FUNCTION(openssl_spki_export)
+{
+ int spkstr_len;
+ char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL;
+
+ EVP_PKEY *pkey = NULL;
+ NETSCAPE_SPKI *spki = NULL;
+ BIO *out = BIO_new(BIO_s_mem());
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) {
+ return;
+ }
+ RETVAL_FALSE;
+
+ if (spkstr == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC");
+ goto cleanup;
+ }
+
+ spkstr_cleaned = emalloc(spkstr_len + 1);
+ openssl_spki_cleanup(spkstr, spkstr_cleaned);
+
+ spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned));
+ if (spki == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC");
+ goto cleanup;
+ }
+
+ pkey = X509_PUBKEY_get(spki->spkac->pubkey);
+ if (pkey == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to acquire signed public key");
+ goto cleanup;
+ }
+
+ out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ PEM_write_bio_PUBKEY(out, pkey);
+ goto cleanup;
+
+cleanup:
+
+ if (spki != NULL) {
+ NETSCAPE_SPKI_free(spki);
+ }
+ if (out != NULL) {
+ BIO_free_all(out);
+ }
+ if (pkey != NULL) {
+ EVP_PKEY_free(pkey);
+ }
+ if (spkstr_cleaned != NULL) {
+ efree(spkstr_cleaned);
+ }
+ if (s != NULL) {
+ efree(s);
+ }
+}
+/* }}} */
+
+/* {{{ proto string openssl_spki_export_challenge(string spki)
+ Exports spkac challenge from existing spki to var */
+PHP_FUNCTION(openssl_spki_export_challenge)
+{
+ int spkstr_len;
+ char *spkstr = NULL, * spkstr_cleaned = NULL;
+
+ NETSCAPE_SPKI *spki = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) {
+ return;
+ }
+ RETVAL_FALSE;
+
+ if (spkstr == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC");
+ goto cleanup;
+ }
+
+ spkstr_cleaned = emalloc(spkstr_len + 1);
+ openssl_spki_cleanup(spkstr, spkstr_cleaned);
+
+ spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned));
+ if (spki == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode SPKAC");
+ goto cleanup;
+ }
+
+ RETVAL_STRING((char *) ASN1_STRING_data(spki->spkac->challenge), 1);
+ goto cleanup;
+
+cleanup:
+ if (spkstr_cleaned != NULL) {
+ efree(spkstr_cleaned);
+ }
+}
+/* }}} */
+
+/* {{{ strip line endings from spkac */
+int openssl_spki_cleanup(const char *src, char *dest)
+{
+ int removed=0;
+
+ while (*src) {
+ if (*src!='\n'&&*src!='\r') {
+ *dest++=*src;
+ } else {
+ ++removed;
+ }
+ ++src;
+ }
+ *dest=0;
+ return removed;
+}
+/* }}} */
+
/* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
Exports a CERT to file or a var */
PHP_FUNCTION(openssl_x509_export)
@@ -1377,6 +1690,121 @@ PHP_FUNCTION(openssl_x509_export)
}
/* }}} */
+static int php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw, char **out, int *out_len TSRMLS_DC)
+{
+ unsigned char md[EVP_MAX_MD_SIZE];
+ const EVP_MD *mdtype;
+ unsigned int n;
+
+ if (!(mdtype = EVP_get_digestbyname(method))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
+ return FAILURE;
+ } else if (!X509_digest(peer, mdtype, md, &n)) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not generate signature");
+ return FAILURE;
+ }
+
+ if (raw) {
+ *out_len = n;
+ *out = estrndup((char *) md, n);
+ } else {
+ *out_len = n * 2;
+ *out = emalloc(*out_len + 1);
+
+ make_digest_ex(*out, md, n);
+ }
+
+ return SUCCESS;
+}
+
+static int php_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected TSRMLS_DC)
+{
+ char *fingerprint;
+ int fingerprint_len;
+ int result = -1;
+
+ if (php_openssl_x509_fingerprint(peer, method, 0, &fingerprint, &fingerprint_len TSRMLS_CC) == SUCCESS) {
+ result = strcmp(expected, fingerprint);
+ efree(fingerprint);
+ }
+
+ return result;
+}
+
+static zend_bool php_x509_fingerprint_match(X509 *peer, zval *val TSRMLS_DC)
+{
+ if (Z_TYPE_P(val) == IS_STRING) {
+ const char *method = NULL;
+
+ switch (Z_STRLEN_P(val)) {
+ case 32:
+ method = "md5";
+ break;
+
+ case 40:
+ method = "sha1";
+ break;
+ }
+
+ return method && php_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val) TSRMLS_CC) == 0;
+ } else if (Z_TYPE_P(val) == IS_ARRAY) {
+ HashPosition pos;
+ zval **current;
+ char *key;
+ uint key_len;
+ ulong key_index;
+
+ for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(val), &pos);
+ zend_hash_get_current_data_ex(Z_ARRVAL_P(val), (void **)&current, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(Z_ARRVAL_P(val), &pos)
+ ) {
+ int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(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) TSRMLS_CC) != 0
+ ) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+PHP_FUNCTION(openssl_x509_fingerprint)
+{
+ X509 *cert;
+ zval **zcert;
+ long certresource;
+ zend_bool raw_output = 0;
+ char *method = "sha1";
+ int method_len;
+
+ char *fingerprint;
+ int fingerprint_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) {
+ return;
+ }
+
+ cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
+ if (cert == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
+ RETURN_FALSE;
+ }
+
+ if (php_openssl_x509_fingerprint(cert, method, raw_output, &fingerprint, &fingerprint_len TSRMLS_CC) == SUCCESS) {
+ RETVAL_STRINGL(fingerprint, fingerprint_len, 0);
+ } else {
+ RETVAL_FALSE;
+ }
+
+ if (certresource == -1 && cert) {
+ X509_free(cert);
+ }
+}
+
/* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
Checks if a private key corresponds to a CERT */
PHP_FUNCTION(openssl_x509_check_private_key)
@@ -4506,14 +4934,12 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
{
php_stream *stream;
SSL *ssl;
- X509 *err_cert;
int err, depth, ret;
zval **val;
ret = preverify_ok;
/* determine the status for the current cert */
- err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
@@ -4541,12 +4967,91 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
}
/* }}} */
+static zend_bool matches_wildcard_name(const char *subjectname, const char *certname)
+{
+ char *wildcard;
+ int prefix_len, suffix_len, subject_len;
+
+ if (strcasecmp(subjectname, certname) == 0) {
+ return 1;
+ }
+
+ if (!(wildcard = strchr(certname, '*'))) {
+ return 0;
+ }
+
+ // 1) prefix, if not empty, must match subject
+ prefix_len = wildcard - certname;
+ if (prefix_len && strncasecmp(subjectname, certname, prefix_len) != 0) {
+ return 0;
+ }
+
+ suffix_len = strlen(wildcard + 1);
+ subject_len = strlen(subjectname);
+ if (suffix_len <= subject_len) {
+ /* 2) suffix must match
+ * 3) no . between prefix and suffix
+ **/
+ return strcasecmp(wildcard + 1, subjectname + subject_len - suffix_len) == 0 &&
+ memchr(subjectname + prefix_len, '.', subject_len - suffix_len - prefix_len) == NULL;
+ }
+
+ return 0;
+}
+
+static zend_bool matches_san_list(X509 *peer, const char *subject_name)
+{
+ int i;
+ zend_bool is_match = 0;
+ unsigned char *cert_name;
+
+ GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0);
+ int alt_name_count = sk_GENERAL_NAME_num(alt_names);
+
+ for (i = 0; i < alt_name_count; i++) {
+ GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i);
+
+ if (GEN_DNS == san->type) {
+ ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName);
+ is_match = matches_wildcard_name(subject_name, (char *) cert_name);
+ OPENSSL_free(cert_name);
+ }
+
+ if (is_match) {
+ break;
+ }
+ }
+
+ return is_match;
+}
+
+static zend_bool matches_common_name(X509 *peer, const char *subject_name TSRMLS_DC)
+{
+ char buf[1024];
+ X509_NAME *cert_name;
+ zend_bool is_match = 0;
+ int cert_name_len;
+
+ cert_name = X509_get_subject_name(peer);
+ cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf));
+
+ if (cert_name_len == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
+ } else if (cert_name_len != strlen(buf)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf);
+ } else if (matches_wildcard_name(subject_name, buf)) {
+ is_match = 1;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", cert_name_len, buf, subject_name);
+ }
+
+ return is_match;
+}
+
int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC) /* {{{ */
{
zval **val = NULL;
char *cnmatch = NULL;
- X509_NAME *name;
- char buf[1024];
int err;
/* verification is turned off */
@@ -4577,36 +5082,25 @@ 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 */
- name = X509_get_subject_name(peer);
-
- /* Does the common name match ? (used primarily for https://) */
- GET_VER_OPT_STRING("CN_match", cnmatch);
- if (cnmatch) {
- int match = 0;
- int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf));
-
- if (name_len == -1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
- return FAILURE;
- } else if (name_len != strlen(buf)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", name_len, buf);
- return FAILURE;
- }
-
- match = strcmp(cnmatch, buf) == 0;
- if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') {
- /* Try wildcard */
-
- if (strchr(buf+2, '.')) {
- char *tmp = strstr(cnmatch, buf+1);
-
- match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch, '.');
+ 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 TSRMLS_CC)) {
+ 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");
}
+ }
- if (!match) {
- /* didn't match */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch);
+ GET_VER_OPT_STRING("CN_match", cnmatch);
+
+ if (cnmatch) {
+ if (matches_san_list(peer, cnmatch)) {
+ return SUCCESS;
+ } else if (matches_common_name(peer, cnmatch TSRMLS_CC)) {
+ return SUCCESS;
+ } else {
return FAILURE;
}
}