diff options
Diffstat (limited to 'ext/openssl')
-rw-r--r-- | ext/openssl/config0.m4 | 4 | ||||
-rw-r--r-- | ext/openssl/openssl.c | 2440 | ||||
-rw-r--r-- | ext/openssl/openssl.dsp | 111 | ||||
-rw-r--r-- | ext/openssl/openssl.mak | 2 | ||||
-rw-r--r-- | ext/openssl/php_openssl.h | 5 | ||||
-rw-r--r-- | ext/openssl/tests/bug60632.phpt | 3 | ||||
-rw-r--r-- | ext/openssl/tests/bug70438.phpt | 29 | ||||
-rw-r--r-- | ext/openssl/tests/bug71475.phpt | 16 | ||||
-rw-r--r-- | ext/openssl/tests/bug72165.phpt | 17 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_csr_sign_basic.phpt | 4 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_free_key.phpt | 77 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt | 1 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_x509_checkpurpose.phpt | 149 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_x509_export_basic.phpt | 4 | ||||
-rw-r--r-- | ext/openssl/tests/session_meta_capture.phpt | 6 | ||||
-rw-r--r-- | ext/openssl/xp_ssl.c | 1089 |
16 files changed, 2199 insertions, 1758 deletions
diff --git a/ext/openssl/config0.m4 b/ext/openssl/config0.m4 index a9484b4acc..01fc89b28d 100644 --- a/ext/openssl/config0.m4 +++ b/ext/openssl/config0.m4 @@ -3,7 +3,7 @@ dnl $Id$ dnl PHP_ARG_WITH(openssl, for OpenSSL support, -[ --with-openssl[=DIR] Include OpenSSL support (requires OpenSSL >= 0.9.6)]) +[ --with-openssl[=DIR] Include OpenSSL support (requires OpenSSL >= 0.9.8)]) PHP_ARG_WITH(kerberos, for Kerberos support, [ --with-kerberos[=DIR] OPENSSL: Include Kerberos support], no, no) @@ -19,8 +19,6 @@ if test "$PHP_OPENSSL" != "no"; then PHP_SETUP_KERBEROS(OPENSSL_SHARED_LIBADD) fi - AC_CHECK_LIB(ssl, DSA_get_default_method, AC_DEFINE(HAVE_DSA_DEFAULT_METHOD, 1, [OpenSSL 0.9.7 or later])) - AC_CHECK_LIB(crypto, X509_free, AC_DEFINE(HAVE_DSA_DEFAULT_METHOD, 1, [OpenSSL 0.9.7 or later])) AC_CHECK_FUNCS([RAND_egd]) PHP_SETUP_OPENSSL(OPENSSL_SHARED_LIBADD, diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index f8641c62fc..6bf1d6b25f 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -16,7 +16,7 @@ | Wez Furlong <wez@thebrainroom.com> | | Sascha Kettler <kettler@gmx.net> | | Pierre-Alain Joye <pierre@php.net> | - | Marc Delling <delling@silpion.de> (PKCS12 functions) | + | Marc Delling <delling@silpion.de> (PKCS12 functions) | +----------------------------------------------------------------------+ */ @@ -42,6 +42,10 @@ /* OpenSSL includes */ #include <openssl/evp.h> +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/dh.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/crypto.h> @@ -55,7 +59,7 @@ /* Common */ #include <time.h> -#ifdef NETWARE +#if defined(NETWARE) || (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900) #define timezone _timezone /* timezone is called _timezone in LibC */ #endif @@ -354,6 +358,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_seal, 0, 0, 4) ZEND_ARG_INFO(1, ekeys) /* arary */ ZEND_ARG_INFO(0, pubkeys) /* array */ ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(1, iv) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0) @@ -361,6 +366,7 @@ ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0) ZEND_ARG_INFO(1, opendata) ZEND_ARG_INFO(0, ekey) ZEND_ARG_INFO(0, privkey) + ZEND_ARG_INFO(0, iv) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0) @@ -455,7 +461,7 @@ const zend_function_entry openssl_functions[] = { /* x.509 cert funcs */ PHP_FE(openssl_x509_read, arginfo_openssl_x509_read) - PHP_FE(openssl_x509_free, arginfo_openssl_x509_free) + PHP_FE(openssl_x509_free, arginfo_openssl_x509_free) PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse) PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose) PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key) @@ -503,9 +509,9 @@ const zend_function_entry openssl_functions[] = { PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods) PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods) - PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key) + PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key) - PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes) + PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes) PHP_FE(openssl_error_string, arginfo_openssl_error_string) PHP_FE_END }; @@ -522,7 +528,7 @@ zend_module_entry openssl_module_entry = { NULL, NULL, PHP_MINFO(openssl), - NO_VERSION_YET, + PHP_OPENSSL_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ @@ -531,6 +537,25 @@ zend_module_entry openssl_module_entry = { ZEND_GET_MODULE(openssl) #endif +/* number conversion flags checks */ +#define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name) \ + do { \ + if (_cond) { \ + php_error_docref(NULL, E_WARNING, #_name" is too long"); \ + RETURN_FALSE; \ + } \ + } while(0) +/* check if size_t can be safely casted to int */ +#define PHP_OPENSSL_CHECK_SIZE_T_TO_INT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_INT_OVFL(_var), _name) +/* check if size_t can be safely casted to unsigned int */ +#define PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_UINT_OVFL(_var), _name) +/* check if long can be safely casted to int */ +#define PHP_OPENSSL_CHECK_LONG_TO_INT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_LONG_EXCEEDS_INT(_var), _name) + + static int le_key; static int le_x509; static int le_csr; @@ -543,7 +568,7 @@ int php_openssl_get_x509_list_id(void) /* {{{ */ /* }}} */ /* {{{ resource destructors */ -static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) +static void php_pkey_free(zend_resource *rsrc) { EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr; @@ -552,13 +577,13 @@ static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) EVP_PKEY_free(pkey); } -static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) +static void php_x509_free(zend_resource *rsrc) { X509 *x509 = (X509 *)rsrc->ptr; X509_free(x509); } -static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) +static void php_csr_free(zend_resource *rsrc) { X509_REQ * csr = (X509_REQ*)rsrc->ptr; X509_REQ_free(csr); @@ -566,12 +591,12 @@ static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* }}} */ /* {{{ openssl open_basedir check */ -inline static int php_openssl_open_base_dir_chk(char *filename TSRMLS_DC) +inline static int php_openssl_open_base_dir_chk(char *filename) { - if (php_check_open_basedir(filename TSRMLS_CC)) { + if (php_check_open_basedir(filename)) { return -1; } - + return 0; } /* }}} */ @@ -595,8 +620,8 @@ struct php_x509_request { /* {{{ */ LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */ LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */ #else - LHASH * global_config; /* Global SSL config */ - LHASH * req_config; /* SSL config for this request */ + LHASH * global_config; /* Global SSL config */ + LHASH * req_config; /* SSL config for this request */ #endif const EVP_MD * md_alg; const EVP_MD * digest; @@ -612,22 +637,22 @@ struct php_x509_request { /* {{{ */ EVP_PKEY * priv_key; - const EVP_CIPHER * priv_key_encrypt_cipher; + const EVP_CIPHER * priv_key_encrypt_cipher; }; /* }}} */ -static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC); -static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC); -static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC); -static X509_STORE * setup_verify(zval * calist TSRMLS_DC); +static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval); +static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval); +static int php_openssl_is_private_key(EVP_PKEY* pkey); +static X509_STORE * setup_verify(zval * calist); static STACK_OF(X509) * load_all_certs_from_file(char *certfile); -static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC); -static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC); +static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource ** resourceval); +static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req); -static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */ +static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) /* {{{ */ { - zval **data; - zval *subitem, *subentries; + zval *data; + zval subitem, tmp; int i; char *sname; int nid; @@ -636,18 +661,17 @@ static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int s ASN1_OBJECT * obj; if (key != NULL) { - MAKE_STD_ZVAL(subitem); - array_init(subitem); + array_init(&subitem); } else { - subitem = val; + ZVAL_COPY_VALUE(&subitem, val); } - + for (i = 0; i < X509_NAME_entry_count(name); i++) { unsigned char *to_add; int to_add_len = 0; - ne = X509_NAME_get_entry(name, i); + ne = X509_NAME_get_entry(name, i); obj = X509_NAME_ENTRY_get_object(ne); nid = OBJ_obj2nid(obj); @@ -666,35 +690,33 @@ static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int s } if (to_add_len != -1) { - if (zend_hash_find(Z_ARRVAL_P(subitem), sname, strlen(sname)+1, (void**)&data) == SUCCESS) { - if (Z_TYPE_PP(data) == IS_ARRAY) { - subentries = *data; - add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1); - } else if (Z_TYPE_PP(data) == IS_STRING) { - MAKE_STD_ZVAL(subentries); - array_init(subentries); - add_next_index_stringl(subentries, Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1); - add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1); - zend_hash_update(Z_ARRVAL_P(subitem), sname, strlen(sname)+1, &subentries, sizeof(zval*), NULL); + if ((data = zend_hash_str_find(Z_ARRVAL(subitem), sname, strlen(sname))) != NULL) { + if (Z_TYPE_P(data) == IS_ARRAY) { + add_next_index_stringl(data, (char *)to_add, to_add_len); + } else if (Z_TYPE_P(data) == IS_STRING) { + array_init(&tmp); + add_next_index_str(&tmp, zend_string_copy(Z_STR_P(data))); + add_next_index_stringl(&tmp, (char *)to_add, to_add_len); + zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp); } } else { - add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1); + add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len); } } } if (key != NULL) { - zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL); + zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem); } } /* }}} */ static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */ { - add_assoc_stringl(val, key, (char *)str->data, str->length, 1); + add_assoc_stringl(val, key, (char *)str->data, str->length); } /* }}} */ -static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */ +static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */ { /* This is how the time string is formatted: @@ -710,22 +732,22 @@ static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */ long gmadjust = 0; if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal ASN1 data type for timestamp"); + php_error_docref(NULL, E_WARNING, "illegal ASN1 data type for timestamp"); return (time_t)-1; } if (ASN1_STRING_length(timestr) != strlen((const char*)ASN1_STRING_data(timestr))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal length in timestamp"); + php_error_docref(NULL, E_WARNING, "illegal length in timestamp"); return (time_t)-1; } if (ASN1_STRING_length(timestr) < 13) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data); + php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data); return (time_t)-1; } if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && ASN1_STRING_length(timestr) < 15) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data); + php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data); return (time_t)-1; } @@ -787,17 +809,17 @@ static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */ /* }}} */ #if OPENSSL_VERSION_NUMBER >= 0x10000002L -static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config TSRMLS_DC) /* {{{ */ +static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config) /* {{{ */ #else -static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config TSRMLS_DC) +static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config) #endif { X509V3_CTX ctx; - + X509V3_set_ctx_test(&ctx); X509V3_set_conf_lhash(&ctx, config); if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s", + php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s", section_label, section, config_filename); @@ -807,7 +829,7 @@ static inline int php_openssl_config_check_syntax(const char * section_label, co } /* }}} */ -static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */ +static int add_oid_section(struct php_x509_request * req) /* {{{ */ { char * str; STACK_OF(CONF_VALUE) * sktmp; @@ -820,13 +842,13 @@ static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */ } sktmp = CONF_get_section(req->req_config, str); if (sktmp == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str); + php_error_docref(NULL, E_WARNING, "problem loading oid section %s", str); return FAILURE; } for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { cnf = sk_CONF_VALUE_value(sktmp, i); if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value); + php_error_docref(NULL, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value); return FAILURE; } } @@ -835,32 +857,49 @@ static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */ /* }}} */ #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req)) -#define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req TSRMLS_CC) -#define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval TSRMLS_CC) +#define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req) +#define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval) #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \ - req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE + req->config_filename, req->var, req->req_config) == FAILURE) return FAILURE #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \ - if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS && Z_TYPE_PP(item) == IS_STRING) \ - varname = Z_STRVAL_PP(item); \ + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_STRING) \ + varname = Z_STRVAL_P(item); \ else \ varname = defval #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \ - if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS && Z_TYPE_PP(item) == IS_LONG) \ - varname = Z_LVAL_PP(item); \ + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_LONG) \ + varname = (int)Z_LVAL_P(item); \ else \ varname = defval -static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo); +static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo); + +/* {{{ strip line endings from spkac */ +static 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; +} +/* }}} */ -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) /* {{{ */ +static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args) /* {{{ */ { char * str; - zval ** item; + zval * item; SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename); SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req"); @@ -873,14 +912,14 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option /* read in the oids */ str = CONF_get_string(req->req_config, NULL, "oid_file"); - if (str && !php_openssl_open_base_dir_chk(str TSRMLS_CC)) { + if (str && !php_openssl_open_base_dir_chk(str)) { BIO *oid_bio = BIO_new_file(str, "r"); if (oid_bio) { OBJ_create_objects(oid_bio); BIO_free(oid_bio); } } - if (add_oid_section(req TSRMLS_CC) == FAILURE) { + if (add_oid_section(req) == FAILURE) { return FAILURE; } SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name, @@ -894,8 +933,8 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT); - if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) { - req->priv_key_encrypt = Z_BVAL_PP(item); + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) { + req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0; } else { str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key"); if (str == NULL) { @@ -908,14 +947,14 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option } } - if (req->priv_key_encrypt && optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher"), (void**)&item) == SUCCESS - && Z_TYPE_PP(item) == IS_LONG) { - long cipher_algo = Z_LVAL_PP(item); + if (req->priv_key_encrypt && optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL + && Z_TYPE_P(item) == IS_LONG) { + zend_long cipher_algo = Z_LVAL_P(item); const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo); if (cipher == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm for private key."); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm for private key."); return FAILURE; - } else { + } else { req->priv_key_encrypt_cipher = cipher; } } else { @@ -923,7 +962,7 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option } - + /* digest alg */ if (req->digest_name == NULL) { req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md"); @@ -940,17 +979,17 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option /* set the string mask */ str = CONF_get_string(req->req_config, req->section_name, "string_mask"); if (str && !ASN1_STRING_set_default_mask_asc(str)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid global string mask setting %s", str); + php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str); return FAILURE; } PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section); - + return SUCCESS; } /* }}} */ -static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */ +static void php_openssl_dispose_config(struct php_x509_request * req) /* {{{ */ { if (req->priv_key) { EVP_PKEY_free(req->priv_key); @@ -983,7 +1022,7 @@ static inline void php_openssl_rand_add_timeval() /* {{{ */ #endif -static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded TSRMLS_DC) /* {{{ */ +static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */ { char buffer[MAXPATHLEN]; @@ -1002,7 +1041,7 @@ static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *se } if (file == NULL || !RAND_load_file(file, -1)) { if (RAND_status() == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to load random state; not enough random data!"); + php_error_docref(NULL, E_WARNING, "unable to load random state; not enough random data!"); return FAILURE; } return FAILURE; @@ -1016,7 +1055,6 @@ static int php_openssl_write_rand_file(const char * file, int egdsocket, int see { char buffer[MAXPATHLEN]; - TSRMLS_FETCH(); if (egdsocket || !seeded) { /* if we did not manage to read the seed file, we should not write @@ -1028,14 +1066,14 @@ static int php_openssl_write_rand_file(const char * file, int egdsocket, int see } PHP_OPENSSL_RAND_ADD_TIME(); if (file == NULL || !RAND_write_file(file)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to write random state"); + php_error_docref(NULL, E_WARNING, "unable to write random state"); return FAILURE; } return SUCCESS; } /* }}} */ -static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */ +static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */ EVP_MD *mdtype; switch (algo) { @@ -1081,7 +1119,7 @@ static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */ } /* }}} */ -static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* {{{ */ +static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo) { /* {{{ */ switch (algo) { #ifndef OPENSSL_NO_RC2 case PHP_OPENSSL_CIPHER_RC2_40: @@ -1130,7 +1168,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL) PHP_INI_END() /* }}} */ - + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(openssl) @@ -1151,10 +1189,10 @@ PHP_MINIT_FUNCTION(openssl) /* register a resource id number with OpenSSL so that we can map SSL -> stream structures in * OpenSSL callbacks */ ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL); - + REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT); - + /* purposes for cert purpose checking */ REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT); @@ -1216,7 +1254,7 @@ PHP_MINIT_FUNCTION(openssl) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT); #endif - + /* Values for key types */ REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT); #ifndef NO_DSA @@ -1250,23 +1288,25 @@ PHP_MINIT_FUNCTION(openssl) strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename)); } - php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC); - php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC); + php_stream_xport_register("ssl", php_openssl_ssl_socket_factory); +#ifndef OPENSSL_NO_SSL3 + php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory); +#endif #ifndef OPENSSL_NO_SSL2 - php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC); + php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory); #endif - 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); + php_stream_xport_register("tls", php_openssl_ssl_socket_factory); + php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory); #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); + php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory); + php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory); #endif /* override the default tcp socket provider */ - php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC); + php_stream_xport_register("tcp", php_openssl_ssl_socket_factory); - php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC); - php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC); + php_register_url_stream_wrapper("https", &php_stream_http_wrapper); + php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper); REGISTER_INI_ENTRIES(); @@ -1301,23 +1341,25 @@ PHP_MSHUTDOWN_FUNCTION(openssl) ERR_free_strings(); #endif - php_unregister_url_stream_wrapper("https" TSRMLS_CC); - php_unregister_url_stream_wrapper("ftps" TSRMLS_CC); + php_unregister_url_stream_wrapper("https"); + php_unregister_url_stream_wrapper("ftps"); - php_stream_xport_unregister("ssl" TSRMLS_CC); + php_stream_xport_unregister("ssl"); #ifndef OPENSSL_NO_SSL2 - php_stream_xport_unregister("sslv2" TSRMLS_CC); + php_stream_xport_unregister("sslv2"); #endif - php_stream_xport_unregister("sslv3" TSRMLS_CC); - php_stream_xport_unregister("tls" TSRMLS_CC); - php_stream_xport_unregister("tlsv1.0" TSRMLS_CC); +#ifndef OPENSSL_NO_SSL3 + php_stream_xport_unregister("sslv3"); +#endif + php_stream_xport_unregister("tls"); + php_stream_xport_unregister("tlsv1.0"); #if OPENSSL_VERSION_NUMBER >= 0x10001001L - php_stream_xport_unregister("tlsv1.1" TSRMLS_CC); - php_stream_xport_unregister("tlsv1.2" TSRMLS_CC); + php_stream_xport_unregister("tlsv1.1"); + php_stream_xport_unregister("tlsv1.2"); #endif /* reinstate the default tcp handler */ - php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC); + php_stream_xport_register("tcp", php_stream_generic_socket_factory); UNREGISTER_INI_ENTRIES(); @@ -1333,16 +1375,16 @@ 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, "default_cert_file", (char *) X509_get_default_cert_file()); + add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env()); + add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir()); + add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env()); + add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir()); + add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area()); add_assoc_string(return_value, "ini_cafile", - zend_ini_string("openssl.cafile", sizeof("openssl.cafile"), 0), 1); + zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0)); add_assoc_string(return_value, "ini_capath", - zend_ini_string("openssl.capath", sizeof("openssl.capath"), 0), 1); + zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0)); } /* }}} */ @@ -1356,50 +1398,46 @@ PHP_FUNCTION(openssl_get_cert_locations) If you supply makeresource, the result will be registered as an x509 resource and it's value returned in makeresource. */ -static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC) +static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval) { X509 *cert = NULL; if (resourceval) { - *resourceval = -1; + *resourceval = NULL; } - if (Z_TYPE_PP(val) == IS_RESOURCE) { + if (Z_TYPE_P(val) == IS_RESOURCE) { /* is it an x509 resource ? */ void * what; - int type; + zend_resource *res = Z_RES_P(val); - what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509", &type, 1, le_x509); + what = zend_fetch_resource(res, "OpenSSL X.509", le_x509); if (!what) { return NULL; } /* this is so callers can decide if they should free the X509 */ if (resourceval) { - *resourceval = Z_LVAL_PP(val); - } - if (type == le_x509) { - return (X509*)what; + *resourceval = res; + Z_ADDREF_P(val); } - /* other types could be used here - eg: file pointers and read in the data from them */ - - return NULL; + return (X509*)what; } - if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) { + if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { return NULL; } /* force it to be a string and check if it refers to a file */ convert_to_string_ex(val); - if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) { + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { /* read cert from the named file */ BIO *in; - if (php_openssl_open_base_dir_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) { return NULL; } - in = BIO_new_file(Z_STRVAL_PP(val) + (sizeof("file://") - 1), "r"); + in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), "r"); if (in == NULL) { return NULL; } @@ -1408,7 +1446,7 @@ static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * r } else { BIO *in; - in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); if (in == NULL) { return NULL; } @@ -1421,7 +1459,7 @@ static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * r } if (cert && makeresource && resourceval) { - *resourceval = zend_list_insert(cert, le_x509 TSRMLS_CC); + *resourceval = zend_register_resource(cert, le_x509); } return cert; } @@ -1433,25 +1471,25 @@ static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * r PHP_FUNCTION(openssl_x509_export_to_file) { X509 * cert; - zval ** zcert; + zval * zcert; zend_bool notext = 1; BIO * bio_out; - long certresource; + zend_resource *certresource; char * filename; - int filename_len; + size_t filename_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) { return; } RETVAL_FALSE; - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { return; } @@ -1464,9 +1502,9 @@ PHP_FUNCTION(openssl_x509_export_to_file) RETVAL_TRUE; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } BIO_free(bio_out); @@ -1478,11 +1516,12 @@ PHP_FUNCTION(openssl_x509_export_to_file) outputting results to var */ PHP_FUNCTION(openssl_spki_new) { - int challenge_len; - char * challenge = NULL, * spkstr = NULL, * s = NULL; - long keyresource = -1; + size_t challenge_len; + char * challenge = NULL, * spkstr = NULL; + zend_string * s = NULL; + zend_resource *keyresource = NULL; const char *spkac = "SPKAC="; - long algo = OPENSSL_ALGO_MD5; + zend_long algo = OPENSSL_ALGO_MD5; zval *method = NULL; zval * zpkey = NULL; @@ -1490,15 +1529,15 @@ PHP_FUNCTION(openssl_spki_new) 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) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) { return; } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(&zpkey, 0, challenge, 1, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, 1, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied private key"); + php_error_docref(NULL, E_WARNING, "Unable to use supplied private key"); goto cleanup; } @@ -1506,66 +1545,70 @@ PHP_FUNCTION(openssl_spki_new) 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"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC"); goto cleanup; } if (challenge) { - ASN1_STRING_set(spki->spkac->challenge, challenge, challenge_len); + if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) { + php_error_docref(NULL, E_WARNING, "Unable to set challenge data"); + goto cleanup; + } } if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to embed public key"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC"); goto cleanup; } - s = emalloc(strlen(spkac) + strlen(spkstr) + 1); - sprintf(s, "%s%s", spkac, spkstr); + s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0); + sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr); + ZSTR_LEN(s) = strlen(ZSTR_VAL(s)); - RETVAL_STRINGL(s, strlen(s), 0); + RETVAL_STR(s); goto cleanup; cleanup: - if (keyresource == -1 && spki != NULL) { + if (keyresource == NULL && spki != NULL) { NETSCAPE_SPKI_free(spki); } - if (keyresource == -1 && pkey != NULL) { + if (keyresource == NULL && pkey != NULL) { EVP_PKEY_free(pkey); } - if (keyresource == -1 && spkstr != NULL) { + if (keyresource == NULL && spkstr != NULL) { efree(spkstr); } - if (s && strlen(s) <= 0) { + if (s && ZSTR_LEN(s) <= 0) { RETVAL_FALSE; } - if (keyresource == -1 && s != NULL) { - efree(s); + if (keyresource == NULL && s != NULL) { + zend_string_release(s); } } /* }}} */ @@ -1574,39 +1617,40 @@ cleanup: Verifies spki returns boolean */ PHP_FUNCTION(openssl_spki_verify) { - int spkstr_len, i = 0; + size_t spkstr_len; + int i = 0, spkstr_cleaned_len = 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) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { return; } RETVAL_FALSE; if (spkstr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); goto cleanup; } spkstr_cleaned = emalloc(spkstr_len + 1); - openssl_spki_cleanup(spkstr, spkstr_cleaned); + spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned)); - if (strlen(spkstr_cleaned)<=0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SPKAC"); + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); goto cleanup; } - spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); if (spki == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key"); goto cleanup; } @@ -1634,44 +1678,50 @@ cleanup: Exports public key from existing spki to var */ PHP_FUNCTION(openssl_spki_export) { - int spkstr_len; + size_t spkstr_len; char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL; + int spkstr_cleaned_len; EVP_PKEY *pkey = NULL; NETSCAPE_SPKI *spki = NULL; BIO *out = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { return; } RETVAL_FALSE; if (spkstr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); goto cleanup; } spkstr_cleaned = emalloc(spkstr_len + 1); - openssl_spki_cleanup(spkstr, spkstr_cleaned); + spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned)); - spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); if (spki == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC"); + php_error_docref(NULL, 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"); + php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key"); goto cleanup; } out = BIO_new(BIO_s_mem()); - if (out && PEM_write_bio_PUBKEY(out, pkey)) { + if (out && PEM_write_bio_PUBKEY(out, pkey)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(out, &bio_buf); - RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length, 1); + RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length); } goto cleanup; @@ -1699,31 +1749,37 @@ cleanup: Exports spkac challenge from existing spki to var */ PHP_FUNCTION(openssl_spki_export_challenge) { - int spkstr_len; + size_t spkstr_len; char *spkstr = NULL, * spkstr_cleaned = NULL; + int spkstr_cleaned_len; NETSCAPE_SPKI *spki = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { return; } RETVAL_FALSE; if (spkstr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); goto cleanup; } spkstr_cleaned = emalloc(spkstr_len + 1); - openssl_spki_cleanup(spkstr, spkstr_cleaned); + spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned)); + + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } - spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); if (spki == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode SPKAC"); + php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC"); goto cleanup; } - RETVAL_STRING((char *) ASN1_STRING_data(spki->spkac->challenge), 1); + RETVAL_STRING((char *) ASN1_STRING_data(spki->spkac->challenge)); goto cleanup; cleanup: @@ -1733,42 +1789,24 @@ cleanup: } /* }}} */ -/* {{{ 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) { X509 * cert; - zval ** zcert, *zout; + zval * zcert, *zout; zend_bool notext = 1; BIO * bio_out; - long certresource; + zend_resource *certresource; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|b", &zcert, &zout, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|b", &zcert, &zout, ¬ext) == FAILURE) { return; } RETVAL_FALSE; - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } @@ -1776,79 +1814,77 @@ PHP_FUNCTION(openssl_x509_export) if (!notext) { X509_print(bio_out, cert); } - if (PEM_write_bio_X509(bio_out, cert)) { + if (PEM_write_bio_X509(bio_out, cert)) { BUF_MEM *bio_buf; zval_dtor(zout); BIO_get_mem_ptr(bio_out, &bio_buf); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } BIO_free(bio_out); } /* }}} */ -int php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw, char **out, int *out_len TSRMLS_DC) +zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw) { unsigned char md[EVP_MAX_MD_SIZE]; const EVP_MD *mdtype; unsigned int n; + zend_string *ret; if (!(mdtype = EVP_get_digestbyname(method))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm"); - return FAILURE; + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); + return NULL; } else if (!X509_digest(peer, mdtype, md, &n)) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not generate signature"); - return FAILURE; + php_error_docref(NULL, E_ERROR, "Could not generate signature"); + return NULL; } if (raw) { - *out_len = n; - *out = estrndup((char *) md, n); + ret = zend_string_init((char*)md, n, 0); } else { - *out_len = n * 2; - *out = emalloc(*out_len + 1); - - make_digest_ex(*out, md, n); + ret = zend_string_alloc(n * 2, 0); + make_digest_ex(ZSTR_VAL(ret), md, n); + ZSTR_VAL(ret)[n * 2] = '\0'; } - return SUCCESS; + return ret; } PHP_FUNCTION(openssl_x509_fingerprint) { X509 *cert; - zval **zcert; - long certresource; + zval *zcert; + zend_resource *certresource; zend_bool raw_output = 0; char *method = "sha1"; - int method_len; - - char *fingerprint; - int fingerprint_len; + size_t method_len; + zend_string *fingerprint; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) { return; } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); + php_error_docref(NULL, 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); + fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output); + if (fingerprint) { + RETVAL_STR(fingerprint); } else { RETVAL_FALSE; } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } } @@ -1857,29 +1893,29 @@ PHP_FUNCTION(openssl_x509_fingerprint) Checks if a private key corresponds to a CERT */ PHP_FUNCTION(openssl_x509_check_private_key) { - zval ** zcert, **zkey; + zval * zcert, *zkey; X509 * cert = NULL; EVP_PKEY * key = NULL; - long certresource = -1, keyresource = -1; + zend_resource *certresource = NULL, *keyresource = NULL; RETVAL_FALSE; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) { + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) { return; } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { RETURN_FALSE; - } - key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC); + } + key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource); if (key) { RETVAL_BOOL(X509_check_private_key(cert, key)); } - if (keyresource == -1 && key) { + if (keyresource == NULL && key) { EVP_PKEY_free(key); } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } } @@ -1904,10 +1940,10 @@ static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) p = extension->value->data; length = extension->value->length; if (method->it) { - names = (GENERAL_NAMES*)(ASN1_item_d2i(NULL, &p, length, - ASN1_ITEM_ptr(method->it))); + names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length, + ASN1_ITEM_ptr(method->it))); } else { - names = (GENERAL_NAMES*)(method->d2i(NULL, &p, length)); + names = (GENERAL_NAMES*) (method->d2i(NULL, &p, length)); } if (names == NULL) { return -1; @@ -1915,33 +1951,33 @@ static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) num = sk_GENERAL_NAME_num(names); for (i = 0; i < num; i++) { - GENERAL_NAME *name; - ASN1_STRING *as; - name = sk_GENERAL_NAME_value(names, i); - switch (name->type) { - case GEN_EMAIL: - BIO_puts(bio, "email:"); - as = name->d.rfc822Name; - BIO_write(bio, ASN1_STRING_data(as), - ASN1_STRING_length(as)); - break; - case GEN_DNS: - BIO_puts(bio, "DNS:"); - as = name->d.dNSName; - BIO_write(bio, ASN1_STRING_data(as), - ASN1_STRING_length(as)); - break; - case GEN_URI: - BIO_puts(bio, "URI:"); - as = name->d.uniformResourceIdentifier; - BIO_write(bio, ASN1_STRING_data(as), - ASN1_STRING_length(as)); - break; - default: - /* use builtin print for GEN_OTHERNAME, GEN_X400, - * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID - */ - GENERAL_NAME_print(bio, name); + GENERAL_NAME *name; + ASN1_STRING *as; + name = sk_GENERAL_NAME_value(names, i); + switch (name->type) { + case GEN_EMAIL: + BIO_puts(bio, "email:"); + as = name->d.rfc822Name; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + case GEN_DNS: + BIO_puts(bio, "DNS:"); + as = name->d.dNSName; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + case GEN_URI: + BIO_puts(bio, "URI:"); + as = name->d.uniformResourceIdentifier; + BIO_write(bio, ASN1_STRING_data(as), + ASN1_STRING_length(as)); + break; + default: + /* use builtin print for GEN_OTHERNAME, GEN_X400, + * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID + */ + GENERAL_NAME_print(bio, name); } /* trailing ', ' except for last element */ if (i < (num - 1)) { @@ -1957,64 +1993,62 @@ static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) Returns an array of the fields/values of the CERT */ PHP_FUNCTION(openssl_x509_parse) { - zval ** zcert; + zval * zcert; X509 * cert = NULL; - long certresource = -1; + zend_resource *certresource = NULL; int i, sig_nid; zend_bool useshortnames = 1; char * tmpstr; - zval * subitem; + zval subitem; X509_EXTENSION *extension; char *extname; - BIO *bio_out; + BIO *bio_out; BUF_MEM *bio_buf; char buf[256]; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcert, &useshortnames) == FAILURE) { return; } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { RETURN_FALSE; } array_init(return_value); if (cert->name) { - add_assoc_string(return_value, "name", cert->name, 1); + add_assoc_string(return_value, "name", cert->name); } /* add_assoc_bool(return_value, "valid", cert->valid); */ - add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames TSRMLS_CC); + add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames); /* hash as used in CA directories to lookup cert by subject name */ { char buf[32]; snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert)); - add_assoc_string(return_value, "hash", buf, 1); + add_assoc_string(return_value, "hash", buf); } - - add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames TSRMLS_CC); + + add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames); add_assoc_long(return_value, "version", X509_get_version(cert)); - add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1); + add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert))); add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert)); add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert)); - add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC)); - add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC)); + add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert))); + add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert))); tmpstr = (char *)X509_alias_get0(cert, NULL); if (tmpstr) { - add_assoc_string(return_value, "alias", tmpstr, 1); + add_assoc_string(return_value, "alias", tmpstr); } sig_nid = OBJ_obj2nid((cert)->sig_alg->algorithm); - add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid), 1); - add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid), 1); + add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid)); + add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid)); add_assoc_long(return_value, "signatureTypeNID", sig_nid); - - MAKE_STD_ZVAL(subitem); - array_init(subitem); + array_init(&subitem); /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines in x509v3.h */ @@ -2022,31 +2056,29 @@ PHP_FUNCTION(openssl_x509_parse) int id, purpset; char * pname; X509_PURPOSE * purp; - zval * subsub; + zval subsub; - MAKE_STD_ZVAL(subsub); - array_init(subsub); + array_init(&subsub); purp = X509_PURPOSE_get0(i); id = X509_PURPOSE_get_id(purp); purpset = X509_check_purpose(cert, id, 0); - add_index_bool(subsub, 0, purpset); + add_index_bool(&subsub, 0, purpset); purpset = X509_check_purpose(cert, id, 1); - add_index_bool(subsub, 1, purpset); + add_index_bool(&subsub, 1, purpset); pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp); - add_index_string(subsub, 2, pname, 1); + add_index_string(&subsub, 2, pname); /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */ - add_index_zval(subitem, id, subsub); + add_index_zval(&subitem, id, &subsub); } - add_assoc_zval(return_value, "purposes", subitem); + add_assoc_zval(return_value, "purposes", &subitem); - MAKE_STD_ZVAL(subitem); - array_init(subitem); + array_init(&subitem); for (i = 0; i < X509_get_ext_count(cert); i++) { @@ -2063,10 +2095,10 @@ PHP_FUNCTION(openssl_x509_parse) if (nid == NID_subject_alt_name) { if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) { BIO_get_mem_ptr(bio_out, &bio_buf); - add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); } else { zval_dtor(return_value); - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } BIO_free(bio_out); @@ -2075,15 +2107,15 @@ PHP_FUNCTION(openssl_x509_parse) } else if (X509V3_EXT_print(bio_out, extension, 0, 0)) { BIO_get_mem_ptr(bio_out, &bio_buf); - add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); } else { - add_assoc_asn1_string(subitem, extname, X509_EXTENSION_get_data(extension)); + add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension)); } BIO_free(bio_out); } - add_assoc_zval(return_value, "extensions", subitem); + add_assoc_zval(return_value, "extensions", &subitem); - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } } @@ -2096,27 +2128,26 @@ static STACK_OF(X509) * load_all_certs_from_file(char *certfile) STACK_OF(X509) *stack=NULL, *ret=NULL; BIO *in=NULL; X509_INFO *xi; - TSRMLS_FETCH(); if(!(stack = sk_X509_new_null())) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure"); + php_error_docref(NULL, E_ERROR, "memory allocation failure"); goto end; } - if (php_openssl_open_base_dir_chk(certfile TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(certfile)) { sk_X509_free(stack); goto end; } if(!(in=BIO_new_file(certfile, "r"))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile); + php_error_docref(NULL, E_WARNING, "error opening the file, %s", certfile); sk_X509_free(stack); goto end; } /* This loads from a file, a stack of x509/crl/pkey sets */ if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile); + php_error_docref(NULL, E_WARNING, "error reading the file, %s", certfile); sk_X509_free(stack); goto end; } @@ -2131,7 +2162,7 @@ static STACK_OF(X509) * load_all_certs_from_file(char *certfile) X509_INFO_free(xi); } if(!sk_X509_num(stack)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile); + php_error_docref(NULL, E_WARNING, "no certificates in file, %s", certfile); sk_X509_free(stack); goto end; } @@ -2149,11 +2180,10 @@ static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, { int ret=0; X509_STORE_CTX *csc; - TSRMLS_FETCH(); csc = X509_STORE_CTX_new(); if (csc == NULL) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure"); + php_error_docref(NULL, E_ERROR, "memory allocation failure"); return 0; } X509_STORE_CTX_init(csc, ctx, x, untrustedchain); @@ -2171,16 +2201,17 @@ static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */ PHP_FUNCTION(openssl_x509_checkpurpose) { - zval ** zcert, * zcainfo = NULL; + zval * zcert, * zcainfo = NULL; X509_STORE * cainfo = NULL; X509 * cert = NULL; - long certresource = -1; + zend_resource *certresource = NULL; STACK_OF(X509) * untrustedchain = NULL; - long purpose; + zend_long purpose; char * untrusted = NULL; - int untrusted_len = 0, ret; + size_t untrusted_len = 0; + int ret; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) { return; } @@ -2193,16 +2224,16 @@ PHP_FUNCTION(openssl_x509_checkpurpose) } } - cainfo = setup_verify(zcainfo TSRMLS_CC); + cainfo = setup_verify(zcainfo); if (cainfo == NULL) { goto clean_exit; } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { goto clean_exit; } - ret = check_cert(cainfo, cert, untrustedchain, purpose); + ret = check_cert(cainfo, cert, untrustedchain, (int)purpose); if (ret != 0 && ret != 1) { RETVAL_LONG(ret); } else { @@ -2210,11 +2241,11 @@ PHP_FUNCTION(openssl_x509_checkpurpose) } clean_exit: - if (certresource == 1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } - if (cainfo) { - X509_STORE_free(cainfo); + if (cainfo) { + X509_STORE_free(cainfo); } if (untrustedchain) { sk_X509_pop_free(untrustedchain, X509_free); @@ -2226,12 +2257,13 @@ clean_exit: * calist is an array containing file and directory names. create a * certificate store and add those certs to it for use in verification. */ -static X509_STORE * setup_verify(zval * calist TSRMLS_DC) +static X509_STORE * setup_verify(zval * calist) { X509_STORE *store; X509_LOOKUP * dir_lookup, * file_lookup; - HashPosition pos; int ndirs = 0, nfiles = 0; + zval * item; + zend_stat_t sb; store = X509_STORE_new(); @@ -2240,39 +2272,32 @@ static X509_STORE * setup_verify(zval * calist TSRMLS_DC) } if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) { - zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos); - for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) { - zval ** item; - struct stat sb; - - if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) { - break; - } + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(calist), item) { convert_to_string_ex(item); - if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item)); + if (VCWD_STAT(Z_STRVAL_P(item), &sb) == -1) { + php_error_docref(NULL, E_WARNING, "unable to stat %s", Z_STRVAL_P(item)); continue; } if ((sb.st_mode & S_IFREG) == S_IFREG) { file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); - if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item)); + if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + php_error_docref(NULL, E_WARNING, "error loading file %s", Z_STRVAL_P(item)); } else { nfiles++; } file_lookup = NULL; } else { dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); - if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item)); - } else { + if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + php_error_docref(NULL, E_WARNING, "error loading directory %s", Z_STRVAL_P(item)); + } else { ndirs++; } dir_lookup = NULL; } - } + } ZEND_HASH_FOREACH_END(); } if (nfiles == 0) { file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); @@ -2294,17 +2319,18 @@ static X509_STORE * setup_verify(zval * calist TSRMLS_DC) Reads X.509 certificates */ PHP_FUNCTION(openssl_x509_read) { - zval **cert; + zval *cert; X509 *x509; + zend_resource *res; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) { return; } - Z_TYPE_P(return_value) = IS_RESOURCE; - x509 = php_openssl_x509_from_zval(cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC); + x509 = php_openssl_x509_from_zval(cert, 1, &res); + ZVAL_RES(return_value, res); if (x509 == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!"); + php_error_docref(NULL, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!"); RETURN_FALSE; } } @@ -2317,11 +2343,13 @@ PHP_FUNCTION(openssl_x509_free) zval *x509; X509 *cert; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &x509) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509); - zend_list_delete(Z_LVAL_P(x509)); + if ((cert = (X509 *)zend_fetch_resource(Z_RES_P(x509), "OpenSSL X.509", le_x509)) == NULL) { + RETURN_FALSE; + } + zend_list_close(Z_RES_P(x509)); } /* }}} */ @@ -2339,47 +2367,42 @@ static void php_sk_X509_free(STACK_OF(X509) * sk) /* {{{ */ } /* }}} */ -static STACK_OF(X509) * php_array_to_X509_sk(zval ** zcerts TSRMLS_DC) /* {{{ */ +static STACK_OF(X509) * php_array_to_X509_sk(zval * zcerts) /* {{{ */ { - HashPosition hpos; - zval ** zcertval; + zval * zcertval; STACK_OF(X509) * sk = NULL; - X509 * cert; - long certresource; + X509 * cert; + zend_resource *certresource; sk = sk_X509_new_null(); /* get certs */ - if (Z_TYPE_PP(zcerts) == IS_ARRAY) { - zend_hash_internal_pointer_reset_ex(HASH_OF(*zcerts), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(*zcerts), (void**)&zcertval, &hpos) == SUCCESS) { - - cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC); + if (Z_TYPE_P(zcerts) == IS_ARRAY) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zcerts), zcertval) { + cert = php_openssl_x509_from_zval(zcertval, 0, &certresource); if (cert == NULL) { goto clean_exit; } - if (certresource != -1) { + if (certresource != NULL) { cert = X509_dup(cert); - + if (cert == NULL) { goto clean_exit; } - + } sk_X509_push(sk, cert); - - zend_hash_move_forward_ex(HASH_OF(*zcerts), &hpos); - } + } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ - cert = php_openssl_x509_from_zval(zcerts, 0, &certresource TSRMLS_CC); - + cert = php_openssl_x509_from_zval(zcerts, 0, &certresource); + if (cert == NULL) { goto clean_exit; } - if (certresource != -1) { + if (certresource != NULL) { cert = X509_dup(cert); if (cert == NULL) { goto clean_exit; @@ -2388,8 +2411,8 @@ static STACK_OF(X509) * php_array_to_X509_sk(zval ** zcerts TSRMLS_DC) /* {{{ */ sk_X509_push(sk, cert); } - clean_exit: - return sk; +clean_exit: + return sk; } /* }}} */ @@ -2402,75 +2425,75 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) PKCS12 * p12 = NULL; char * filename; char * friendly_name = NULL; - int filename_len; + size_t filename_len; char * pass; - int pass_len; - zval **zcert = NULL, *zpkey = NULL, *args = NULL; + size_t pass_len; + zval *zcert = NULL, *zpkey = NULL, *args = NULL; EVP_PKEY *priv_key = NULL; - long certresource, keyresource; - zval ** item; + zend_resource *certresource, *keyresource; + zval * item; STACK_OF(X509) *ca = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE) return; RETVAL_FALSE; - - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } - priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); if (priv_key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3"); + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; } if (cert && !X509_check_private_key(cert, priv_key)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert"); + php_error_docref(NULL, E_WARNING, "private key does not correspond to cert"); goto cleanup; } - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { goto cleanup; } /* parse extra config from args array, promote this to an extra function */ - if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS && Z_TYPE_PP(item) == IS_STRING) - friendly_name = Z_STRVAL_PP(item); + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && Z_TYPE_P(item) == IS_STRING) + friendly_name = Z_STRVAL_P(item); /* certpbe (default RC2-40) keypbe (default 3DES) friendly_caname */ - if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS) - ca = php_array_to_X509_sk(item TSRMLS_CC); + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) + ca = php_array_to_X509_sk(item); /* end parse extra config */ /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca, - int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/ + int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/ p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0); - bio_out = BIO_new_file(filename, "w"); + bio_out = BIO_new_file(filename, "w"); if (bio_out) { - + i2d_PKCS12_bio(bio_out, p12); RETVAL_TRUE; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); } BIO_free(bio_out); PKCS12_free(p12); php_sk_X509_free(ca); - + cleanup: - if (keyresource == -1 && priv_key) { + if (keyresource == NULL && priv_key) { EVP_PKEY_free(priv_key); } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } } @@ -2485,50 +2508,50 @@ PHP_FUNCTION(openssl_pkcs12_export) PKCS12 * p12 = NULL; zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL; EVP_PKEY *priv_key = NULL; - long certresource, keyresource; + zend_resource *certresource, *keyresource; char * pass; - int pass_len; + size_t pass_len; char * friendly_name = NULL; - zval ** item; + zval * item; STACK_OF(X509) *ca = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/zs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE) return; RETVAL_FALSE; - - cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC); + + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } - priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); if (priv_key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3"); + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; } if (cert && !X509_check_private_key(cert, priv_key)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert"); + php_error_docref(NULL, E_WARNING, "private key does not correspond to cert"); goto cleanup; } /* parse extra config from args array, promote this to an extra function */ - if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS && Z_TYPE_PP(item) == IS_STRING) - friendly_name = Z_STRVAL_PP(item); + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && Z_TYPE_P(item) == IS_STRING) + friendly_name = Z_STRVAL_P(item); - if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS) - ca = php_array_to_X509_sk(item TSRMLS_CC); + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) + ca = php_array_to_X509_sk(item); /* end parse extra config */ - + p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0); bio_out = BIO_new(BIO_s_mem()); - if (i2d_PKCS12_bio(bio_out, p12)) { + if (i2d_PKCS12_bio(bio_out, p12)) { BUF_MEM *bio_buf; zval_dtor(zout); BIO_get_mem_ptr(bio_out, &bio_buf); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } @@ -2536,13 +2559,13 @@ PHP_FUNCTION(openssl_pkcs12_export) BIO_free(bio_out); PKCS12_free(p12); php_sk_X509_free(ca); - + cleanup: - if (keyresource == -1 && priv_key) { + if (keyresource == NULL && priv_key) { EVP_PKEY_free(priv_key); } - if (certresource == -1 && cert) { + if (certresource == NULL && cert) { X509_free(cert); } } @@ -2552,9 +2575,9 @@ cleanup: Parses a PKCS12 to an array */ PHP_FUNCTION(openssl_pkcs12_read) { - zval *zout = NULL, *zextracerts, *zcert, *zpkey; + zval *zout = NULL, zextracerts, zcert, zpkey; char *pass, *zp12; - int pass_len, zp12_len; + size_t pass_len, zp12_len; PKCS12 * p12 = NULL; EVP_PKEY * pkey = NULL; X509 * cert = NULL; @@ -2562,16 +2585,18 @@ PHP_FUNCTION(openssl_pkcs12_read) BIO * bio_in = NULL; int i; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szs", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/s", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE) return; RETVAL_FALSE; - + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(zp12_len, pkcs12); + bio_in = BIO_new(BIO_s_mem()); - - if(!BIO_write(bio_in, zp12, zp12_len)) + + if(0 >= BIO_write(bio_in, zp12, (int)zp12_len)) goto cleanup; - + if(d2i_PKCS12_bio(bio_in, &p12)) { if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) { BIO * bio_out; @@ -2583,9 +2608,8 @@ PHP_FUNCTION(openssl_pkcs12_read) if (PEM_write_bio_X509(bio_out, cert)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); - MAKE_STD_ZVAL(zcert); - ZVAL_STRINGL(zcert, bio_buf->data, bio_buf->length, 1); - add_assoc_zval(zout, "cert", zcert); + ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); + add_assoc_zval(zout, "cert", &zcert); } BIO_free(bio_out); @@ -2593,17 +2617,15 @@ PHP_FUNCTION(openssl_pkcs12_read) if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); - MAKE_STD_ZVAL(zpkey); - ZVAL_STRINGL(zpkey, bio_buf->data, bio_buf->length, 1); - add_assoc_zval(zout, "pkey", zpkey); + ZVAL_STRINGL(&zpkey, bio_buf->data, bio_buf->length); + add_assoc_zval(zout, "pkey", &zpkey); } BIO_free(bio_out); - MAKE_STD_ZVAL(zextracerts); - array_init(zextracerts); - + array_init(&zextracerts); + for (i=0;;i++) { - zval * zextracert; + zval zextracert; X509* aCA = sk_X509_pop(ca); if (!aCA) break; @@ -2619,10 +2641,9 @@ PHP_FUNCTION(openssl_pkcs12_read) if (PEM_write_bio_X509(bio_out, aCA)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); - MAKE_STD_ZVAL(zextracert); - ZVAL_STRINGL(zextracert, bio_buf->data, bio_buf->length, 1); - add_index_zval(zextracerts, i, zextracert); - + ZVAL_STRINGL(&zextracert, bio_buf->data, bio_buf->length); + add_index_zval(&zextracerts, i, &zextracert); + } BIO_free(bio_out); @@ -2630,25 +2651,25 @@ PHP_FUNCTION(openssl_pkcs12_read) } if(ca) { sk_X509_free(ca); - add_assoc_zval(zout, "extracerts", zextracerts); + add_assoc_zval(zout, "extracerts", &zextracerts); } else { - zval_dtor(zextracerts); + zval_dtor(&zextracerts); } - + RETVAL_TRUE; - + PKCS12_free(p12); } } - - cleanup: + + cleanup: if (bio_in) { BIO_free(bio_in); } if (pkey) { EVP_PKEY_free(pkey); } - if (cert) { + if (cert) { X509_free(cert); } } @@ -2657,7 +2678,7 @@ PHP_FUNCTION(openssl_pkcs12_read) /* {{{ x509 CSR functions */ /* {{{ php_openssl_make_REQ */ -static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs TSRMLS_DC) +static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs) { STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL; char * str, *dn_sect, *attr_sect; @@ -2667,7 +2688,7 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z return FAILURE; } dn_sk = CONF_get_section(req->req_config, dn_sect); - if (dn_sk == NULL) { + if (dn_sk == NULL) { return FAILURE; } attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes"); @@ -2685,52 +2706,44 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z char * type; CONF_VALUE * v; X509_NAME * subj; - HashPosition hpos; - zval ** item; - + zval * item; + zend_string * strindex = NULL; + subj = X509_REQ_get_subject_name(csr); /* apply values from the dn hash */ - zend_hash_internal_pointer_reset_ex(HASH_OF(dn), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(dn), (void**)&item, &hpos) == SUCCESS) { - char * strindex = NULL; - uint strindexlen = 0; - ulong intindex; - - zend_hash_get_current_key_ex(HASH_OF(dn), &strindex, &strindexlen, &intindex, 0, &hpos); - - convert_to_string_ex(item); - + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) { if (strindex) { int nid; - nid = OBJ_txt2nid(strindex); + convert_to_string_ex(item); + + nid = OBJ_txt2nid(ZSTR_VAL(strindex)); if (nid != NID_undef) { - if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, - (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) + if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, + (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "dn: add_entry_by_NID %d -> %s (failed; check error" " queue and value of string_mask OpenSSL option " "if illegal characters are reported)", - nid, Z_STRVAL_PP(item)); + nid, Z_STRVAL_P(item)); return FAILURE; } } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex); + php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); } } - zend_hash_move_forward_ex(HASH_OF(dn), &hpos); - } + } ZEND_HASH_FOREACH_END(); /* Finally apply defaults from config file */ for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { int len; char buffer[200 + 1]; /*200 + \0 !*/ - + v = sk_CONF_VALUE_value(dn_sk, i); type = v->name; - - len = strlen(type); + + len = (int)strlen(type); if (len < sizeof("_default")) { continue; } @@ -2744,7 +2757,7 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z memcpy(buffer, type, len); buffer[len] = '\0'; type = buffer; - + /* Skip past any leading X. X: X, etc to allow for multiple * instances */ for (str = type; *str; str++) { @@ -2762,39 +2775,35 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z continue; } if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value); + php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value); return FAILURE; } if (!X509_NAME_entry_count(subj)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "no objects specified in config file"); + php_error_docref(NULL, E_WARNING, "no objects specified in config file"); return FAILURE; } } if (attribs) { - zend_hash_internal_pointer_reset_ex(HASH_OF(attribs), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(attribs), (void**)&item, &hpos) == SUCCESS) { - char *strindex = NULL; - uint strindexlen; - ulong intindex; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) { + int nid; - zend_hash_get_current_key_ex(HASH_OF(attribs), &strindex, &strindexlen, &intindex, 0, &hpos); - convert_to_string_ex(item); + if (NULL == strindex) { + php_error_docref(NULL, E_WARNING, "dn: numeric fild names are not supported"); + continue; + } - if (strindex) { - int nid; + convert_to_string_ex(item); - nid = OBJ_txt2nid(strindex); - if (nid != NID_undef) { - if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item)); - return FAILURE; - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex); + nid = OBJ_txt2nid(ZSTR_VAL(strindex)); + if (nid != NID_undef) { + if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) { + php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_P(item)); + return FAILURE; } + } else { + php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); } - zend_hash_move_forward_ex(HASH_OF(attribs), &hpos); - } + } ZEND_HASH_FOREACH_END(); for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { v = sk_CONF_VALUE_value(attr_sk, i); /* if it is already set, skip this */ @@ -2803,7 +2812,7 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z continue; } if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_UTF8, (unsigned char*)v->value, -1)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "add1_attr_by_txt %s -> %s (failed; check error queue " "and value of string_mask OpenSSL option if illegal " "characters are reported)", @@ -2820,41 +2829,42 @@ static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, z /* }}} */ /* {{{ php_openssl_csr_from_zval */ -static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC) +static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource **resourceval) { X509_REQ * csr = NULL; char * filename = NULL; BIO * in; - + if (resourceval) { - *resourceval = -1; + *resourceval = NULL; } - if (Z_TYPE_PP(val) == IS_RESOURCE) { + if (Z_TYPE_P(val) == IS_RESOURCE) { void * what; - int type; + zend_resource *res = Z_RES_P(val); - what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509 CSR", &type, 1, le_csr); + what = zend_fetch_resource(res, "OpenSSL X.509 CSR", le_csr); if (what) { if (resourceval) { - *resourceval = Z_LVAL_PP(val); + *resourceval = res; + Z_ADDREF_P(val); } return (X509_REQ*)what; } return NULL; - } else if (Z_TYPE_PP(val) != IS_STRING) { + } else if (Z_TYPE_P(val) != IS_STRING) { return NULL; } - if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) { - filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1); + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { + filename = Z_STRVAL_P(val) + (sizeof("file://") - 1); } if (filename) { - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { return NULL; } in = BIO_new_file(filename, "r"); } else { - in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); } csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL); BIO_free(in); @@ -2870,22 +2880,23 @@ PHP_FUNCTION(openssl_csr_export_to_file) X509_REQ * csr; zval * zcsr = NULL; zend_bool notext = 1; - char * filename = NULL; int filename_len; + char * filename = NULL; + size_t filename_len; BIO * bio_out; - long csr_resource; + zend_resource *csr_resource; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) { return; } RETVAL_FALSE; - csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC); + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); if (csr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); return; } - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { return; } @@ -2897,10 +2908,10 @@ PHP_FUNCTION(openssl_csr_export_to_file) PEM_write_bio_X509_REQ(bio_out, csr); RETVAL_TRUE; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); } - if (csr_resource == -1 && csr) { + if (csr_resource == NULL && csr) { X509_REQ_free(csr); } BIO_free(bio_out); @@ -2915,17 +2926,17 @@ PHP_FUNCTION(openssl_csr_export) zval * zcsr = NULL, *zout=NULL; zend_bool notext = 1; BIO * bio_out; + zend_resource *csr_resource; - long csr_resource; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zcsr, &zout, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|b", &zcsr, &zout, ¬ext) == FAILURE) { return; } + RETVAL_FALSE; - csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC); + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); if (csr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); return; } @@ -2941,12 +2952,12 @@ PHP_FUNCTION(openssl_csr_export) BIO_get_mem_ptr(bio_out, &bio_buf); zval_dtor(zout); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } - if (csr_resource == -1 && csr) { + if (csr_resource == NULL && csr) { X509_REQ_free(csr); } BIO_free(bio_out); @@ -2957,77 +2968,78 @@ PHP_FUNCTION(openssl_csr_export) Signs a cert with another CERT */ PHP_FUNCTION(openssl_csr_sign) { - zval ** zcert = NULL, **zcsr, **zpkey, *args = NULL; - long num_days; - long serial = 0L; + zval * zcert = NULL, *zcsr, *zpkey, *args = NULL; + zend_long num_days; + zend_long serial = Z_L(0); X509 * cert = NULL, *new_cert = NULL; X509_REQ * csr; EVP_PKEY * key = NULL, *priv_key = NULL; - long csr_resource, certresource = 0, keyresource = -1; + zend_resource *csr_resource, *certresource = NULL, *keyresource = NULL; int i; struct php_x509_request req; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ!Zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE) + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz!zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE) return; RETVAL_FALSE; PHP_SSL_REQ_INIT(&req); - - csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC); + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); if (csr == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); return; } if (zcert) { - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 2"); + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 2"); goto cleanup; } } - priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource TSRMLS_CC); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); if (priv_key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3"); + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; } if (cert && !X509_check_private_key(cert, priv_key)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert"); + php_error_docref(NULL, E_WARNING, "private key does not correspond to signing cert"); goto cleanup; } - + if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) { goto cleanup; } /* Check that the request matches the signature */ key = X509_REQ_get_pubkey(csr); if (key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error unpacking public key"); + php_error_docref(NULL, E_WARNING, "error unpacking public key"); goto cleanup; } i = X509_REQ_verify(csr, key); if (i < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature verification problems"); + php_error_docref(NULL, E_WARNING, "Signature verification problems"); goto cleanup; } else if (i == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature did not match the certificate request"); + php_error_docref(NULL, E_WARNING, "Signature did not match the certificate request"); goto cleanup; } - + /* Now we can get on with it */ - + new_cert = X509_new(); if (new_cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "No memory"); + php_error_docref(NULL, E_WARNING, "No memory"); goto cleanup; } /* Version 3 cert */ if (!X509_set_version(new_cert, 2)) goto cleanup; - ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial); - + + ASN1_INTEGER_set(X509_get_serialNumber(new_cert), (long)serial); + X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr)); if (cert == NULL) { @@ -3037,14 +3049,14 @@ PHP_FUNCTION(openssl_csr_sign) goto cleanup; } X509_gmtime_adj(X509_get_notBefore(new_cert), 0); - X509_gmtime_adj(X509_get_notAfter(new_cert), (long)60*60*24*num_days); + X509_gmtime_adj(X509_get_notAfter(new_cert), 60*60*24*(long)num_days); i = X509_set_pubkey(new_cert, key); if (!i) { goto cleanup; } if (req.extensions_section) { X509V3_CTX ctx; - + X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0); X509V3_set_conf_lhash(&ctx, req.req_config); if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) { @@ -3054,14 +3066,14 @@ PHP_FUNCTION(openssl_csr_sign) /* Now sign it */ if (!X509_sign(new_cert, priv_key, req.digest)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it"); + php_error_docref(NULL, E_WARNING, "failed to sign it"); goto cleanup; } - + /* Succeeded; lets return the cert */ - RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509 TSRMLS_CC)); + ZVAL_RES(return_value, zend_register_resource(new_cert, le_x509)); new_cert = NULL; - + cleanup: if (cert == new_cert) { @@ -3069,16 +3081,16 @@ cleanup: } PHP_SSL_REQ_DISPOSE(&req); - if (keyresource == -1 && priv_key) { + if (keyresource == NULL && priv_key) { EVP_PKEY_free(priv_key); } if (key) { EVP_PKEY_free(key); } - if (csr_resource == -1 && csr) { + if (csr_resource == NULL && csr) { X509_REQ_free(csr); } - if (certresource == -1 && cert) { + if (zcert && certresource == NULL && cert) { X509_free(cert); } if (new_cert) { @@ -3096,32 +3108,32 @@ PHP_FUNCTION(openssl_csr_new) zval * out_pkey; X509_REQ * csr = NULL; int we_made_the_key = 1; - long key_resource; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) { + zend_resource *key_resource; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "az/|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) { return; } RETVAL_FALSE; - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { /* Generate or use a private key */ if (Z_TYPE_P(out_pkey) != IS_NULL) { - req.priv_key = php_openssl_evp_from_zval(&out_pkey, 0, NULL, 0, &key_resource TSRMLS_CC); + req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, &key_resource); if (req.priv_key != NULL) { we_made_the_key = 0; } } if (req.priv_key == NULL) { - php_openssl_generate_private_key(&req TSRMLS_CC); + php_openssl_generate_private_key(&req); } if (req.priv_key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to generate a private key"); + php_error_docref(NULL, E_WARNING, "Unable to generate a private key"); } else { csr = X509_REQ_new(); if (csr) { - if (php_openssl_make_REQ(&req, csr, dn, attribs TSRMLS_CC) == SUCCESS) { + if (php_openssl_make_REQ(&req, csr, dn, attribs) == SUCCESS) { X509V3_CTX ext_ctx; X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0); @@ -3131,23 +3143,23 @@ PHP_FUNCTION(openssl_csr_new) if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config, &ext_ctx, req.request_extensions_section, csr)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading extension section %s", req.request_extensions_section); + php_error_docref(NULL, E_WARNING, "Error loading extension section %s", req.request_extensions_section); } else { RETVAL_TRUE; - + if (X509_REQ_sign(csr, req.priv_key, req.digest)) { - RETVAL_RESOURCE(zend_list_insert(csr, le_csr TSRMLS_CC)); - csr = NULL; + ZVAL_RES(return_value, zend_register_resource(csr, le_csr)); + csr = NULL; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request"); + php_error_docref(NULL, E_WARNING, "Error signing request"); } if (we_made_the_key) { /* and a resource for the private key */ zval_dtor(out_pkey); - ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key TSRMLS_CC)); + ZVAL_RES(out_pkey, zend_register_resource(req.priv_key, le_key)); req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ - } else if (key_resource != -1) { + } else if (key_resource != NULL) { req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ } } @@ -3172,17 +3184,17 @@ PHP_FUNCTION(openssl_csr_new) Returns the subject of a CERT or FALSE on error */ PHP_FUNCTION(openssl_csr_get_subject) { - zval ** zcsr; + zval * zcsr; zend_bool use_shortnames = 1; - long csr_resource; + zend_resource *csr_resource; X509_NAME * subject; X509_REQ * csr; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) { return; } - csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC); + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); if (csr == NULL) { RETURN_FALSE; @@ -3191,7 +3203,7 @@ PHP_FUNCTION(openssl_csr_get_subject) subject = X509_REQ_get_subject_name(csr); array_init(return_value); - add_assoc_name_entry(return_value, NULL, subject, use_shortnames TSRMLS_CC); + add_assoc_name_entry(return_value, NULL, subject, use_shortnames); return; } /* }}} */ @@ -3200,26 +3212,25 @@ PHP_FUNCTION(openssl_csr_get_subject) Returns the subject of a CERT or FALSE on error */ PHP_FUNCTION(openssl_csr_get_public_key) { - zval ** zcsr; + zval * zcsr; zend_bool use_shortnames = 1; - long csr_resource; + zend_resource *csr_resource; X509_REQ * csr; EVP_PKEY *tpubkey; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) { return; } - csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC); + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); if (csr == NULL) { RETURN_FALSE; } tpubkey=X509_REQ_get_pubkey(csr); - RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key TSRMLS_CC)); - return; + RETURN_RES(zend_register_resource(tpubkey, le_key)); } /* }}} */ @@ -3240,16 +3251,16 @@ PHP_FUNCTION(openssl_csr_get_public_key) empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in the Apache error log! */ -static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC) +static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval) { EVP_PKEY * key = NULL; X509 * cert = NULL; int free_cert = 0; - long cert_res = -1; + zend_resource *cert_res = NULL; char * filename = NULL; zval tmp; - Z_TYPE(tmp) = IS_NULL; + ZVAL_NULL(&tmp); #define TMP_CLEAN \ if (Z_TYPE(tmp) == IS_STRING) {\ @@ -3258,62 +3269,62 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * return NULL; if (resourceval) { - *resourceval = -1; + *resourceval = NULL; } - if (Z_TYPE_PP(val) == IS_ARRAY) { - zval ** zphrase; - + if (Z_TYPE_P(val) == IS_ARRAY) { + zval * zphrase; + /* get passphrase */ - if (zend_hash_index_find(HASH_OF(*val), 1, (void **)&zphrase) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); + if ((zphrase = zend_hash_index_find(Z_ARRVAL_P(val), 1)) == NULL) { + php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); return NULL; } - - if (Z_TYPE_PP(zphrase) == IS_STRING) { - passphrase = Z_STRVAL_PP(zphrase); + + if (Z_TYPE_P(zphrase) == IS_STRING) { + passphrase = Z_STRVAL_P(zphrase); } else { - tmp = **zphrase; - zval_copy_ctor(&tmp); + ZVAL_COPY(&tmp, zphrase); convert_to_string(&tmp); passphrase = Z_STRVAL(tmp); } /* now set val to be the key param and continue */ - if (zend_hash_index_find(HASH_OF(*val), 0, (void **)&val) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); + if ((val = zend_hash_index_find(Z_ARRVAL_P(val), 0)) == NULL) { + php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); TMP_CLEAN; } } - if (Z_TYPE_PP(val) == IS_RESOURCE) { + if (Z_TYPE_P(val) == IS_RESOURCE) { void * what; - int type; + zend_resource * res = Z_RES_P(val); - what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key); + what = zend_fetch_resource2(res, "OpenSSL X.509/key", le_x509, le_key); if (!what) { TMP_CLEAN; } - if (resourceval) { - *resourceval = Z_LVAL_PP(val); + if (resourceval) { + *resourceval = res; + Z_ADDREF_P(val); } - if (type == le_x509) { + if (res->type == le_x509) { /* extract key from cert, depending on public_key param */ cert = (X509*)what; free_cert = 0; - } else if (type == le_key) { + } else if (res->type == le_key) { int is_priv; - is_priv = php_openssl_is_private_key((EVP_PKEY*)what TSRMLS_CC); + is_priv = php_openssl_is_private_key((EVP_PKEY*)what); /* check whether it is actually a private key if requested */ if (!public_key && !is_priv) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param is a public key"); + php_error_docref(NULL, E_WARNING, "supplied key param is a public key"); TMP_CLEAN; } if (public_key && is_priv) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Don't know how to get public key from this private key"); + php_error_docref(NULL, E_WARNING, "Don't know how to get public key from this private key"); TMP_CLEAN; } else { if (Z_TYPE(tmp) == IS_STRING) { @@ -3328,21 +3339,21 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * } } else { /* force it to be a string and check if it refers to a file */ - /* passing non string values leaks, object uses toString, it returns NULL - * See bug38255.phpt + /* passing non string values leaks, object uses toString, it returns NULL + * See bug38255.phpt */ - if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) { + if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { TMP_CLEAN; } convert_to_string_ex(val); - if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) { - filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1); + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { + filename = Z_STRVAL_P(val) + (sizeof("file://") - 1); } /* it's an X509 file/cert of some kind, and we need to extract the data from that */ if (public_key) { - cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC); - free_cert = (cert_res == -1); + cert = php_openssl_x509_from_zval(val, 0, &cert_res); + free_cert = (cert_res == NULL); /* actual extraction done later */ if (!cert) { /* not a X509 certificate, try to retrieve public key */ @@ -3350,7 +3361,7 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * if (filename) { in = BIO_new_file(filename, "r"); } else { - in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); } if (in == NULL) { TMP_CLEAN; @@ -3363,12 +3374,12 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * BIO *in; if (filename) { - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { TMP_CLEAN; } in = BIO_new_file(filename, "r"); } else { - in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); } if (in == NULL) { @@ -3388,7 +3399,7 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * X509_free(cert); } if (key && makeresource && resourceval) { - *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key); + *resourceval = zend_register_resource(key, le_key); } if (Z_TYPE(tmp) == IS_STRING) { zval_dtor(&tmp); @@ -3398,42 +3409,67 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * /* }}} */ /* {{{ php_openssl_generate_private_key */ -static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC) +static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) { char * randfile = NULL; int egdsocket, seeded; EVP_PKEY * return_val = NULL; - + if (req->priv_key_bits < MIN_KEY_LENGTH) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d", + php_error_docref(NULL, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d", MIN_KEY_LENGTH, req->priv_key_bits); return NULL; } randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE"); - php_openssl_load_rand_file(randfile, &egdsocket, &seeded TSRMLS_CC); - + php_openssl_load_rand_file(randfile, &egdsocket, &seeded); + if ((req->priv_key = EVP_PKEY_new()) != NULL) { switch(req->priv_key_type) { case OPENSSL_KEYTYPE_RSA: - PHP_OPENSSL_RAND_ADD_TIME(); - if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) { - return_val = req->priv_key; + { + RSA* rsaparam; +#if OPENSSL_VERSION_NUMBER < 0x10002000L + /* OpenSSL 1.0.2 deprecates RSA_generate_key */ + PHP_OPENSSL_RAND_ADD_TIME(); + rsaparam = (RSA*)RSA_generate_key(req->priv_key_bits, RSA_F4, NULL, NULL); +#else + { + BIGNUM *bne = (BIGNUM *)BN_new(); + if (BN_set_word(bne, RSA_F4) != 1) { + BN_free(bne); + php_error_docref(NULL, E_WARNING, "failed setting exponent"); + return NULL; + } + rsaparam = RSA_new(); + PHP_OPENSSL_RAND_ADD_TIME(); + RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL); + BN_free(bne); + } +#endif + if (rsaparam && EVP_PKEY_assign_RSA(req->priv_key, rsaparam)) { + return_val = req->priv_key; + } } break; -#if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD) +#if !defined(NO_DSA) case OPENSSL_KEYTYPE_DSA: PHP_OPENSSL_RAND_ADD_TIME(); { - DSA *dsapar = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL); - if (dsapar) { - DSA_set_method(dsapar, DSA_get_default_method()); - if (DSA_generate_key(dsapar)) { - if (EVP_PKEY_assign_DSA(req->priv_key, dsapar)) { + DSA *dsaparam = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10002000L + dsaparam = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL); +#else + DSA_generate_parameters_ex(dsaparam, req->priv_key_bits, NULL, 0, NULL, NULL, NULL); +#endif + if (dsaparam) { + DSA_set_method(dsaparam, DSA_get_default_method()); + if (DSA_generate_key(dsaparam)) { + if (EVP_PKEY_assign_DSA(req->priv_key, dsaparam)) { return_val = req->priv_key; } } else { - DSA_free(dsapar); + DSA_free(dsaparam); } } } @@ -3443,42 +3479,46 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req case OPENSSL_KEYTYPE_DH: PHP_OPENSSL_RAND_ADD_TIME(); { - DH *dhpar = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL); int codes = 0; - - if (dhpar) { - DH_set_method(dhpar, DH_get_default_method()); - if (DH_check(dhpar, &codes) && codes == 0 && DH_generate_key(dhpar)) { - if (EVP_PKEY_assign_DH(req->priv_key, dhpar)) { + DH *dhparam = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10002000L + dhparam = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL); +#else + DH_generate_parameters_ex(dhparam, req->priv_key_bits, 2, NULL); +#endif + if (dhparam) { + DH_set_method(dhparam, DH_get_default_method()); + if (DH_check(dhparam, &codes) && codes == 0 && DH_generate_key(dhparam)) { + if (EVP_PKEY_assign_DH(req->priv_key, dhparam)) { return_val = req->priv_key; } } else { - DH_free(dhpar); + DH_free(dhparam); } } } break; #endif default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type"); + php_error_docref(NULL, E_WARNING, "Unsupported private key type"); } } php_openssl_write_rand_file(randfile, egdsocket, seeded); - + if (return_val == NULL) { EVP_PKEY_free(req->priv_key); req->priv_key = NULL; return NULL; } - + return return_val; } /* }}} */ /* {{{ php_openssl_is_private_key Check whether the supplied key is a private key by checking if the secret prime factors are set */ -static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC) +static int php_openssl_is_private_key(EVP_PKEY* pkey) { assert(pkey != NULL); @@ -3500,7 +3540,7 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC) case EVP_PKEY_DSA4: assert(pkey->pkey.dsa != NULL); - if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){ + if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){ return 0; } break; @@ -3524,7 +3564,7 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC) break; #endif default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); break; } return 1; @@ -3534,20 +3574,20 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC) #define OPENSSL_PKEY_GET_BN(_type, _name) do { \ if (pkey->pkey._type->_name != NULL) { \ int len = BN_num_bytes(pkey->pkey._type->_name); \ - char *str = emalloc(len + 1); \ - BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)str); \ - str[len] = 0; \ - add_assoc_stringl(_type, #_name, str, len, 0); \ + zend_string *str = zend_string_alloc(len, 0); \ + BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)ZSTR_VAL(str)); \ + ZSTR_VAL(str)[len] = 0; \ + add_assoc_str(&_type, #_name, str); \ } \ } while (0) #define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \ - zval **bn; \ - if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \ - Z_TYPE_PP(bn) == IS_STRING) { \ + zval *bn; \ + if ((bn = zend_hash_str_find(_ht, #_name, sizeof(#_name)-1)) != NULL && \ + Z_TYPE_P(bn) == IS_STRING) { \ _type->_name = BN_bin2bn( \ - (unsigned char*)Z_STRVAL_PP(bn), \ - Z_STRLEN_PP(bn), NULL); \ + (unsigned char*)Z_STRVAL_P(bn), \ + (int)Z_STRLEN_P(bn), NULL); \ } \ } while (0); @@ -3598,9 +3638,9 @@ PHP_FUNCTION(openssl_pkey_new) { struct php_x509_request req; zval * args = NULL; - zval **data; + zval *data; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &args) == FAILURE) { return; } RETVAL_FALSE; @@ -3608,23 +3648,23 @@ PHP_FUNCTION(openssl_pkey_new) if (args && Z_TYPE_P(args) == IS_ARRAY) { EVP_PKEY *pkey; - if (zend_hash_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa"), (void**)&data) == SUCCESS && - Z_TYPE_PP(data) == IS_ARRAY) { - pkey = EVP_PKEY_new(); - if (pkey) { + if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa")-1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { RSA *rsa = RSA_new(); if (rsa) { - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, n); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, e); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, d); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, p); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, q); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmp1); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmq1); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, n); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, e); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, d); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, p); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, q); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, dmp1); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, dmq1); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, iqmp); if (rsa->n && rsa->d) { if (EVP_PKEY_assign_RSA(pkey, rsa)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); + RETURN_RES(zend_register_resource(pkey, le_key)); } } RSA_free(rsa); @@ -3632,20 +3672,20 @@ PHP_FUNCTION(openssl_pkey_new) EVP_PKEY_free(pkey); } RETURN_FALSE; - } else if (zend_hash_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa"), (void**)&data) == SUCCESS && - Z_TYPE_PP(data) == IS_ARRAY) { - pkey = EVP_PKEY_new(); - if (pkey) { + } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { DSA *dsa = DSA_new(); if (dsa) { - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, p); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, q); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, g); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, priv_key); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, pub_key); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, p); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, q); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, g); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, priv_key); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, pub_key); if (php_openssl_pkey_init_dsa(dsa)) { if (EVP_PKEY_assign_DSA(pkey, dsa)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); + RETURN_RES(zend_register_resource(pkey, le_key)); } } DSA_free(dsa); @@ -3653,19 +3693,20 @@ PHP_FUNCTION(openssl_pkey_new) EVP_PKEY_free(pkey); } RETURN_FALSE; - } else if (zend_hash_find(Z_ARRVAL_P(args), "dh", sizeof("dh"), (void**)&data) == SUCCESS && - Z_TYPE_PP(data) == IS_ARRAY) { - pkey = EVP_PKEY_new(); - if (pkey) { + } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { DH *dh = DH_new(); if (dh) { - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, p); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, g); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, priv_key); - OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, pub_key); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, p); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, g); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, priv_key); + OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, pub_key); if (php_openssl_pkey_init_dh(dh)) { if (EVP_PKEY_assign_DH(pkey, dh)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); + ZVAL_COPY_VALUE(return_value, zend_list_insert(pkey, le_key)); + return; } } DH_free(dh); @@ -3674,15 +3715,15 @@ PHP_FUNCTION(openssl_pkey_new) } RETURN_FALSE; } - } + } PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { - if (php_openssl_generate_private_key(&req TSRMLS_CC)) { + if (php_openssl_generate_private_key(&req)) { /* pass back a key resource */ - RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key TSRMLS_CC)); + RETVAL_RES(zend_register_resource(req.priv_key, le_key)); /* make sure the cleanup code doesn't zap it! */ req.priv_key = NULL; } @@ -3696,33 +3737,35 @@ PHP_FUNCTION(openssl_pkey_new) PHP_FUNCTION(openssl_pkey_export_to_file) { struct php_x509_request req; - zval ** zpkey, * args = NULL; - char * passphrase = NULL; - int passphrase_len = 0; - char * filename = NULL; - int filename_len = 0; - long key_resource = -1; + zval * zpkey, * args = NULL; + char * passphrase = NULL; + size_t passphrase_len = 0; + char * filename = NULL; + size_t filename_len = 0; + zend_resource *key_resource = NULL; int pem_write = 0; EVP_PKEY * key; BIO * bio_out = NULL; const EVP_CIPHER * cipher; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) { + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) { return; } RETVAL_FALSE; - key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource); if (key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); RETURN_FALSE; } - - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(filename)) { RETURN_FALSE; } - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { @@ -3741,11 +3784,11 @@ PHP_FUNCTION(openssl_pkey_export_to_file) switch (EVP_PKEY_type(key->type)) { #ifdef HAVE_EVP_PKEY_EC case EVP_PKEY_EC: - pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL); + pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); break; #endif default: - pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL); + pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); break; } @@ -3757,7 +3800,7 @@ PHP_FUNCTION(openssl_pkey_export_to_file) } PHP_SSL_REQ_DISPOSE(&req); - if (key_resource == -1 && key) { + if (key_resource == NULL && key) { EVP_PKEY_free(key); } if (bio_out) { @@ -3771,27 +3814,28 @@ PHP_FUNCTION(openssl_pkey_export_to_file) PHP_FUNCTION(openssl_pkey_export) { struct php_x509_request req; - zval ** zpkey, * args = NULL, *out; - char * passphrase = NULL; - int passphrase_len = 0; - long key_resource = -1; + zval * zpkey, * args = NULL, *out; + char * passphrase = NULL; size_t passphrase_len = 0; int pem_write = 0; + zend_resource *key_resource = NULL; EVP_PKEY * key; BIO * bio_out = NULL; const EVP_CIPHER * cipher; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) { + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) { return; } RETVAL_FALSE; - key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource); if (key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1"); + php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); RETURN_FALSE; } - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { @@ -3810,11 +3854,11 @@ PHP_FUNCTION(openssl_pkey_export) switch (EVP_PKEY_type(key->type)) { #ifdef HAVE_EVP_PKEY_EC case EVP_PKEY_EC: - pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL); + pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); break; #endif default: - pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL); + pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); break; } @@ -3828,12 +3872,12 @@ PHP_FUNCTION(openssl_pkey_export) bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr); zval_dtor(out); - ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len, 1); + ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len); } } PHP_SSL_REQ_DISPOSE(&req); - if (key_resource == -1 && key) { + if (key_resource == NULL && key) { EVP_PKEY_free(key); } if (bio_out) { @@ -3846,19 +3890,19 @@ PHP_FUNCTION(openssl_pkey_export) Gets public key from X.509 certificate */ PHP_FUNCTION(openssl_pkey_get_public) { - zval **cert; + zval *cert; EVP_PKEY *pkey; + zend_resource *res; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) { return; } - Z_TYPE_P(return_value) = IS_RESOURCE; - pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &Z_LVAL_P(return_value) TSRMLS_CC); - + pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &res); if (pkey == NULL) { RETURN_FALSE; } - zend_list_addref(Z_LVAL_P(return_value)); + ZVAL_RES(return_value, res); + Z_ADDREF_P(return_value); } /* }}} */ @@ -3869,11 +3913,13 @@ PHP_FUNCTION(openssl_pkey_free) zval *key; EVP_PKEY *pkey; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key); - zend_list_delete(Z_LVAL_P(key)); + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { + RETURN_FALSE; + } + zend_list_close(Z_RES_P(key)); } /* }}} */ @@ -3881,21 +3927,22 @@ PHP_FUNCTION(openssl_pkey_free) Gets private keys */ PHP_FUNCTION(openssl_pkey_get_private) { - zval **cert; + zval *cert; EVP_PKEY *pkey; char * passphrase = ""; - int passphrase_len = sizeof("")-1; + size_t passphrase_len = sizeof("")-1; + zend_resource *res; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &cert, &passphrase, &passphrase_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) { return; } - Z_TYPE_P(return_value) = IS_RESOURCE; - pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &Z_LVAL_P(return_value) TSRMLS_CC); + pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &res); if (pkey == NULL) { RETURN_FALSE; } - zend_list_addref(Z_LVAL_P(return_value)); + ZVAL_RES(return_value, res); + Z_ADDREF_P(return_value); } /* }}} */ @@ -3909,13 +3956,12 @@ PHP_FUNCTION(openssl_pkey_get_details) BIO *out; unsigned int pbio_len; char *pbio; - long ktype; + zend_long ktype; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key); - if (!pkey) { + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { RETURN_FALSE; } out = BIO_new(BIO_s_mem()); @@ -3924,8 +3970,8 @@ PHP_FUNCTION(openssl_pkey_get_details) array_init(return_value); add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey)); - add_assoc_stringl(return_value, "key", pbio, pbio_len, 1); - /*TODO: Use the real values once the openssl constants are used + add_assoc_stringl(return_value, "key", pbio, pbio_len); + /*TODO: Use the real values once the openssl constants are used * See the enum at the top of this file */ switch (EVP_PKEY_type(pkey->type)) { @@ -3934,10 +3980,9 @@ PHP_FUNCTION(openssl_pkey_get_details) ktype = OPENSSL_KEYTYPE_RSA; if (pkey->pkey.rsa != NULL) { - zval *rsa; + zval rsa; - ALLOC_INIT_ZVAL(rsa); - array_init(rsa); + array_init(&rsa); OPENSSL_PKEY_GET_BN(rsa, n); OPENSSL_PKEY_GET_BN(rsa, e); OPENSSL_PKEY_GET_BN(rsa, d); @@ -3946,10 +3991,10 @@ PHP_FUNCTION(openssl_pkey_get_details) OPENSSL_PKEY_GET_BN(rsa, dmp1); OPENSSL_PKEY_GET_BN(rsa, dmq1); OPENSSL_PKEY_GET_BN(rsa, iqmp); - add_assoc_zval(return_value, "rsa", rsa); + add_assoc_zval(return_value, "rsa", &rsa); } - break; + break; case EVP_PKEY_DSA: case EVP_PKEY_DSA2: case EVP_PKEY_DSA3: @@ -3957,32 +4002,30 @@ PHP_FUNCTION(openssl_pkey_get_details) ktype = OPENSSL_KEYTYPE_DSA; if (pkey->pkey.dsa != NULL) { - zval *dsa; + zval dsa; - ALLOC_INIT_ZVAL(dsa); - array_init(dsa); + array_init(&dsa); OPENSSL_PKEY_GET_BN(dsa, p); OPENSSL_PKEY_GET_BN(dsa, q); OPENSSL_PKEY_GET_BN(dsa, g); OPENSSL_PKEY_GET_BN(dsa, priv_key); OPENSSL_PKEY_GET_BN(dsa, pub_key); - add_assoc_zval(return_value, "dsa", dsa); + add_assoc_zval(return_value, "dsa", &dsa); } break; case EVP_PKEY_DH: - + ktype = OPENSSL_KEYTYPE_DH; if (pkey->pkey.dh != NULL) { - zval *dh; + zval dh; - ALLOC_INIT_ZVAL(dh); - array_init(dh); + array_init(&dh); OPENSSL_PKEY_GET_BN(dh, p); OPENSSL_PKEY_GET_BN(dh, g); OPENSSL_PKEY_GET_BN(dh, priv_key); OPENSSL_PKEY_GET_BN(dh, pub_key); - add_assoc_zval(return_value, "dh", dh); + add_assoc_zval(return_value, "dh", &dh); } break; @@ -3990,7 +4033,7 @@ PHP_FUNCTION(openssl_pkey_get_details) case EVP_PKEY_EC: ktype = OPENSSL_KEYTYPE_EC; if (pkey->pkey.ec != NULL) { - zval *ec; + zval ec; const EC_GROUP *ec_group; int nid; char *crv_sn; @@ -4005,23 +4048,22 @@ PHP_FUNCTION(openssl_pkey_get_details) if (nid == NID_undef) { break; } - ALLOC_INIT_ZVAL(ec); - array_init(ec); + array_init(&ec); // Short object name crv_sn = (char*) OBJ_nid2sn(nid); if (crv_sn != NULL) { - add_assoc_string(ec, "curve_name", crv_sn, 1); + add_assoc_string(&ec, "curve_name", crv_sn); } obj = OBJ_nid2obj(nid); if (obj != NULL) { int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1); - add_assoc_stringl(ec, "curve_oid", (char*)oir_buf, oir_len, 1); + add_assoc_stringl(&ec, "curve_oid", (char*)oir_buf, oir_len); ASN1_OBJECT_free(obj); } - add_assoc_zval(return_value, "ec", ec); + add_assoc_zval(return_value, "ec", &ec); } break; #endif @@ -4043,15 +4085,18 @@ PHP_FUNCTION(openssl_pkey_get_details) Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */ PHP_FUNCTION(openssl_pbkdf2) { - long key_length = 0, iterations = 0; - char *password; int password_len; - char *salt; int salt_len; - char *method; int method_len = 0; - unsigned char *out_buffer; + zend_long key_length = 0, iterations = 0; + char *password; + size_t password_len; + char *salt; + size_t salt_len; + char *method; + size_t method_len = 0; + zend_string *out_buffer; const EVP_MD *digest; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssll|s", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssll|s", &password, &password_len, &salt, &salt_len, &key_length, &iterations, @@ -4059,7 +4104,7 @@ PHP_FUNCTION(openssl_pbkdf2) return; } - if (key_length <= 0 || key_length > INT_MAX) { + if (key_length <= 0) { RETURN_FALSE; } @@ -4070,17 +4115,22 @@ PHP_FUNCTION(openssl_pbkdf2) } if (!digest) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); RETURN_FALSE; } - out_buffer = emalloc(key_length + 1); - out_buffer[key_length] = '\0'; + PHP_OPENSSL_CHECK_LONG_TO_INT(key_length, key); + PHP_OPENSSL_CHECK_LONG_TO_INT(iterations, iterations); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(salt_len, salt); + + out_buffer = zend_string_alloc(key_length, 0); - if (PKCS5_PBKDF2_HMAC(password, password_len, (unsigned char *)salt, salt_len, iterations, digest, key_length, out_buffer) == 1) { - RETVAL_STRINGL((char *)out_buffer, key_length, 0); + if (PKCS5_PBKDF2_HMAC(password, (int)password_len, (unsigned char *)salt, (int)salt_len, (int)iterations, digest, (int)key_length, (unsigned char*)ZSTR_VAL(out_buffer)) == 1) { + ZSTR_VAL(out_buffer)[key_length] = 0; + RETURN_NEW_STR(out_buffer); } else { - efree(out_buffer); + zend_string_release(out_buffer); RETURN_FALSE; } } @@ -4100,20 +4150,24 @@ PHP_FUNCTION(openssl_pkcs7_verify) STACK_OF(X509) *others = NULL; PKCS7 * p7 = NULL; BIO * in = NULL, * datain = NULL, * dataout = NULL; - long flags = 0; - char * filename; int filename_len; - char * extracerts = NULL; int extracerts_len = 0; - char * signersfilename = NULL; int signersfilename_len = 0; - char * datafilename = NULL; int datafilename_len = 0; - + zend_long flags = 0; + char * filename; + size_t filename_len; + char * extracerts = NULL; + size_t extracerts_len = 0; + char * signersfilename = NULL; + size_t signersfilename_len = 0; + char * datafilename = NULL; + size_t datafilename_len = 0; + RETVAL_LONG(-1); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pl|papp", &filename, &filename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|papp", &filename, &filename_len, &flags, &signersfilename, &signersfilename_len, &cainfo, &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) { return; } - + if (extracerts) { others = load_all_certs_from_file(extracerts); if (others == NULL) { @@ -4123,12 +4177,12 @@ PHP_FUNCTION(openssl_pkcs7_verify) flags = flags & ~PKCS7_DETACHED; - store = setup_verify(cainfo TSRMLS_CC); + store = setup_verify(cainfo); if (!store) { goto clean_exit; } - if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename)) { goto clean_exit; } @@ -4146,7 +4200,7 @@ PHP_FUNCTION(openssl_pkcs7_verify) if (datafilename) { - if (php_openssl_open_base_dir_chk(datafilename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(datafilename)) { goto clean_exit; } @@ -4159,21 +4213,21 @@ PHP_FUNCTION(openssl_pkcs7_verify) zend_printf("Calling PKCS7 verify\n"); #endif - if (PKCS7_verify(p7, others, store, datain, dataout, flags)) { + if (PKCS7_verify(p7, others, store, datain, dataout, (int)flags)) { RETVAL_TRUE; if (signersfilename) { BIO *certout; - - if (php_openssl_open_base_dir_chk(signersfilename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(signersfilename)) { goto clean_exit; } - + certout = BIO_new_file(signersfilename, "w"); if (certout) { int i; - signers = PKCS7_get0_signers(p7, NULL, flags); + signers = PKCS7_get0_signers(p7, NULL, (int)flags); for(i = 0; i < sk_X509_num(signers); i++) { PEM_write_bio_X509(certout, sk_X509_value(signers, i)); @@ -4181,7 +4235,7 @@ PHP_FUNCTION(openssl_pkcs7_verify) BIO_free(certout); sk_X509_free(signers); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename); + php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename); RETVAL_LONG(-1); } } @@ -4203,30 +4257,29 @@ clean_exit: Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */ PHP_FUNCTION(openssl_pkcs7_encrypt) { - zval ** zrecipcerts, * zheaders = NULL; + zval * zrecipcerts, * zheaders = NULL; STACK_OF(X509) * recipcerts = NULL; BIO * infile = NULL, * outfile = NULL; - long flags = 0; + zend_long flags = 0; PKCS7 * p7 = NULL; - HashPosition hpos; - zval ** zcertval; + zval * zcertval; X509 * cert; const EVP_CIPHER *cipher = NULL; - long cipherid = PHP_OPENSSL_CIPHER_DEFAULT; - uint strindexlen; - ulong intindex; - char * strindex; - char * infilename = NULL; int infilename_len; - char * outfilename = NULL; int outfilename_len; - + zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT; + zend_string * strindex; + char * infilename = NULL; + size_t infilename_len; + char * outfilename = NULL; + size_t outfilename_len; + RETVAL_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZa!|ll", &infilename, &infilename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len, &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE) return; - - if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { return; } @@ -4236,24 +4289,23 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) } outfile = BIO_new_file(outfilename, "w"); - if (outfile == NULL) { + if (outfile == NULL) { goto clean_exit; } recipcerts = sk_X509_new_null(); /* get certs */ - if (Z_TYPE_PP(zrecipcerts) == IS_ARRAY) { - zend_hash_internal_pointer_reset_ex(HASH_OF(*zrecipcerts), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(*zrecipcerts), (void**)&zcertval, &hpos) == SUCCESS) { - long certresource; + if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) { + zend_resource *certresource; - cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcertval, 0, &certresource); if (cert == NULL) { goto clean_exit; } - if (certresource != -1) { + if (certresource != NULL) { /* we shouldn't free this particular cert, as it is a resource. make a copy and push that on the stack instead */ cert = X509_dup(cert); @@ -4262,19 +4314,17 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) } } sk_X509_push(recipcerts, cert); - - zend_hash_move_forward_ex(HASH_OF(*zrecipcerts), &hpos); - } + } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ - long certresource; + zend_resource *certresource; - cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource); if (cert == NULL) { goto clean_exit; } - if (certresource != -1) { + if (certresource != NULL) { /* we shouldn't free this particular cert, as it is a resource. make a copy and push that on the stack instead */ cert = X509_dup(cert); @@ -4289,11 +4339,11 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) cipher = php_openssl_get_evp_cipher_from_algo(cipherid); if (cipher == NULL) { /* shouldn't happen */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher"); + php_error_docref(NULL, E_WARNING, "Failed to get cipher"); goto clean_exit; } - p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, flags); + p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (int)flags); if (p7 == NULL) { goto clean_exit; @@ -4301,27 +4351,21 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) /* tack on extra headers */ if (zheaders) { - zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&zcertval, &hpos) == SUCCESS) { - strindex = NULL; - zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos); - + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) { convert_to_string_ex(zcertval); if (strindex) { - BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(zcertval)); + BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval)); } else { - BIO_printf(outfile, "%s\n", Z_STRVAL_PP(zcertval)); + BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval)); } - - zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos); - } + } ZEND_HASH_FOREACH_END(); } (void)BIO_reset(infile); /* write the encrypted data */ - SMIME_write_PKCS7(outfile, p7, infile, flags); + SMIME_write_PKCS7(outfile, p7, infile, (int)flags); RETVAL_TRUE; @@ -4340,70 +4384,70 @@ clean_exit: PHP_FUNCTION(openssl_pkcs7_sign) { - zval ** zcert, ** zprivkey, * zheaders; - zval ** hval; + zval * zcert, * zprivkey, * zheaders; + zval * hval; X509 * cert = NULL; EVP_PKEY * privkey = NULL; - long flags = PKCS7_DETACHED; + zend_long flags = PKCS7_DETACHED; PKCS7 * p7 = NULL; BIO * infile = NULL, * outfile = NULL; STACK_OF(X509) *others = NULL; - long certresource = -1, keyresource = -1; - ulong intindex; - uint strindexlen; - HashPosition hpos; - char * strindex; - char * infilename; int infilename_len; - char * outfilename; int outfilename_len; - char * extracertsfilename = NULL; int extracertsfilename_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZZa!|lp!", + zend_resource *certresource = NULL, *keyresource = NULL; + zend_string * strindex; + char * infilename; + size_t infilename_len; + char * outfilename; + size_t outfilename_len; + char * extracertsfilename = NULL; + size_t extracertsfilename_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|lp!", &infilename, &infilename_len, &outfilename, &outfilename_len, &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename, &extracertsfilename_len) == FAILURE) { return; } - + RETVAL_FALSE; if (extracertsfilename) { others = load_all_certs_from_file(extracertsfilename); - if (others == NULL) { + if (others == NULL) { goto clean_exit; } } - privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource TSRMLS_CC); + privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource); if (privkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting private key"); + php_error_docref(NULL, E_WARNING, "error getting private key"); goto clean_exit; } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting cert"); + php_error_docref(NULL, E_WARNING, "error getting cert"); goto clean_exit; } - if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { goto clean_exit; } infile = BIO_new_file(infilename, "r"); if (infile == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening input file %s!", infilename); + php_error_docref(NULL, E_WARNING, "error opening input file %s!", infilename); goto clean_exit; } outfile = BIO_new_file(outfilename, "w"); if (outfile == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening output file %s!", outfilename); + php_error_docref(NULL, E_WARNING, "error opening output file %s!", outfilename); goto clean_exit; } - p7 = PKCS7_sign(cert, privkey, others, infile, flags); + p7 = PKCS7_sign(cert, privkey, others, infile, (int)flags); if (p7 == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error creating PKCS7 structure!"); + php_error_docref(NULL, E_WARNING, "error creating PKCS7 structure!"); goto clean_exit; } @@ -4411,23 +4455,18 @@ PHP_FUNCTION(openssl_pkcs7_sign) /* tack on extra headers */ if (zheaders) { - zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos); - while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&hval, &hpos) == SUCCESS) { - strindex = NULL; - zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos); - + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) { convert_to_string_ex(hval); if (strindex) { - BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(hval)); + BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval)); } else { - BIO_printf(outfile, "%s\n", Z_STRVAL_PP(hval)); + BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval)); } - zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos); - } + } ZEND_HASH_FOREACH_END(); } /* write the signed data */ - SMIME_write_PKCS7(outfile, p7, infile, flags); + SMIME_write_PKCS7(outfile, p7, infile, (int)flags); RETVAL_TRUE; @@ -4438,10 +4477,10 @@ clean_exit: if (others) { sk_X509_pop_free(others, X509_free); } - if (privkey && keyresource == -1) { + if (privkey && keyresource == NULL) { EVP_PKEY_free(privkey); } - if (cert && certresource == -1) { + if (cert && certresource == NULL) { X509_free(cert); } } @@ -4452,35 +4491,37 @@ clean_exit: PHP_FUNCTION(openssl_pkcs7_decrypt) { - zval ** recipcert, ** recipkey = NULL; + zval * recipcert, * recipkey = NULL; X509 * cert = NULL; EVP_PKEY * key = NULL; - long certresval, keyresval; + zend_resource *certresval, *keyresval; BIO * in = NULL, * out = NULL, * datain = NULL; PKCS7 * p7 = NULL; - char * infilename; int infilename_len; - char * outfilename; int outfilename_len; + char * infilename; + size_t infilename_len; + char * outfilename; + size_t outfilename_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZ|Z", &infilename, &infilename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|z", &infilename, &infilename_len, &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) { return; } RETVAL_FALSE; - cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC); + cert = php_openssl_x509_from_zval(recipcert, 0, &certresval); if (cert == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert"); + php_error_docref(NULL, E_WARNING, "unable to coerce parameter 3 to x509 cert"); goto clean_exit; } - key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval TSRMLS_CC); + key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval); if (key == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key"); + php_error_docref(NULL, E_WARNING, "unable to get private key"); goto clean_exit; } - - if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { goto clean_exit; } @@ -4498,7 +4539,7 @@ PHP_FUNCTION(openssl_pkcs7_decrypt) if (p7 == NULL) { goto clean_exit; } - if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) { + if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) { RETVAL_TRUE; } clean_exit: @@ -4506,10 +4547,10 @@ clean_exit: BIO_free(datain); BIO_free(in); BIO_free(out); - if (cert && certresval == -1) { + if (cert && certresval == NULL) { X509_free(cert); } - if (key && keyresval == -1) { + if (key && keyresval == NULL) { EVP_PKEY_free(key); } } @@ -4521,55 +4562,57 @@ clean_exit: Encrypts data with private key */ PHP_FUNCTION(openssl_private_encrypt) { - zval **key, *crypted; + zval *key, *crypted; EVP_PKEY *pkey; int cryptedlen; - unsigned char *cryptedbuf = NULL; + zend_string *cryptedbuf = NULL; int successful = 0; - long keyresource = -1; + zend_resource *keyresource = NULL; char * data; - int data_len; - long padding = RSA_PKCS1_PADDING; + size_t data_len; + zend_long padding = RSA_PKCS1_PADDING; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key param is not a valid private key"); + php_error_docref(NULL, E_WARNING, "key param is not a valid private key"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + cryptedlen = EVP_PKEY_size(pkey); - cryptedbuf = emalloc(cryptedlen + 1); + cryptedbuf = zend_string_alloc(cryptedlen, 0); switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_private_encrypt(data_len, - (unsigned char *)data, - cryptedbuf, - pkey->pkey.rsa, - padding) == cryptedlen); + successful = (RSA_private_encrypt((int)data_len, + (unsigned char *)data, + (unsigned char *)ZSTR_VAL(cryptedbuf), + pkey->pkey.rsa, + (int)padding) == cryptedlen); break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); } if (successful) { zval_dtor(crypted); - cryptedbuf[cryptedlen] = '\0'; - ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } if (cryptedbuf) { - efree(cryptedbuf); + zend_string_release(cryptedbuf); } - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } } @@ -4579,64 +4622,66 @@ PHP_FUNCTION(openssl_private_encrypt) Decrypts data with private key */ PHP_FUNCTION(openssl_private_decrypt) { - zval **key, *crypted; + zval *key, *crypted; EVP_PKEY *pkey; int cryptedlen; - unsigned char *cryptedbuf = NULL; + zend_string *cryptedbuf = NULL; unsigned char *crypttemp; int successful = 0; - long padding = RSA_PKCS1_PADDING; - long keyresource = -1; + zend_long padding = RSA_PKCS1_PADDING; + zend_resource *keyresource = NULL; char * data; - int data_len; + size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid private key"); + php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + cryptedlen = EVP_PKEY_size(pkey); crypttemp = emalloc(cryptedlen + 1); switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_private_decrypt(data_len, - (unsigned char *)data, - crypttemp, - pkey->pkey.rsa, - padding); + cryptedlen = RSA_private_decrypt((int)data_len, + (unsigned char *)data, + crypttemp, + pkey->pkey.rsa, + (int)padding); if (cryptedlen != -1) { - cryptedbuf = emalloc(cryptedlen + 1); - memcpy(cryptedbuf, crypttemp, cryptedlen); + cryptedbuf = zend_string_alloc(cryptedlen, 0); + memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen); successful = 1; } break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); } efree(crypttemp); if (successful) { zval_dtor(crypted); - cryptedbuf[cryptedlen] = '\0'; - ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } - if (cryptedbuf) { - efree(cryptedbuf); + if (cryptedbuf) { + zend_string_release(cryptedbuf); } } /* }}} */ @@ -4645,56 +4690,57 @@ PHP_FUNCTION(openssl_private_decrypt) Encrypts data with public key */ PHP_FUNCTION(openssl_public_encrypt) { - zval **key, *crypted; + zval *key, *crypted; EVP_PKEY *pkey; int cryptedlen; - unsigned char *cryptedbuf; + zend_string *cryptedbuf; int successful = 0; - long keyresource = -1; - long padding = RSA_PKCS1_PADDING; + zend_resource *keyresource = NULL; + zend_long padding = RSA_PKCS1_PADDING; char * data; - int data_len; + size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) return; - RETVAL_FALSE; - - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC); + + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key"); + php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + cryptedlen = EVP_PKEY_size(pkey); - cryptedbuf = emalloc(cryptedlen + 1); + cryptedbuf = zend_string_alloc(cryptedlen, 0); switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_public_encrypt(data_len, - (unsigned char *)data, - cryptedbuf, - pkey->pkey.rsa, - padding) == cryptedlen); + successful = (RSA_public_encrypt((int)data_len, + (unsigned char *)data, + (unsigned char *)ZSTR_VAL(cryptedbuf), + pkey->pkey.rsa, + (int)padding) == cryptedlen); break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); } if (successful) { zval_dtor(crypted); - cryptedbuf[cryptedlen] = '\0'; - ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } if (cryptedbuf) { - efree(cryptedbuf); + zend_string_release(cryptedbuf); } } /* }}} */ @@ -4703,65 +4749,67 @@ PHP_FUNCTION(openssl_public_encrypt) Decrypts data with public key */ PHP_FUNCTION(openssl_public_decrypt) { - zval **key, *crypted; + zval *key, *crypted; EVP_PKEY *pkey; int cryptedlen; - unsigned char *cryptedbuf = NULL; + zend_string *cryptedbuf = NULL; unsigned char *crypttemp; int successful = 0; - long keyresource = -1; - long padding = RSA_PKCS1_PADDING; + zend_resource *keyresource = NULL; + zend_long padding = RSA_PKCS1_PADDING; char * data; - int data_len; + size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; - - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC); + + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key"); + php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + cryptedlen = EVP_PKEY_size(pkey); crypttemp = emalloc(cryptedlen + 1); switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_public_decrypt(data_len, - (unsigned char *)data, - crypttemp, - pkey->pkey.rsa, - padding); + cryptedlen = RSA_public_decrypt((int)data_len, + (unsigned char *)data, + crypttemp, + pkey->pkey.rsa, + (int)padding); if (cryptedlen != -1) { - cryptedbuf = emalloc(cryptedlen + 1); - memcpy(cryptedbuf, crypttemp, cryptedlen); + cryptedbuf = zend_string_alloc(cryptedlen, 0); + memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen); successful = 1; } break; - + default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); - + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + } efree(crypttemp); if (successful) { zval_dtor(crypted); - cryptedbuf[cryptedlen] = '\0'; - ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } if (cryptedbuf) { - efree(cryptedbuf); + zend_string_release(cryptedbuf); } - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } } @@ -4780,7 +4828,7 @@ PHP_FUNCTION(openssl_error_string) val = ERR_get_error(); if (val) { - RETURN_STRING(ERR_error_string(val, buf), 1); + RETURN_STRING(ERR_error_string(val, buf)); } else { RETURN_FALSE; } @@ -4791,24 +4839,24 @@ PHP_FUNCTION(openssl_error_string) Signs data */ PHP_FUNCTION(openssl_sign) { - zval **key, *signature; + zval *key, *signature; EVP_PKEY *pkey; - int siglen; - unsigned char *sigbuf; - long keyresource = -1; + unsigned int siglen; + zend_string *sigbuf; + zend_resource *keyresource = NULL; char * data; - int data_len; + size_t data_len; EVP_MD_CTX md_ctx; zval *method = NULL; - long signature_algo = OPENSSL_ALGO_SHA1; + zend_long signature_algo = OPENSSL_ALGO_SHA1; const EVP_MD *mdtype; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|z", &data, &data_len, &signature, &key, &method) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) { return; } - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a private key"); + php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key"); RETURN_FALSE; } @@ -4820,30 +4868,31 @@ PHP_FUNCTION(openssl_sign) } else if (Z_TYPE_P(method) == IS_STRING) { mdtype = EVP_get_digestbyname(Z_STRVAL_P(method)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } if (!mdtype) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } siglen = EVP_PKEY_size(pkey); - sigbuf = emalloc(siglen + 1); + sigbuf = zend_string_alloc(siglen, 0); EVP_SignInit(&md_ctx, mdtype); EVP_SignUpdate(&md_ctx, data, data_len); - if (EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) { + if (EVP_SignFinal (&md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, pkey)) { zval_dtor(signature); - sigbuf[siglen] = '\0'; - ZVAL_STRINGL(signature, (char *)sigbuf, siglen, 0); + ZSTR_VAL(sigbuf)[siglen] = '\0'; + ZSTR_LEN(sigbuf) = siglen; + ZVAL_NEW_STR(signature, sigbuf); RETVAL_TRUE; } else { efree(sigbuf); RETVAL_FALSE; } EVP_MD_CTX_cleanup(&md_ctx); - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } } @@ -4853,21 +4902,25 @@ PHP_FUNCTION(openssl_sign) Verifys data */ PHP_FUNCTION(openssl_verify) { - zval **key; + zval *key; EVP_PKEY *pkey; int err; - EVP_MD_CTX md_ctx; + EVP_MD_CTX md_ctx; const EVP_MD *mdtype; - long keyresource = -1; - char * data; int data_len; - char * signature; int signature_len; + zend_resource *keyresource = NULL; + char * data; + size_t data_len; + char * signature; + size_t signature_len; zval *method = NULL; - long signature_algo = OPENSSL_ALGO_SHA1; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) { + zend_long signature_algo = OPENSSL_ALGO_SHA1; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) { return; } + PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature); + if (method == NULL || Z_TYPE_P(method) == IS_LONG) { if (method != NULL) { signature_algo = Z_LVAL_P(method); @@ -4876,26 +4929,26 @@ PHP_FUNCTION(openssl_verify) } else if (Z_TYPE_P(method) == IS_STRING) { mdtype = EVP_get_digestbyname(Z_STRVAL_P(method)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } if (!mdtype) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a public key"); + php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key"); RETURN_FALSE; } - EVP_VerifyInit (&md_ctx, mdtype); + EVP_VerifyInit (&md_ctx, mdtype); EVP_VerifyUpdate (&md_ctx, data, data_len); - err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey); + err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey); EVP_MD_CTX_cleanup(&md_ctx); - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } RETURN_LONG(err); @@ -4906,66 +4959,69 @@ PHP_FUNCTION(openssl_verify) Seals data */ PHP_FUNCTION(openssl_seal) { - zval *pubkeys, **pubkey, *sealdata, *ekeys; + zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL; HashTable *pubkeysht; - HashPosition pos; EVP_PKEY **pkeys; - long * key_resources; /* so we know what to cleanup */ - int i, len1, len2, *eksl, nkeys; - unsigned char *buf = NULL, **eks; - char * data; int data_len; + zend_resource ** key_resources; /* so we know what to cleanup */ + int i, len1, len2, *eksl, nkeys, iv_len; + unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks; + char * data; + size_t data_len; char *method =NULL; - int method_len = 0; + size_t method_len = 0; const EVP_CIPHER *cipher; EVP_CIPHER_CTX ctx; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|sz/", &data, &data_len, + &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) { return; } - - pubkeysht = HASH_OF(pubkeys); + pubkeysht = Z_ARRVAL_P(pubkeys); nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0; if (!nkeys) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array"); + php_error_docref(NULL, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + if (method) { cipher = EVP_get_cipherbyname(method); if (!cipher) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); - RETURN_FALSE; - } - if (EVP_CIPHER_iv_length(cipher) > 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ciphers with modes requiring IV are not supported"); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } } else { cipher = EVP_rc4(); } + iv_len = EVP_CIPHER_iv_length(cipher); + if (!iv && iv_len > 0) { + php_error_docref(NULL, E_WARNING, + "Cipher algorithm requires an IV to be supplied as a sixth parameter"); + RETURN_FALSE; + } + pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0); eksl = safe_emalloc(nkeys, sizeof(*eksl), 0); eks = safe_emalloc(nkeys, sizeof(*eks), 0); memset(eks, 0, sizeof(*eks) * nkeys); - key_resources = safe_emalloc(nkeys, sizeof(long), 0); - memset(key_resources, 0, sizeof(*key_resources) * nkeys); + key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0); + memset(key_resources, 0, sizeof(zend_resource*) * nkeys); + memset(pkeys, 0, sizeof(*pkeys) * nkeys); /* get the public keys we are using to seal this data */ - zend_hash_internal_pointer_reset_ex(pubkeysht, &pos); i = 0; - while (zend_hash_get_current_data_ex(pubkeysht, (void **) &pubkey, - &pos) == SUCCESS) { - pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i] TSRMLS_CC); + ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) { + pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i]); if (pkeys[i] == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a public key (%dth member of pubkeys)", i+1); + php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1); RETVAL_FALSE; goto clean_exit; } eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1); - zend_hash_move_forward_ex(pubkeysht, &pos); i++; - } + } ZEND_HASH_FOREACH_END(); if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) { RETVAL_FALSE; @@ -4973,47 +5029,39 @@ PHP_FUNCTION(openssl_seal) goto clean_exit; } -#if 0 - /* Need this if allow ciphers that require initialization vector */ - ivlen = EVP_CIPHER_CTX_iv_length(&ctx); - iv = ivlen ? emalloc(ivlen + 1) : NULL; -#endif /* allocate one byte extra to make room for \0 */ buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx)); EVP_CIPHER_CTX_cleanup(&ctx); - if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) { + if (!EVP_SealInit(&ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) || + !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len) || + !EVP_SealFinal(&ctx, buf + len1, &len2)) { RETVAL_FALSE; efree(buf); EVP_CIPHER_CTX_cleanup(&ctx); goto clean_exit; } - EVP_SealFinal(&ctx, buf + len1, &len2); - if (len1 + len2 > 0) { zval_dtor(sealdata); buf[len1 + len2] = '\0'; - buf = erealloc(buf, len1 + len2 + 1); - ZVAL_STRINGL(sealdata, (char *)buf, len1 + len2, 0); + ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0)); + efree(buf); zval_dtor(ekeys); array_init(ekeys); for (i=0; i<nkeys; i++) { eks[i][eksl[i]] = '\0'; - add_next_index_stringl(ekeys, erealloc(eks[i], eksl[i] + 1), eksl[i], 0); + add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]); + efree(eks[i]); eks[i] = NULL; } -#if 0 - /* If allow ciphers that need IV, we need this */ - zval_dtor(*ivec); - if (ivlen) { - iv[ivlen] = '\0'; - ZVAL_STRINGL(*ivec, erealloc(iv, ivlen + 1), ivlen, 0); - } else { - ZVAL_EMPTY_STRING(*ivec); + + if (iv) { + zval_dtor(iv); + iv_buf[iv_len] = '\0'; + ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0)); } -#endif } else { efree(buf); } @@ -5022,10 +5070,10 @@ PHP_FUNCTION(openssl_seal) clean_exit: for (i=0; i<nkeys; i++) { - if (key_resources[i] == -1) { + if (key_resources[i] == NULL && pkeys[i] != NULL) { EVP_PKEY_free(pkeys[i]); } - if (eks[i]) { + if (eks[i]) { efree(eks[i]); } } @@ -5040,73 +5088,95 @@ clean_exit: Opens data */ PHP_FUNCTION(openssl_open) { - zval **privkey, *opendata; + zval *privkey, *opendata; EVP_PKEY *pkey; - int len1, len2; - unsigned char *buf; - long keyresource = -1; + int len1, len2, cipher_iv_len; + unsigned char *buf, *iv_buf; + zend_resource *keyresource = NULL; EVP_CIPHER_CTX ctx; - char * data; int data_len; - char * ekey; int ekey_len; - char *method =NULL; - int method_len = 0; + char * data; + size_t data_len; + char * ekey; + size_t ekey_len; + char *method = NULL, *iv = NULL; + size_t method_len = 0, iv_len = 0; const EVP_CIPHER *cipher; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata, + &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) { return; } - pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource TSRMLS_CC); + pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource); if (pkey == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key"); + php_error_docref(NULL, E_WARNING, "unable to coerce parameter 4 into a private key"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(ekey_len, ekey); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + if (method) { cipher = EVP_get_cipherbyname(method); if (!cipher) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm."); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); RETURN_FALSE; } } else { cipher = EVP_rc4(); } - + + cipher_iv_len = EVP_CIPHER_iv_length(cipher); + if (cipher_iv_len > 0) { + if (!iv) { + php_error_docref(NULL, E_WARNING, + "Cipher algorithm requires an IV to be supplied as a sixth parameter"); + RETURN_FALSE; + } + if (cipher_iv_len != iv_len) { + php_error_docref(NULL, E_WARNING, "IV length is invalid"); + RETURN_FALSE; + } + iv_buf = (unsigned char *)iv; + } else { + iv_buf = NULL; + } + buf = emalloc(data_len + 1); - if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) { + if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) && + EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) { if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) { efree(buf); RETVAL_FALSE; } else { zval_dtor(opendata); buf[len1 + len2] = '\0'; - ZVAL_STRINGL(opendata, erealloc(buf, len1 + len2 + 1), len1 + len2, 0); + ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0)); + efree(buf); RETVAL_TRUE; } } else { efree(buf); RETVAL_FALSE; } - if (keyresource == -1) { + if (keyresource == NULL) { EVP_PKEY_free(pkey); } EVP_CIPHER_CTX_cleanup(&ctx); } /* }}} */ - - static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */ { - add_next_index_string((zval*)arg, (char*)name->name, 1); + add_next_index_string((zval*)arg, (char*)name->name); } /* }}} */ static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */ { if (name->alias == 0) { - add_next_index_string((zval*)arg, (char*)name->name, 1); + add_next_index_string((zval*)arg, (char*)name->name); } } /* }}} */ @@ -5117,12 +5187,12 @@ PHP_FUNCTION(openssl_get_md_methods) { zend_bool aliases = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) { return; } array_init(return_value); OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, - aliases ? openssl_add_method_or_alias: openssl_add_method, + aliases ? openssl_add_method_or_alias: openssl_add_method, return_value); } /* }}} */ @@ -5133,12 +5203,12 @@ PHP_FUNCTION(openssl_get_cipher_methods) { zend_bool aliases = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) { return; } array_init(return_value); OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, - aliases ? openssl_add_method_or_alias: openssl_add_method, + aliases ? openssl_add_method_or_alias: openssl_add_method, return_value); } /* }}} */ @@ -5149,46 +5219,48 @@ PHP_FUNCTION(openssl_digest) { zend_bool raw_output = 0; char *data, *method; - int data_len, method_len; + size_t data_len, method_len; const EVP_MD *mdtype; EVP_MD_CTX md_ctx; - int siglen; - unsigned char *sigbuf; + unsigned int siglen; + zend_string *sigbuf; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) { return; } mdtype = EVP_get_digestbyname(method); if (!mdtype) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); RETURN_FALSE; } siglen = EVP_MD_size(mdtype); - sigbuf = emalloc(siglen + 1); + sigbuf = zend_string_alloc(siglen, 0); EVP_DigestInit(&md_ctx, mdtype); EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len); - if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int *)&siglen)) { + if (EVP_DigestFinal (&md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) { if (raw_output) { - sigbuf[siglen] = '\0'; - RETVAL_STRINGL((char *)sigbuf, siglen, 0); + ZSTR_VAL(sigbuf)[siglen] = '\0'; + ZSTR_LEN(sigbuf) = siglen; + RETVAL_STR(sigbuf); } else { int digest_str_len = siglen * 2; - char *digest_str = emalloc(digest_str_len + 1); + zend_string *digest_str = zend_string_alloc(digest_str_len, 0); - make_digest_ex(digest_str, sigbuf, siglen); - efree(sigbuf); - RETVAL_STRINGL(digest_str, digest_str_len, 0); + make_digest_ex(ZSTR_VAL(digest_str), (unsigned char*)ZSTR_VAL(sigbuf), siglen); + ZSTR_VAL(digest_str)[digest_str_len] = '\0'; + zend_string_release(sigbuf); + RETVAL_STR(digest_str); } } else { - efree(sigbuf); + zend_string_release(sigbuf); RETVAL_FALSE; } } /* }}} */ -static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_required_len TSRMLS_DC) +static zend_bool php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_required_len) { char *iv_new; @@ -5199,25 +5271,25 @@ static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_requir iv_new = ecalloc(1, iv_required_len + 1); - if (*piv_len <= 0) { + if (*piv_len == 0) { /* BC behavior */ *piv_len = iv_required_len; - *piv = iv_new; + *piv = iv_new; return 1; } if (*piv_len < iv_required_len) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is only %d bytes long, cipher expects an IV of precisely %d bytes, padding with \\0", *piv_len, iv_required_len); + php_error_docref(NULL, E_WARNING, "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0", *piv_len, iv_required_len); memcpy(iv_new, *piv, *piv_len); *piv_len = iv_required_len; - *piv = iv_new; + *piv = iv_new; return 1; } - php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is %d bytes long which is longer than the %d expected by selected cipher, truncating", *piv_len, iv_required_len); + php_error_docref(NULL, E_WARNING, "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating", *piv_len, iv_required_len); memcpy(iv_new, *piv, iv_required_len); *piv_len = iv_required_len; - *piv = iv_new; + *piv = iv_new; return 1; } @@ -5226,24 +5298,28 @@ static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_requir Encrypts given data with given method and key, returns raw or base64 encoded string */ PHP_FUNCTION(openssl_encrypt) { - long options = 0; + zend_long options = 0; char *data, *method, *password, *iv = ""; - int data_len, method_len, password_len, iv_len = 0, max_iv_len; + size_t data_len, method_len, password_len, iv_len = 0, max_iv_len; const EVP_CIPHER *cipher_type; EVP_CIPHER_CTX cipher_ctx; - int i=0, outlen, keylen; - unsigned char *outbuf, *key; + int i=0, keylen; + size_t outlen; + zend_string *outbuf; + unsigned char *key; zend_bool free_iv; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) { return; } cipher_type = EVP_get_cipherbyname(method); if (!cipher_type) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + keylen = EVP_CIPHER_key_length(cipher_type); if (keylen > password_len) { key = emalloc(keylen); @@ -5254,45 +5330,42 @@ PHP_FUNCTION(openssl_encrypt) } max_iv_len = EVP_CIPHER_iv_length(cipher_type); - if (iv_len <= 0 && max_iv_len > 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended"); + if (iv_len == 0 && max_iv_len > 0) { + php_error_docref(NULL, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended"); } - free_iv = php_openssl_validate_iv(&iv, &iv_len, max_iv_len TSRMLS_CC); + free_iv = php_openssl_validate_iv(&iv, &iv_len, max_iv_len); outlen = data_len + EVP_CIPHER_block_size(cipher_type); - outbuf = safe_emalloc(outlen, 1, 1); + outbuf = zend_string_alloc(outlen, 0); EVP_EncryptInit(&cipher_ctx, cipher_type, NULL, NULL); if (password_len > keylen) { - EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + EVP_CIPHER_CTX_set_key_length(&cipher_ctx, (int)password_len); } EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv); if (options & OPENSSL_ZERO_PADDING) { EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); } if (data_len > 0) { - EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len); + EVP_EncryptUpdate(&cipher_ctx, (unsigned char*)ZSTR_VAL(outbuf), &i, (unsigned char *)data, (int)data_len); } outlen = i; - if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) { + if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + i, &i)) { outlen += i; if (options & OPENSSL_RAW_DATA) { - outbuf[outlen] = '\0'; - RETVAL_STRINGL_CHECK((char *)outbuf, outlen, 0); + ZSTR_VAL(outbuf)[outlen] = '\0'; + ZSTR_LEN(outbuf) = outlen; + RETVAL_STR(outbuf); } else { - int base64_str_len; - char *base64_str; + zend_string *base64_str; - base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len); - efree(outbuf); - if (!base64_str) { - RETVAL_FALSE; - } else { - RETVAL_STRINGL(base64_str, base64_str_len, 0); - } + base64_str = php_base64_encode((unsigned char*)ZSTR_VAL(outbuf), outlen); + zend_string_release(outbuf); + RETVAL_STR(base64_str); } } else { - efree(outbuf); + zend_string_release(outbuf); RETVAL_FALSE; } if (key != (unsigned char*)password) { @@ -5306,43 +5379,46 @@ PHP_FUNCTION(openssl_encrypt) /* }}} */ /* {{{ proto string openssl_decrypt(string data, string method, string password [, long options=0 [, string $iv = '']]) - Takes raw or base64 encoded string and dectupt it using given method and key */ + Takes raw or base64 encoded string and decrypts it using given method and key */ PHP_FUNCTION(openssl_decrypt) { - long options = 0; + zend_long options = 0; char *data, *method, *password, *iv = ""; - int data_len, method_len, password_len, iv_len = 0; + size_t data_len, method_len, password_len, iv_len = 0; const EVP_CIPHER *cipher_type; EVP_CIPHER_CTX cipher_ctx; - int i, outlen, keylen; - unsigned char *outbuf, *key; - int base64_str_len; - char *base64_str = NULL; + int i, keylen; + size_t outlen; + zend_string *outbuf; + unsigned char *key; + zend_string *base64_str = NULL; zend_bool free_iv; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) { return; } if (!method_len) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); RETURN_FALSE; } + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + cipher_type = EVP_get_cipherbyname(method); if (!cipher_type) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); RETURN_FALSE; } if (!(options & OPENSSL_RAW_DATA)) { - base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len); + base64_str = php_base64_decode((unsigned char*)data, data_len); if (!base64_str) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to base64 decode the input"); + php_error_docref(NULL, E_WARNING, "Failed to base64 decode the input"); RETURN_FALSE; } - data_len = base64_str_len; - data = base64_str; + data_len = ZSTR_LEN(base64_str); + data = ZSTR_VAL(base64_str); } keylen = EVP_CIPHER_key_length(cipher_type); @@ -5354,27 +5430,29 @@ PHP_FUNCTION(openssl_decrypt) key = (unsigned char*)password; } - free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type) TSRMLS_CC); + free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type)); outlen = data_len + EVP_CIPHER_block_size(cipher_type); - outbuf = emalloc(outlen + 1); + outbuf = zend_string_alloc(outlen, 0); EVP_DecryptInit(&cipher_ctx, cipher_type, NULL, NULL); if (password_len > keylen) { - EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + EVP_CIPHER_CTX_set_key_length(&cipher_ctx, (int)password_len); } EVP_DecryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv); if (options & OPENSSL_ZERO_PADDING) { EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); } - EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len); + EVP_DecryptUpdate(&cipher_ctx, (unsigned char*)ZSTR_VAL(outbuf), &i, (unsigned char *)data, (int)data_len); outlen = i; - if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) { + if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + i, &i)) { outlen += i; - outbuf[outlen] = '\0'; - RETVAL_STRINGL((char *)outbuf, outlen, 0); + ZSTR_VAL(outbuf)[outlen] = '\0'; + ZSTR_LEN(outbuf) = outlen; + RETVAL_STR(outbuf); } else { - efree(outbuf); + zend_string_release(outbuf); RETVAL_FALSE; } if (key != (unsigned char*)password) { @@ -5384,7 +5462,7 @@ PHP_FUNCTION(openssl_decrypt) efree(iv); } if (base64_str) { - efree(base64_str); + zend_string_release(base64_str); } EVP_CIPHER_CTX_cleanup(&cipher_ctx); } @@ -5394,21 +5472,21 @@ PHP_FUNCTION(openssl_decrypt) PHP_FUNCTION(openssl_cipher_iv_length) { char *method; - int method_len; + size_t method_len; const EVP_CIPHER *cipher_type; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len) == FAILURE) { return; } if (!method_len) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); RETURN_FALSE; } cipher_type = EVP_get_cipherbyname(method); if (!cipher_type) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm"); + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); RETURN_FALSE; } @@ -5423,30 +5501,34 @@ PHP_FUNCTION(openssl_dh_compute_key) { zval *key; char *pub_str; - int pub_len; + size_t pub_len; EVP_PKEY *pkey; BIGNUM *pub; - char *data; + zend_string *data; int len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, &pub_len, &key) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sr", &pub_str, &pub_len, &key) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key); - if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) { + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { + RETURN_FALSE; + } + if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) { RETURN_FALSE; } - pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key); + pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL); - data = emalloc(DH_size(pkey->pkey.dh) + 1); - len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh); + data = zend_string_alloc(DH_size(pkey->pkey.dh), 0); + len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, pkey->pkey.dh); if (len >= 0) { - data[len] = 0; - RETVAL_STRINGL(data, len, 0); + ZSTR_LEN(data) = len; + ZSTR_VAL(data)[len] = 0; + RETVAL_STR(data); } else { - efree(data); + zend_string_release(data); RETVAL_FALSE; } @@ -5458,47 +5540,53 @@ PHP_FUNCTION(openssl_dh_compute_key) Returns a string of the length specified filled with random pseudo bytes */ PHP_FUNCTION(openssl_random_pseudo_bytes) { - long buffer_length; - unsigned char *buffer = NULL; + zend_long buffer_length; + zend_string *buffer = NULL; zval *zstrong_result_returned = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|z", &buffer_length, &zstrong_result_returned) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) { return; } if (zstrong_result_returned) { zval_dtor(zstrong_result_returned); - ZVAL_BOOL(zstrong_result_returned, 0); + ZVAL_FALSE(zstrong_result_returned); } - if (buffer_length <= 0 || buffer_length > INT_MAX) { + if (buffer_length <= 0 +#ifndef PHP_WIN32 + || ZEND_LONG_INT_OVFL(buffer_length) +#endif + ) { RETURN_FALSE; } - - buffer = safe_emalloc(buffer_length, 1, 1); + buffer = zend_string_alloc(buffer_length, 0); #ifdef PHP_WIN32 /* random/urandom equivalent on Windows */ - if (php_win32_get_random_bytes(buffer, (size_t) buffer_length) == FAILURE){ - efree(buffer); + if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){ + zend_string_release(buffer); if (zstrong_result_returned) { - ZVAL_BOOL(zstrong_result_returned, 0); + ZVAL_FALSE(zstrong_result_returned); } RETURN_FALSE; } #else + + PHP_OPENSSL_CHECK_LONG_TO_INT(buffer_length, length); PHP_OPENSSL_RAND_ADD_TIME(); - if (RAND_bytes(buffer, buffer_length) <= 0) { - efree(buffer); + /* FIXME loop if requested size > INT_MAX */ + if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) { + zend_string_release(buffer); if (zstrong_result_returned) { - ZVAL_BOOL(zstrong_result_returned, 0); + ZVAL_FALSE(zstrong_result_returned); } RETURN_FALSE; } #endif - buffer[buffer_length] = 0; - RETVAL_STRINGL((char *)buffer, buffer_length, 0); + ZSTR_VAL(buffer)[buffer_length] = 0; + RETVAL_STR(buffer); if (zstrong_result_returned) { ZVAL_BOOL(zstrong_result_returned, 1); diff --git a/ext/openssl/openssl.dsp b/ext/openssl/openssl.dsp deleted file mode 100644 index 857666a6a3..0000000000 --- a/ext/openssl/openssl.dsp +++ /dev/null @@ -1,111 +0,0 @@ -# Microsoft Developer Studio Project File - Name="openssl" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=openssl - Win32 Debug_TS
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "openssl.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "openssl.mak" CFG="openssl - Win32 Debug_TS"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "openssl - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "openssl - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "openssl - Win32 Release_TS"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release_TS"
-# PROP BASE Intermediate_Dir "Release_TS"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release_TS"
-# PROP Intermediate_Dir "Release_TS"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENSSL_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_OPENSSL" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_OPENSSL_EXT=1 /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x407 /d "NDEBUG"
-# ADD RSC /l 0x407 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 php5ts.lib ssleay32.lib libeay32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_openssl.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
-
-!ELSEIF "$(CFG)" == "openssl - Win32 Debug_TS"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug_TS"
-# PROP BASE Intermediate_Dir "Debug_TS"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug_TS"
-# PROP Intermediate_Dir "Debug_TS"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENSSL_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_OPENSSL" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_OPENSSL_EXT=1 /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x407 /d "_DEBUG"
-# ADD RSC /l 0x407 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 php5ts_debug.lib ssleay32.lib libeay32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_openssl.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
-
-!ENDIF
-
-# Begin Target
-
-# Name "openssl - Win32 Release_TS"
-# Name "openssl - Win32 Debug_TS"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\openssl.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xp_ssl.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\php_openssl.h
-# End Source File
-# End Group
-# End Target
-# End Project
diff --git a/ext/openssl/openssl.mak b/ext/openssl/openssl.mak index a0c6fa483e..9bc053b662 100644 --- a/ext/openssl/openssl.mak +++ b/ext/openssl/openssl.mak @@ -4,7 +4,7 @@ PROJECT_ROOT = ..\.. # Module details MODULE_NAME = php_ossl -MODULE_DESC = "PHP 5 - OpenSSL Extension" +MODULE_DESC = "PHP 7 - OpenSSL Extension" VMAJ = 1 VMIN = 0 VREV = 0 diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 36b8bbbeb9..92e01241f4 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -26,6 +26,9 @@ extern zend_module_entry openssl_module_entry; #define phpext_openssl_ptr &openssl_module_entry +#include "php_version.h" +#define PHP_OPENSSL_VERSION PHP_VERSION + #define OPENSSL_RAW_DATA 1 #define OPENSSL_ZERO_PADDING 2 diff --git a/ext/openssl/tests/bug60632.phpt b/ext/openssl/tests/bug60632.phpt index a4b473112b..eb51276fa5 100644 --- a/ext/openssl/tests/bug60632.phpt +++ b/ext/openssl/tests/bug60632.phpt @@ -6,6 +6,7 @@ if (!extension_loaded("openssl")) die("skip openssl not loaded"); ?> --FILE-- <?php + $pkey = openssl_pkey_new(array( 'digest_alg' => 'sha256', 'private_key_bits' => 1024, @@ -22,5 +23,5 @@ $result = openssl_seal('test phrase', $encrypted, $ekeys, array($pubkey), 'AES-2 echo "Done"; ?> --EXPECTF-- -Warning: openssl_seal(): Ciphers with modes requiring IV are not supported in %s on line %d +Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d Done diff --git a/ext/openssl/tests/bug70438.phpt b/ext/openssl/tests/bug70438.phpt new file mode 100644 index 0000000000..937e9f3bd9 --- /dev/null +++ b/ext/openssl/tests/bug70438.phpt @@ -0,0 +1,29 @@ +--TEST-- +Request #70438: Add IV parameter for openssl_seal and openssl_open +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) { + print "skip"; +} +if (!in_array('AES-128-CBC', openssl_get_cipher_methods(true))) { + print "skip"; +} +?> +--FILE-- +<?php +$data = "openssl_seal() test"; +$cipher = 'AES-128-CBC'; +$pub_key = "file://" . dirname(__FILE__) . "/public.key"; +$priv_key = "file://" . dirname(__FILE__) . "/private_rsa_1024.key"; + +openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), $cipher); +openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), 'sparkles', $iv); +openssl_seal($data, $sealed, $ekeys, array($pub_key, $pub_key), $cipher, $iv); +openssl_open($sealed, $decrypted, $ekeys[0], $priv_key, $cipher, $iv); +echo $decrypted; +?> +--EXPECTF-- +Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d + +Warning: openssl_seal(): Unknown signature algorithm. in %s on line %d +openssl_seal() test diff --git a/ext/openssl/tests/bug71475.phpt b/ext/openssl/tests/bug71475.phpt new file mode 100644 index 0000000000..e959371c4c --- /dev/null +++ b/ext/openssl/tests/bug71475.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #71475: openssl_seal() uninitialized memory usage +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip openssl not loaded"); +?> +--FILE-- +<?php +$_ = str_repeat("A", 512); +openssl_seal($_, $_, $_, array_fill(0,64,0)); +?> +DONE +--EXPECTF-- + +Warning: openssl_seal(): not a public key (1th member of pubkeys) in %s%ebug71475.php on line %d +DONE diff --git a/ext/openssl/tests/bug72165.phpt b/ext/openssl/tests/bug72165.phpt new file mode 100644 index 0000000000..93b3c3d4a8 --- /dev/null +++ b/ext/openssl/tests/bug72165.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72165 Null pointer dereference - openssl_csr_new +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +?> +--FILE-- +<?php +$var0 = array(0 => "hello", 1 => "world"); +$var2 = openssl_csr_new(array(0),$var0,null,array(0)); +?> +==DONE== +--EXPECTF-- +Warning: openssl_csr_new(): dn: numeric fild names are not supported in %sbug72165.php on line %d + +Warning: openssl_csr_new(): add1_attr_by_txt challengePassword_min -> 4 (failed; check error queue and value of string_mask OpenSSL option if illegal characters are reported) in %sbug72165.php on line %d +==DONE== diff --git a/ext/openssl/tests/openssl_csr_sign_basic.phpt b/ext/openssl/tests/openssl_csr_sign_basic.phpt index ae948e3d25..34cf50a997 100644 --- a/ext/openssl/tests/openssl_csr_sign_basic.phpt +++ b/ext/openssl/tests/openssl_csr_sign_basic.phpt @@ -54,7 +54,7 @@ bool(false) Warning: openssl_csr_sign(): cannot get private key from parameter 3 in %s on line %d bool(false) -Warning: openssl_csr_sign() expects parameter 4 to be long, string given in %s on line %d +Warning: openssl_csr_sign() expects parameter 4 to be integer, string given in %s on line %d NULL Warning: openssl_csr_sign() expects parameter 5 to be array, string given in %s on line %d @@ -74,7 +74,7 @@ Warning: openssl_csr_sign(): key array must be of the form array(0 => key, 1 => Warning: openssl_csr_sign(): cannot get private key from parameter 3 in %s on line %d bool(false) -Warning: openssl_csr_sign() expects parameter 4 to be long, array given in %s on line %d +Warning: openssl_csr_sign() expects parameter 4 to be integer, array given in %s on line %d NULL resource(%d) of type (OpenSSL X.509) diff --git a/ext/openssl/tests/openssl_free_key.phpt b/ext/openssl/tests/openssl_free_key.phpt new file mode 100644 index 0000000000..816f7cf5eb --- /dev/null +++ b/ext/openssl/tests/openssl_free_key.phpt @@ -0,0 +1,77 @@ +--TEST-- +void openssl_free_key ( resource $key_identifier ); +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - @phpsp - sao paulo - br +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) + die("skip"); +if (!@openssl_pkey_new()) + die("skip cannot create private key"); +?> +--FILE-- +<?php +echo "Creating private key\n"; + +/* stack up some entropy; performance is not critical, + * and being slow will most likely even help the test. + */ +for ($z = "", $i = 0; $i < 1024; $i++) { + $z .= $i * $i; + if (function_exists("usleep")) + usleep($i); +} + +$privkey = openssl_pkey_new(); + +if ($privkey === false) + die("failed to create private key"); + +$passphrase = "banana"; +$key_file_name = tempnam(sys_get_temp_dir(), "ssl"); +if ($key_file_name === false) + die("failed to get a temporary filename!"); + +echo "Export key to file\n"; + +openssl_pkey_export_to_file($privkey, $key_file_name, $passphrase) or die("failed to export to file $key_file_name"); + +echo "Load key from file - array syntax\n"; + +$loaded_key = openssl_pkey_get_private(array("file://$key_file_name", $passphrase)); + +if ($loaded_key === false) + die("failed to load key using array syntax"); + +openssl_free_key($loaded_key); + +echo "Load key using direct syntax\n"; + +$loaded_key = openssl_pkey_get_private("file://$key_file_name", $passphrase); + +if ($loaded_key === false) + die("failed to load key using direct syntax"); + +openssl_free_key($loaded_key); + +echo "Load key manually and use string syntax\n"; + +$key_content = file_get_contents($key_file_name); +$loaded_key = openssl_pkey_get_private($key_content, $passphrase); + +if ($loaded_key === false) + die("failed to load key using string syntax"); + +openssl_free_key($loaded_key); + +echo "OK!\n"; + +@unlink($key_file_name); +?> +--EXPECT-- +Creating private key +Export key to file +Load key from file - array syntax +Load key using direct syntax +Load key manually and use string syntax +OK! diff --git a/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt b/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt index 0fdb9856eb..e8ba264550 100644 --- a/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt +++ b/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt @@ -27,7 +27,6 @@ echo "Done\n"; ?> --EXPECTF-- string(57) "Object of class stdClass could not be converted to string" -string(45) "Object of class stdClass to string conversion" string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" bool(false) object(stdClass)#1 (0) { diff --git a/ext/openssl/tests/openssl_x509_checkpurpose.phpt b/ext/openssl/tests/openssl_x509_checkpurpose.phpt new file mode 100644 index 0000000000..2126330a02 --- /dev/null +++ b/ext/openssl/tests/openssl_x509_checkpurpose.phpt @@ -0,0 +1,149 @@ +--TEST-- +int openssl_x509_checkpurpose ( mixed $x509cert , int $purpose [, array $cainfo = array() [, string $untrustedfile ]] ) function +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> +--SKIPIF-- +<?php if (!extension_loaded("openssl")) print "skip"; +if (OPENSSL_VERSION_NUMBER < 0x10000000) die("skip Output requires OpenSSL 1.0"); +?> +--FILE-- +<?php +$cert = "file://" . dirname(__FILE__) . "/cert.crt"; +$bert = "file://" . dirname(__FILE__) . "/bug41033.pem"; +$sert = "file://" . dirname(__FILE__) . "/san-cert.pem"; +$cpca = dirname(__FILE__) . "/san-ca.pem"; +$utfl = dirname(__FILE__) . "/sni_server_domain1.pem"; + +/* int openssl_x509_checkpurpose ( mixed $x509cert , int $purpose); */ +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_NS_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_SIGN)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_ENCRYPT)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_CRL_SIGN)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_CLIENT)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_NS_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_SIGN)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_ENCRYPT)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_CRL_SIGN)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_ANY)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_CLIENT)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_NS_SSL_SERVER)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_SIGN)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_ENCRYPT)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_CRL_SIGN)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_ANY)); + +/* int openssl_x509_checkpurpose ( mixed $x509cert , int $purpose [, array $cainfo = array() ] ); */ +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_NS_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_CRL_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_CLIENT, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_NS_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_CRL_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_ANY, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_CLIENT, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_NS_SSL_SERVER, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_CRL_SIGN, array($cpca))); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_ANY, array($cpca))); + +/* int openssl_x509_checkpurpose ( mixed $x509cert , int $purpose [, array $cainfo = array() [, string $untrustedfile ]] ); function */ +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_NS_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_CRL_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_CLIENT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_NS_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_CRL_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($bert, X509_PURPOSE_ANY, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_CLIENT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_NS_SSL_SERVER, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_ENCRYPT, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_CRL_SIGN, array($cpca), $utfl)); +var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_ANY, array($cpca), $utfl)); +?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/openssl/tests/openssl_x509_export_basic.phpt b/ext/openssl/tests/openssl_x509_export_basic.phpt index cfe1cad524..4177bd7798 100644 --- a/ext/openssl/tests/openssl_x509_export_basic.phpt +++ b/ext/openssl/tests/openssl_x509_export_basic.phpt @@ -18,6 +18,10 @@ var_dump(openssl_x509_export($c, $output3)); // read an invalid cert, fails var_dump(openssl_x509_export($d, $output4)); // read cert from a resource var_dump(openssl_x509_export($e, $output5)); // read an array, fails +if (PHP_EOL !== "\n") { + $a = str_replace(PHP_EOL, "\n", $a); +} + var_dump(strcmp($output, $a)); var_dump(strcmp($output, $output2)); var_dump(strcmp($output, $output3)); diff --git a/ext/openssl/tests/session_meta_capture.phpt b/ext/openssl/tests/session_meta_capture.phpt index 650d5c6959..a09d7e8780 100644 --- a/ext/openssl/tests/session_meta_capture.phpt +++ b/ext/openssl/tests/session_meta_capture.phpt @@ -36,17 +36,17 @@ $clientCode = <<<'CODE' phpt_wait(); stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); - stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; var_dump($meta['protocol']); stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT); - stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; var_dump($meta['protocol']); stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); - stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); + @stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; var_dump($meta['protocol']); CODE; diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index d5490331d6..208aafcd7b 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -28,14 +28,20 @@ #include "ext/standard/file.h" #include "ext/standard/url.h" #include "streams/php_streams_int.h" -#include "ext/standard/php_smart_str.h" +#include "zend_smart_str.h" #include "php_openssl.h" #include "php_network.h" #include <openssl/ssl.h> +#include <openssl/rsa.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/err.h> +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#include <openssl/bn.h> +#include <openssl/dh.h> +#endif + #ifdef PHP_WIN32 #include "win32/winutil.h" #include "win32/time.h" @@ -50,13 +56,33 @@ #include <sys/select.h> #endif +/* OpenSSL 1.0.2 removes SSLv2 support entirely*/ +#if OPENSSL_VERSION_NUMBER < 0x10002000L && !defined(OPENSSL_NO_SSL2) +#define HAVE_SSL2 1 +#endif + +#ifndef OPENSSL_NO_SSL3 +#define HAVE_SSL3 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#define HAVE_TLS11 1 +#define HAVE_TLS12 1 +#endif + #if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x0090800fL #define HAVE_ECDH 1 #endif -#if OPENSSL_VERSION_NUMBER >= 0x00908070L && !defined(OPENSSL_NO_TLSEXT) -#define HAVE_SNI 1 +#if !defined(OPENSSL_NO_TLSEXT) +#if OPENSSL_VERSION_NUMBER >= 0x00908070L +#define HAVE_TLS_SNI 1 #endif +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#define HAVE_TLS_ALPN 1 +#endif +#endif + /* Flags for determining allowed stream crypto methods */ #define STREAM_CRYPTO_IS_CLIENT (1<<0) @@ -67,20 +93,24 @@ #define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5) /* Simplify ssl context option retrieval */ -#define GET_VER_OPT(name) (stream->context && SUCCESS == php_stream_context_get_option(stream->context, "ssl", name, &val)) -#define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_PP(val); } -#define GET_VER_OPT_LONG(name, num) if (GET_VER_OPT(name)) { convert_to_long_ex(val); num = Z_LVAL_PP(val); } +#define GET_VER_OPT(name) (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL) +#define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); } +#define GET_VER_OPT_LONG(name, num) if (GET_VER_OPT(name)) { convert_to_long_ex(val); num = Z_LVAL_P(val); } /* Used for peer verification in windows */ #define PHP_X509_NAME_ENTRY_TO_UTF8(ne, i, out) ASN1_STRING_to_UTF8(&out, X509_NAME_ENTRY_get_data(X509_NAME_get_entry(ne, i))) +#ifndef OPENSSL_NO_RSA +static RSA *tmp_rsa_cb(SSL *s, int is_export, int keylength); +#endif + extern php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl); -extern int php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw, char **out, int *out_len TSRMLS_DC); +extern zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw); extern int php_openssl_get_ssl_stream_data_index(); extern int php_openssl_get_x509_list_id(void); static struct timeval subtract_timeval( struct timeval a, struct timeval b ); static int compare_timeval( struct timeval a, struct timeval b ); -static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC); +static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count); php_stream_ops php_openssl_socket_ops; @@ -92,13 +122,21 @@ typedef struct _php_openssl_sni_cert_t { /* Provides leaky bucket handhsake renegotiation rate-limiting */ typedef struct _php_openssl_handshake_bucket_t { - long prev_handshake; - long limit; - long window; + zend_long prev_handshake; + zend_long limit; + zend_long window; float tokens; unsigned should_close; } php_openssl_handshake_bucket_t; +#ifdef HAVE_TLS_ALPN +/* Holds the available server ALPN protocols for negotiation */ +typedef struct _php_openssl_alpn_ctx_t { + unsigned char *data; + unsigned short len; +} php_openssl_alpn_ctx; +#endif + /* This implementation is very closely tied to the that of the native * sockets implemented in the core. * Don't try this technique in other extensions! @@ -115,6 +153,9 @@ typedef struct _php_openssl_netstream_data_t { php_openssl_handshake_bucket_t *reneg; php_openssl_sni_cert_t *sni_certs; unsigned sni_cert_count; +#ifdef HAVE_TLS_ALPN + php_openssl_alpn_ctx *alpn_ctx; +#endif char *url_name; unsigned state_set:1; unsigned _spare:31; @@ -122,32 +163,28 @@ typedef struct _php_openssl_netstream_data_t { /* it doesn't matter that we do some hash traversal here, since it is done only * in an error condition arising from a network connection problem */ -static int is_http_stream_talking_to_iis(php_stream *stream TSRMLS_DC) /* {{{ */ +static int is_http_stream_talking_to_iis(php_stream *stream) /* {{{ */ { - if (stream->wrapperdata && stream->wrapper && strcasecmp(stream->wrapper->wops->label, "HTTP") == 0) { + if (Z_TYPE(stream->wrapperdata) == IS_ARRAY && stream->wrapper && strcasecmp(stream->wrapper->wops->label, "HTTP") == 0) { /* the wrapperdata is an array zval containing the headers */ - zval **tmp; + zval *tmp; #define SERVER_MICROSOFT_IIS "Server: Microsoft-IIS" #define SERVER_GOOGLE "Server: GFE/" - - zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream->wrapperdata)); - while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(stream->wrapperdata), (void**)&tmp)) { - if (strncasecmp(Z_STRVAL_PP(tmp), SERVER_MICROSOFT_IIS, sizeof(SERVER_MICROSOFT_IIS)-1) == 0) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(stream->wrapperdata), tmp) { + if (strncasecmp(Z_STRVAL_P(tmp), SERVER_MICROSOFT_IIS, sizeof(SERVER_MICROSOFT_IIS)-1) == 0) { return 1; - } else if (strncasecmp(Z_STRVAL_PP(tmp), SERVER_GOOGLE, sizeof(SERVER_GOOGLE)-1) == 0) { + } else if (strncasecmp(Z_STRVAL_P(tmp), SERVER_GOOGLE, sizeof(SERVER_GOOGLE)-1) == 0) { return 1; } - - zend_hash_move_forward(Z_ARRVAL_P(stream->wrapperdata)); - } + } ZEND_HASH_FOREACH_END(); } return 0; } /* }}} */ -static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init TSRMLS_DC) /* {{{ */ +static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init) /* {{{ */ { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; int err = SSL_get_error(sslsock->ssl_handle, nr_bytes); @@ -171,8 +208,8 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init case SSL_ERROR_SYSCALL: if (ERR_peek_error() == 0) { if (nr_bytes == 0) { - if (!is_http_stream_talking_to_iis(stream TSRMLS_CC) && ERR_get_error() != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + if (!is_http_stream_talking_to_iis(stream) && ERR_get_error() != 0) { + php_error_docref(NULL, E_WARNING, "SSL: fatal protocol error"); } SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); @@ -181,7 +218,7 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init } else { char *estr = php_socket_strerror(php_socket_errno(), NULL, 0); - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "SSL: %s", estr); efree(estr); @@ -190,7 +227,7 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init break; } - + /* fall through */ default: /* some other error */ @@ -198,7 +235,7 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init switch (ERR_GET_REASON(ecode)) { case SSL_R_NO_SHARED_CIPHER: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. This could be because the server is missing an SSL certificate (local_cert context option)"); + php_error_docref(NULL, E_WARNING, "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. This could be because the server is missing an SSL certificate (local_cert context option)"); retry = 0; break; @@ -206,7 +243,7 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init do { /* NULL is automatically added */ ERR_error_string_n(ecode, esbuf, sizeof(esbuf)); - if (ebuf.c) { + if (ebuf.s) { smart_str_appendc(&ebuf, '\n'); } smart_str_appends(&ebuf, esbuf); @@ -214,16 +251,16 @@ static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init smart_str_0(&ebuf); - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "SSL operation failed with code %d. %s%s", err, - ebuf.c ? "OpenSSL Error messages:\n" : "", - ebuf.c ? ebuf.c : ""); - if (ebuf.c) { + ebuf.s ? "OpenSSL Error messages:\n" : "", + ebuf.s ? ZSTR_VAL(ebuf.s) : ""); + if (ebuf.s) { smart_str_free(&ebuf); } } - + retry = 0; errno = 0; } @@ -236,8 +273,9 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ php_stream *stream; SSL *ssl; int err, depth, ret; - zval **val; - unsigned long allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH; + zval *val; + zend_ulong allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH; + ret = preverify_ok; @@ -252,14 +290,14 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ /* if allow_self_signed is set, make sure that verification succeeds */ if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && - zend_is_true(*val) + zend_is_true(val) ) { ret = 1; } /* check the depth */ GET_VER_OPT_LONG("verify_depth", allowed_depth); - if ((unsigned long)depth > allowed_depth) { + if ((zend_ulong)depth > allowed_depth) { ret = 0; X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); } @@ -268,21 +306,21 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ } /* }}} */ -static int php_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected TSRMLS_DC) +static int php_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected) { - char *fingerprint; - int fingerprint_len; + zend_string *fingerprint; int result = -1; - if (php_openssl_x509_fingerprint(peer, method, 0, &fingerprint, &fingerprint_len TSRMLS_CC) == SUCCESS) { - result = strcasecmp(expected, fingerprint); - efree(fingerprint); + fingerprint = php_openssl_x509_fingerprint(peer, method, 0); + if (fingerprint) { + result = strcasecmp(expected, ZSTR_VAL(fingerprint)); + zend_string_release(fingerprint); } return result; } -static zend_bool php_x509_fingerprint_match(X509 *peer, zval *val TSRMLS_DC) +static zend_bool php_x509_fingerprint_match(X509 *peer, zval *val) { if (Z_TYPE_P(val) == IS_STRING) { const char *method = NULL; @@ -297,39 +335,29 @@ static zend_bool php_x509_fingerprint_match(X509 *peer, zval *val TSRMLS_DC) break; } - return method && php_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val) TSRMLS_CC) == 0; - + return method && php_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val)) == 0; } else if (Z_TYPE_P(val) == IS_ARRAY) { - HashPosition pos; - zval **current; - char *key; - uint key_len; - ulong key_index; + zval *current; + zend_string *key; if (!zend_hash_num_elements(Z_ARRVAL_P(val))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); return 0; } - for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(val), &pos); - zend_hash_get_current_data_ex(Z_ARRVAL_P(val), (void **)¤t, &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_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(val), key, current) { + if (key == NULL || Z_TYPE_P(current) != IS_STRING) { + php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); return 0; } - if (php_x509_fingerprint_cmp(peer, key, Z_STRVAL_PP(current) TSRMLS_CC) != 0) { + if (php_x509_fingerprint_cmp(peer, ZSTR_VAL(key), Z_STRVAL_P(current)) != 0) { return 0; } - } + } ZEND_HASH_FOREACH_END(); return 1; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint value; fingerprint string or array of the form [algo => fingerprint] required"); } @@ -339,7 +367,8 @@ static zend_bool php_x509_fingerprint_match(X509 *peer, zval *val TSRMLS_DC) static zend_bool matches_wildcard_name(const char *subjectname, const char *certname) /* {{{ */ { char *wildcard = NULL; - int prefix_len, suffix_len, subject_len; + ptrdiff_t prefix_len; + size_t suffix_len, subject_len; if (strcasecmp(subjectname, certname) == 0) { return 1; @@ -414,9 +443,9 @@ static zend_bool matches_san_list(X509 *peer, const char *subject_name) /* {{{ * } } /* No, we aren't bothering to check IPv6 addresses. Why? - * Because IP SAN names are officially deprecated and are - * not allowed by CAs starting in 2015. Deal with it. - */ + * * Because IP SAN names are officially deprecated and are + * * not allowed by CAs starting in 2015. Deal with it. + * */ } } @@ -424,7 +453,7 @@ static zend_bool matches_san_list(X509 *peer, const char *subject_name) /* {{{ * } /* }}} */ -static zend_bool matches_common_name(X509 *peer, const char *subject_name TSRMLS_DC) /* {{{ */ +static zend_bool matches_common_name(X509 *peer, const char *subject_name) /* {{{ */ { char buf[1024]; X509_NAME *cert_name; @@ -435,44 +464,42 @@ static zend_bool matches_common_name(X509 *peer, const char *subject_name TSRMLS 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"); + php_error_docref(NULL, 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); + php_error_docref(NULL, 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); + php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", cert_name_len, buf, subject_name); } return is_match; } /* }}} */ -static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC) /* {{{ */ +static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream) /* {{{ */ { - zval **val = NULL; + zval *val = NULL; char *peer_name = NULL; int err, must_verify_peer, must_verify_peer_name, - must_verify_fingerprint, - has_cnmatch_ctx_opt; + must_verify_fingerprint; php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; must_verify_peer = GET_VER_OPT("verify_peer") - ? zend_is_true(*val) + ? zend_is_true(val) : sslsock->is_client; - has_cnmatch_ctx_opt = GET_VER_OPT("CN_match"); - must_verify_peer_name = (has_cnmatch_ctx_opt || GET_VER_OPT("verify_peer_name")) - ? zend_is_true(*val) + must_verify_peer_name = GET_VER_OPT("verify_peer_name") + ? zend_is_true(val) : sslsock->is_client; must_verify_fingerprint = GET_VER_OPT("peer_fingerprint"); if ((must_verify_peer || must_verify_peer_name || must_verify_fingerprint) && peer == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not get peer certificate"); + php_error_docref(NULL, E_WARNING, "Could not get peer certificate"); return FAILURE; } @@ -484,13 +511,13 @@ static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stre /* fine */ break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - if (GET_VER_OPT("allow_self_signed") && zend_is_true(*val)) { + if (GET_VER_OPT("allow_self_signed") && zend_is_true(val)) { /* allowed */ break; } /* not allowed, so fall through */ default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err) @@ -501,15 +528,15 @@ static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stre /* If a peer_fingerprint match is required this trumps peer and peer_name verification */ if (must_verify_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, + if (Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_ARRAY) { + if (!php_x509_fingerprint_match(peer, val)) { + php_error_docref(NULL, E_WARNING, "peer_fingerprint match failure" ); return FAILURE; } } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Expected peer fingerprint must be a string or an array" ); return FAILURE; @@ -520,12 +547,6 @@ static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stre if (must_verify_peer_name) { GET_VER_OPT_STRING("peer_name", peer_name); - if (has_cnmatch_ctx_opt) { - GET_VER_OPT_STRING("CN_match", peer_name); - php_error(E_DEPRECATED, - "the 'CN_match' SSL context option is deprecated in favor of 'peer_name'" - ); - } /* If no peer name was specified we use the autodetected url name in client environments */ if (peer_name == NULL && sslsock->is_client) { peer_name = sslsock->url_name; @@ -534,7 +555,7 @@ static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stre if (peer_name) { if (matches_san_list(peer, peer_name)) { return SUCCESS; - } else if (matches_common_name(peer, peer_name TSRMLS_CC)) { + } else if (matches_common_name(peer, peer_name)) { return SUCCESS; } else { return FAILURE; @@ -551,16 +572,16 @@ static int apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stre static int passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */ { php_stream *stream = (php_stream *)data; - zval **val = NULL; + zval *val = NULL; char *passphrase = NULL; /* TODO: could expand this to make a callback into PHP user-space */ GET_VER_OPT_STRING("passphrase", passphrase); if (passphrase) { - if (Z_STRLEN_PP(val) < num - 1) { - memcpy(buf, Z_STRVAL_PP(val), Z_STRLEN_PP(val)+1); - return Z_STRLEN_PP(val); + if (Z_STRLEN_P(val) < num - 1) { + memcpy(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)+1); + return (int)Z_STRLEN_P(val); } } return 0; @@ -576,10 +597,9 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / php_stream *stream; php_openssl_netstream_data_t *sslsock; - zval **val; + zval *val; zend_bool is_self_signed = 0; - TSRMLS_FETCH(); stream = (php_stream*)arg; sslsock = (php_openssl_netstream_data_t*)stream->abstract; @@ -597,7 +617,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / err_code = e; } - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error encoding X509 certificate: %d: %s", err_code, ERR_error_string(err_code, err_buf)); + php_error_docref(NULL, E_WARNING, "Error encoding X509 certificate: %d: %s", err_code, ERR_error_string(err_code, err_buf)); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } @@ -605,7 +625,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / OPENSSL_free(der_buf); if (cert_ctx == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error creating certificate context: %s", php_win_err()); + php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", php_win_err()); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } } @@ -627,7 +647,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / chain_flags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; if (!CertGetCertificateChain(NULL, cert_ctx, NULL, NULL, &chain_params, chain_flags, NULL, &cert_chain_ctx)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error getting certificate chain: %s", php_win_err()); + php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", php_win_err()); CertFreeCertificateContext(cert_ctx); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } @@ -668,7 +688,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / cert_name = X509_get_subject_name(x509_store_ctx->cert); index = X509_NAME_get_index_by_NID(cert_name, NID_commonName, -1); if (index < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate certificate CN"); + php_error_docref(NULL, E_WARNING, "Unable to locate certificate CN"); CertFreeCertificateChain(cert_chain_ctx); CertFreeCertificateContext(cert_ctx); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); @@ -678,7 +698,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, NULL, 0); if (num_wchars == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); + php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); OPENSSL_free(cert_name_utf8); CertFreeCertificateChain(cert_chain_ctx); CertFreeCertificateContext(cert_ctx); @@ -689,7 +709,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, server_name, num_wchars); if (num_wchars == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); + php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); efree(server_name); OPENSSL_free(cert_name_utf8); CertFreeCertificateChain(cert_chain_ctx); @@ -711,14 +731,14 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / CertFreeCertificateContext(cert_ctx); if (!verify_result) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error verifying certificate chain policy: %s", php_win_err()); + php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", php_win_err()); RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); } if (chain_policy_status.dwError != 0) { /* The chain does not match the policy */ if (is_self_signed && chain_policy_status.dwError == CERT_E_UNTRUSTEDROOT - && GET_VER_OPT("allow_self_signed") && zend_is_true(*val)) { + && GET_VER_OPT("allow_self_signed") && zend_is_true(val)) { /* allow self-signed certs */ X509_STORE_CTX_set_error(x509_store_ctx, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); } else { @@ -732,7 +752,7 @@ static int win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) / /* }}} */ #endif -static long load_stream_cafile(X509_STORE *cert_store, const char *cafile TSRMLS_DC) /* {{{ */ +static long load_stream_cafile(X509_STORE *cert_store, const char *cafile) /* {{{ */ { php_stream *stream; X509 *cert; @@ -812,9 +832,9 @@ static long load_stream_cafile(X509_STORE *cert_store, const char *cafile TSRMLS } /* }}} */ -static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ +static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ { - zval **val = NULL; + zval *val = NULL; char *cafile = NULL; char *capath = NULL; php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; @@ -823,7 +843,7 @@ static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) GET_VER_OPT_STRING("capath", capath); if (cafile == NULL) { - cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile"), 0); + cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0); cafile = strlen(cafile) ? cafile : NULL; } else if (!sslsock->is_client) { /* Servers need to load and assign CA names from the cafile */ @@ -837,13 +857,13 @@ static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) } if (capath == NULL) { - capath = zend_ini_string("openssl.capath", sizeof("openssl.capath"), 0); + capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0); capath = strlen(capath) ? capath : NULL; } if (cafile || capath) { if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) { - if (cafile && !load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile TSRMLS_CC)) { + if (cafile && !load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile)) { return FAILURE; } } @@ -853,7 +873,7 @@ static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); #else if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Unable to set default verify locations and no CA settings specified"); return FAILURE; } @@ -866,15 +886,15 @@ static int enable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) } /* }}} */ -static void disable_peer_verification(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ +static void disable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ { SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); } /* }}} */ -static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ +static int set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */ { - zval **val = NULL; + zval *val = NULL; char *certfile = NULL; GET_VER_OPT_STRING("local_cert", certfile); @@ -886,7 +906,7 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ if (VCWD_REALPATH(certfile, resolved_path_buff)) { /* a certificate to use for authentication */ if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer", certfile); + php_error_docref(NULL, E_WARNING, "Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer", certfile); return FAILURE; } GET_VER_OPT_STRING("local_pk", private_key); @@ -895,15 +915,15 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ char resolved_path_buff_pk[MAXPATHLEN]; if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) { if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk); + php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk); return FAILURE; } } } else { if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff); + php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff); return FAILURE; - } + } } #if OPENSSL_VERSION_NUMBER < 0x10001001L @@ -923,7 +943,7 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ } while (0); #endif if (!SSL_CTX_check_private_key(ctx)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Private key does not match certificate!"); + php_error_docref(NULL, E_WARNING, "Private key does not match certificate!"); } } } @@ -932,74 +952,73 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */ } /* }}} */ -static const SSL_METHOD *php_select_crypto_method(long method_value, int is_client TSRMLS_DC) /* {{{ */ +static const SSL_METHOD *php_select_crypto_method(zend_long method_value, int is_client) /* {{{ */ { if (method_value == STREAM_CRYPTO_METHOD_SSLv2) { -#ifndef OPENSSL_NO_SSL2 - return is_client ? SSLv2_client_method() : SSLv2_server_method(); +#ifdef HAVE_SSL2 + return is_client ? (SSL_METHOD *)SSLv2_client_method() : (SSL_METHOD *)SSLv2_server_method(); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, + "SSLv2 unavailable in the OpenSSL library against which PHP is linked"); return NULL; #endif } else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) { -#ifndef OPENSSL_NO_SSL3 +#ifdef HAVE_SSL3 return is_client ? SSLv3_client_method() : SSLv3_server_method(); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "SSLv3 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, + "SSLv3 unavailable in the OpenSSL library against which PHP is linked"); return NULL; #endif } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_0) { return is_client ? TLSv1_client_method() : TLSv1_server_method(); } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_1) { -#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#ifdef HAVE_TLS11 return is_client ? TLSv1_1_client_method() : TLSv1_1_server_method(); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, + "TLSv1.1 unavailable in the OpenSSL library against which PHP is linked"); return NULL; #endif } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2) { -#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#ifdef HAVE_TLS12 return is_client ? TLSv1_2_client_method() : TLSv1_2_server_method(); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, + "TLSv1.2 unavailable in the OpenSSL library against which PHP is linked"); return NULL; #endif } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Invalid crypto method"); return NULL; } } /* }}} */ -static long php_get_crypto_method_ctx_flags(long method_flags TSRMLS_DC) /* {{{ */ +static int php_get_crypto_method_ctx_flags(int method_flags) /* {{{ */ { - long ssl_ctx_options = SSL_OP_ALL; + int ssl_ctx_options = SSL_OP_ALL; -#ifndef OPENSSL_NO_SSL2 +#ifdef HAVE_SSL2 if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv2)) { ssl_ctx_options |= SSL_OP_NO_SSLv2; } #endif -#ifndef OPENSSL_NO_SSL3 +#ifdef HAVE_SSL3 if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) { ssl_ctx_options |= SSL_OP_NO_SSLv3; } #endif -#ifndef OPENSSL_NO_TLS1 if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_0)) { ssl_ctx_options |= SSL_OP_NO_TLSv1; } -#endif -#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#ifdef HAVE_TLS11 if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_1)) { ssl_ctx_options |= SSL_OP_NO_TLSv1_1; } - +#endif +#ifdef HAVE_TLS12 if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_2)) { ssl_ctx_options |= SSL_OP_NO_TLSv1_2; } @@ -1014,7 +1033,7 @@ static void limit_handshake_reneg(const SSL *ssl) /* {{{ */ php_stream *stream; php_openssl_netstream_data_t *sslsock; struct timeval now; - long elapsed_time; + zend_long elapsed_time; stream = php_openssl_get_stream_from_ssl_handle(ssl); sslsock = (php_openssl_netstream_data_t*)stream->abstract; @@ -1037,39 +1056,33 @@ static void limit_handshake_reneg(const SSL *ssl) /* {{{ */ /* The token level exceeds our allowed limit */ if (sslsock->reneg->tokens > sslsock->reneg->limit) { - zval **val; + zval *val; - TSRMLS_FETCH(); sslsock->reneg->should_close = 1; - if (stream->context && SUCCESS == php_stream_context_get_option(stream->context, - "ssl", "reneg_limit_callback", &val) + if (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "reneg_limit_callback")) != NULL ) { - zval *param, **params[1], *retval; + zval param, retval; - MAKE_STD_ZVAL(param); - php_stream_to_zval(stream, param); - params[0] = ¶m; + php_stream_to_zval(stream, ¶m); /* Closing the stream inside this callback would segfault! */ stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; - if (FAILURE == call_user_function_ex(EG(function_table), NULL, *val, &retval, 1, params, 0, NULL TSRMLS_CC)) { + if (FAILURE == call_user_function_ex(EG(function_table), NULL, val, &retval, 1, ¶m, 0, NULL)) { php_error(E_WARNING, "SSL: failed invoking reneg limit notification callback"); } stream->flags ^= PHP_STREAM_FLAG_NO_FCLOSE; /* If the reneg_limit_callback returned true don't auto-close */ - if (retval != NULL && Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval) == 1) { + if (Z_TYPE(retval) == IS_TRUE) { sslsock->reneg->should_close = 0; } - FREE_ZVAL(param); - if (retval != NULL) { - zval_ptr_dtor(&retval); - } + zval_ptr_dtor(&retval); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "SSL: client-initiated handshake rate limit exceeded by peer"); } } @@ -1087,16 +1100,16 @@ static void info_callback(const SSL *ssl, int where, int ret) /* {{{ */ static void init_server_reneg_limit(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ { - zval **val; - long limit = OPENSSL_DEFAULT_RENEG_LIMIT; - long window = OPENSSL_DEFAULT_RENEG_WINDOW; + zval *val; + zend_long limit = OPENSSL_DEFAULT_RENEG_LIMIT; + zend_long window = OPENSSL_DEFAULT_RENEG_WINDOW; - if (stream->context && - SUCCESS == php_stream_context_get_option(stream->context, - "ssl", "reneg_limit", &val) + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "reneg_limit")) ) { - convert_to_long(*val); - limit = Z_LVAL_PP(val); + convert_to_long(val); + limit = Z_LVAL_P(val); } /* No renegotiation rate-limiting */ @@ -1104,12 +1117,12 @@ static void init_server_reneg_limit(php_stream *stream, php_openssl_netstream_da return; } - if (stream->context && - SUCCESS == php_stream_context_get_option(stream->context, - "ssl", "reneg_window", &val) + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "reneg_window")) ) { - convert_to_long(*val); - window = Z_LVAL_PP(val); + convert_to_long(val); + window = Z_LVAL_P(val); } sslsock->reneg = (void*)pemalloc(sizeof(php_openssl_handshake_bucket_t), @@ -1126,45 +1139,53 @@ static void init_server_reneg_limit(php_stream *stream, php_openssl_netstream_da } /* }}} */ -static int set_server_rsa_key(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* {{{ */ +#ifndef OPENSSL_NO_RSA +static RSA *tmp_rsa_cb(SSL *s, int is_export, int keylength) { - zval ** val; - int rsa_key_size; - RSA* rsa; - - if (php_stream_context_get_option(stream->context, "ssl", "rsa_key_size", &val) == SUCCESS) { - rsa_key_size = (int) Z_LVAL_PP(val); - if ((rsa_key_size != 1) && (rsa_key_size & (rsa_key_size - 1))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "RSA key size requires a power of 2: %d", rsa_key_size); - rsa_key_size = 2048; - } - } else { - rsa_key_size = 2048; - } - - rsa = RSA_generate_key(rsa_key_size, RSA_F4, NULL, NULL); + BIGNUM *bn = NULL; + static RSA *rsa_tmp = NULL; - if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting RSA key"); - RSA_free(rsa); - return FAILURE; + if (!rsa_tmp && ((bn = BN_new()) == NULL)) { + php_error_docref(NULL, E_WARNING, "allocation error generating RSA key"); + } + if (!rsa_tmp && bn) { + if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) == NULL) || + !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) { + if (rsa_tmp) { + RSA_free(rsa_tmp); + } + rsa_tmp = NULL; + } + BN_free(bn); } - RSA_free(rsa); - - return SUCCESS; + return (rsa_tmp); } -/* }}} */ +#endif -static int set_server_dh_param(SSL_CTX *ctx, char *dh_path TSRMLS_DC) /* {{{ */ +#ifndef OPENSSL_NO_DH +static int set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */ { DH *dh; BIO* bio; + zval *zdhpath; + + zdhpath = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param"); + if (zdhpath == NULL) { +#if 0 + /* Coming in OpenSSL 1.1 ... eventually we'll want to enable this + * in the absence of an explicit dh_param. + */ + SSL_CTX_set_dh_auto(ctx, 1); +#endif + return SUCCESS; + } - bio = BIO_new_file(dh_path, "r"); + convert_to_string_ex(zdhpath); + bio = BIO_new_file(Z_STRVAL_P(zdhpath), "r"); if (bio == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid dh_param file: %s", dh_path); + php_error_docref(NULL, E_WARNING, "invalid dh_param"); return FAILURE; } @@ -1172,12 +1193,12 @@ static int set_server_dh_param(SSL_CTX *ctx, char *dh_path TSRMLS_DC) /* {{{ */ BIO_free(bio); if (dh == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed reading DH params from file: %s", dh_path); + php_error_docref(NULL, E_WARNING, "failed reading DH params"); return FAILURE; } if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "DH param assignment failed"); + php_error_docref(NULL, E_WARNING, "failed assigning DH params"); DH_free(dh); return FAILURE; } @@ -1187,32 +1208,35 @@ static int set_server_dh_param(SSL_CTX *ctx, char *dh_path TSRMLS_DC) /* {{{ */ return SUCCESS; } /* }}} */ +#endif #ifdef HAVE_ECDH -static int set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* {{{ */ +static int set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */ { - zval **val; + zval *zvcurve; int curve_nid; - char *curve_str; EC_KEY *ecdh; - if (php_stream_context_get_option(stream->context, "ssl", "ecdh_curve", &val) == SUCCESS) { - convert_to_string_ex(val); - curve_str = Z_STRVAL_PP(val); - curve_nid = OBJ_sn2nid(curve_str); + zvcurve = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve"); + if (zvcurve == NULL) { +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_CTX_set_ecdh_auto(ctx, 1); + return SUCCESS; +#else + curve_nid = NID_X9_62_prime256v1; +#endif + } else { + convert_to_string_ex(zvcurve); + curve_nid = OBJ_sn2nid(Z_STRVAL_P(zvcurve)); if (curve_nid == NID_undef) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid ECDH curve: %s", curve_str); + php_error_docref(NULL, E_WARNING, "invalid ecdh_curve specified"); return FAILURE; } - } else { - curve_nid = NID_X9_62_prime256v1; } ecdh = EC_KEY_new_by_curve_name(curve_nid); if (ecdh == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "Failed generating ECDH curve"); - + php_error_docref(NULL, E_WARNING, "failed generating ECDH curve"); return FAILURE; } @@ -1224,57 +1248,37 @@ static int set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* /* }}} */ #endif -static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* {{{ */ +static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */ { - zval **val; + zval *zv; long ssl_ctx_options = SSL_CTX_get_options(ctx); #ifdef HAVE_ECDH - if (FAILURE == set_server_ecdh_curve(stream, ctx TSRMLS_CC)) { - return FAILURE; - } -#else - if (SUCCESS == php_stream_context_get_option(stream->context, "ssl", "ecdh_curve", &val)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "ECDH curve support not compiled into the OpenSSL lib against which PHP is linked"); - + if (set_server_ecdh_curve(stream, ctx) == FAILURE) { return FAILURE; } #endif - if (php_stream_context_get_option(stream->context, "ssl", "dh_param", &val) == SUCCESS) { - convert_to_string_ex(val); - if (FAILURE == set_server_dh_param(ctx, Z_STRVAL_PP(val) TSRMLS_CC)) { - return FAILURE; - } - } - - if (FAILURE == set_server_rsa_key(stream, ctx TSRMLS_CC)) { - return FAILURE; - } - - if (SUCCESS == php_stream_context_get_option( - stream->context, "ssl", "honor_cipher_order", &val) && - zend_is_true(*val) - ) { - ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; +#ifndef OPENSSL_NO_RSA + SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); +#endif + /* We now use tmp_rsa_cb to generate a key of appropriate size whenever necessary */ + if (php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size") != NULL) { + php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed"); } - if (SUCCESS == php_stream_context_get_option( - stream->context, "ssl", "single_dh_use", &val) && - zend_is_true(*val) - ) { +#ifndef OPENSSL_NO_DH + set_server_dh_param(stream, ctx); + zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "single_dh_use"); + if (zv != NULL && zend_is_true(zv)) { ssl_ctx_options |= SSL_OP_SINGLE_DH_USE; } +#endif -#ifdef HAVE_ECDH - if (SUCCESS == php_stream_context_get_option( - stream->context, "ssl", "single_ecdh_use", &val) && - zend_is_true(*val) - ) { - ssl_ctx_options |= SSL_OP_SINGLE_ECDH_USE; + zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "honor_cipher_order"); + if (zv != NULL && zend_is_true(zv)) { + ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; } -#endif SSL_CTX_set_options(ctx, ssl_ctx_options); @@ -1282,7 +1286,7 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) } /* }}} */ -#ifdef HAVE_SNI +#ifdef HAVE_TLS_SNI static int server_sni_callback(SSL *ssl_handle, int *al, void *arg) /* {{{ */ { php_stream *stream; @@ -1314,21 +1318,18 @@ static int server_sni_callback(SSL *ssl_handle, int *al, void *arg) /* {{{ */ } /* }}} */ -static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock TSRMLS_DC) +static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) { - zval **val; - zval **current; - char *key; - uint key_len; - ulong key_index; - int key_type; - HashPosition pos; + zval *val; + zval *current; + zend_string *key; + zend_ulong key_index; int i = 0; char resolved_path_buff[MAXPATHLEN]; SSL_CTX *ctx; /* If the stream ctx disables SNI we're finished here */ - if (GET_VER_OPT("SNI_enabled") && !zend_is_true(*val)) { + if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { return SUCCESS; } @@ -1337,16 +1338,16 @@ static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *s return SUCCESS; } - if (Z_TYPE_PP(val) != IS_ARRAY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + if (Z_TYPE_P(val) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "SNI_server_certs requires an array mapping host names to cert paths" ); return FAILURE; } - sslsock->sni_cert_count = zend_hash_num_elements(Z_ARRVAL_PP(val)); + sslsock->sni_cert_count = zend_hash_num_elements(Z_ARRVAL_P(val)); if (sslsock->sni_cert_count == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "SNI_server_certs host cert array must not be empty" ); return FAILURE; @@ -1357,25 +1358,23 @@ static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *s ); memset(sslsock->sni_certs, 0, sslsock->sni_cert_count * sizeof(php_openssl_sni_cert_t)); - 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) - ) { - 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) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), key_index, key, current) { + (void) key_index; + + if (!key) { + php_error_docref(NULL, E_WARNING, "SNI_server_certs array requires string host name keys" ); return FAILURE; } - if (VCWD_REALPATH(Z_STRVAL_PP(current), resolved_path_buff)) { + if (VCWD_REALPATH(Z_STRVAL_P(current), resolved_path_buff)) { /* The hello method is not inherited by SSL structs when assigning a new context * inside the SNI callback, so the just use SSLv23 */ ctx = SSL_CTX_new(SSLv23_server_method()); if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "failed setting local cert chain file `%s'; " \ "check that your cafile/capath settings include " \ "details of your certificate and its issuer", @@ -1384,25 +1383,25 @@ static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *s SSL_CTX_free(ctx); return FAILURE; } else if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "failed setting private key from file `%s'", resolved_path_buff ); SSL_CTX_free(ctx); return FAILURE; } else { - sslsock->sni_certs[i].name = pestrdup(key, php_stream_is_persistent(stream)); + sslsock->sni_certs[i].name = pestrdup(ZSTR_VAL(key), php_stream_is_persistent(stream)); sslsock->sni_certs[i].ctx = ctx; ++i; } } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "failed setting local cert chain file `%s'; file not found", - Z_STRVAL_PP(current) + Z_STRVAL_P(current) ); return FAILURE; } - } + } ZEND_HASH_FOREACH_END(); SSL_CTX_set_tlsext_servername_callback(sslsock->ctx, server_sni_callback); @@ -1411,11 +1410,11 @@ static int enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *s static void enable_client_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ { - zval **val; + zval *val; char *sni_server_name; /* If SNI is explicitly disabled we're finished here */ - if (GET_VER_OPT("SNI_enabled") && !zend_is_true(*val)) { + if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { return; } @@ -1423,11 +1422,6 @@ static void enable_client_sni(php_stream *stream, php_openssl_netstream_data_t * GET_VER_OPT_STRING("peer_name", sni_server_name); - if (GET_VER_OPT("SNI_server_name")) { - GET_VER_OPT_STRING("SNI_server_name", sni_server_name); - php_error(E_DEPRECATED, "SNI_server_name is deprecated in favor of peer_name"); - } - if (sni_server_name) { SSL_set_tlsext_host_name(sslsock->ssl_handle, sni_server_name); } @@ -1435,20 +1429,80 @@ static void enable_client_sni(php_stream *stream, php_openssl_netstream_data_t * /* }}} */ #endif +#ifdef HAVE_TLS_ALPN +/*- + * parses a comma-separated list of strings into a string suitable for SSL_CTX_set_next_protos_advertised + * outlen: (output) set to the length of the resulting buffer on success. + * err: (maybe NULL) on failure, an error message line is written to this BIO. + * in: a NULL terminated string like "abc,def,ghi" + * + * returns: an emalloced buffer or NULL on failure. + */ +static unsigned char *alpn_protos_parse(unsigned short *outlen, const char *in) +{ + size_t len; + unsigned char *out; + size_t i, start = 0; + + len = strlen(in); + if (len >= 65535) { + return NULL; + } + + out = emalloc(strlen(in) + 1); + if (!out) { + return NULL; + } + + for (i = 0; i <= len; ++i) { + if (i == len || in[i] == ',') { + if (i - start > 255) { + efree(out); + return NULL; + } + out[start] = i - start; + start = i + 1; + } else { + out[i + 1] = in[i]; + } + } + + *outlen = len + 1; + + return out; +} + +static int server_alpn_callback(SSL *ssl_handle, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) +{ + php_openssl_netstream_data_t *sslsock = arg; + + if (SSL_select_next_proto + ((unsigned char **)out, outlen, sslsock->alpn_ctx->data, sslsock->alpn_ctx->len, in, + inlen) != OPENSSL_NPN_NEGOTIATED) { + return SSL_TLSEXT_ERR_NOACK; + } + + return SSL_TLSEXT_ERR_OK; +} + +#endif + int php_openssl_setup_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam - TSRMLS_DC) /* {{{ */ + ) /* {{{ */ { const SSL_METHOD *method; - long ssl_ctx_options; - long method_flags; + int ssl_ctx_options; + int method_flags; char *cipherlist = NULL; - zval **val; + char *alpn_protocols = NULL; + zval *val; if (sslsock->ssl_handle) { if (sslsock->s.is_blocked) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); + php_error_docref(NULL, E_WARNING, "SSL/TLS already set-up for this stream"); return FAILURE; } else { return SUCCESS; @@ -1465,13 +1519,13 @@ int php_openssl_setup_crypto(php_stream *stream, /* Should we use a specific crypto method or is generic SSLv23 okay? */ if ((method_flags & (method_flags-1)) == 0) { ssl_ctx_options = SSL_OP_ALL; - method = php_select_crypto_method(method_flags, sslsock->is_client TSRMLS_CC); + method = php_select_crypto_method(method_flags, sslsock->is_client); if (method == NULL) { return FAILURE; } } else { method = sslsock->is_client ? SSLv23_client_method() : SSLv23_server_method(); - ssl_ctx_options = php_get_crypto_method_ctx_flags(method_flags TSRMLS_CC); + ssl_ctx_options = php_get_crypto_method_ctx_flags(method_flags); if (ssl_ctx_options == -1) { return FAILURE; } @@ -1485,12 +1539,12 @@ int php_openssl_setup_crypto(php_stream *stream, #endif if (sslsock->ctx == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL context creation failure"); + php_error_docref(NULL, E_WARNING, "SSL context creation failure"); return FAILURE; } #if OPENSSL_VERSION_NUMBER >= 0x0090806fL - if (GET_VER_OPT("no_ticket") && zend_is_true(*val)) { + if (GET_VER_OPT("no_ticket") && zend_is_true(val)) { ssl_ctx_options |= SSL_OP_NO_TICKET; } #endif @@ -1500,14 +1554,14 @@ int php_openssl_setup_crypto(php_stream *stream, #endif #if OPENSSL_VERSION_NUMBER >= 0x10000000L - if (!GET_VER_OPT("disable_compression") || zend_is_true(*val)) { + if (!GET_VER_OPT("disable_compression") || zend_is_true(val)) { ssl_ctx_options |= SSL_OP_NO_COMPRESSION; } #endif - if (GET_VER_OPT("verify_peer") && !zend_is_true(*val)) { - disable_peer_verification(sslsock->ctx, stream TSRMLS_CC); - } else if (FAILURE == enable_peer_verification(sslsock->ctx, stream TSRMLS_CC)) { + if (GET_VER_OPT("verify_peer") && !zend_is_true(val)) { + disable_peer_verification(sslsock->ctx, stream); + } else if (FAILURE == enable_peer_verification(sslsock->ctx, stream)) { return FAILURE; } @@ -1528,22 +1582,54 @@ int php_openssl_setup_crypto(php_stream *stream, return FAILURE; } } - if (FAILURE == set_local_cert(sslsock->ctx, stream TSRMLS_CC)) { + + GET_VER_OPT_STRING("alpn_protocols", alpn_protocols); + if (alpn_protocols) { +#ifdef HAVE_TLS_ALPN + { + unsigned short alpn_len; + unsigned char *alpn = alpn_protos_parse(&alpn_len, alpn_protocols); + + if (alpn == NULL) { + php_error_docref(NULL, E_WARNING, "Failed parsing comma-separated TLS ALPN protocol string"); + SSL_CTX_free(sslsock->ctx); + sslsock->ctx = NULL; + return FAILURE; + } + if (sslsock->is_client) { + SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len); + } else { + sslsock->alpn_ctx = (php_openssl_alpn_ctx *) emalloc(sizeof(php_openssl_alpn_ctx)); + sslsock->alpn_ctx->data = (unsigned char*)estrndup((const char*)alpn, alpn_len); + sslsock->alpn_ctx->len = alpn_len; + SSL_CTX_set_alpn_select_cb(sslsock->ctx, server_alpn_callback, sslsock); + } + + efree(alpn); + } +#else + php_error_docref(NULL, E_WARNING, + "alpn_protocols support is not compiled into the OpenSSL library against which PHP is linked"); +#endif + } + + if (FAILURE == set_local_cert(sslsock->ctx, stream)) { return FAILURE; } SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options); if (sslsock->is_client == 0 && - stream->context && - FAILURE == set_server_specific_opts(stream, sslsock->ctx TSRMLS_CC) + PHP_STREAM_CONTEXT(stream) && + FAILURE == set_server_specific_opts(stream, sslsock->ctx) ) { return FAILURE; } sslsock->ssl_handle = SSL_new(sslsock->ctx); + if (sslsock->ssl_handle == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL handle creation failure"); + php_error_docref(NULL, E_WARNING, "SSL handle creation failure"); SSL_CTX_free(sslsock->ctx); sslsock->ctx = NULL; return FAILURE; @@ -1552,18 +1638,18 @@ int php_openssl_setup_crypto(php_stream *stream, } if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) { - handle_ssl_error(stream, 0, 1 TSRMLS_CC); + handle_ssl_error(stream, 0, 1); } -#ifdef HAVE_SNI +#ifdef HAVE_TLS_SNI /* Enable server-side SNI */ - if (sslsock->is_client == 0 && enable_server_sni(stream, sslsock TSRMLS_CC) == FAILURE) { + if (!sslsock->is_client && enable_server_sni(stream, sslsock) == FAILURE) { return FAILURE; } #endif /* Enable server-side handshake renegotiation rate-limiting */ - if (sslsock->is_client == 0) { + if (!sslsock->is_client) { init_server_reneg_limit(stream, sslsock); } @@ -1576,9 +1662,9 @@ int php_openssl_setup_crypto(php_stream *stream, if (cparam->inputs.session) { if (cparam->inputs.session->ops != &php_openssl_socket_ops) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied session stream must be an SSL enabled stream"); + php_error_docref(NULL, E_WARNING, "supplied session stream must be an SSL enabled stream"); } else if (((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied SSL session stream is not initialized"); + php_error_docref(NULL, E_WARNING, "supplied SSL session stream is not initialized"); } else { SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle); } @@ -1588,79 +1674,90 @@ int php_openssl_setup_crypto(php_stream *stream, } /* }}} */ -static zval *capture_session_meta(SSL *ssl_handle) /* {{{ */ +static zend_array *capture_session_meta(SSL *ssl_handle) /* {{{ */ { - zval *meta_arr; + zval meta_arr; char *proto_str; long proto = SSL_version(ssl_handle); const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl_handle); switch (proto) { -#if OPENSSL_VERSION_NUMBER >= 0x10001001L - case TLS1_2_VERSION: proto_str = "TLSv1.2"; break; - case TLS1_1_VERSION: proto_str = "TLSv1.1"; break; +#ifdef HAVE_TLS12 + case TLS1_2_VERSION: + proto_str = "TLSv1.2"; + break; +#endif +#ifdef HAVE_TLS11 + case TLS1_1_VERSION: + proto_str = "TLSv1.1"; + break; +#endif + case TLS1_VERSION: + proto_str = "TLSv1"; + break; +#ifdef HAVE_SSL3 + case SSL3_VERSION: + proto_str = "SSLv3"; + break; +#endif +#ifdef HAVE_SSL2 + case SSL2_VERSION: + proto_str = "SSLv2"; + break; #endif - case TLS1_VERSION: proto_str = "TLSv1"; break; - case SSL3_VERSION: proto_str = "SSLv3"; break; - case SSL2_VERSION: proto_str = "SSLv2"; break; default: proto_str = "UNKNOWN"; } - MAKE_STD_ZVAL(meta_arr); - array_init(meta_arr); - add_assoc_string(meta_arr, "protocol", proto_str, 1); - add_assoc_string(meta_arr, "cipher_name", (char *) SSL_CIPHER_get_name(cipher), 1); - add_assoc_long(meta_arr, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL)); - add_assoc_string(meta_arr, "cipher_version", SSL_CIPHER_get_version(cipher), 1); + array_init(&meta_arr); + add_assoc_string(&meta_arr, "protocol", proto_str); + add_assoc_string(&meta_arr, "cipher_name", (char *) SSL_CIPHER_get_name(cipher)); + add_assoc_long(&meta_arr, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL)); + add_assoc_string(&meta_arr, "cipher_version", SSL_CIPHER_get_version(cipher)); - return meta_arr; + return Z_ARR(meta_arr); } /* }}} */ -static int capture_peer_certs(php_stream *stream, php_openssl_netstream_data_t *sslsock, X509 *peer_cert TSRMLS_DC) /* {{{ */ +static int capture_peer_certs(php_stream *stream, php_openssl_netstream_data_t *sslsock, X509 *peer_cert) /* {{{ */ { - zval **val, *zcert; + 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) + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_peer_cert")) && + 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); + ZVAL_RES(&zcert, zend_register_resource(peer_cert, php_openssl_get_x509_list_id())); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate", &zcert); + zval_ptr_dtor(&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) + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_peer_cert_chain")) && + zend_is_true(val) ) { - zval *arr; + 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); + 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); + ZVAL_RES(&zcert, zend_register_resource(mycert, php_openssl_get_x509_list_id())); + add_next_index_zval(&arr, &zcert); } } else { - ZVAL_NULL(arr); + ZVAL_NULL(&arr); } - php_stream_context_set_option(stream->context, "ssl", "peer_certificate_chain", arr); - zval_dtor(arr); - efree(arr); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate_chain", &arr); + zval_ptr_dtor(&arr); } return cert_captured; @@ -1670,7 +1767,7 @@ static int capture_peer_certs(php_stream *stream, php_openssl_netstream_data_t * static int php_openssl_enable_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam - TSRMLS_DC) + ) { int n; int retry = 1; @@ -1683,7 +1780,7 @@ static int php_openssl_enable_crypto(php_stream *stream, int blocked = sslsock->s.is_blocked, has_timeout = 0; -#ifdef HAVE_SNI +#ifdef HAVE_TLS_SNI if (sslsock->is_client) { enable_client_sni(stream, sslsock); } @@ -1698,20 +1795,20 @@ static int php_openssl_enable_crypto(php_stream *stream, sslsock->state_set = 1; } - if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) { + if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0)) { sslsock->s.is_blocked = 0; } - + timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout; has_timeout = !sslsock->s.is_blocked && (timeout->tv_sec || timeout->tv_usec); /* gettimeofday is not monotonic; using it here is not strictly correct */ if (has_timeout) { gettimeofday(&start_time, NULL); } - + do { struct timeval cur_time, - elapsed_time = {0}; + elapsed_time; if (sslsock->is_client) { n = SSL_connect(sslsock->ssl_handle); @@ -1724,20 +1821,20 @@ static int php_openssl_enable_crypto(php_stream *stream, elapsed_time = subtract_timeval( cur_time, start_time ); if (compare_timeval( elapsed_time, *timeout) > 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL: Handshake timed out"); + php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out"); return -1; } } if (n <= 0) { /* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */ - retry = handle_ssl_error(stream, n, blocked TSRMLS_CC); + retry = handle_ssl_error(stream, n, blocked); if (retry) { /* wait until something interesting happens in the socket. It may be a * timeout. Also consider the unlikely of possibility of a write block */ int err = SSL_get_error(sslsock->ssl_handle, n); struct timeval left_time; - + if (has_timeout) { left_time = subtract_timeval( *timeout, elapsed_time ); } @@ -1749,33 +1846,37 @@ static int php_openssl_enable_crypto(php_stream *stream, } } while (retry); - if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked TSRMLS_CC)) { + if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked)) { sslsock->s.is_blocked = blocked; } if (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); + if (peer_cert && PHP_STREAM_CONTEXT(stream)) { + cert_captured = capture_peer_certs(stream, sslsock, peer_cert); } - if (FAILURE == apply_peer_verification_policy(sslsock->ssl_handle, peer_cert, stream TSRMLS_CC)) { + if (FAILURE == apply_peer_verification_policy(sslsock->ssl_handle, peer_cert, stream)) { SSL_shutdown(sslsock->ssl_handle); n = -1; - } else { + } else { sslsock->ssl_active = 1; - if (stream->context) { - zval **val; - - if (SUCCESS == php_stream_context_get_option(stream->context, - "ssl", "capture_session_meta", &val) && - zend_is_true(*val) + if (PHP_STREAM_CONTEXT(stream)) { + zval *val; + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_session_meta")) ) { - zval *meta_arr = capture_session_meta(sslsock->ssl_handle); - php_stream_context_set_option(stream->context, "ssl", "session_meta", meta_arr); - zval_dtor(meta_arr); - efree(meta_arr); + php_error(E_DEPRECATED, + "capture_session_meta is deprecated; its information is now available via stream_get_meta_data()" + ); + } + + if (val && zend_is_true(val)) { + zval meta_arr; + ZVAL_ARR(&meta_arr, capture_session_meta(sslsock->ssl_handle)); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "session_meta", &meta_arr); + zval_ptr_dtor(&meta_arr); } } } @@ -1783,9 +1884,10 @@ static int php_openssl_enable_crypto(php_stream *stream, n = 0; } else { n = -1; + /* We want to capture the peer cert even if verification fails*/ 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 (peer_cert && PHP_STREAM_CONTEXT(stream)) { + cert_captured = capture_peer_certs(stream, sslsock, peer_cert); } } @@ -1804,15 +1906,15 @@ static int php_openssl_enable_crypto(php_stream *stream, return -1; } -static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)/* {{{ */ +static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count) /* {{{ */ { - return php_openssl_sockop_io(1, stream, buf, count TSRMLS_CC); + return php_openssl_sockop_io( 1, stream, buf, count ); } /* }}} */ -static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ +static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ { - return php_openssl_sockop_io(0, stream, (char*)buf, count TSRMLS_CC); + return php_openssl_sockop_io( 0, stream, (char*)buf, count ); } /* }}} */ @@ -1823,10 +1925,9 @@ static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size * report that back to PHP * */ -static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC) +static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count) /* {{{ */ { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; - int nr_bytes = 0; /* Only do this if SSL is active. */ if (sslsock->ssl_active) { @@ -1835,13 +1936,19 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz struct timeval *timeout = NULL; int began_blocked = sslsock->s.is_blocked; int has_timeout = 0; + int nr_bytes = 0; + + /* prevent overflow in openssl */ + if (count > INT_MAX) { + count = INT_MAX; + } /* never use a timeout with non-blocking sockets */ if (began_blocked && &sslsock->s.timeout) { timeout = &sslsock->s.timeout; } - if (timeout && php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC) == SUCCESS) { + if (timeout && php_set_sock_blocking(sslsock->s.socket, 0) == SUCCESS) { sslsock->s.is_blocked = 0; } @@ -1854,7 +1961,7 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz /* Main IO loop. */ do { struct timeval cur_time, elapsed_time, left_time; - + /* If we have a timeout to check, figure out how much time has elapsed since we started. */ if (has_timeout) { gettimeofday(&cur_time, NULL); @@ -1866,7 +1973,7 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz if (compare_timeval(elapsed_time, *timeout) > 0 ) { /* If the socket was originally blocking, set it back. */ if (began_blocked) { - php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC); + php_set_sock_blocking(sslsock->s.socket, 1); sslsock->s.is_blocked = 1; } sslsock->s.timeout_event = 1; @@ -1876,17 +1983,17 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz /* Now, do the IO operation. Don't block if we can't complete... */ if (read) { - nr_bytes = SSL_read(sslsock->ssl_handle, buf, count); + nr_bytes = SSL_read(sslsock->ssl_handle, buf, (int)count); if (sslsock->reneg && sslsock->reneg->should_close) { /* renegotiation rate limiting triggered */ - php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR TSRMLS_CC); + php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); nr_bytes = 0; stream->eof = 1; - break; + break; } } else { - nr_bytes = SSL_write(sslsock->ssl_handle, buf, count); + nr_bytes = SSL_write(sslsock->ssl_handle, buf, (int)count); } /* Now, how much time until we time out? */ @@ -1899,7 +2006,7 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz /* Get the error code from SSL, and check to see if it's an error or not. */ int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); - retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC); + retry = handle_ssl_error(stream, nr_bytes, 0); /* If we get this (the above doesn't check) then we'll retry as well. */ if (errno == EAGAIN && err == SSL_ERROR_WANT_READ && read) { @@ -1908,7 +2015,7 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz if (errno == EAGAIN && err == SSL_ERROR_WANT_WRITE && read == 0) { retry = 1; } - + /* Also, on reads, we may get this condition on an EOF. We should check properly. */ if (read) { stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); @@ -1936,8 +2043,9 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz int err = SSL_get_error(sslsock->ssl_handle, nr_bytes); /* If we didn't get any error, then let's return it to PHP. */ - if (err == SSL_ERROR_NONE) - break; + if (err == SSL_ERROR_NONE) { + break; + } /* Otherwise, we need to wait again (up to time_left or we get an error) */ if (began_blocked) { @@ -1950,39 +2058,39 @@ static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, siz } } } - /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */ + + /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */ } while (retry); /* Tell PHP if we read / wrote bytes. */ if (nr_bytes > 0) { - php_stream_notify_progress_increment(stream->context, nr_bytes, 0); + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); } /* And if we were originally supposed to be blocking, let's reset the socket to that. */ - if (began_blocked && php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC) == SUCCESS) { + if (began_blocked && php_set_sock_blocking(sslsock->s.socket, 1) == SUCCESS) { sslsock->s.is_blocked = 1; } + + return 0 > nr_bytes ? 0 : nr_bytes; } else { + size_t nr_bytes = 0; + /* - * This block is if we had no timeout... We will just sit and wait forever on the IO operation. + * This block is if we had no timeout... We will just sit and wait forever on the IO operation. */ if (read) { - nr_bytes = php_stream_socket_ops.read(stream, buf, count TSRMLS_CC); + nr_bytes = php_stream_socket_ops.read(stream, buf, count); } else { - nr_bytes = php_stream_socket_ops.write(stream, buf, count TSRMLS_CC); + nr_bytes = php_stream_socket_ops.write(stream, buf, count); } - } - /* PHP doesn't expect a negative return. */ - if (nr_bytes < 0) { - nr_bytes = 0; + return nr_bytes; } - - return nr_bytes; } /* }}} */ -struct timeval subtract_timeval( struct timeval a, struct timeval b ) +static struct timeval subtract_timeval( struct timeval a, struct timeval b ) { struct timeval difference; @@ -1997,7 +2105,7 @@ struct timeval subtract_timeval( struct timeval a, struct timeval b ) return difference; } -int compare_timeval( struct timeval a, struct timeval b ) +static int compare_timeval( struct timeval a, struct timeval b ) { if (a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec) ) { return 1; @@ -2008,7 +2116,7 @@ int compare_timeval( struct timeval a, struct timeval b ) } } -static int php_openssl_sockop_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ +static int php_openssl_sockop_close(php_stream *stream, int close_handle) /* {{{ */ { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; #ifdef PHP_WIN32 @@ -2078,20 +2186,20 @@ static int php_openssl_sockop_close(php_stream *stream, int close_handle TSRMLS_ } /* }}} */ -static int php_openssl_sockop_flush(php_stream *stream TSRMLS_DC) /* {{{ */ +static int php_openssl_sockop_flush(php_stream *stream) /* {{{ */ { - return php_stream_socket_ops.flush(stream TSRMLS_CC); + return php_stream_socket_ops.flush(stream); } /* }}} */ -static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ +static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */ { - return php_stream_socket_ops.stat(stream, ssb TSRMLS_CC); + return php_stream_socket_ops.stat(stream, ssb); } /* }}} */ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock, - php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC) + php_stream_xport_param *xparam STREAMS_DC) { int clisock; @@ -2099,13 +2207,12 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ clisock = php_network_accept_incoming(sock->s.socket, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, - xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL, xparam->inputs.timeout, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &xparam->outputs.error_code - TSRMLS_CC); + ); if (clisock >= 0) { php_openssl_netstream_data_t *clisockdata; @@ -2121,12 +2228,12 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ memcpy(clisockdata, sock, sizeof(clisockdata->s)); clisockdata->s.socket = clisock; - + xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); if (xparam->outputs.client) { - xparam->outputs.client->context = stream->context; - if (stream->context) { - zend_list_addref(stream->context->rsrc_id); + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; } } } @@ -2140,9 +2247,9 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ clisockdata->method = sock->method; if (php_stream_xport_crypto_setup(xparam->outputs.client, clisockdata->method, - NULL TSRMLS_CC) < 0 || php_stream_xport_crypto_enable( - xparam->outputs.client, 1 TSRMLS_CC) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enable crypto"); + NULL) < 0 || php_stream_xport_crypto_enable( + xparam->outputs.client, 1) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); php_stream_close(xparam->outputs.client); xparam->outputs.client = NULL; @@ -2150,17 +2257,69 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ } } } - + return xparam->outputs.client == NULL ? -1 : 0; } -static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) +static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam) { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; php_stream_xport_crypto_param *cparam = (php_stream_xport_crypto_param *)ptrparam; php_stream_xport_param *xparam = (php_stream_xport_param *)ptrparam; switch (option) { + case PHP_STREAM_OPTION_META_DATA_API: + if (sslsock->ssl_active) { + zval tmp; + char *proto_str; + const SSL_CIPHER *cipher; + + array_init(&tmp); + + switch (SSL_version(sslsock->ssl_handle)) { +#ifdef HAVE_TLS12 + case TLS1_2_VERSION: proto_str = "TLSv1.2"; break; +#endif +#ifdef HAVE_TLS11 + case TLS1_1_VERSION: proto_str = "TLSv1.1"; break; +#endif + case TLS1_VERSION: proto_str = "TLSv1"; break; +#ifdef HAVE_SSL3 + case SSL3_VERSION: proto_str = "SSLv3"; break; +#endif +#ifdef HAVE_SSL2 + case SSL2_VERSION: proto_str = "SSLv2"; break; +#endif + default: proto_str = "UNKNOWN"; + } + + cipher = SSL_get_current_cipher(sslsock->ssl_handle); + + add_assoc_string(&tmp, "protocol", proto_str); + add_assoc_string(&tmp, "cipher_name", (char *) SSL_CIPHER_get_name(cipher)); + add_assoc_long(&tmp, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL)); + add_assoc_string(&tmp, "cipher_version", SSL_CIPHER_get_version(cipher)); + +#ifdef HAVE_TLS_ALPN + { + const unsigned char *alpn_proto = NULL; + unsigned int alpn_proto_len = 0; + + SSL_get0_alpn_selected(sslsock->ssl_handle, &alpn_proto, &alpn_proto_len); + if (alpn_proto) { + add_assoc_stringl(&tmp, "alpn_protocol", (char *)alpn_proto, alpn_proto_len); + } + } +#endif + add_assoc_zval((zval *)ptrparam, "crypto", &tmp); + } + + add_assoc_bool((zval *)ptrparam, "timed_out", sslsock->s.timeout_event); + add_assoc_bool((zval *)ptrparam, "blocked", sslsock->s.is_blocked); + add_assoc_bool((zval *)ptrparam, "eof", stream->eof); + + return PHP_STREAM_OPTION_RETURN_OK; + case PHP_STREAM_OPTION_CHECK_LIVENESS: { struct timeval tv; @@ -2169,7 +2328,11 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val if (value == -1) { if (sslsock->s.timeout.tv_sec == -1) { - tv.tv_sec = FG(default_socket_timeout); +#ifdef _WIN32 + tv.tv_sec = (long)FG(default_socket_timeout); +#else + tv.tv_sec = (time_t)FG(default_socket_timeout); +#endif tv.tv_usec = 0; } else { tv = sslsock->connect_timeout; @@ -2213,17 +2376,17 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val } return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } - + case PHP_STREAM_OPTION_CRYPTO_API: switch(cparam->op) { case STREAM_XPORT_CRYPTO_OP_SETUP: - cparam->outputs.returncode = php_openssl_setup_crypto(stream, sslsock, cparam TSRMLS_CC); + cparam->outputs.returncode = php_openssl_setup_crypto(stream, sslsock, cparam); return PHP_STREAM_OPTION_RETURN_OK; break; case STREAM_XPORT_CRYPTO_OP_ENABLE: - cparam->outputs.returncode = php_openssl_enable_crypto(stream, sslsock, cparam TSRMLS_CC); + cparam->outputs.returncode = php_openssl_enable_crypto(stream, sslsock, cparam); return PHP_STREAM_OPTION_RETURN_OK; break; default: @@ -2240,16 +2403,16 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val case STREAM_XPORT_OP_CONNECT_ASYNC: /* TODO: Async connects need to check the enable_on_connect option when * we notice that the connect has actually been established */ - php_stream_socket_ops.set_option(stream, option, value, ptrparam TSRMLS_CC); + php_stream_socket_ops.set_option(stream, option, value, ptrparam); if ((sslsock->enable_on_connect) && ((xparam->outputs.returncode == 0) || - (xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && + (xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && xparam->outputs.returncode == 1 && xparam->outputs.error_code == EINPROGRESS))) { - if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL TSRMLS_CC) < 0 || - php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enable crypto"); + if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL) < 0 || + php_stream_xport_crypto_enable(stream, 1) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); xparam->outputs.returncode = -1; } } @@ -2258,9 +2421,9 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val case STREAM_XPORT_OP_ACCEPT: /* we need to copy the additional fields that the underlying tcp transport * doesn't know about */ - xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC TSRMLS_CC); + xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC); + - return PHP_STREAM_OPTION_RETURN_OK; default: @@ -2269,10 +2432,10 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val } } - return php_stream_socket_ops.set_option(stream, option, value, ptrparam TSRMLS_CC); + return php_stream_socket_ops.set_option(stream, option, value, ptrparam); } -static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) +static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret) { php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; @@ -2329,20 +2492,20 @@ php_stream_ops php_openssl_socket_ops = { php_openssl_sockop_set_option, }; -static long get_crypto_method(php_stream_context *ctx, long crypto_method) +static zend_long get_crypto_method(php_stream_context *ctx, zend_long crypto_method) { - zval **val; + zval *val; - if (ctx && php_stream_context_get_option(ctx, "ssl", "crypto_method", &val) == SUCCESS) { + if (ctx && (val = php_stream_context_get_option(ctx, "ssl", "crypto_method")) != NULL) { convert_to_long_ex(val); - crypto_method = (long)Z_LVAL_PP(val); + crypto_method = (zend_long)Z_LVAL_P(val); crypto_method |= STREAM_CRYPTO_IS_CLIENT; } return crypto_method; } -static char *get_url_name(const char *resourcename, size_t resourcenamelen, int is_persistent TSRMLS_DC) +static char *get_url_name(const char *resourcename, size_t resourcenamelen, int is_persistent) { php_url *url; @@ -2381,7 +2544,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, const char *resourcename, size_t resourcenamelen, const char *persistent_id, int options, int flags, struct timeval *timeout, - php_stream_context *context STREAMS_DC TSRMLS_DC) + php_stream_context *context STREAMS_DC) { php_stream *stream = NULL; php_openssl_netstream_data_t *sslsock = NULL; @@ -2391,7 +2554,11 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->s.is_blocked = 1; /* this timeout is used by standard stream funcs, therefor it should use the default value */ - sslsock->s.timeout.tv_sec = FG(default_socket_timeout); +#ifdef _WIN32 + sslsock->s.timeout.tv_sec = (long)FG(default_socket_timeout); +#else + sslsock->s.timeout.tv_sec = (time_t)FG(default_socket_timeout); +#endif sslsock->s.timeout.tv_usec = 0; /* use separate timeout for our private funcs */ @@ -2403,7 +2570,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->s.socket = -1; /* Initialize context as NULL */ - sslsock->ctx = NULL; + sslsock->ctx = NULL; stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+"); @@ -2416,20 +2583,22 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = get_crypto_method(context, STREAM_CRYPTO_METHOD_ANY_CLIENT); } else if (strncmp(proto, "sslv2", protolen) == 0) { -#ifdef OPENSSL_NO_SSL2 - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against"); - return NULL; -#else +#ifdef HAVE_SSL2 sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT; +#else + php_error_docref(NULL, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; #endif } else if (strncmp(proto, "sslv3", protolen) == 0) { -#ifdef OPENSSL_NO_SSL3 - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library PHP is linked against"); - return NULL; -#else +#ifdef HAVE_SSL3 sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; +#else + php_error_docref(NULL, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; #endif } else if (strncmp(proto, "tls", protolen) == 0) { sslsock->enable_on_connect = 1; @@ -2438,24 +2607,26 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; } else if (strncmp(proto, "tlsv1.1", protolen) == 0) { -#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#ifdef HAVE_TLS11 sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, "TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); return NULL; #endif } else if (strncmp(proto, "tlsv1.2", protolen) == 0) { -#if OPENSSL_VERSION_NUMBER >= 0x10001001L +#ifdef HAVE_TLS12 sslsock->enable_on_connect = 1; sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library PHP is linked against"); + php_error_docref(NULL, E_WARNING, "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); return NULL; #endif } - sslsock->url_name = get_url_name(resourcename, resourcenamelen, !!persistent_id TSRMLS_CC); + sslsock->url_name = get_url_name(resourcename, resourcenamelen, !!persistent_id); return stream; } |