--- embedaddon/php/ext/openssl/openssl.c 2012/02/21 23:47:59 1.1 +++ embedaddon/php/ext/openssl/openssl.c 2013/10/14 08:02:27 1.1.1.4 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,11 +16,11 @@ | Wez Furlong | | Sascha Kettler | | Pierre-Alain Joye | - | Marc Delling (PKCS12 functions) | + | Marc Delling (PKCS12 functions) | +----------------------------------------------------------------------+ */ -/* $Id: openssl.c,v 1.1 2012/02/21 23:47:59 misho Exp $ */ +/* $Id: openssl.c,v 1.1.1.4 2013/10/14 08:02:27 misho Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -36,6 +36,10 @@ #include "ext/standard/md5.h" #include "ext/standard/base64.h" +#if PHP_WIN32 +# include "win32/winutil.h" +#endif + /* OpenSSL includes */ #include #include @@ -65,7 +69,13 @@ #define OPENSSL_ALGO_MD2 4 #endif #define OPENSSL_ALGO_DSS1 5 - +#if OPENSSL_VERSION_NUMBER >= 0x0090708fL +#define OPENSSL_ALGO_SHA224 6 +#define OPENSSL_ALGO_SHA256 7 +#define OPENSSL_ALGO_SHA384 8 +#define OPENSSL_ALGO_SHA512 9 +#define OPENSSL_ALGO_RMD160 10 +#endif #define DEBUG_SMIME 0 /* FIXME: Use the openssl constants instead of @@ -89,6 +99,9 @@ enum php_openssl_cipher_type { PHP_OPENSSL_CIPHER_RC2_64, PHP_OPENSSL_CIPHER_DES, PHP_OPENSSL_CIPHER_3DES, + PHP_OPENSSL_CIPHER_AES_128_CBC, + PHP_OPENSSL_CIPHER_AES_192_CBC, + PHP_OPENSSL_CIPHER_AES_256_CBC, PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40 }; @@ -347,7 +360,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, method) ZEND_ARG_INFO(0, password) - ZEND_ARG_INFO(0, raw_output) + ZEND_ARG_INFO(0, options) ZEND_ARG_INFO(0, iv) ZEND_END_ARG_INFO() @@ -355,7 +368,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, ZEND_ARG_INFO(0, data) ZEND_ARG_INFO(0, method) ZEND_ARG_INFO(0, password) - ZEND_ARG_INFO(0, raw_input) + ZEND_ARG_INFO(0, options) ZEND_ARG_INFO(0, iv) ZEND_END_ARG_INFO() @@ -497,16 +510,13 @@ static void php_csr_free(zend_rsrc_list_entry *rsrc TS } /* }}} */ -/* {{{ openssl safe_mode & open_basedir checks */ -inline static int php_openssl_safe_mode_chk(char *filename TSRMLS_DC) +/* {{{ openssl open_basedir check */ +inline static int php_openssl_open_base_dir_chk(char *filename TSRMLS_DC) { - if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { - return -1; - } if (php_check_open_basedir(filename TSRMLS_CC)) { return -1; } - + return 0; } /* }}} */ @@ -536,6 +546,8 @@ struct php_x509_request { /* {{{ */ int priv_key_encrypt; EVP_PKEY * priv_key; + + const EVP_CIPHER * priv_key_encrypt_cipher; }; /* }}} */ @@ -549,6 +561,7 @@ static EVP_PKEY * php_openssl_generate_private_key(str static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */ { + zval **data; zval *subitem, *subentries; int i, j = -1, last = -1, obj_cnt = 0; char *sname; @@ -563,10 +576,10 @@ static void add_assoc_name_entry(zval * val, char * ke } else { subitem = val; } - + for (i = 0; i < X509_NAME_entry_count(name); i++) { unsigned char *to_add; - int to_add_len; + int to_add_len = 0; ne = X509_NAME_get_entry(name, i); @@ -580,39 +593,27 @@ static void add_assoc_name_entry(zval * val, char * ke sname = (char *) OBJ_nid2ln(nid); } - MAKE_STD_ZVAL(subentries); - array_init(subentries); + str = X509_NAME_ENTRY_get_data(ne); + if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) { + to_add_len = ASN1_STRING_to_UTF8(&to_add, str); + } else { + to_add = ASN1_STRING_data(str); + to_add_len = ASN1_STRING_length(str); + } - last = -1; - for (;;) { - j = X509_NAME_get_index_by_OBJ(name, obj, last); - if (j < 0) { - if (last != -1) break; - } else { - obj_cnt++; - ne = X509_NAME_get_entry(name, j); - str = X509_NAME_ENTRY_get_data(ne); - if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) { - to_add_len = ASN1_STRING_to_UTF8(&to_add, str); - if (to_add_len != -1) { - add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1); - } - } else { - to_add = ASN1_STRING_data(str); - to_add_len = ASN1_STRING_length(str); + 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); } - } - last = j; - } - i = last; - - if (obj_cnt > 1) { - add_assoc_zval_ex(subitem, sname, strlen(sname) + 1, subentries); - } else { - zval_dtor(subentries); - FREE_ZVAL(subentries); - if (obj_cnt && str && to_add_len > -1) { + } else { add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1); } } @@ -706,7 +707,7 @@ static inline int php_openssl_config_check_syntax(cons #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)) { @@ -766,6 +767,9 @@ static int add_oid_section(struct php_x509_request * r else \ varname = defval +static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo); + + static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */ { char * str; @@ -782,7 +786,7 @@ static int php_openssl_parse_config(struct php_x509_re /* read in the oids */ str = CONF_get_string(req->req_config, NULL, "oid_file"); - if (str && !php_openssl_safe_mode_chk(str TSRMLS_CC)) { + if (str && !php_openssl_open_base_dir_chk(str TSRMLS_CC)) { BIO *oid_bio = BIO_new_file(str, "r"); if (oid_bio) { OBJ_create_objects(oid_bio); @@ -816,7 +820,22 @@ static int php_openssl_parse_config(struct php_x509_re req->priv_key_encrypt = 1; } } - + + 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) { + long cipher_algo = Z_LVAL_PP(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."); + return FAILURE; + } else { + req->priv_key_encrypt_cipher = cipher; + } + } else { + req->priv_key_encrypt_cipher = NULL; + } + + + /* digest alg */ if (req->digest_name == NULL) { req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md"); @@ -838,7 +857,7 @@ static int php_openssl_parse_config(struct php_x509_re } PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section); - + return SUCCESS; } /* }}} */ @@ -860,12 +879,10 @@ static void php_openssl_dispose_config(struct php_x509 } /* }}} */ -static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */ +static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded TSRMLS_DC) /* {{{ */ { char buffer[MAXPATHLEN]; - TSRMLS_FETCH(); - *egdsocket = 0; *seeded = 0; @@ -932,6 +949,23 @@ static EVP_MD * php_openssl_get_evp_md_from_algo(long case OPENSSL_ALGO_DSS1: mdtype = (EVP_MD *) EVP_dss1(); break; +#if OPENSSL_VERSION_NUMBER >= 0x0090708fL + case OPENSSL_ALGO_SHA224: + mdtype = (EVP_MD *) EVP_sha224(); + break; + case OPENSSL_ALGO_SHA256: + mdtype = (EVP_MD *) EVP_sha256(); + break; + case OPENSSL_ALGO_SHA384: + mdtype = (EVP_MD *) EVP_sha384(); + break; + case OPENSSL_ALGO_SHA512: + mdtype = (EVP_MD *) EVP_sha512(); + break; + case OPENSSL_ALGO_RMD160: + mdtype = (EVP_MD *) EVP_ripemd160(); + break; +#endif default: return NULL; break; @@ -962,6 +996,20 @@ static const EVP_CIPHER * php_openssl_get_evp_cipher_f return EVP_des_ede3_cbc(); break; #endif + +#ifndef OPENSSL_NO_AES + case PHP_OPENSSL_CIPHER_AES_128_CBC: + return EVP_aes_128_cbc(); + break; + case PHP_OPENSSL_CIPHER_AES_192_CBC: + return EVP_aes_192_cbc(); + break; + case PHP_OPENSSL_CIPHER_AES_256_CBC: + return EVP_aes_256_cbc(); + break; +#endif + + default: return NULL; break; @@ -984,17 +1032,15 @@ PHP_MINIT_FUNCTION(openssl) OpenSSL_add_all_digests(); OpenSSL_add_all_algorithms(); - ERR_load_ERR_strings(); - ERR_load_crypto_strings(); - ERR_load_EVP_strings(); + SSL_load_error_strings(); /* 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); @@ -1014,6 +1060,13 @@ PHP_MINIT_FUNCTION(openssl) REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT); +#if OPENSSL_VERSION_NUMBER >= 0x0090708fL + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT); +#endif /* flags for S/MIME */ REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT); @@ -1041,6 +1094,11 @@ PHP_MINIT_FUNCTION(openssl) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT); #endif +#ifndef OPENSSL_NO_AES + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT); + 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); @@ -1052,6 +1110,9 @@ PHP_MINIT_FUNCTION(openssl) REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT); #endif + REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT); + #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) /* SNI support included in OpenSSL >= 0.9.8j */ REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT); @@ -1084,7 +1145,7 @@ PHP_MINIT_FUNCTION(openssl) php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC); php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC); - + return SUCCESS; } /* }}} */ @@ -1174,7 +1235,7 @@ static X509 * php_openssl_x509_from_zval(zval ** val, /* read cert from the named file */ BIO *in; - if (php_openssl_safe_mode_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) { return NULL; } @@ -1200,7 +1261,7 @@ static X509 * php_openssl_x509_from_zval(zval ** val, } if (cert && makeresource && resourceval) { - *resourceval = zend_list_insert(cert, le_x509); + *resourceval = zend_list_insert(cert, le_x509 TSRMLS_CC); } return cert; } @@ -1219,7 +1280,7 @@ PHP_FUNCTION(openssl_x509_export_to_file) char * filename; int filename_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) { return; } RETVAL_FALSE; @@ -1230,7 +1291,7 @@ PHP_FUNCTION(openssl_x509_export_to_file) return; } - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { return; } @@ -1304,14 +1365,14 @@ PHP_FUNCTION(openssl_x509_check_private_key) long certresource = -1, keyresource = -1; RETVAL_FALSE; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) { return; } cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); if (cert == NULL) { RETURN_FALSE; - } + } key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC); if (key) { RETVAL_BOOL(X509_check_private_key(cert, key)); @@ -1326,6 +1387,74 @@ PHP_FUNCTION(openssl_x509_check_private_key) } /* }}} */ +/* Special handling of subjectAltName, see CVE-2013-4073 + * Christian Heimes + */ + +static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) +{ + GENERAL_NAMES *names; + const X509V3_EXT_METHOD *method = NULL; + long i, length, num; + const unsigned char *p; + + method = X509V3_EXT_get(extension); + if (method == NULL) { + return -1; + } + + 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))); + } else { + names = (GENERAL_NAMES*)(method->d2i(NULL, &p, length)); + } + if (names == NULL) { + return -1; + } + + 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); + } + /* trailing ', ' except for last element */ + if (i < (num - 1)) { + BIO_puts(bio, ", "); + } + } + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + + return 0; +} + /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true]) Returns an array of the fields/values of the CERT */ PHP_FUNCTION(openssl_x509_parse) @@ -1364,11 +1493,11 @@ PHP_FUNCTION(openssl_x509_parse) snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert)); add_assoc_string(return_value, "hash", buf, 1); } - + add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames TSRMLS_CC); 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)), 1); add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert)); add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert)); @@ -1422,15 +1551,30 @@ PHP_FUNCTION(openssl_x509_parse) for (i = 0; i < X509_get_ext_count(cert); i++) { + int nid; extension = X509_get_ext(cert, i); - if (OBJ_obj2nid(X509_EXTENSION_get_object(extension)) != NID_undef) { + nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); + if (nid != NID_undef) { extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension))); } else { OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1); extname = buf; } bio_out = BIO_new(BIO_s_mem()); - if (X509V3_EXT_print(bio_out, extension, 0, 0)) { + 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); + } else { + zval_dtor(return_value); + if (certresource == -1 && cert) { + X509_free(cert); + } + BIO_free(bio_out); + RETURN_FALSE; + } + } + 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); } else { @@ -1460,7 +1604,7 @@ static STACK_OF(X509) * load_all_certs_from_file(char goto end; } - if (php_openssl_safe_mode_chk(certfile TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(certfile TSRMLS_CC)) { sk_X509_free(stack); goto end; } @@ -1570,8 +1714,8 @@ clean_exit: if (certresource == 1 && 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); @@ -1624,7 +1768,7 @@ static X509_STORE * setup_verify(zval * calist TSRMLS_ 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 { + } else { ndirs++; } dir_lookup = NULL; @@ -1718,11 +1862,11 @@ static STACK_OF(X509) * php_array_to_X509_sk(zval ** z if (certresource != -1) { cert = X509_dup(cert); - + if (cert == NULL) { goto clean_exit; } - + } sk_X509_push(sk, cert); @@ -1731,7 +1875,7 @@ static STACK_OF(X509) * php_array_to_X509_sk(zval ** z } else { /* a single certificate */ cert = php_openssl_x509_from_zval(zcerts, 0, &certresource TSRMLS_CC); - + if (cert == NULL) { goto clean_exit; } @@ -1768,15 +1912,11 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) zval ** item; STACK_OF(X509) *ca = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zszs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE) return; RETVAL_FALSE; - if (strlen(filename) != filename_len) { - return; - } - cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC); if (cert == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); @@ -1791,7 +1931,7 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert"); goto cleanup; } - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { goto cleanup; } @@ -1812,9 +1952,9 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) 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; @@ -1825,13 +1965,13 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) BIO_free(bio_out); PKCS12_free(p12); php_sk_X509_free(ca); - + cleanup: if (keyresource == -1 && priv_key) { EVP_PKEY_free(priv_key); } - if (certresource == -1 && cert) { + if (certresource == -1 && cert) { X509_free(cert); } } @@ -1857,7 +1997,7 @@ PHP_FUNCTION(openssl_pkcs12_export) return; RETVAL_FALSE; - + cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC); if (cert == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1"); @@ -1880,7 +2020,7 @@ PHP_FUNCTION(openssl_pkcs12_export) if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS) ca = php_array_to_X509_sk(item TSRMLS_CC); /* 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()); @@ -1897,13 +2037,13 @@ PHP_FUNCTION(openssl_pkcs12_export) BIO_free(bio_out); PKCS12_free(p12); php_sk_X509_free(ca); - + cleanup: if (keyresource == -1 && priv_key) { EVP_PKEY_free(priv_key); } - if (certresource == -1 && cert) { + if (certresource == -1 && cert) { X509_free(cert); } } @@ -1927,12 +2067,12 @@ PHP_FUNCTION(openssl_pkcs12_read) return; RETVAL_FALSE; - + bio_in = BIO_new(BIO_s_mem()); - + if(!BIO_write(bio_in, zp12, zp12_len)) goto cleanup; - + if(d2i_PKCS12_bio(bio_in, &p12)) { if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) { BIO * bio_out; @@ -1962,12 +2102,12 @@ PHP_FUNCTION(openssl_pkcs12_read) MAKE_STD_ZVAL(zextracerts); array_init(zextracerts); - + for (i=0;;i++) { zval * zextracert; X509* aCA = sk_X509_pop(ca); if (!aCA) break; - + bio_out = BIO_new(BIO_s_mem()); if (PEM_write_bio_X509(bio_out, aCA)) { BUF_MEM *bio_buf; @@ -1975,7 +2115,7 @@ PHP_FUNCTION(openssl_pkcs12_read) MAKE_STD_ZVAL(zextracert); ZVAL_STRINGL(zextracert, bio_buf->data, bio_buf->length, 1); add_index_zval(zextracerts, i, zextracert); - + } BIO_free(bio_out); @@ -1987,13 +2127,13 @@ PHP_FUNCTION(openssl_pkcs12_read) } else { zval_dtor(zextracerts); } - + RETVAL_TRUE; - + PKCS12_free(p12); } } - + cleanup: if (bio_in) { BIO_free(bio_in); @@ -2001,7 +2141,7 @@ PHP_FUNCTION(openssl_pkcs12_read) if (pkey) { EVP_PKEY_free(pkey); } - if (cert) { + if (cert) { X509_free(cert); } } @@ -2020,7 +2160,7 @@ static int php_openssl_make_REQ(struct php_x509_reques 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"); @@ -2040,15 +2180,15 @@ static int php_openssl_make_REQ(struct php_x509_reques X509_NAME * subj; HashPosition hpos; zval ** item; - + 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; + 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); @@ -2058,10 +2198,14 @@ static int php_openssl_make_REQ(struct php_x509_reques nid = OBJ_txt2nid(strindex); if (nid != NID_undef) { - if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, + 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, "dn: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item)); + php_error_docref(NULL TSRMLS_CC, 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)); return FAILURE; } } else { @@ -2075,10 +2219,10 @@ static int php_openssl_make_REQ(struct php_x509_reques 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); if (len < sizeof("_default")) { continue; @@ -2093,7 +2237,7 @@ static int php_openssl_make_REQ(struct php_x509_reques 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++) { @@ -2110,7 +2254,7 @@ static int php_openssl_make_REQ(struct php_x509_reques if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) { continue; } - if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_ASC, (unsigned char*)v->value, -1, -1, 0)) { + 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); return FAILURE; } @@ -2134,7 +2278,7 @@ static int php_openssl_make_REQ(struct php_x509_reques nid = OBJ_txt2nid(strindex); if (nid != NID_undef) { - if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) { + 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; } @@ -2151,8 +2295,12 @@ static int php_openssl_make_REQ(struct php_x509_reques if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) { continue; } - if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_ASC, (unsigned char*)v->value, -1)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "add1_attr_by_txt %s -> %s (failed)", v->name, v->value); + 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, + "add1_attr_by_txt %s -> %s (failed; check error queue " + "and value of string_mask OpenSSL option if illegal " + "characters are reported)", + v->name, v->value); return FAILURE; } } @@ -2170,7 +2318,7 @@ static X509_REQ * php_openssl_csr_from_zval(zval ** va X509_REQ * csr = NULL; char * filename = NULL; BIO * in; - + if (resourceval) { *resourceval = -1; } @@ -2194,7 +2342,7 @@ static X509_REQ * php_openssl_csr_from_zval(zval ** va filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1); } if (filename) { - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { return NULL; } in = BIO_new_file(filename, "r"); @@ -2219,22 +2367,18 @@ PHP_FUNCTION(openssl_csr_export_to_file) BIO * bio_out; long csr_resource; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) { return; } RETVAL_FALSE; - if (strlen(filename) != filename_len) { - return; - } - csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC); if (csr == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); return; } - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { return; } @@ -2315,13 +2459,13 @@ PHP_FUNCTION(openssl_csr_sign) long csr_resource, certresource = 0, keyresource = -1; 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) return; RETVAL_FALSE; PHP_SSL_REQ_INIT(&req); - + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC); if (csr == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1"); @@ -2343,7 +2487,7 @@ PHP_FUNCTION(openssl_csr_sign) php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert"); goto cleanup; } - + if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) { goto cleanup; } @@ -2363,9 +2507,9 @@ PHP_FUNCTION(openssl_csr_sign) php_error_docref(NULL TSRMLS_CC, 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"); @@ -2376,7 +2520,7 @@ PHP_FUNCTION(openssl_csr_sign) goto cleanup; ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial); - + X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr)); if (cert == NULL) { @@ -2393,7 +2537,7 @@ PHP_FUNCTION(openssl_csr_sign) } 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)) { @@ -2406,11 +2550,11 @@ PHP_FUNCTION(openssl_csr_sign) php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it"); goto cleanup; } - + /* Succeeded; lets return the cert */ - RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509)); + RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509 TSRMLS_CC)); new_cert = NULL; - + cleanup: if (cert == new_cert) { @@ -2427,7 +2571,7 @@ cleanup: if (csr_resource == -1 && csr) { X509_REQ_free(csr); } - if (certresource == -1 && cert) { + if (certresource == -1 && cert) { X509_free(cert); } if (new_cert) { @@ -2446,12 +2590,12 @@ PHP_FUNCTION(openssl_csr_new) 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) { return; } RETVAL_FALSE; - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { @@ -2483,10 +2627,10 @@ PHP_FUNCTION(openssl_csr_new) php_error_docref(NULL TSRMLS_CC, 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)); - csr = NULL; + RETVAL_RESOURCE(zend_list_insert(csr, le_csr TSRMLS_CC)); + csr = NULL; } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request"); } @@ -2494,7 +2638,7 @@ PHP_FUNCTION(openssl_csr_new) 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)); + ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key TSRMLS_CC)); req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ } else if (key_resource != -1) { req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ @@ -2567,7 +2711,7 @@ PHP_FUNCTION(openssl_csr_get_public_key) } tpubkey=X509_REQ_get_pubkey(csr); - RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key)); + RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key TSRMLS_CC)); return; } /* }}} */ @@ -2611,14 +2755,14 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** va } if (Z_TYPE_PP(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)"); return NULL; } - + if (Z_TYPE_PP(zphrase) == IS_STRING) { passphrase = Z_STRVAL_PP(zphrase); } else { @@ -2643,7 +2787,7 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** va if (!what) { TMP_CLEAN; } - if (resourceval) { + if (resourceval) { *resourceval = Z_LVAL_PP(val); } if (type == le_x509) { @@ -2677,8 +2821,8 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** va } } 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)) { TMP_CLEAN; @@ -2712,7 +2856,7 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval ** va BIO *in; if (filename) { - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { TMP_CLEAN; } in = BIO_new_file(filename, "r"); @@ -2752,7 +2896,7 @@ static EVP_PKEY * php_openssl_generate_private_key(str 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", MIN_KEY_LENGTH, req->priv_key_bits); @@ -2760,8 +2904,8 @@ static EVP_PKEY * php_openssl_generate_private_key(str } randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE"); - php_openssl_load_rand_file(randfile, &egdsocket, &seeded); - + php_openssl_load_rand_file(randfile, &egdsocket, &seeded TSRMLS_CC); + if ((req->priv_key = EVP_PKEY_new()) != NULL) { switch(req->priv_key_type) { case OPENSSL_KEYTYPE_RSA: @@ -2811,13 +2955,13 @@ static EVP_PKEY * php_openssl_generate_private_key(str } 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; } /* }}} */ @@ -2846,7 +2990,7 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey T 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; @@ -2921,7 +3065,7 @@ PHP_FUNCTION(openssl_pkey_new) OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp); if (rsa->n && rsa->d) { if (EVP_PKEY_assign_RSA(pkey, rsa)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key)); + RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); } } RSA_free(rsa); @@ -2945,7 +3089,7 @@ PHP_FUNCTION(openssl_pkey_new) DSA_generate_key(dsa); } if (EVP_PKEY_assign_DSA(pkey, dsa)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key)); + RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); } } DSA_free(dsa); @@ -2968,7 +3112,7 @@ PHP_FUNCTION(openssl_pkey_new) DH_generate_key(dh); } if (EVP_PKEY_assign_DH(pkey, dh)) { - RETURN_RESOURCE(zend_list_insert(pkey, le_key)); + RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC)); } } DH_free(dh); @@ -2977,7 +3121,7 @@ PHP_FUNCTION(openssl_pkey_new) } RETURN_FALSE; } - } + } PHP_SSL_REQ_INIT(&req); @@ -2985,7 +3129,7 @@ PHP_FUNCTION(openssl_pkey_new) { if (php_openssl_generate_private_key(&req TSRMLS_CC)) { /* pass back a key resource */ - RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key)); + RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key TSRMLS_CC)); /* make sure the cleanup code doesn't zap it! */ req.priv_key = NULL; } @@ -3006,34 +3150,34 @@ PHP_FUNCTION(openssl_pkey_export_to_file) EVP_PKEY * key; BIO * bio_out = NULL; const EVP_CIPHER * cipher; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) { + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) { return; } RETVAL_FALSE; - if (strlen(filename) != filename_len) { - return; - } - key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC); if (key == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1"); RETURN_FALSE; } - - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { RETURN_FALSE; } - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { bio_out = BIO_new_file(filename, "w"); if (passphrase && req.priv_key_encrypt) { - cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + if (req.priv_key_encrypt_cipher) { + cipher = req.priv_key_encrypt_cipher; + } else { + cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + } } else { cipher = NULL; } @@ -3065,7 +3209,7 @@ PHP_FUNCTION(openssl_pkey_export) 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) { return; } @@ -3077,14 +3221,18 @@ PHP_FUNCTION(openssl_pkey_export) php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1"); RETURN_FALSE; } - + PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { bio_out = BIO_new(BIO_s_mem()); if (passphrase && req.priv_key_encrypt) { - cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + if (req.priv_key_encrypt_cipher) { + cipher = req.priv_key_encrypt_cipher; + } else { + cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + } } else { cipher = NULL; } @@ -3128,6 +3276,7 @@ PHP_FUNCTION(openssl_pkey_get_public) if (pkey == NULL) { RETURN_FALSE; } + zend_list_addref(Z_LVAL_P(return_value)); } /* }}} */ @@ -3164,6 +3313,7 @@ PHP_FUNCTION(openssl_pkey_get_private) if (pkey == NULL) { RETURN_FALSE; } + zend_list_addref(Z_LVAL_P(return_value)); } /* }}} */ @@ -3193,7 +3343,7 @@ 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 + /*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)) { @@ -3217,7 +3367,7 @@ PHP_FUNCTION(openssl_pkey_get_details) add_assoc_zval(return_value, "rsa", rsa); } - break; + break; case EVP_PKEY_DSA: case EVP_PKEY_DSA2: case EVP_PKEY_DSA3: @@ -3238,7 +3388,7 @@ PHP_FUNCTION(openssl_pkey_get_details) } break; case EVP_PKEY_DH: - + ktype = OPENSSL_KEYTYPE_DH; if (pkey->pkey.dh != NULL) { @@ -3254,7 +3404,7 @@ PHP_FUNCTION(openssl_pkey_get_details) } break; -#ifdef EVP_PKEY_EC +#ifdef EVP_PKEY_EC case EVP_PKEY_EC: ktype = OPENSSL_KEYTYPE_EC; break; @@ -3288,15 +3438,15 @@ PHP_FUNCTION(openssl_pkcs7_verify) char * extracerts = NULL; int extracerts_len = 0; char * signersfilename = NULL; int signersfilename_len = 0; char * datafilename = NULL; int datafilename_len = 0; - + RETVAL_LONG(-1); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sass", &filename, &filename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "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) { @@ -3311,7 +3461,7 @@ PHP_FUNCTION(openssl_pkcs7_verify) if (!store) { goto clean_exit; } - if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) { goto clean_exit; } @@ -3329,7 +3479,7 @@ PHP_FUNCTION(openssl_pkcs7_verify) if (datafilename) { - if (php_openssl_safe_mode_chk(datafilename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(datafilename TSRMLS_CC)) { goto clean_exit; } @@ -3348,11 +3498,11 @@ PHP_FUNCTION(openssl_pkcs7_verify) if (signersfilename) { BIO *certout; - - if (php_openssl_safe_mode_chk(signersfilename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(signersfilename TSRMLS_CC)) { goto clean_exit; } - + certout = BIO_new_file(signersfilename, "w"); if (certout) { int i; @@ -3401,32 +3551,25 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) char * strindex; char * infilename = NULL; int infilename_len; char * outfilename = NULL; int outfilename_len; - + RETVAL_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZa!|ll", &infilename, &infilename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZa!|ll", &infilename, &infilename_len, &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE) return; - if (strlen(infilename) != infilename_len) { - return; - } - if (strlen(outfilename) != outfilename_len) { + if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { return; } - if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) { - return; - } - infile = BIO_new_file(infilename, "r"); if (infile == NULL) { goto clean_exit; } outfile = BIO_new_file(outfilename, "w"); - if (outfile == NULL) { + if (outfile == NULL) { goto clean_exit; } @@ -3547,25 +3690,18 @@ PHP_FUNCTION(openssl_pkcs7_sign) char * outfilename; int outfilename_len; char * extracertsfilename = NULL; int extracertsfilename_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZZa!|ls", + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZZa!|lp", &infilename, &infilename_len, &outfilename, &outfilename_len, &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename, &extracertsfilename_len) == FAILURE) { return; } + RETVAL_FALSE; - if (strlen(infilename) != infilename_len) { - return; - } - - if (strlen(outfilename) != outfilename_len) { - return; - } - if (extracertsfilename) { others = load_all_certs_from_file(extracertsfilename); - if (others == NULL) { + if (others == NULL) { goto clean_exit; } } @@ -3582,7 +3718,7 @@ PHP_FUNCTION(openssl_pkcs7_sign) goto clean_exit; } - if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) { + if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { goto clean_exit; } @@ -3658,21 +3794,13 @@ PHP_FUNCTION(openssl_pkcs7_decrypt) char * infilename; int infilename_len; char * outfilename; int outfilename_len; - RETVAL_FALSE; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|Z", &infilename, &infilename_len, + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZ|Z", &infilename, &infilename_len, &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) { return; } - if (strlen(infilename) != infilename_len) { - return; - } + RETVAL_FALSE; - if (strlen(outfilename) != outfilename_len) { - return; - } - cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC); if (cert == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert"); @@ -3684,8 +3812,8 @@ PHP_FUNCTION(openssl_pkcs7_decrypt) php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key"); goto clean_exit; } - - if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) { + + if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) { goto clean_exit; } @@ -3703,7 +3831,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: @@ -3736,7 +3864,7 @@ PHP_FUNCTION(openssl_private_encrypt) int data_len; 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() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; @@ -3754,10 +3882,10 @@ PHP_FUNCTION(openssl_private_encrypt) switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_private_encrypt(data_len, - (unsigned char *)data, - cryptedbuf, - pkey->pkey.rsa, + successful = (RSA_private_encrypt(data_len, + (unsigned char *)data, + cryptedbuf, + pkey->pkey.rsa, padding) == cryptedlen); break; default: @@ -3774,7 +3902,7 @@ PHP_FUNCTION(openssl_private_encrypt) if (cryptedbuf) { efree(cryptedbuf); } - if (keyresource == -1) { + if (keyresource == -1) { EVP_PKEY_free(pkey); } } @@ -3812,10 +3940,10 @@ PHP_FUNCTION(openssl_private_decrypt) switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_private_decrypt(data_len, - (unsigned char *)data, - crypttemp, - pkey->pkey.rsa, + cryptedlen = RSA_private_decrypt(data_len, + (unsigned char *)data, + crypttemp, + pkey->pkey.rsa, padding); if (cryptedlen != -1) { cryptedbuf = emalloc(cryptedlen + 1); @@ -3840,7 +3968,7 @@ PHP_FUNCTION(openssl_private_decrypt) if (keyresource == -1) { EVP_PKEY_free(pkey); } - if (cryptedbuf) { + if (cryptedbuf) { efree(cryptedbuf); } } @@ -3864,7 +3992,7 @@ PHP_FUNCTION(openssl_public_encrypt) return; RETVAL_FALSE; - + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC); if (pkey == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key"); @@ -3877,10 +4005,10 @@ PHP_FUNCTION(openssl_public_encrypt) switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_public_encrypt(data_len, - (unsigned char *)data, - cryptedbuf, - pkey->pkey.rsa, + successful = (RSA_public_encrypt(data_len, + (unsigned char *)data, + cryptedbuf, + pkey->pkey.rsa, padding) == cryptedlen); break; default: @@ -3923,7 +4051,7 @@ PHP_FUNCTION(openssl_public_decrypt) return; } RETVAL_FALSE; - + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC); if (pkey == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key"); @@ -3936,10 +4064,10 @@ PHP_FUNCTION(openssl_public_decrypt) switch (pkey->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_public_decrypt(data_len, - (unsigned char *)data, - crypttemp, - pkey->pkey.rsa, + cryptedlen = RSA_public_decrypt(data_len, + (unsigned char *)data, + crypttemp, + pkey->pkey.rsa, padding); if (cryptedlen != -1) { cryptedbuf = emalloc(cryptedlen + 1); @@ -3947,10 +4075,10 @@ PHP_FUNCTION(openssl_public_decrypt) successful = 1; } break; - + default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!"); - + } efree(crypttemp); @@ -4068,7 +4196,7 @@ PHP_FUNCTION(openssl_verify) char * signature; int 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) { return; } @@ -4127,7 +4255,7 @@ PHP_FUNCTION(openssl_seal) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) { return; } - + pubkeysht = HASH_OF(pubkeys); nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0; if (!nkeys) { @@ -4222,7 +4350,7 @@ clean_exit: if (key_resources[i] == -1) { EVP_PKEY_free(pkeys[i]); } - if (eks[i]) { + if (eks[i]) { efree(eks[i]); } } @@ -4268,13 +4396,13 @@ PHP_FUNCTION(openssl_open) } else { cipher = EVP_rc4(); } - + 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_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) { efree(buf); - if (keyresource == -1) { + if (keyresource == -1) { EVP_PKEY_free(pkey); } RETURN_FALSE; @@ -4511,7 +4639,7 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream 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); return NULL; - } + } } tmpssl = SSL_new(ctx); @@ -4568,7 +4696,7 @@ PHP_FUNCTION(openssl_get_md_methods) } 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); } /* }}} */ @@ -4584,7 +4712,7 @@ PHP_FUNCTION(openssl_get_cipher_methods) } 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); } /* }}} */ @@ -4668,20 +4796,20 @@ static zend_bool php_openssl_validate_iv(char **piv, i } -/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false [, string $iv='']]) +/* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv='']]) Encrypts given data with given method and key, returns raw or base64 encoded string */ PHP_FUNCTION(openssl_encrypt) { - zend_bool raw_output = 0; + long options = 0; char *data, *method, *password, *iv = ""; int data_len, method_len, password_len, iv_len = 0, max_iv_len; const EVP_CIPHER *cipher_type; EVP_CIPHER_CTX cipher_ctx; - int i, outlen, keylen; + int i=0, outlen, keylen; unsigned char *outbuf, *key; zend_bool free_iv; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|bs", &data, &data_len, &method, &method_len, &password, &password_len, &raw_output, &iv, &iv_len) == FAILURE) { + 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) { return; } cipher_type = EVP_get_cipherbyname(method); @@ -4713,13 +4841,16 @@ PHP_FUNCTION(openssl_encrypt) EVP_CIPHER_CTX_set_key_length(&cipher_ctx, 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); } outlen = i; if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) { outlen += i; - if (raw_output) { + if (options & OPENSSL_RAW_DATA) { outbuf[outlen] = '\0'; RETVAL_STRINGL((char *)outbuf, outlen, 0); } else { @@ -4744,11 +4875,11 @@ PHP_FUNCTION(openssl_encrypt) } /* }}} */ -/* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false [, string $iv = '']]) +/* {{{ 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 */ PHP_FUNCTION(openssl_decrypt) { - zend_bool raw_input = 0; + long options = 0; char *data, *method, *password, *iv = ""; int data_len, method_len, password_len, iv_len = 0; const EVP_CIPHER *cipher_type; @@ -4759,7 +4890,7 @@ PHP_FUNCTION(openssl_decrypt) char *base64_str = NULL; zend_bool free_iv; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|bs", &data, &data_len, &method, &method_len, &password, &password_len, &raw_input, &iv, &iv_len) == FAILURE) { + 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) { return; } @@ -4774,8 +4905,12 @@ PHP_FUNCTION(openssl_decrypt) RETURN_FALSE; } - if (!raw_input) { + if (!(options & OPENSSL_RAW_DATA)) { base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len); + if (!base64_str) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to base64 decode the input"); + RETURN_FALSE; + } data_len = base64_str_len; data = base64_str; } @@ -4799,6 +4934,9 @@ PHP_FUNCTION(openssl_decrypt) EVP_CIPHER_CTX_set_key_length(&cipher_ctx, 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); outlen = i; if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) { @@ -4910,10 +5048,25 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) buffer = emalloc(buffer_length + 1); +#ifdef PHP_WIN32 + strong_result = 1; + /* random/urandom equivalent on Windows */ + if (php_win32_get_random_bytes(buffer, (size_t) buffer_length) == FAILURE) { + efree(buffer); + if (zstrong_result_returned) { + ZVAL_BOOL(zstrong_result_returned, 0); + } + RETURN_FALSE; + } +#else if ((strong_result = RAND_pseudo_bytes(buffer, buffer_length)) < 0) { efree(buffer); + if (zstrong_result_returned) { + ZVAL_BOOL(zstrong_result_returned, 0); + } RETURN_FALSE; } +#endif buffer[buffer_length] = 0; RETVAL_STRINGL((char *)buffer, buffer_length, 0);