/ext/openssl/openssl.c
C | 6595 lines | 5257 code | 868 blank | 470 comment | 1492 complexity | fc00f3cc45b888f17bb7d4e0a60efcd8 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) 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 |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Stig Venaas <venaas@php.net> |
- | Wez Furlong <wez@thebrainroom.com> |
- | Sascha Kettler <kettler@gmx.net> |
- | Pierre-Alain Joye <pierre@php.net> |
- | Marc Delling <delling@silpion.de> (PKCS12 functions) |
- | Jakub Zelenka <bukka@php.net> |
- +----------------------------------------------------------------------+
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_ini.h"
- #include "php_openssl.h"
- #include "zend_exceptions.h"
- /* PHP Includes */
- #include "ext/standard/file.h"
- #include "ext/standard/info.h"
- #include "ext/standard/php_fopen_wrappers.h"
- #include "ext/standard/md5.h"
- #include "ext/standard/base64.h"
- #ifdef PHP_WIN32
- # include "win32/winutil.h"
- #endif
- /* 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>
- #include <openssl/pem.h>
- #include <openssl/err.h>
- #include <openssl/conf.h>
- #include <openssl/rand.h>
- #include <openssl/ssl.h>
- #include <openssl/pkcs12.h>
- /* Common */
- #include <time.h>
- #if (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900)
- #define timezone _timezone /* timezone is called _timezone in LibC */
- #endif
- #define MIN_KEY_LENGTH 384
- #define OPENSSL_ALGO_SHA1 1
- #define OPENSSL_ALGO_MD5 2
- #define OPENSSL_ALGO_MD4 3
- #ifdef HAVE_OPENSSL_MD2_H
- #define OPENSSL_ALGO_MD2 4
- #endif
- #if PHP_OPENSSL_API_VERSION < 0x10100
- #define OPENSSL_ALGO_DSS1 5
- #endif
- #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
- #define DEBUG_SMIME 0
- #if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
- #define HAVE_EVP_PKEY_EC 1
- #endif
- #include "openssl_arginfo.h"
- ZEND_DECLARE_MODULE_GLOBALS(openssl)
- /* FIXME: Use the openssl constants instead of
- * enum. It is now impossible to match real values
- * against php constants. Also sorry to break the
- * enum principles here, BC...
- */
- enum php_openssl_key_type {
- OPENSSL_KEYTYPE_RSA,
- OPENSSL_KEYTYPE_DSA,
- OPENSSL_KEYTYPE_DH,
- OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
- #ifdef HAVE_EVP_PKEY_EC
- OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
- #endif
- };
- enum php_openssl_cipher_type {
- PHP_OPENSSL_CIPHER_RC2_40,
- PHP_OPENSSL_CIPHER_RC2_128,
- 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
- };
- /* {{{ openssl_module_entry
- */
- zend_module_entry openssl_module_entry = {
- STANDARD_MODULE_HEADER,
- "openssl",
- ext_functions,
- PHP_MINIT(openssl),
- PHP_MSHUTDOWN(openssl),
- NULL,
- NULL,
- PHP_MINFO(openssl),
- PHP_OPENSSL_VERSION,
- PHP_MODULE_GLOBALS(openssl),
- PHP_GINIT(openssl),
- PHP_GSHUTDOWN(openssl),
- NULL,
- STANDARD_MODULE_PROPERTIES_EX
- };
- /* }}} */
- #ifdef COMPILE_DL_OPENSSL
- ZEND_GET_MODULE(openssl)
- #endif
- /* {{{ OpenSSL compatibility functions and macros */
- #if PHP_OPENSSL_API_VERSION < 0x10100
- #define EVP_PKEY_get0_RSA(_pkey) _pkey->pkey.rsa
- #define EVP_PKEY_get0_DH(_pkey) _pkey->pkey.dh
- #define EVP_PKEY_get0_DSA(_pkey) _pkey->pkey.dsa
- #define EVP_PKEY_get0_EC_KEY(_pkey) _pkey->pkey.ec
- static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
- {
- r->n = n;
- r->e = e;
- r->d = d;
- return 1;
- }
- static int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
- {
- r->p = p;
- r->q = q;
- return 1;
- }
- static int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
- {
- r->dmp1 = dmp1;
- r->dmq1 = dmq1;
- r->iqmp = iqmp;
- return 1;
- }
- static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
- {
- *n = r->n;
- *e = r->e;
- *d = r->d;
- }
- static void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
- {
- *p = r->p;
- *q = r->q;
- }
- static void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
- {
- *dmp1 = r->dmp1;
- *dmq1 = r->dmq1;
- *iqmp = r->iqmp;
- }
- static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
- {
- *p = dh->p;
- *q = dh->q;
- *g = dh->g;
- }
- static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
- {
- dh->p = p;
- dh->q = q;
- dh->g = g;
- return 1;
- }
- static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
- {
- *pub_key = dh->pub_key;
- *priv_key = dh->priv_key;
- }
- static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
- {
- dh->pub_key = pub_key;
- dh->priv_key = priv_key;
- return 1;
- }
- static void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
- {
- *p = d->p;
- *q = d->q;
- *g = d->g;
- }
- int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
- {
- d->p = p;
- d->q = q;
- d->g = g;
- return 1;
- }
- static void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
- {
- *pub_key = d->pub_key;
- *priv_key = d->priv_key;
- }
- int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
- {
- d->pub_key = pub_key;
- d->priv_key = priv_key;
- return 1;
- }
- static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
- {
- return M_ASN1_STRING_data(asn1);
- }
- #if PHP_OPENSSL_API_VERSION < 0x10002
- static int X509_get_signature_nid(const X509 *x)
- {
- return OBJ_obj2nid(x->sig_alg->algorithm);
- }
- #endif
- #define OpenSSL_version SSLeay_version
- #define OPENSSL_VERSION SSLEAY_VERSION
- #define X509_getm_notBefore X509_get_notBefore
- #define X509_getm_notAfter X509_get_notAfter
- #define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_cleanup
- #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)
- /* number conversion flags checks */
- #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(_cond, _name) \
- do { \
- if (_cond) { \
- php_error_docref(NULL, E_WARNING, #_name" is too long"); \
- return NULL; \
- } \
- } 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 int */
- #define PHP_OPENSSL_CHECK_SIZE_T_TO_INT_NORET(_var, _name) \
- PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(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)
- /* check if long can be safely casted to int */
- #define PHP_OPENSSL_CHECK_LONG_TO_INT_NORET(_var, _name) \
- PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(ZEND_LONG_EXCEEDS_INT(_var), _name)
- /* {{{ php_openssl_store_errors */
- void php_openssl_store_errors()
- {
- struct php_openssl_errors *errors;
- int error_code = ERR_get_error();
- if (!error_code) {
- return;
- }
- if (!OPENSSL_G(errors)) {
- OPENSSL_G(errors) = pecalloc(1, sizeof(struct php_openssl_errors), 1);
- }
- errors = OPENSSL_G(errors);
- do {
- errors->top = (errors->top + 1) % ERR_NUM_ERRORS;
- if (errors->top == errors->bottom) {
- errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS;
- }
- errors->buffer[errors->top] = error_code;
- } while ((error_code = ERR_get_error()));
- }
- /* }}} */
- static int le_key;
- static int le_x509;
- static int le_csr;
- static int ssl_stream_data_index;
- int php_openssl_get_x509_list_id(void) /* {{{ */
- {
- return le_x509;
- }
- /* }}} */
- /* {{{ resource destructors */
- static void php_openssl_pkey_free(zend_resource *rsrc)
- {
- EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
- assert(pkey != NULL);
- EVP_PKEY_free(pkey);
- }
- static void php_openssl_x509_free(zend_resource *rsrc)
- {
- X509 *x509 = (X509 *)rsrc->ptr;
- X509_free(x509);
- }
- static void php_openssl_csr_free(zend_resource *rsrc)
- {
- X509_REQ * csr = (X509_REQ*)rsrc->ptr;
- X509_REQ_free(csr);
- }
- /* }}} */
- /* {{{ openssl open_basedir check */
- inline static int php_openssl_open_base_dir_chk(char *filename)
- {
- if (php_check_open_basedir(filename)) {
- return -1;
- }
- return 0;
- }
- /* }}} */
- php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
- {
- return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
- }
- int php_openssl_get_ssl_stream_data_index()
- {
- return ssl_stream_data_index;
- }
- /* openssl -> PHP "bridging" */
- /* true global; readonly after module startup */
- static char default_ssl_conf_filename[MAXPATHLEN];
- struct php_x509_request { /* {{{ */
- LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */
- LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */
- const EVP_MD * md_alg;
- const EVP_MD * digest;
- char * section_name,
- * config_filename,
- * digest_name,
- * extensions_section,
- * request_extensions_section;
- int priv_key_bits;
- int priv_key_type;
- int priv_key_encrypt;
- #ifdef HAVE_EVP_PKEY_EC
- int curve_name;
- #endif
- EVP_PKEY * priv_key;
- const EVP_CIPHER * priv_key_encrypt_cipher;
- };
- /* }}} */
- 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, size_t passphrase_len,
- int makeresource, zend_resource **resourceval);
- static int php_openssl_is_private_key(EVP_PKEY* pkey);
- static X509_STORE * php_openssl_setup_verify(zval * calist);
- static STACK_OF(X509) * php_openssl_load_all_certs_from_file(char *certfile);
- 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 php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) /* {{{ */
- {
- zval *data;
- zval subitem, tmp;
- int i;
- char *sname;
- int nid;
- X509_NAME_ENTRY * ne;
- ASN1_STRING * str = NULL;
- ASN1_OBJECT * obj;
- if (key != NULL) {
- array_init(&subitem);
- } else {
- ZVAL_COPY_VALUE(&subitem, val);
- }
- for (i = 0; i < X509_NAME_entry_count(name); i++) {
- const unsigned char *to_add = NULL;
- int to_add_len = 0;
- unsigned char *to_add_buf = NULL;
- ne = X509_NAME_get_entry(name, i);
- obj = X509_NAME_ENTRY_get_object(ne);
- nid = OBJ_obj2nid(obj);
- if (shortname) {
- sname = (char *) OBJ_nid2sn(nid);
- } else {
- sname = (char *) OBJ_nid2ln(nid);
- }
- str = X509_NAME_ENTRY_get_data(ne);
- if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
- /* ASN1_STRING_to_UTF8(3): The converted data is copied into a newly allocated buffer */
- to_add_len = ASN1_STRING_to_UTF8(&to_add_buf, str);
- to_add = to_add_buf;
- } else {
- /* ASN1_STRING_get0_data(3): Since this is an internal pointer it should not be freed or modified in any way */
- to_add = ASN1_STRING_get0_data(str);
- to_add_len = ASN1_STRING_length(str);
- }
- if (to_add_len != -1) {
- 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, (const 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, (const char *)to_add, to_add_len);
- zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp);
- }
- } else {
- /* it might be better to expand it and pass zval from ZVAL_STRING
- * to zend_symtable_str_update so we do not silently drop const
- * but we need a test to cover this part first */
- add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len);
- }
- } else {
- php_openssl_store_errors();
- }
- if (to_add_buf != NULL) {
- OPENSSL_free(to_add_buf);
- }
- }
- if (key != NULL) {
- zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem);
- }
- }
- /* }}} */
- static void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
- {
- add_assoc_stringl(val, key, (char *)str->data, str->length);
- }
- /* }}} */
- static time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */
- {
- /*
- This is how the time string is formatted:
- snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
- ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
- */
- time_t ret;
- struct tm thetime;
- char * strbuf;
- char * thestr;
- long gmadjust = 0;
- size_t timestr_len;
- if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
- php_error_docref(NULL, E_WARNING, "Illegal ASN1 data type for timestamp");
- return (time_t)-1;
- }
- timestr_len = (size_t)ASN1_STRING_length(timestr);
- if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) {
- php_error_docref(NULL, E_WARNING, "Illegal length in timestamp");
- return (time_t)-1;
- }
- if (timestr_len < 13 && timestr_len != 11) {
- 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 && timestr_len < 15) {
- php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", timestr->data);
- return (time_t)-1;
- }
- strbuf = estrdup((const char *)ASN1_STRING_get0_data(timestr));
- memset(&thetime, 0, sizeof(thetime));
- /* we work backwards so that we can use atoi more easily */
- thestr = strbuf + timestr_len - 3;
- if (timestr_len == 11) {
- thetime.tm_sec = 0;
- } else {
- thetime.tm_sec = atoi(thestr);
- *thestr = '\0';
- thestr -= 2;
- }
- thetime.tm_min = atoi(thestr);
- *thestr = '\0';
- thestr -= 2;
- thetime.tm_hour = atoi(thestr);
- *thestr = '\0';
- thestr -= 2;
- thetime.tm_mday = atoi(thestr);
- *thestr = '\0';
- thestr -= 2;
- thetime.tm_mon = atoi(thestr)-1;
- *thestr = '\0';
- if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
- thestr -= 2;
- thetime.tm_year = atoi(thestr);
- if (thetime.tm_year < 68) {
- thetime.tm_year += 100;
- }
- } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
- thestr -= 4;
- thetime.tm_year = atoi(thestr) - 1900;
- }
- thetime.tm_isdst = -1;
- ret = mktime(&thetime);
- #if HAVE_STRUCT_TM_TM_GMTOFF
- gmadjust = thetime.tm_gmtoff;
- #else
- /*
- ** If correcting for daylight savings time, we set the adjustment to
- ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
- ** set the adjustment to the main timezone + 3600 seconds.
- */
- gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone);
- #endif
- ret += gmadjust;
- efree(strbuf);
- return ret;
- }
- /* }}} */
- static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config) /* {{{ */
- {
- 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_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s",
- section_label,
- section,
- config_filename);
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */
- {
- char * str;
- STACK_OF(CONF_VALUE) * sktmp;
- CONF_VALUE * cnf;
- int i;
- str = CONF_get_string(req->req_config, NULL, "oid_section");
- if (str == NULL) {
- php_openssl_store_errors();
- return SUCCESS;
- }
- sktmp = CONF_get_section(req->req_config, str);
- if (sktmp == NULL) {
- php_openssl_store_errors();
- 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_sn2nid(cnf->name) == NID_undef && OBJ_ln2nid(cnf->name) == NID_undef &&
- OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Problem creating object %s=%s", cnf->name, cnf->value);
- return FAILURE;
- }
- }
- return SUCCESS;
- }
- /* }}} */
- #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
- #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) == FAILURE) return FAILURE
- #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
- do { \
- 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; \
- if (varname == NULL) { \
- php_openssl_store_errors(); \
- } \
- } \
- } while(0)
- #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
- 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(zend_long algo);
- /* {{{ strip line endings from spkac */
- static int php_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;
- }
- /* }}} */
- static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args) /* {{{ */
- {
- char * str;
- 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");
- req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
- if (req->global_config == NULL) {
- php_openssl_store_errors();
- }
- req->req_config = CONF_load(NULL, req->config_filename, NULL);
- if (req->req_config == NULL) {
- php_openssl_store_errors();
- return FAILURE;
- }
- /* read in the oids */
- str = CONF_get_string(req->req_config, NULL, "oid_file");
- if (str == NULL) {
- php_openssl_store_errors();
- } else if (!php_openssl_open_base_dir_chk(str)) {
- BIO *oid_bio = BIO_new_file(str, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
- if (oid_bio) {
- OBJ_create_objects(oid_bio);
- BIO_free(oid_bio);
- php_openssl_store_errors();
- }
- }
- if (php_openssl_add_oid_section(req) == FAILURE) {
- return FAILURE;
- }
- SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
- CONF_get_string(req->req_config, req->section_name, "default_md"));
- SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
- CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
- SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
- CONF_get_string(req->req_config, req->section_name, "req_extensions"));
- SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
- CONF_get_number(req->req_config, req->section_name, "default_bits"));
- SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
- 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) {
- str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
- /* it is sure that there are some errors as str was NULL for encrypt_rsa_key */
- php_openssl_store_errors();
- }
- if (str != NULL && strcmp(str, "no") == 0) {
- req->priv_key_encrypt = 0;
- } else {
- req->priv_key_encrypt = 1;
- }
- }
- 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, 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");
- }
- if (req->digest_name != NULL) {
- req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
- } else {
- php_openssl_store_errors();
- }
- if (req->md_alg == NULL) {
- req->md_alg = req->digest = EVP_sha1();
- php_openssl_store_errors();
- }
- PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
- #ifdef HAVE_EVP_PKEY_EC
- /* set the ec group curve name */
- req->curve_name = NID_undef;
- if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "curve_name", sizeof("curve_name")-1)) != NULL
- && Z_TYPE_P(item) == IS_STRING) {
- req->curve_name = OBJ_sn2nid(Z_STRVAL_P(item));
- if (req->curve_name == NID_undef) {
- php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(item));
- return FAILURE;
- }
- }
- #endif
- /* set the string mask */
- str = CONF_get_string(req->req_config, req->section_name, "string_mask");
- if (str == NULL) {
- php_openssl_store_errors();
- } else if (!ASN1_STRING_set_default_mask_asc(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) /* {{{ */
- {
- if (req->priv_key) {
- EVP_PKEY_free(req->priv_key);
- req->priv_key = NULL;
- }
- if (req->global_config) {
- CONF_free(req->global_config);
- req->global_config = NULL;
- }
- if (req->req_config) {
- CONF_free(req->req_config);
- req->req_config = NULL;
- }
- }
- /* }}} */
- #if defined(PHP_WIN32) || PHP_OPENSSL_API_VERSION >= 0x10100
- #define PHP_OPENSSL_RAND_ADD_TIME() ((void) 0)
- #else
- #define PHP_OPENSSL_RAND_ADD_TIME() php_openssl_rand_add_timeval()
- static inline void php_openssl_rand_add_timeval() /* {{{ */
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- RAND_add(&tv, sizeof(tv), 0.0);
- }
- /* }}} */
- #endif
- static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
- {
- char buffer[MAXPATHLEN];
- *egdsocket = 0;
- *seeded = 0;
- if (file == NULL) {
- file = RAND_file_name(buffer, sizeof(buffer));
- #ifdef HAVE_RAND_EGD
- } else if (RAND_egd(file) > 0) {
- /* if the given filename is an EGD socket, don't
- * write anything back to it */
- *egdsocket = 1;
- return SUCCESS;
- #endif
- }
- if (file == NULL || !RAND_load_file(file, -1)) {
- if (RAND_status() == 0) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to load random state; not enough random data!");
- return FAILURE;
- }
- return FAILURE;
- }
- *seeded = 1;
- return SUCCESS;
- }
- /* }}} */
- static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
- {
- char buffer[MAXPATHLEN];
- if (egdsocket || !seeded) {
- /* if we did not manage to read the seed file, we should not write
- * a low-entropy seed file back */
- return FAILURE;
- }
- if (file == NULL) {
- file = RAND_file_name(buffer, sizeof(buffer));
- }
- PHP_OPENSSL_RAND_ADD_TIME();
- if (file == NULL || !RAND_write_file(file)) {
- php_openssl_store_errors();
- 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(zend_long algo) { /* {{{ */
- EVP_MD *mdtype;
- switch (algo) {
- case OPENSSL_ALGO_SHA1:
- mdtype = (EVP_MD *) EVP_sha1();
- break;
- case OPENSSL_ALGO_MD5:
- mdtype = (EVP_MD *) EVP_md5();
- break;
- case OPENSSL_ALGO_MD4:
- mdtype = (EVP_MD *) EVP_md4();
- break;
- #ifdef HAVE_OPENSSL_MD2_H
- case OPENSSL_ALGO_MD2:
- mdtype = (EVP_MD *) EVP_md2();
- break;
- #endif
- #if PHP_OPENSSL_API_VERSION < 0x10100
- case OPENSSL_ALGO_DSS1:
- mdtype = (EVP_MD *) EVP_dss1();
- break;
- #endif
- 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;
- default:
- return NULL;
- break;
- }
- return mdtype;
- }
- /* }}} */
- 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:
- return EVP_rc2_40_cbc();
- break;
- case PHP_OPENSSL_CIPHER_RC2_64:
- return EVP_rc2_64_cbc();
- break;
- case PHP_OPENSSL_CIPHER_RC2_128:
- return EVP_rc2_cbc();
- break;
- #endif
- #ifndef OPENSSL_NO_DES
- case PHP_OPENSSL_CIPHER_DES:
- return EVP_des_cbc();
- break;
- case PHP_OPENSSL_CIPHER_3DES:
- 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;
- }
- }
- /* }}} */
- /* {{{ INI Settings */
- PHP_INI_BEGIN()
- PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL)
- PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL)
- PHP_INI_END()
- /* }}} */
- /* {{{ PHP_MINIT_FUNCTION
- */
- PHP_MINIT_FUNCTION(openssl)
- {
- char * config_filename;
- le_key = zend_register_list_destructors_ex(php_openssl_pkey_free, NULL, "OpenSSL key", module_number);
- le_x509 = zend_register_list_destructors_ex(php_openssl_x509_free, NULL, "OpenSSL X.509", module_number);
- le_csr = zend_register_list_destructors_ex(php_openssl_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
- #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
- OPENSSL_config(NULL);
- SSL_library_init();
- OpenSSL_add_all_ciphers();
- OpenSSL_add_all_digests();
- OpenSSL_add_all_algorithms();
- #if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && OPENSSL_VERSION_NUMBER < 0x100020000
- EVP_add_cipher(EVP_aes_128_ccm());
- EVP_add_cipher(EVP_aes_192_ccm());
- EVP_add_cipher(EVP_aes_256_ccm());
- #endif
- SSL_load_error_strings();
- #else
- OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
- #endif
- /* 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);
- REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
- #ifdef X509_PURPOSE_ANY
- REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
- #endif
- /* signature algorithm constants */
- REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
- #ifdef HAVE_OPENSSL_MD2_H
- REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
- #endif
- #if PHP_OPENSSL_API_VERSION < 0x10100
- REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
- #endif
- 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);
- /* flags for S/MIME */
- REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
- /* Informational stream wrapper constants */
- REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
- /* Ciphers */
- #ifndef OPENSSL_NO_RC2
- REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
- #endif
- #ifndef OPENSSL_NO_DES
- 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);
- #ifndef NO_DSA
- REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
- #endif
- REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
- #ifdef HAVE_EVP_PKEY_EC
- 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);
- REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT);
- #ifndef OPENSSL_NO_TLSEXT
- /* SNI support included */
- REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
- #endif
- /* Determine default SSL configuration file */
- config_filename = getenv("OPENSSL_CONF");
- if (config_filename == NULL) {
- config_filename = getenv("SSLEAY_CONF");
- }
- /* default to 'openssl.cnf' if no environment variable is set */
- if (config_filename == NULL) {
- snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
- X509_get_default_cert_area(),
- "openssl.cnf");
- } else {
- strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
- }
- 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
- php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
- php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory);
- php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory);
- php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory);
- #if OPENSSL_VERSION_NUMBER >= 0x10101000
- php_stream_xport_register("tlsv1.3", php_openssl_ssl_socket_factory);
- #endif
- /* override the default tcp socket provider */
- php_stream_xport_register("tcp", php_openssl_ssl_socket_factory);
- php_register_url_stream_wrapper("https", &php_stream_http_wrapper);
- php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper);
- REGISTER_INI_ENTRIES();
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_GINIT_FUNCTION
- */
- PHP_GINIT_FUNCTION(openssl)
- {
- #if defined(COMPILE_DL_OPENSSL) && defined(ZTS)
- ZEND_TSRMLS_CACHE_UPDATE();
- #endif
- openssl_globals->errors = NULL;
- }
- /* }}} */
- /* {{{ PHP_GSHUTDOWN_FUNCTION
- */
- PHP_GSHUTDOWN_FUNCTION(openssl)
- {
- if (openssl_globals->errors) {
- pefree(openssl_globals->errors, 1);
- }
- }
- /* }}} */
- /* {{{ PHP_MINFO_FUNCTION
- */
- PHP_MINFO_FUNCTION(openssl)
- {
- php_info_print_table_start();
- php_info_print_table_row(2, "OpenSSL support", "enabled");
- php_info_print_table_row(2, "OpenSSL Library Version", OpenSSL_version(OPENSSL_VERSION));
- php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
- php_info_print_table_row(2, "Openssl default config", default_ssl_conf_filename);
- php_info_print_table_end();
- DISPLAY_INI_ENTRIES();
- }
- /* }}} */
- /* {{{ PHP_MSHUTDOWN_FUNCTION
- */
- PHP_MSHUTDOWN_FUNCTION(openssl)
- {
- #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
- EVP_cleanup();
- /* prevent accessing locking callback from unloaded extension */
- CRYPTO_set_locking_callback(NULL);
- /* free allocated error strings */
- ERR_free_strings();
- CONF_modules_free();
- #endif
- php_unregister_url_stream_wrapper("https");
- php_unregister_url_stream_wrapper("ftps");
- php_stream_xport_unregister("ssl");
- #ifndef OPENSSL_NO_SSL3
- php_stream_xport_unregister("sslv3");
- #endif
- php_stream_xport_unregister("tls");
- php_stream_xport_unregister("tlsv1.0");
- php_stream_xport_unregister("tlsv1.1");
- php_stream_xport_unregister("tlsv1.2");
- #if OPENSSL_VERSION_NUMBER >= 0x10101000
- php_stream_xport_unregister("tlsv1.3");
- #endif
- /* reinstate the default tcp handler */
- php_stream_xport_register("tcp", php_stream_generic_socket_factory);
- UNREGISTER_INI_ENTRIES();
- return SUCCESS;
- }
- /* }}} */
- /* {{{ x509 cert functions */
- /* {{{ proto array openssl_get_cert_locations(void)
- Retrieve an array mapping available certificate locations */
- PHP_FUNCTION(openssl_get_cert_locations)
- {
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- array_init(return_value);
- 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")-1, 0));
- add_assoc_string(return_value, "ini_capath",
- zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0));
- }
- /* }}} */
- /* {{{ php_openssl_x509_from_zval
- Given a zval, coerce it into an X509 object.
- The zval can be:
- . X509 resource created using openssl_read_x509()
- . if it starts with file:// then it will be interpreted as the path to that cert
- . it will be interpreted as the cert data
- 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, zend_resource **resourceval)
- {
- X509 *cert = NULL;
- BIO *in;
- if (resourceval) {
- *resourceval = NULL;
- }
- if (Z_TYPE_P(val) == IS_RESOURCE) {
- /* is it an x509 resource ? */
- void * what;
- zend_resource *res = Z_RES_P(val);
- what = zend_fetch_resource(res, "OpenSSL X.509", le_x509);
- if (!what) {
- return NULL;
- }
- if (resourceval) {
- *resourceval = res;
- if (makeresource) {
- Z_ADDREF_P(val);
- }
- }
- return (X509*)what;
- }
- 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 */
- if (!try_convert_to_string(val)) {
- return NULL;
- }
- if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
- if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) {
- return NULL;
- }
- in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
- if (in == NULL) {
- php_openssl_store_errors();
- return NULL;
- }
- cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
- } else {
- in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
- if (in == NULL) {
- php_openssl_store_errors();
- return NULL;
- }
- #ifdef TYPEDEF_D2I_OF
- cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
- #else
- cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
- #endif
- }
- if (!BIO_free(in)) {
- php_openssl_store_errors();
- }
- if (cert == NULL) {
- php_openssl_store_errors();
- return NULL;
- }
- if (makeresource && resourceval) {
- *resourceval = zend_register_resource(cert, le_x509);
- }
- return cert;
- }
- /* }}} */
- /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
- Exports a CERT to file or a var */
- PHP_FUNCTION(openssl_x509_export_to_file)
- {
- X509 * cert;
- zval * zcert;
- zend_bool notext = 1;
- BIO * bio_out;
- char * filename;
- size_t filename_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- cert = php_openssl_x509_from_zval(zcert, 0, NULL);
- if (cert == NULL) {
- php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
- return;
- }
- if (php_openssl_open_base_dir_chk(filename)) {
- return;
- }
- bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
- if (bio_out) {
- if (!notext && !X509_print(bio_out, cert)) {
- php_openssl_store_errors();
- }
- if (!PEM_write_bio_X509(bio_out, cert)) {
- php_openssl_store_errors();
- }
- RETVAL_TRUE;
- } else {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Error opening file %s", filename);
- }
- if (Z_TYPE_P(zcert) != IS_RESOURCE) {
- X509_free(cert);
- }
- if (!BIO_free(bio_out)) {
- php_openssl_store_errors();
- }
- }
- /* }}} */
- /* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method])
- Creates new private key (or uses existing) and creates a new spki cert
- outputting results to var */
- PHP_FUNCTION(openssl_spki_new)
- {
- size_t challenge_len;
- char * challenge = NULL, * spkstr = NULL;
- zend_string * s = NULL;
- zend_resource *keyresource = NULL;
- const char *spkac = "SPKAC=";
- zend_long algo = OPENSSL_ALGO_MD5;
- zval * zpkey = NULL;
- EVP_PKEY * pkey = NULL;
- NETSCAPE_SPKI *spki=NULL;
- const EVP_MD *mdtype;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &zpkey, &challenge, &challenge_len, &algo) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- PHP_OPENSSL_CHECK_SIZE_T_TO_INT(challenge_len, challenge);
- pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, challenge_len, 1, &keyresource);
- if (pkey == NULL) {
- if (!EG(exception)) {
- php_error_docref(NULL, E_WARNING, "Unable to use supplied private key");
- }
- goto cleanup;
- }
- mdtype = php_openssl_get_evp_md_from_algo(algo);
- if (!mdtype) {
- php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
- goto cleanup;
- }
- if ((spki = NETSCAPE_SPKI_new()) == NULL) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC");
- goto cleanup;
- }
- if (challenge) {
- if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to set challenge data");
- goto cleanup;
- }
- }
- if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to embed public key");
- goto cleanup;
- }
- if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to sign with specified algorithm");
- goto cleanup;
- }
- spkstr = NETSCAPE_SPKI_b64_encode(spki);
- if (!spkstr){
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC");
- goto cleanup;
- }
- s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0);
- sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr);
- ZSTR_LEN(s) = strlen(ZSTR_VAL(s));
- OPENSSL_free(spkstr);
- RETVAL_STR(s);
- goto cleanup;
- cleanup:
- if (spki != NULL) {
- NETSCAPE_SPKI_free(spki);
- }
- if (keyresource == NULL && pkey != NULL) {
- EVP_PKEY_free(pkey);
- }
- if (s && ZSTR_LEN(s) <= 0) {
- RETVAL_FALSE;
- }
- if (keyresource == NULL && s != NULL) {
- zend_string_release_ex(s, 0);
- }
- }
- /* }}} */
- /* {{{ proto bool openssl_spki_verify(string spki)
- Verifies spki returns boolean */
- PHP_FUNCTION(openssl_spki_verify)
- {
- size_t spkstr_len;
- int i = 0, spkstr_cleaned_len = 0;
- char *spkstr, * spkstr_cleaned = NULL;
- EVP_PKEY *pkey = NULL;
- NETSCAPE_SPKI *spki = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- spkstr_cleaned = emalloc(spkstr_len + 1);
- spkstr_cleaned_len = (int)(spkstr_len - php_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, spkstr_cleaned_len);
- if (spki == NULL) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
- goto cleanup;
- }
- pkey = X509_PUBKEY_get(spki->spkac->pubkey);
- if (pkey == NULL) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
- goto cleanup;
- }
- i = NETSCAPE_SPKI_verify(spki, pkey);
- goto cleanup;
- cleanup:
- if (spki != NULL) {
- NETSCAPE_SPKI_free(spki);
- }
- if (pkey != NULL) {
- EVP_PKEY_free(pkey);
- }
- if (spkstr_cleaned != NULL) {
- efree(spkstr_cleaned);
- }
- if (i > 0) {
- RETVAL_TRUE;
- } else {
- php_openssl_store_errors();
- }
- }
- /* }}} */
- /* {{{ proto string openssl_spki_export(string spki)
- Exports public key from existing spki to var */
- PHP_FUNCTION(openssl_spki_export)
- {
- size_t spkstr_len;
- char *spkstr, * 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(), "s", &spkstr, &spkstr_len) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- spkstr_cleaned = emalloc(spkstr_len + 1);
- spkstr_cleaned_len = (int)(spkstr_len - php_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, spkstr_cleaned_len);
- if (spki == NULL) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
- goto cleanup;
- }
- pkey = X509_PUBKEY_get(spki->spkac->pubkey);
- if (pkey == NULL) {
- php_openssl_store_errors();
- 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)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(out, &bio_buf);
- RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length);
- } else {
- php_openssl_store_errors();
- }
- goto cleanup;
- cleanup:
- if (spki != NULL) {
- NETSCAPE_SPKI_free(spki);
- }
- if (out != NULL) {
- BIO_free_all(out);
- }
- if (pkey != NULL) {
- EVP_PKEY_free(pkey);
- }
- if (spkstr_cleaned != NULL) {
- efree(spkstr_cleaned);
- }
- if (s != NULL) {
- efree(s);
- }
- }
- /* }}} */
- /* {{{ proto string openssl_spki_export_challenge(string spki)
- Exports spkac challenge from existing spki to var */
- PHP_FUNCTION(openssl_spki_export_challenge)
- {
- size_t spkstr_len;
- char *spkstr, * spkstr_cleaned = NULL;
- int spkstr_cleaned_len;
- NETSCAPE_SPKI *spki = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- spkstr_cleaned = emalloc(spkstr_len + 1);
- spkstr_cleaned_len = (int)(spkstr_len - php_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, spkstr_cleaned_len);
- if (spki == NULL) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC");
- goto cleanup;
- }
- RETVAL_STRING((const char *)ASN1_STRING_get0_data(spki->spkac->challenge));
- goto cleanup;
- cleanup:
- if (spkstr_cleaned != NULL) {
- efree(spkstr_cleaned);
- }
- if (spki) {
- NETSCAPE_SPKI_free(spki);
- }
- }
- /* }}} */
- /* {{{ 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;
- zend_bool notext = 1;
- BIO * bio_out;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|b", &zcert, &zout, ¬ext) == FAILURE) {
- RETURN_THROWS();
- }
- RETVAL_FALSE;
- cert = php_openssl_x509_from_zval(zcert, 0, NULL);
- if (cert == NULL) {
- php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
- return;
- }
- bio_out = BIO_new(BIO_s_mem());
- if (!bio_out) {
- php_openssl_store_errors();
- goto cleanup;
- }
- if (!notext && !X509_print(bio_out, cert)) {
- php_openssl_store_errors();
- }
- if (PEM_write_bio_X509(bio_out, cert)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
- ZEND_TRY_ASSIGN_REF_STRINGL(zout, bio_buf->data, bio_buf->length);
- RETVAL_TRUE;
- } else {
- php_openssl_store_errors();
- }
- BIO_free(bio_out);
- cleanup:
- if (Z_TYPE_P(zcert) != IS_RESOURCE) {
- X509_free(cert);
- }
- }
- /* }}} */
- 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, E_WARNING, "Unknown signature algorithm");
- return NULL;
- } else if (!X509_digest(peer, mdtype, md, &n)) {
- php_openssl_store_errors();
- php_error_docref(NULL, E_ERROR, "Could not generate signature");
- return NULL;
- }
- if (raw) {
- ret = zend_string_init((char*)md, n, 0);
- } else {
- ret = zend_string_alloc(n * 2, 0);
- make_digest_ex(ZSTR_VAL(ret), md, n);
- ZSTR_VAL(ret)[n * 2] = '\0';
- }
- return ret;
- }
- PHP_FUNCTION(openssl_x509_fingerprint)
- {
- X509 *cert;
- zval *zcert;
- zend_bool raw_output = 0;
- char *method = "sha1";
- size_t method_len;
- zend_string *fingerprint;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) {
- RETURN_THROWS();
- }
- cert = php_openssl_x509_from_zval(zcert, 0, NULL);
- if (cert == NULL) {
- php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
- RETURN_FALSE;
- }
- fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output);
- if (fingerprint) {
- RETVAL_STR(fingerprint);
- } else {
- RETVAL_FALSE;
- }
- if (Z_TYPE_P(zcert) != IS_RESOURCE) {
- X509_free(cert);
- }
- }
- /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
- Checks if a private key corresponds to a CERT */
- PHP_FUNCTION(openssl_x509_check_private_key)
- {
- zval * zcert, *zkey;
- X509 * cert = NULL;
- EVP_PKEY * key = NULL;
- zend_resource *keyresource = NULL;
- RETVAL_FALSE;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) {
- RETURN_THROWS();
- }
- cert = php…
Large files files are truncated, but you can click here to view the full file