📄 openssl.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 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> | +----------------------------------------------------------------------+ *//* $Id: openssl.c,v 1.52.2.23.2.2 2007/01/01 09:46:45 sebastian Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_openssl.h"/* PHP Includes */#include "ext/standard/file.h"#include "ext/standard/info.h"/* OpenSSL includes */#include <openssl/evp.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>#define DEFAULT_KEY_LENGTH 512#define MIN_KEY_LENGTH 384#define DEBUG_SMIME 0static unsigned char arg2_force_ref[] = { 2, BYREF_NONE, BYREF_FORCE };static unsigned char arg2and3_force_ref[] = { 3, BYREF_NONE, BYREF_FORCE, BYREF_FORCE };enum php_openssl_key_type { OPENSSL_KEYTYPE_RSA, OPENSSL_KEYTYPE_DSA, OPENSSL_KEYTYPE_DH, OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA};/* {{{ openssl_functions[] */function_entry openssl_functions[] = {/* public/private key functions */ PHP_FE(openssl_pkey_free, NULL) PHP_FE(openssl_pkey_new, NULL) PHP_FE(openssl_pkey_export, arg2_force_ref) PHP_FE(openssl_pkey_export_to_file, NULL) PHP_FE(openssl_pkey_get_private, NULL) PHP_FE(openssl_pkey_get_public, NULL) PHP_FALIAS(openssl_free_key, openssl_pkey_free, NULL) PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, NULL) PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, NULL)/* x.509 cert funcs */ PHP_FE(openssl_x509_read, NULL) PHP_FE(openssl_x509_free, NULL) PHP_FE(openssl_x509_parse, NULL) PHP_FE(openssl_x509_checkpurpose, NULL) PHP_FE(openssl_x509_check_private_key, NULL) PHP_FE(openssl_x509_export, arg2_force_ref) PHP_FE(openssl_x509_export_to_file, NULL)/* CSR funcs */ PHP_FE(openssl_csr_new, arg2_force_ref) PHP_FE(openssl_csr_export, arg2_force_ref) PHP_FE(openssl_csr_export_to_file, NULL) PHP_FE(openssl_csr_sign, NULL) PHP_FE(openssl_sign, arg2_force_ref) PHP_FE(openssl_verify, NULL) PHP_FE(openssl_seal, arg2and3_force_ref) PHP_FE(openssl_open, arg2_force_ref)/* for S/MIME handling */ PHP_FE(openssl_pkcs7_verify, NULL) PHP_FE(openssl_pkcs7_decrypt, NULL) PHP_FE(openssl_pkcs7_sign, NULL) PHP_FE(openssl_pkcs7_encrypt, NULL) PHP_FE(openssl_private_encrypt, arg2_force_ref) PHP_FE(openssl_private_decrypt, arg2_force_ref) PHP_FE(openssl_public_encrypt, arg2_force_ref) PHP_FE(openssl_public_decrypt, arg2_force_ref) PHP_FE(openssl_error_string, NULL) {NULL, NULL, NULL}};/* }}} *//* {{{ openssl_module_entry */zend_module_entry openssl_module_entry = { STANDARD_MODULE_HEADER, "openssl", openssl_functions, PHP_MINIT(openssl), PHP_MSHUTDOWN(openssl), NULL, NULL, PHP_MINFO(openssl), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES};/* }}} */#ifdef COMPILE_DL_OPENSSLZEND_GET_MODULE(openssl)#endifstatic int le_key;static int le_x509;static int le_csr;static int ssl_stream_data_index;/* {{{ resource destructors */static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC){ EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr; assert(pkey != NULL); EVP_PKEY_free(pkey);}static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC){ X509 *x509 = (X509 *)rsrc->ptr; X509_free(x509);}static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC){ X509_REQ * csr = (X509_REQ*)rsrc->ptr; X509_REQ_free(csr);}/* }}} *//* {{{ openssl safe_mode & open_basedir checks */inline static int php_openssl_safe_mode_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;}/* }}} *//* {{{ openssl -> PHP "bridging" *//* true global; readonly after module startup */static char default_ssl_conf_filename[MAXPATHLEN];struct php_x509_request { LHASH * global_config; /* Global SSL config */ LHASH * 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; EVP_PKEY * priv_key;};static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC);static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);static X509_STORE * setup_verify(zval * calist TSRMLS_DC);static STACK_OF(X509) * load_all_certs_from_file(char *certfile);static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC);static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC){ zval *subitem, *subentries; int i, j = -1, last = -1, obj_cnt = 0; char *sname; int nid; X509_NAME_ENTRY * ne; ASN1_STRING * str; ASN1_OBJECT * obj; MAKE_STD_ZVAL(subitem); array_init(subitem); for (i = 0; i < X509_NAME_entry_count(name); i++) { ne = X509_NAME_get_entry(name, i); obj = X509_NAME_ENTRY_get_object(ne); nid = OBJ_obj2nid(obj); obj_cnt = 0; if (shortname) { sname = (char *) OBJ_nid2sn(nid); } else { sname = (char *) OBJ_nid2ln(nid); } MAKE_STD_ZVAL(subentries); array_init(subentries); 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); add_next_index_stringl(subentries, str->data, str->length, 1); } 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) { add_assoc_stringl(subitem, sname, str->data, str->length, 1); } } } zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL);}static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str){ add_assoc_stringl(val, key, str->data, str->length, 1);}static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC){/* This is how the time string is formatted: sprintf(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; if (timestr->length < 13) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data); return (time_t)-1; } strbuf = estrdup(timestr->data); memset(&thetime, 0, sizeof(thetime)); /* we work backwards so that we can use atoi more easily */ thestr = strbuf + timestr->length - 3; 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'; thestr -= 2; thetime.tm_year = atoi(thestr); if (thetime.tm_year < 68) thetime.tm_year += 100; thetime.tm_isdst = -1; ret = mktime(&thetime);#if HAVE_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 + 3600);#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 * config TSRMLS_DC){ X509V3_CTX ctx; X509V3_set_ctx_test(&ctx); X509V3_set_conf_lhash(&ctx, config); if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s", section_label, section, config_filename); return FAILURE; } return SUCCESS;}static int add_oid_section(struct php_x509_request * req TSRMLS_DC){ 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) return SUCCESS; sktmp = CONF_get_section(req->req_config, str); if (sktmp == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str); return FAILURE; } for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { cnf = sk_CONF_VALUE_value(sktmp, i); if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value); 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 TSRMLS_CC)#define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval TSRMLS_CC)#define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \ req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE#define SET_OPTIONAL_STRING_ARG(key, varname, defval) \ if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \ varname = Z_STRVAL_PP(item); \ else \ varname = defval#define SET_OPTIONAL_LONG_ARG(key, varname, defval) \ if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \ varname = Z_LVAL_PP(item); \ else \ varname = defvalstatic int php_openssl_parse_config( struct php_x509_request * req, zval * optional_args TSRMLS_DC ){ 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); req->req_config = CONF_load(NULL, req->config_filename, NULL); if (req->req_config == NULL) return FAILURE; /* read in the oids */ str = CONF_get_string(req->req_config, NULL, "oid_file"); if (str && !php_openssl_safe_mode_chk(str TSRMLS_CC)) { BIO *oid_bio = BIO_new_file(str, "r"); if (oid_bio) { OBJ_create_objects(oid_bio); BIO_free(oid_bio); } } if (add_oid_section(req TSRMLS_CC) == FAILURE) 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->extensions_section, CONF_get_string(req->req_config, req->request_extensions_section, "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 && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) { req->priv_key_encrypt = Z_BVAL_PP(item); } 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"); if (str && strcmp(str, "no") == 0) req->priv_key_encrypt = 0; else req->priv_key_encrypt = 1; } /* 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) req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name); if (req->md_alg == NULL) req->md_alg = req->digest = EVP_md5(); PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -