2000-11-14 03:47:20 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2004-01-08 16:18:22 +08:00
| PHP Version 5 |
2000-11-14 03:47:20 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 20:51:34 +08:00
| Copyright ( c ) 1997 - 2006 The PHP Group |
2000-11-14 03:47:20 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 20:51:34 +08:00
| This source file is subject to version 3.01 of the PHP license , |
2000-11-14 03:47:20 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2006-01-01 20:51:34 +08:00
| http : //www.php.net/license/3_01.txt |
2000-11-14 03:47:20 +08:00
| 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 > |
2002-02-28 16:29:35 +08:00
| Wez Furlong < wez @ thebrainroom . com > |
| Sascha Kettler < kettler @ gmx . net > |
2000-11-14 03:47:20 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2001-04-02 07:06:15 +08:00
2000-11-14 03:47:20 +08:00
/* $Id$ */
2001-05-24 18:07:29 +08:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2000-11-14 03:47:20 +08:00
# include "php.h"
# include "php_openssl.h"
/* PHP Includes */
# include "ext/standard/file.h"
# include "ext/standard/info.h"
2003-02-28 02:16:35 +08:00
# include "ext/standard/php_fopen_wrappers.h"
2000-11-14 03:47:20 +08:00
/* OpenSSL includes */
# include <openssl/evp.h>
# include <openssl/x509.h>
2001-04-02 07:06:15 +08:00
# include <openssl/x509v3.h>
# include <openssl/crypto.h>
2000-11-14 17:54:25 +08:00
# include <openssl/pem.h>
2001-04-02 07:06:15 +08:00
# include <openssl/err.h>
2001-09-11 07:57:10 +08:00
# include <openssl/conf.h>
# include <openssl/rand.h>
2003-11-28 01:40:16 +08:00
# include <openssl/ssl.h>
2001-09-11 07:57:10 +08:00
# define DEFAULT_KEY_LENGTH 512
# define MIN_KEY_LENGTH 384
2003-03-31 06:25:23 +08:00
# define OPENSSL_ALGO_SHA1 1
# define OPENSSL_ALGO_MD5 2
# define OPENSSL_ALGO_MD4 3
# define OPENSSL_ALGO_MD2 4
2000-11-14 17:54:25 +08:00
2001-09-08 01:09:56 +08:00
# define DEBUG_SMIME 0
2003-08-04 01:44:39 +08:00
static
ZEND_BEGIN_ARG_INFO ( arg2and3_force_ref , 0 )
ZEND_ARG_PASS_INFO ( 0 )
ZEND_ARG_PASS_INFO ( 1 )
ZEND_ARG_PASS_INFO ( 1 )
ZEND_END_ARG_INFO ( ) ;
2000-11-14 03:47:20 +08:00
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
enum php_openssl_key_type {
2001-09-11 07:57:10 +08:00
OPENSSL_KEYTYPE_RSA ,
OPENSSL_KEYTYPE_DSA ,
OPENSSL_KEYTYPE_DH ,
OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA
} ;
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
enum php_openssl_cipher_type {
2003-03-31 06:29:22 +08:00
PHP_OPENSSL_CIPHER_RC2_40 ,
PHP_OPENSSL_CIPHER_RC2_128 ,
PHP_OPENSSL_CIPHER_RC2_64 ,
PHP_OPENSSL_CIPHER_DES ,
PHP_OPENSSL_CIPHER_3DES ,
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
} ;
2001-06-05 21:12:10 +08:00
/* {{{ openssl_functions[]
*/
2005-12-06 10:28:41 +08:00
zend_function_entry openssl_functions [ ] = {
2001-09-11 07:57:10 +08:00
/* public/private key functions */
PHP_FE ( openssl_pkey_free , NULL )
PHP_FE ( openssl_pkey_new , NULL )
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_pkey_export , second_arg_force_ref )
2001-09-11 08:33:25 +08:00
PHP_FE ( openssl_pkey_export_to_file , NULL )
2001-09-11 07:57:10 +08:00
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 )
2001-04-02 07:06:15 +08:00
PHP_FE ( openssl_x509_free , NULL )
2001-09-11 07:57:10 +08:00
PHP_FE ( openssl_x509_parse , NULL )
2001-04-02 07:06:15 +08:00
PHP_FE ( openssl_x509_checkpurpose , NULL )
2001-09-11 07:57:10 +08:00
PHP_FE ( openssl_x509_check_private_key , NULL )
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_x509_export , second_arg_force_ref )
2001-09-11 08:33:25 +08:00
PHP_FE ( openssl_x509_export_to_file , NULL )
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* CSR funcs */
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_csr_new , second_arg_force_ref )
PHP_FE ( openssl_csr_export , second_arg_force_ref )
2001-09-11 08:33:25 +08:00
PHP_FE ( openssl_csr_export_to_file , NULL )
2001-09-11 07:57:10 +08:00
PHP_FE ( openssl_csr_sign , NULL )
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_sign , second_arg_force_ref )
2003-03-31 06:29:22 +08:00
PHP_FE ( openssl_verify , NULL )
PHP_FE ( openssl_seal , arg2and3_force_ref )
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_open , second_arg_force_ref )
2001-09-11 07:57:10 +08:00
2001-04-02 07:06:15 +08:00
/* for S/MIME handling */
2003-03-31 06:29:22 +08:00
PHP_FE ( openssl_pkcs7_verify , NULL )
PHP_FE ( openssl_pkcs7_decrypt , NULL )
PHP_FE ( openssl_pkcs7_sign , NULL )
PHP_FE ( openssl_pkcs7_encrypt , NULL )
2001-04-02 07:06:15 +08:00
2003-08-04 01:44:39 +08:00
PHP_FE ( openssl_private_encrypt , second_arg_force_ref )
PHP_FE ( openssl_private_decrypt , second_arg_force_ref )
PHP_FE ( openssl_public_encrypt , second_arg_force_ref )
PHP_FE ( openssl_public_decrypt , second_arg_force_ref )
2001-05-05 07:42:11 +08:00
2001-04-02 07:06:15 +08:00
PHP_FE ( openssl_error_string , NULL )
2000-11-14 03:47:20 +08:00
{ NULL , NULL , NULL }
} ;
2001-06-05 21:12:10 +08:00
/* }}} */
2000-11-14 03:47:20 +08:00
2001-06-05 21:12:10 +08:00
/* {{{ openssl_module_entry
*/
2000-11-14 03:47:20 +08:00
zend_module_entry openssl_module_entry = {
2001-10-12 07:33:59 +08:00
STANDARD_MODULE_HEADER ,
2000-11-14 03:47:20 +08:00
" openssl " ,
openssl_functions ,
PHP_MINIT ( openssl ) ,
2004-10-26 17:24:07 +08:00
PHP_MSHUTDOWN ( openssl ) ,
2001-04-02 07:06:15 +08:00
NULL ,
2000-11-14 03:47:20 +08:00
NULL ,
PHP_MINFO ( openssl ) ,
2003-03-31 06:29:22 +08:00
NO_VERSION_YET ,
2000-11-14 03:47:20 +08:00
STANDARD_MODULE_PROPERTIES
} ;
2001-06-05 21:12:10 +08:00
/* }}} */
2000-11-14 03:47:20 +08:00
# ifdef COMPILE_DL_OPENSSL
ZEND_GET_MODULE ( openssl )
2003-08-31 20:41:53 +08:00
# ifdef PHP_WIN32
# include "zend_arg_defs.c"
# endif
2000-11-14 03:47:20 +08:00
# endif
2000-11-14 17:54:25 +08:00
static int le_key ;
static int le_x509 ;
2001-09-11 07:57:10 +08:00
static int le_csr ;
2003-11-28 01:40:16 +08:00
static int ssl_stream_data_index ;
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
int php_openssl_get_x509_list_id ( void ) /* { { { */
2006-05-01 07:43:46 +08:00
{
return le_x509 ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2006-05-01 07:43:46 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ resource destructors */
static void php_pkey_free ( zend_rsrc_list_entry * rsrc TSRMLS_DC )
{
EVP_PKEY * pkey = ( EVP_PKEY * ) rsrc - > ptr ;
2002-03-26 08:03:11 +08:00
assert ( pkey ! = NULL ) ;
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
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 ) ;
}
/* }}} */
2002-11-10 13:19:40 +08:00
/* {{{ 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 ;
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ openssl -> PHP "bridging" */
/* true global; readonly after module startup */
2001-10-05 04:10:58 +08:00
static char default_ssl_conf_filename [ MAXPATHLEN ] ;
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
struct php_x509_request { /* {{{ */
2001-09-11 07:57:10 +08:00
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 ;
} ;
2006-07-30 06:52:49 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-08-01 07:47:35 +08:00
static X509 * php_openssl_x509_from_zval ( zval * * val , int makeresource , long * resourceval TSRMLS_DC ) ;
2001-07-30 16:24:42 +08:00
static EVP_PKEY * php_openssl_evp_from_zval ( zval * * val , int public_key , char * passphrase , int makeresource , long * resourceval TSRMLS_DC ) ;
2002-12-12 21:42:23 +08:00
static int php_openssl_is_private_key ( EVP_PKEY * pkey TSRMLS_DC ) ;
2003-03-31 06:29:22 +08:00
static X509_STORE * setup_verify ( zval * calist TSRMLS_DC ) ;
2001-04-02 07:06:15 +08:00
static STACK_OF ( X509 ) * load_all_certs_from_file ( char * certfile ) ;
2001-09-11 07:57:10 +08:00
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 ) ;
2006-07-30 06:52:49 +08:00
static void add_assoc_name_entry ( zval * val , char * key , X509_NAME * name , int shortname TSRMLS_DC ) /* { { { */
2001-09-11 07:57:10 +08:00
{
2005-03-15 05:00:03 +08:00
zval * subitem , * subentries ;
int i , j = - 1 , last = - 1 , obj_cnt = 0 ;
char * sname ;
2001-09-11 07:57:10 +08:00
int nid ;
X509_NAME_ENTRY * ne ;
ASN1_STRING * str ;
ASN1_OBJECT * obj ;
MAKE_STD_ZVAL ( subitem ) ;
array_init ( subitem ) ;
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < X509_NAME_entry_count ( name ) ; i + + ) {
2003-01-05 07:31:55 +08:00
ne = X509_NAME_get_entry ( name , i ) ;
2001-09-11 07:57:10 +08:00
obj = X509_NAME_ENTRY_get_object ( ne ) ;
nid = OBJ_obj2nid ( obj ) ;
2005-03-15 05:00:03 +08:00
obj_cnt = 0 ;
2002-12-11 06:18:58 +08:00
if ( shortname ) {
2005-03-15 05:00:03 +08:00
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 ) ;
2003-01-05 07:31:55 +08:00
} else {
2005-03-15 05:00:03 +08:00
zval_dtor ( subentries ) ;
FREE_ZVAL ( subentries ) ;
2005-03-15 08:27:52 +08:00
if ( obj_cnt ) {
add_assoc_stringl ( subitem , sname , str - > data , str - > length , 1 ) ;
}
2001-09-11 07:57:10 +08:00
}
}
zend_hash_update ( HASH_OF ( val ) , key , strlen ( key ) + 1 , ( void * ) & subitem , sizeof ( subitem ) , NULL ) ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static void add_assoc_asn1_string ( zval * val , char * key , ASN1_STRING * str ) /* { { { */
2001-09-11 07:57:10 +08:00
{
add_assoc_stringl ( val , key , str - > data , str - > length , 1 ) ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static time_t asn1_time_to_time_t ( ASN1_UTCTIME * timestr TSRMLS_DC ) /* { { { */
2001-09-11 07:57:10 +08:00
{
/*
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 ;
2002-12-11 06:18:58 +08:00
if ( timestr - > length < 13 ) {
2002-12-12 22:12:42 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " extension author too lazy to parse %s correctly " , timestr - > data ) ;
2001-09-11 07:57:10 +08:00
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 ) ;
2003-03-31 06:29:22 +08:00
if ( thetime . tm_year < 68 ) {
2001-09-11 07:57:10 +08:00
thetime . tm_year + = 100 ;
2003-03-31 06:29:22 +08:00
}
2001-09-11 07:57:10 +08:00
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 .
*/
2002-12-12 20:18:44 +08:00
gmadjust = - ( thetime . tm_isdst ? ( long ) timezone - 3600 : ( long ) timezone + 3600 ) ;
2001-09-11 07:57:10 +08:00
# endif
ret + = gmadjust ;
efree ( strbuf ) ;
return ret ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
static inline int php_openssl_config_check_syntax (
const char * section_label ,
const char * config_filename ,
const char * section ,
2006-07-30 06:52:49 +08:00
LHASH * config TSRMLS_DC
) /* {{{ */
2001-09-11 07:57:10 +08:00
{
X509V3_CTX ctx ;
X509V3_set_ctx_test ( & ctx ) ;
X509V3_set_conf_lhash ( & ctx , config ) ;
2002-12-11 06:18:58 +08:00
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 " ,
2001-09-11 07:57:10 +08:00
section_label ,
section ,
config_filename ) ;
return FAILURE ;
}
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static int add_oid_section ( struct php_x509_request * req TSRMLS_DC ) /* { { { */
2001-09-11 07:57:10 +08:00
{
char * str ;
STACK_OF ( CONF_VALUE ) * sktmp ;
CONF_VALUE * cnf ;
int i ;
str = CONF_get_string ( req - > req_config , NULL , " oid_section " ) ;
2003-01-05 07:31:55 +08:00
if ( str = = NULL ) {
2001-09-11 07:57:10 +08:00
return SUCCESS ;
2003-03-31 06:29:22 +08:00
}
2001-09-11 07:57:10 +08:00
sktmp = CONF_get_section ( req - > req_config , str ) ;
2002-12-11 06:18:58 +08:00
if ( sktmp = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " problem loading oid section %s " , str ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < sk_CONF_VALUE_num ( sktmp ) ; i + + ) {
2001-09-11 07:57:10 +08:00
cnf = sk_CONF_VALUE_value ( sktmp , i ) ;
2002-12-11 06:18:58 +08:00
if ( OBJ_create ( cnf - > value , cnf - > name , cnf - > name ) = = NID_undef ) {
2003-01-05 07:31:55 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " problem creating object %s=%s " , cnf - > name , cnf - > value ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
}
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
# define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
2001-09-30 21:30:18 +08:00
# 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)
2001-09-11 07:57:10 +08:00
# define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
2001-09-30 21:30:18 +08:00
req - > config_filename , req - > var , req - > req_config TSRMLS_CC ) = = FAILURE ) return FAILURE
2001-09-11 07:57:10 +08:00
# 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 = defval
static int php_openssl_parse_config (
struct php_x509_request * req ,
zval * optional_args
TSRMLS_DC
2006-07-30 06:52:49 +08:00
) /* {{{ */
2001-09-11 07:57:10 +08:00
{
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 ) ;
2003-03-31 06:29:22 +08:00
2003-01-05 07:31:55 +08:00
if ( req - > req_config = = NULL ) {
2001-09-11 07:57:10 +08:00
return FAILURE ;
2003-03-31 06:29:22 +08:00
}
2001-09-11 07:57:10 +08:00
/* read in the oids */
str = CONF_get_string ( req - > req_config , NULL , " oid_file " ) ;
2002-11-10 13:19:40 +08:00
if ( str & & ! php_openssl_safe_mode_chk ( str TSRMLS_CC ) ) {
BIO * oid_bio = BIO_new_file ( str , " r " ) ;
2002-12-11 06:18:58 +08:00
if ( oid_bio ) {
2001-09-11 07:57:10 +08:00
OBJ_create_objects ( oid_bio ) ;
BIO_free ( oid_bio ) ;
}
}
2003-01-05 07:31:55 +08:00
if ( add_oid_section ( req TSRMLS_CC ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return FAILURE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
SET_OPTIONAL_STRING_ARG ( " digest_alg " , req - > digest_name ,
2003-03-31 06:29:22 +08:00
CONF_get_string ( req - > req_config , req - > section_name , " default_md " ) ) ;
2001-09-11 07:57:10 +08:00
SET_OPTIONAL_STRING_ARG ( " x509_extensions " , req - > extensions_section ,
2003-03-31 06:29:22 +08:00
CONF_get_string ( req - > req_config , req - > section_name , " x509_extensions " ) ) ;
2001-09-11 07:57:10 +08:00
SET_OPTIONAL_STRING_ARG ( " req_extensions " , req - > extensions_section ,
2003-03-31 06:29:22 +08:00
CONF_get_string ( req - > req_config , req - > request_extensions_section , " req_extensions " ) ) ;
2001-09-11 07:57:10 +08:00
SET_OPTIONAL_LONG_ARG ( " private_key_bits " , req - > priv_key_bits ,
2003-03-31 06:29:22 +08:00
CONF_get_number ( req - > req_config , req - > section_name , " default_bits " ) ) ;
2001-09-11 07:57:10 +08:00
SET_OPTIONAL_LONG_ARG ( " private_key_type " , req - > priv_key_type , OPENSSL_KEYTYPE_DEFAULT ) ;
2002-12-11 06:18:58 +08:00
if ( optional_args & & zend_hash_find ( Z_ARRVAL_P ( optional_args ) , " encrypt_key " , sizeof ( " encrypt_key " ) , ( void * * ) & item ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
req - > priv_key_encrypt = Z_BVAL_PP ( item ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
str = CONF_get_string ( req - > req_config , req - > section_name , " encrypt_rsa_key " ) ;
2003-01-05 07:31:55 +08:00
if ( str = = NULL ) {
2001-09-11 07:57:10 +08:00
str = CONF_get_string ( req - > req_config , req - > section_name , " encrypt_key " ) ;
2003-03-31 06:29:22 +08:00
}
2003-01-05 07:31:55 +08:00
if ( str & & strcmp ( str , " no " ) = = 0 ) {
2001-09-11 07:57:10 +08:00
req - > priv_key_encrypt = 0 ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
req - > priv_key_encrypt = 1 ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* digest alg */
2003-01-05 07:31:55 +08:00
if ( req - > digest_name = = NULL ) {
2001-09-11 07:57:10 +08:00
req - > digest_name = CONF_get_string ( req - > req_config , req - > section_name , " default_md " ) ;
2003-01-05 07:31:55 +08:00
}
if ( req - > digest_name ) {
2001-09-11 07:57:10 +08:00
req - > digest = req - > md_alg = EVP_get_digestbyname ( req - > digest_name ) ;
2003-01-05 07:31:55 +08:00
}
if ( req - > md_alg = = NULL ) {
2001-09-11 07:57:10 +08:00
req - > md_alg = req - > digest = EVP_md5 ( ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PHP_SSL_CONFIG_SYNTAX_CHECK ( extensions_section ) ;
/* set the string mask */
str = CONF_get_string ( req - > req_config , req - > section_name , " string_mask " ) ;
2002-12-11 06:18:58 +08:00
if ( str & & ! ASN1_STRING_set_default_mask_asc ( str ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Invalid global string mask setting %s " , str ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
2003-01-05 07:31:55 +08:00
if ( req - > request_extensions_section = = NULL ) {
2001-09-11 07:57:10 +08:00
req - > request_extensions_section = CONF_get_string ( req - > req_config , req - > section_name , " req_extensions " ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PHP_SSL_CONFIG_SYNTAX_CHECK ( request_extensions_section ) ;
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static void php_openssl_dispose_config ( struct php_x509_request * req TSRMLS_DC ) /* { { { */
2001-09-11 07:57:10 +08:00
{
2002-12-11 06:18:58 +08:00
if ( req - > priv_key ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( req - > priv_key ) ;
req - > priv_key = NULL ;
}
2002-12-11 06:18:58 +08:00
if ( req - > global_config ) {
2001-09-11 07:57:10 +08:00
CONF_free ( req - > global_config ) ;
req - > global_config = NULL ;
}
2002-12-11 06:18:58 +08:00
if ( req - > req_config ) {
2001-09-11 07:57:10 +08:00
CONF_free ( req - > req_config ) ;
req - > req_config = NULL ;
}
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static int php_openssl_load_rand_file ( const char * file , int * egdsocket , int * seeded ) /* { { { */
2001-09-11 07:57:10 +08:00
{
2001-10-05 04:10:58 +08:00
char buffer [ MAXPATHLEN ] ;
2001-09-11 07:57:10 +08:00
2002-12-11 15:29:51 +08:00
TSRMLS_FETCH ( ) ;
2001-09-11 07:57:10 +08:00
* egdsocket = 0 ;
* seeded = 0 ;
# ifdef WINDOWS
RAND_screen ( ) ;
# endif
2003-01-05 07:31:55 +08:00
if ( file = = NULL ) {
2001-09-11 07:57:10 +08:00
file = RAND_file_name ( buffer , sizeof ( buffer ) ) ;
2003-01-05 07:31:55 +08:00
} else if ( RAND_egd ( file ) > 0 ) {
2001-09-11 07:57:10 +08:00
/* if the given filename is an EGD socket, don't
* write anything back to it */
* egdsocket = 1 ;
return SUCCESS ;
}
2002-12-11 06:18:58 +08:00
if ( file = = NULL | | ! RAND_load_file ( file , - 1 ) ) {
if ( RAND_status ( ) = = 0 ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to load random state; not enough random data! " ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
return FAILURE ;
}
* seeded = 1 ;
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
2006-07-30 06:52:49 +08:00
static int php_openssl_write_rand_file ( const char * file , int egdsocket , int seeded ) /* { { { */
2001-09-11 07:57:10 +08:00
{
2001-10-05 04:10:58 +08:00
char buffer [ MAXPATHLEN ] ;
2003-03-31 06:29:22 +08:00
2002-12-11 10:30:00 +08:00
TSRMLS_FETCH ( ) ;
2003-03-31 06:29:22 +08:00
2002-12-11 06:18:58 +08:00
if ( egdsocket | | ! seeded ) {
2001-09-11 07:57:10 +08:00
/* if we did not manage to read the seed file, we should not write
* a low - entropy seed file back */
return FAILURE ;
}
2003-01-05 07:31:55 +08:00
if ( file = = NULL ) {
2001-09-11 07:57:10 +08:00
file = RAND_file_name ( buffer , sizeof ( buffer ) ) ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( file = = NULL | | ! RAND_write_file ( file ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to write random state " ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2006-07-30 06:10:50 +08:00
static EVP_MD * php_openssl_get_evp_md_from_algo ( 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 ;
case OPENSSL_ALGO_MD2 :
mdtype = ( EVP_MD * ) EVP_md2 ( ) ;
break ;
default :
return NULL ;
break ;
}
return mdtype ;
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-06-05 21:12:10 +08:00
/* {{{ PHP_MINIT_FUNCTION
*/
2000-11-14 03:47:20 +08:00
PHP_MINIT_FUNCTION ( openssl )
{
2001-09-11 07:57:10 +08:00
char * config_filename ;
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
le_key = zend_register_list_destructors_ex ( php_pkey_free , NULL , " OpenSSL key " , module_number ) ;
le_x509 = zend_register_list_destructors_ex ( php_x509_free , NULL , " OpenSSL X.509 " , module_number ) ;
le_csr = zend_register_list_destructors_ex ( php_csr_free , NULL , " OpenSSL X.509 CSR " , module_number ) ;
2001-04-02 07:06:15 +08:00
2005-11-28 19:37:43 +08:00
SSL_library_init ( ) ;
2000-11-18 03:17:07 +08:00
OpenSSL_add_all_ciphers ( ) ;
2001-09-11 07:57:10 +08:00
OpenSSL_add_all_digests ( ) ;
OpenSSL_add_all_algorithms ( ) ;
2001-04-02 07:06:15 +08:00
ERR_load_ERR_strings ( ) ;
ERR_load_crypto_strings ( ) ;
ERR_load_EVP_strings ( ) ;
2003-11-28 01:40:16 +08:00
/* 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 ) ;
2001-04-02 07:06:15 +08:00
/* 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 ) ;
2002-05-01 16:22:17 +08:00
# ifdef X509_PURPOSE_ANY
2001-04-02 07:06:15 +08:00
REGISTER_LONG_CONSTANT ( " X509_PURPOSE_ANY " , X509_PURPOSE_ANY , CONST_CS | CONST_PERSISTENT ) ;
2002-05-01 16:22:17 +08:00
# endif
2001-04-02 07:06:15 +08:00
2003-03-31 06:29:22 +08:00
/* signature algorithm constants */
2003-03-31 06:25:23 +08:00
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 ) ;
REGISTER_LONG_CONSTANT ( " OPENSSL_ALGO_MD2 " , OPENSSL_ALGO_MD2 , CONST_CS | CONST_PERSISTENT ) ;
2003-03-31 06:29:22 +08:00
2001-04-03 07:14:01 +08:00
/* 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 ) ;
2003-03-31 06:29:22 +08:00
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 ) ;
2001-05-05 07:42:11 +08:00
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
/* Ciphers */
2003-03-31 06:29:22 +08:00
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 ) ;
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 ) ;
2001-09-11 07:57:10 +08:00
/* Values for key types */
2003-01-05 07:31:55 +08:00
REGISTER_LONG_CONSTANT ( " OPENSSL_KEYTYPE_RSA " , OPENSSL_KEYTYPE_RSA , CONST_CS | CONST_PERSISTENT ) ;
2001-09-11 07:57:10 +08:00
# ifndef NO_DSA
2003-01-05 07:31:55 +08:00
REGISTER_LONG_CONSTANT ( " OPENSSL_KEYTYPE_DSA " , OPENSSL_KEYTYPE_DSA , CONST_CS | CONST_PERSISTENT ) ;
2001-09-11 07:57:10 +08:00
# endif
2003-01-05 07:31:55 +08:00
REGISTER_LONG_CONSTANT ( " OPENSSL_KEYTYPE_DH " , OPENSSL_KEYTYPE_DH , CONST_CS | CONST_PERSISTENT ) ;
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
/* Determine default SSL configuration file */
config_filename = getenv ( " OPENSSL_CONF " ) ;
2003-01-05 07:31:55 +08:00
if ( config_filename = = NULL ) {
2001-09-11 07:57:10 +08:00
config_filename = getenv ( " SSLEAY_CONF " ) ;
2003-01-05 07:31:55 +08:00
}
2002-07-13 05:46:36 +08:00
/* default to 'openssl.cnf' if no environment variable is set */
if ( config_filename = = NULL ) {
2001-09-11 07:57:10 +08:00
snprintf ( default_ssl_conf_filename , sizeof ( default_ssl_conf_filename ) , " %s/%s " ,
X509_get_default_cert_area ( ) ,
2002-07-13 05:46:36 +08:00
" openssl.cnf " ) ;
2003-01-05 07:31:55 +08:00
} else {
strlcpy ( default_ssl_conf_filename , config_filename , sizeof ( default_ssl_conf_filename ) ) ;
2001-09-11 07:57:10 +08:00
}
2003-02-28 01:43:38 +08:00
php_stream_xport_register ( " ssl " , php_openssl_ssl_socket_factory TSRMLS_CC ) ;
2004-09-10 19:43:47 +08:00
php_stream_xport_register ( " sslv3 " , php_openssl_ssl_socket_factory TSRMLS_CC ) ;
php_stream_xport_register ( " sslv2 " , php_openssl_ssl_socket_factory TSRMLS_CC ) ;
2003-02-28 01:43:38 +08:00
php_stream_xport_register ( " tls " , php_openssl_ssl_socket_factory TSRMLS_CC ) ;
/* override the default tcp socket provider */
php_stream_xport_register ( " tcp " , php_openssl_ssl_socket_factory TSRMLS_CC ) ;
2003-02-28 02:16:35 +08:00
php_register_url_stream_wrapper ( " https " , & php_stream_http_wrapper TSRMLS_CC ) ;
php_register_url_stream_wrapper ( " ftps " , & php_stream_ftp_wrapper TSRMLS_CC ) ;
2003-02-28 01:43:38 +08:00
2000-11-14 03:47:20 +08:00
return SUCCESS ;
}
2001-06-05 21:12:10 +08:00
/* }}} */
2000-11-14 03:47:20 +08:00
2001-06-05 21:12:10 +08:00
/* {{{ PHP_MINFO_FUNCTION
*/
2000-11-14 03:47:20 +08:00
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 Version " , OPENSSL_VERSION_TEXT ) ;
php_info_print_table_end ( ) ;
}
2001-06-05 21:12:10 +08:00
/* }}} */
2000-11-14 03:47:20 +08:00
2001-06-05 21:12:10 +08:00
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
2000-11-18 03:17:07 +08:00
PHP_MSHUTDOWN_FUNCTION ( openssl )
{
EVP_cleanup ( ) ;
2003-02-28 01:43:38 +08:00
2003-02-28 02:16:35 +08:00
php_unregister_url_stream_wrapper ( " https " TSRMLS_CC ) ;
php_unregister_url_stream_wrapper ( " ftps " TSRMLS_CC ) ;
2003-02-28 01:43:38 +08:00
php_stream_xport_unregister ( " ssl " TSRMLS_CC ) ;
2004-09-14 02:30:30 +08:00
php_stream_xport_unregister ( " sslv2 " TSRMLS_CC ) ;
php_stream_xport_unregister ( " sslv3 " TSRMLS_CC ) ;
2003-02-28 01:43:38 +08:00
php_stream_xport_unregister ( " tls " TSRMLS_CC ) ;
/* reinstate the default tcp handler */
php_stream_xport_register ( " tcp " , php_stream_generic_socket_factory TSRMLS_CC ) ;
2000-11-18 03:17:07 +08:00
return SUCCESS ;
}
2001-06-05 21:12:10 +08:00
/* }}} */
2000-11-18 03:17:07 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ x509 cert functions */
2001-06-05 21:12:10 +08:00
/* {{{ php_openssl_x509_from_zval
2001-04-02 07:06:15 +08:00
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 .
*/
2001-08-01 07:47:35 +08:00
static X509 * php_openssl_x509_from_zval ( zval * * val , int makeresource , long * resourceval TSRMLS_DC )
2001-04-02 07:06:15 +08:00
{
X509 * cert = NULL ;
2003-01-05 07:31:55 +08:00
if ( resourceval ) {
2001-04-02 07:06:15 +08:00
* resourceval = - 1 ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_PP ( val ) = = IS_RESOURCE ) {
2001-04-02 07:06:15 +08:00
/* is it an x509 resource ? */
void * what ;
int type ;
2001-07-30 12:58:07 +08:00
what = zend_fetch_resource ( val TSRMLS_CC , - 1 , " OpenSSL X.509 " , & type , 1 , le_x509 ) ;
2003-01-05 07:31:55 +08:00
if ( ! what ) {
2001-04-02 07:06:15 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
/* this is so callers can decide if they should free the X509 */
2003-01-05 07:31:55 +08:00
if ( resourceval ) {
2001-04-02 07:06:15 +08:00
* resourceval = Z_LVAL_PP ( val ) ;
2003-01-05 07:31:55 +08:00
}
if ( type = = le_x509 ) {
2001-04-02 07:06:15 +08:00
return ( X509 * ) what ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
/* other types could be used here - eg: file pointers and read in the data from them */
return NULL ;
}
/* force it to be a string and check if it refers to a file */
convert_to_string_ex ( val ) ;
2003-01-05 07:31:55 +08:00
if ( Z_STRLEN_PP ( val ) > 7 & & memcmp ( Z_STRVAL_PP ( val ) , " file:// " , sizeof ( " file:// " ) - 1 ) = = 0 ) {
2001-04-02 07:06:15 +08:00
/* read cert from the named file */
BIO * in ;
2003-01-05 07:31:55 +08:00
if ( php_openssl_safe_mode_chk ( Z_STRVAL_PP ( val ) + ( sizeof ( " file:// " ) - 1 ) TSRMLS_CC ) ) {
2002-11-10 13:19:40 +08:00
return NULL ;
}
2003-01-05 07:31:55 +08:00
in = BIO_new_file ( Z_STRVAL_PP ( val ) + ( sizeof ( " file:// " ) - 1 ) , " r " ) ;
if ( in = = NULL ) {
2001-04-02 07:06:15 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
cert = PEM_read_bio_X509 ( in , NULL , NULL , NULL ) ;
BIO_free ( in ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-04-02 07:06:15 +08:00
BIO * in ;
in = BIO_new_mem_buf ( Z_STRVAL_PP ( val ) , Z_STRLEN_PP ( val ) ) ;
2003-01-05 07:31:55 +08:00
if ( in = = NULL ) {
2001-04-02 07:06:15 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
cert = ( X509 * ) PEM_ASN1_read_bio ( ( char * ( * ) ( ) ) d2i_X509 , PEM_STRING_X509 , in , NULL , NULL , NULL ) ;
2001-04-02 07:06:15 +08:00
BIO_free ( in ) ;
}
2002-12-11 06:18:58 +08:00
if ( cert & & makeresource & & resourceval ) {
2001-04-02 07:06:15 +08:00
* resourceval = zend_list_insert ( cert , le_x509 ) ;
}
return cert ;
}
2001-09-11 07:57:10 +08:00
2001-06-05 21:12:10 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-12-07 01:51:48 +08:00
/* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
2001-09-11 09:03:59 +08:00
Exports a CERT to file or a var */
2001-09-11 08:33:25 +08:00
PHP_FUNCTION ( openssl_x509_export_to_file )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
X509 * cert ;
2001-09-11 08:33:25 +08:00
zval * zcert = NULL ;
zend_bool notext = 1 ;
2001-09-11 07:57:10 +08:00
BIO * bio_out ;
long certresource ;
2001-09-11 08:33:25 +08:00
char * filename ;
2003-03-07 07:07:28 +08:00
int filename_len ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " rs|b " , & zcert , & filename , & filename_len , & notext ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get cert from parameter 1 " ) ;
2001-09-11 07:57:10 +08:00
return ;
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
return ;
}
2001-09-11 08:33:25 +08:00
bio_out = BIO_new_file ( filename , " w " ) ;
2002-12-11 06:18:58 +08:00
if ( bio_out ) {
2003-01-05 07:31:55 +08:00
if ( ! notext ) {
2001-09-11 07:57:10 +08:00
X509_print ( bio_out , cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PEM_write_bio_X509 ( bio_out , cert ) ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
RETVAL_TRUE ;
2003-01-05 07:31:55 +08:00
} else {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening file %s " , filename ) ;
2003-01-05 07:31:55 +08:00
}
if ( certresource = = - 1 & & cert ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
BIO_free ( bio_out ) ;
}
/* }}} */
2001-12-07 01:51:48 +08:00
/* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
2001-09-11 09:03:59 +08:00
Exports a CERT to file or a var */
2001-09-11 08:33:25 +08:00
PHP_FUNCTION ( openssl_x509_export )
{
X509 * cert ;
zval * zcert = NULL , * zout = NULL ;
zend_bool notext = 1 ;
BIO * bio_out ;
long certresource ;
char * bio_mem_ptr ;
long bio_mem_len ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " rz|b " , & zcert , & zout , & notext ) = = FAILURE ) {
2001-09-11 08:33:25 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
RETVAL_FALSE ;
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get cert from parameter 1 " ) ;
2001-09-11 08:33:25 +08:00
return ;
}
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( ! notext ) {
2001-09-11 08:33:25 +08:00
X509_print ( bio_out , cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
PEM_write_bio_X509 ( bio_out , cert ) ;
bio_mem_len = BIO_get_mem_data ( bio_out , & bio_mem_ptr ) ;
ZVAL_STRINGL ( zout , bio_mem_ptr , bio_mem_len , 1 ) ;
RETVAL_TRUE ;
2003-01-05 07:31:55 +08:00
if ( certresource = = - 1 & & cert ) {
2001-09-11 08:33:25 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
BIO_free ( bio_out ) ;
}
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
2001-09-11 09:03:59 +08:00
Checks if a private key corresponds to a CERT */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_x509_check_private_key )
{
zval * zcert , * zkey ;
X509 * cert = NULL ;
EVP_PKEY * key = NULL ;
long certresource = - 1 , keyresource = - 1 ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zz " , & zcert , & zkey ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
key = php_openssl_evp_from_zval ( & zkey , 0 , " " , 1 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( key ) {
2001-09-11 07:57:10 +08:00
RETVAL_BOOL ( X509_check_private_key ( cert , key ) ) ;
2001-04-02 07:06:15 +08:00
}
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 & & key ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( key ) ;
2003-01-05 07:31:55 +08:00
}
if ( certresource = = - 1 & & cert ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 09:03:59 +08:00
/* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
Returns an array of the fields / values of the CERT */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_x509_parse )
{
zval * zcert ;
X509 * cert = NULL ;
long certresource = - 1 ;
int i ;
zend_bool useshortnames = 1 ;
char * tmpstr ;
zval * subitem ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " z|b " , & zcert , & useshortnames ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
array_init ( return_value ) ;
2003-01-05 07:31:55 +08:00
if ( cert - > name ) {
2001-09-11 07:57:10 +08:00
add_assoc_string ( return_value , " name " , cert - > name , 1 ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
/* add_assoc_bool(return_value, "valid", cert->valid); */
2002-04-13 03:26:08 +08:00
add_assoc_name_entry ( return_value , " subject " , X509_get_subject_name ( cert ) , useshortnames TSRMLS_CC ) ;
2002-03-28 08:56:19 +08:00
/* hash as used in CA directories to lookup cert by subject name */
{
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , " %08lx " , X509_subject_name_hash ( cert ) ) ;
add_assoc_string ( return_value , " hash " , buf , 1 ) ;
}
2002-04-13 03:26:08 +08:00
add_assoc_name_entry ( return_value , " issuer " , X509_get_issuer_name ( cert ) , useshortnames TSRMLS_CC ) ;
2001-09-11 07:57:10 +08:00
add_assoc_long ( return_value , " version " , X509_get_version ( cert ) ) ;
add_assoc_long ( return_value , " serialNumber " , ASN1_INTEGER_get ( X509_get_serialNumber ( cert ) ) ) ;
add_assoc_asn1_string ( return_value , " validFrom " , X509_get_notBefore ( cert ) ) ;
add_assoc_asn1_string ( return_value , " validTo " , X509_get_notAfter ( cert ) ) ;
add_assoc_long ( return_value , " validFrom_time_t " , asn1_time_to_time_t ( X509_get_notBefore ( cert ) TSRMLS_CC ) ) ;
add_assoc_long ( return_value , " validTo_time_t " , asn1_time_to_time_t ( X509_get_notAfter ( cert ) TSRMLS_CC ) ) ;
tmpstr = X509_alias_get0 ( cert , NULL ) ;
2003-01-05 07:31:55 +08:00
if ( tmpstr ) {
2001-09-11 07:57:10 +08:00
add_assoc_string ( return_value , " alias " , tmpstr , 1 ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
/*
add_assoc_long ( return_value , " signaturetypeLONG " , X509_get_signature_type ( cert ) ) ;
add_assoc_string ( return_value , " signaturetype " , OBJ_nid2sn ( X509_get_signature_type ( cert ) ) , 1 ) ;
add_assoc_string ( return_value , " signaturetypeLN " , OBJ_nid2ln ( X509_get_signature_type ( cert ) ) , 1 ) ;
*/
MAKE_STD_ZVAL ( subitem ) ;
array_init ( subitem ) ;
/* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
in x509v3 . h */
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < X509_PURPOSE_get_count ( ) ; i + + ) {
2001-09-11 07:57:10 +08:00
int id , purpset ;
char * pname ;
X509_PURPOSE * purp ;
zval * subsub ;
MAKE_STD_ZVAL ( subsub ) ;
array_init ( subsub ) ;
purp = X509_PURPOSE_get0 ( i ) ;
id = X509_PURPOSE_get_id ( purp ) ;
purpset = X509_check_purpose ( cert , id , 0 ) ;
add_index_bool ( subsub , 0 , purpset ) ;
purpset = X509_check_purpose ( cert , id , 1 ) ;
add_index_bool ( subsub , 1 , purpset ) ;
pname = useshortnames ? X509_PURPOSE_get0_sname ( purp ) : X509_PURPOSE_get0_name ( purp ) ;
add_index_string ( subsub , 2 , pname , 1 ) ;
/* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
add_index_zval ( subitem , id , subsub ) ;
}
add_assoc_zval ( return_value , " purposes " , subitem ) ;
2003-01-05 07:31:55 +08:00
if ( certresource = = - 1 & & cert ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
/* {{{ load_all_certs_from_file */
static STACK_OF ( X509 ) * load_all_certs_from_file ( char * certfile )
{
2003-01-05 07:31:55 +08:00
STACK_OF ( X509_INFO ) * sk = NULL ;
STACK_OF ( X509 ) * stack = NULL , * ret = NULL ;
BIO * in = NULL ;
X509_INFO * xi ;
TSRMLS_FETCH ( ) ;
2001-09-11 07:57:10 +08:00
if ( ! ( stack = sk_X509_new_null ( ) ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_ERROR , " memory allocation failure " ) ;
2001-09-11 07:57:10 +08:00
goto end ;
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( certfile TSRMLS_CC ) ) {
goto end ;
}
2001-09-11 07:57:10 +08:00
if ( ! ( in = BIO_new_file ( certfile , " r " ) ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening the file, %s " , certfile ) ;
2001-09-11 07:57:10 +08:00
goto end ;
}
/* This loads from a file, a stack of x509/crl/pkey sets */
if ( ! ( sk = PEM_X509_INFO_read_bio ( in , NULL , NULL , NULL ) ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error reading the file, %s " , certfile ) ;
2001-09-11 07:57:10 +08:00
goto end ;
}
/* scan over it and pull out the certs */
2003-01-05 07:31:55 +08:00
while ( sk_X509_INFO_num ( sk ) ) {
2001-09-11 07:57:10 +08:00
xi = sk_X509_INFO_shift ( sk ) ;
2003-01-05 07:31:55 +08:00
if ( xi - > x509 ! = NULL ) {
2001-09-11 07:57:10 +08:00
sk_X509_push ( stack , xi - > x509 ) ;
xi - > x509 = NULL ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
X509_INFO_free ( xi ) ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
if ( ! sk_X509_num ( stack ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " no certificates in file, %s " , certfile ) ;
2001-09-11 07:57:10 +08:00
sk_X509_free ( stack ) ;
goto end ;
}
ret = stack ;
end :
BIO_free ( in ) ;
sk_X509_INFO_free ( sk ) ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
return ret ;
}
/* }}} */
/* {{{ check_cert */
static int check_cert ( X509_STORE * ctx , X509 * x , STACK_OF ( X509 ) * untrustedchain , int purpose )
{
int ret = 0 ;
X509_STORE_CTX * csc ;
TSRMLS_FETCH ( ) ;
csc = X509_STORE_CTX_new ( ) ;
2003-01-05 07:31:55 +08:00
if ( csc = = NULL ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_ERROR , " memory allocation failure " ) ;
2001-09-11 07:57:10 +08:00
return 0 ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
X509_STORE_CTX_init ( csc , ctx , x , untrustedchain ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( purpose > = 0 ) {
2001-09-11 07:57:10 +08:00
X509_STORE_CTX_set_purpose ( csc , purpose ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
ret = X509_verify_cert ( csc ) ;
X509_STORE_CTX_free ( csc ) ;
return ret ;
}
/* }}} */
2001-09-11 09:03:59 +08:00
/* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
Checks the CERT to see if it can be used for the purpose in purpose . cainfo holds information about trusted CAs */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_x509_checkpurpose )
{
2001-09-11 08:33:25 +08:00
zval * zcert , * zcainfo = NULL ;
2001-09-11 07:57:10 +08:00
X509_STORE * cainfo = NULL ;
X509 * cert = NULL ;
long certresource = - 1 ;
STACK_OF ( X509 ) * untrustedchain = NULL ;
long purpose ;
char * untrusted = NULL ;
2003-03-07 07:07:28 +08:00
int untrusted_len ;
2001-09-11 07:57:10 +08:00
2001-09-11 08:33:25 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zl|a!s " , & zcert , & purpose , & zcainfo , & untrusted , & untrusted_len )
2003-01-05 07:31:55 +08:00
= = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_LONG ( - 1 ) ;
2002-12-11 06:18:58 +08:00
if ( untrusted ) {
2001-09-11 07:57:10 +08:00
untrustedchain = load_all_certs_from_file ( untrusted ) ;
2003-01-05 07:31:55 +08:00
if ( untrustedchain = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
cainfo = setup_verify ( zcainfo TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cainfo = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
RETVAL_LONG ( check_cert ( cainfo , cert , untrustedchain , purpose ) ) ;
2001-09-11 07:57:10 +08:00
clean_exit :
2003-01-05 07:31:55 +08:00
if ( certresource = = 1 & & cert ) {
2001-04-02 07:06:15 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
if ( cainfo ) {
X509_STORE_free ( cainfo ) ;
}
if ( untrustedchain ) {
2001-09-11 07:57:10 +08:00
sk_X509_pop_free ( untrustedchain , X509_free ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ setup_verify
* calist is an array containing file and directory names . create a
* certificate store and add those certs to it for use in verification .
*/
static X509_STORE * setup_verify ( zval * calist TSRMLS_DC )
{
X509_STORE * store ;
X509_LOOKUP * dir_lookup , * file_lookup ;
HashPosition pos ;
int ndirs = 0 , nfiles = 0 ;
store = X509_STORE_new ( ) ;
2003-01-05 07:31:55 +08:00
if ( store = = NULL ) {
2001-09-11 07:57:10 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
2002-12-11 06:18:58 +08:00
if ( calist & & ( Z_TYPE_P ( calist ) = = IS_ARRAY ) ) {
2001-09-11 07:57:10 +08:00
zend_hash_internal_pointer_reset_ex ( HASH_OF ( calist ) , & pos ) ;
2002-12-11 06:18:58 +08:00
for ( ; ; zend_hash_move_forward_ex ( HASH_OF ( calist ) , & pos ) ) {
2001-09-11 07:57:10 +08:00
zval * * item ;
struct stat sb ;
2003-01-05 07:31:55 +08:00
if ( zend_hash_get_current_data_ex ( HASH_OF ( calist ) , ( void * * ) & item , & pos ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
break ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
convert_to_string_ex ( item ) ;
2002-12-11 06:18:58 +08:00
if ( VCWD_STAT ( Z_STRVAL_PP ( item ) , & sb ) = = - 1 ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to stat %s " , Z_STRVAL_PP ( item ) ) ;
2001-09-11 07:57:10 +08:00
continue ;
}
2002-12-11 06:18:58 +08:00
if ( ( sb . st_mode & S_IFREG ) = = S_IFREG ) {
2001-09-11 07:57:10 +08:00
file_lookup = X509_STORE_add_lookup ( store , X509_LOOKUP_file ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( file_lookup = = NULL | | ! X509_LOOKUP_load_file ( file_lookup , Z_STRVAL_PP ( item ) , X509_FILETYPE_PEM ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error loading file %s " , Z_STRVAL_PP ( item ) ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
nfiles + + ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
file_lookup = NULL ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
dir_lookup = X509_STORE_add_lookup ( store , X509_LOOKUP_hash_dir ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( dir_lookup = = NULL | | ! X509_LOOKUP_add_dir ( dir_lookup , Z_STRVAL_PP ( item ) , X509_FILETYPE_PEM ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error loading directory %s " , Z_STRVAL_PP ( item ) ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
ndirs + + ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
dir_lookup = NULL ;
}
}
}
2002-12-11 06:18:58 +08:00
if ( nfiles = = 0 ) {
2001-09-11 07:57:10 +08:00
file_lookup = X509_STORE_add_lookup ( store , X509_LOOKUP_file ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( file_lookup ) {
2001-09-11 07:57:10 +08:00
X509_LOOKUP_load_file ( file_lookup , NULL , X509_FILETYPE_DEFAULT ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
2002-12-11 06:18:58 +08:00
if ( ndirs = = 0 ) {
2001-09-11 07:57:10 +08:00
dir_lookup = X509_STORE_add_lookup ( store , X509_LOOKUP_hash_dir ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( dir_lookup ) {
2001-09-11 07:57:10 +08:00
X509_LOOKUP_add_dir ( dir_lookup , NULL , X509_FILETYPE_DEFAULT ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
return store ;
2001-04-02 07:06:15 +08:00
}
2001-06-05 21:12:10 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ proto resource openssl_x509_read(mixed cert)
2001-09-11 09:03:59 +08:00
Reads X .509 certificates */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_x509_read )
2001-05-05 07:42:11 +08:00
{
2001-09-11 07:57:10 +08:00
zval * cert ;
X509 * x509 ;
2001-05-05 07:42:11 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " z " , & cert ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
Z_TYPE_P ( return_value ) = IS_RESOURCE ;
x509 = php_openssl_x509_from_zval ( & cert , 1 , & Z_LVAL_P ( return_value ) TSRMLS_CC ) ;
2001-05-05 07:42:11 +08:00
2001-09-11 07:57:10 +08:00
if ( x509 = = NULL ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " supplied parameter cannot be coerced into an X509 certificate! " ) ;
2001-05-05 07:42:11 +08:00
RETURN_FALSE ;
}
}
/* }}} */
2001-12-07 01:51:48 +08:00
/* {{{ proto void openssl_x509_free(resource x509)
2001-09-11 09:03:59 +08:00
Frees X .509 certificates */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_x509_free )
2001-05-05 07:42:11 +08:00
{
2001-09-11 07:57:10 +08:00
zval * x509 ;
X509 * cert ;
2001-05-05 07:42:11 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " r " , & x509 ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
ZEND_FETCH_RESOURCE ( cert , X509 * , & x509 , - 1 , " OpenSSL X.509 " , le_x509 ) ;
zend_list_delete ( Z_LVAL_P ( x509 ) ) ;
2001-05-05 07:42:11 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* }}} */
/* {{{ x509 CSR functions */
/* {{{ php_openssl_make_REQ */
2002-04-13 03:26:08 +08:00
static int php_openssl_make_REQ ( struct php_x509_request * req , X509_REQ * csr , zval * dn , zval * attribs TSRMLS_DC )
2001-05-05 07:42:11 +08:00
{
2001-09-11 07:57:10 +08:00
STACK_OF ( CONF_VALUE ) * dn_sk , * attr_sk = NULL ;
char * str , * dn_sect , * attr_sect ;
dn_sect = CONF_get_string ( req - > req_config , req - > section_name , " distinguished_name " ) ;
2003-01-05 07:31:55 +08:00
if ( dn_sect = = NULL ) {
2001-09-11 07:57:10 +08:00
return FAILURE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
dn_sk = CONF_get_section ( req - > req_config , dn_sect ) ;
2003-01-05 07:31:55 +08:00
if ( dn_sk = = NULL ) {
2001-09-11 07:57:10 +08:00
return FAILURE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
attr_sect = CONF_get_string ( req - > req_config , req - > section_name , " attributes " ) ;
2003-01-05 07:31:55 +08:00
if ( attr_sect = = NULL ) {
2001-09-11 07:57:10 +08:00
attr_sk = NULL ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
attr_sk = CONF_get_section ( req - > req_config , attr_sect ) ;
2003-01-05 07:31:55 +08:00
if ( attr_sk = = NULL ) {
2001-09-11 07:57:10 +08:00
return FAILURE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* setup the version number: version 1 */
2002-12-11 06:18:58 +08:00
if ( X509_REQ_set_version ( csr , 0L ) ) {
2001-09-11 07:57:10 +08:00
int i , nid ;
char * type ;
CONF_VALUE * v ;
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 ) ;
2002-12-11 06:18:58 +08:00
while ( zend_hash_get_current_data_ex ( HASH_OF ( dn ) , ( void * * ) & item , & hpos ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
char * strindex ; int strindexlen ;
long intindex ;
zend_hash_get_current_key_ex ( HASH_OF ( dn ) , & strindex , & strindexlen , & intindex , 0 , & hpos ) ;
2001-05-05 07:42:11 +08:00
2001-09-11 07:57:10 +08:00
convert_to_string_ex ( item ) ;
2001-05-05 07:42:11 +08:00
2002-12-11 06:18:58 +08:00
if ( strindex ) {
2001-09-11 07:57:10 +08:00
int nid ;
nid = OBJ_txt2nid ( strindex ) ;
2002-12-11 06:18:58 +08:00
if ( nid ! = NID_undef ) {
2003-01-05 07:31:55 +08:00
if ( ! X509_NAME_add_entry_by_NID ( subj , nid , MBSTRING_ASC ,
2001-09-11 07:57:10 +08:00
( unsigned char * ) Z_STRVAL_PP ( item ) , - 1 , - 1 , 0 ) )
{
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " dn: add_entry_by_NID %d -> %s (failed) " , nid , Z_STRVAL_PP ( item ) ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
2002-12-11 06:18:58 +08:00
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " dn: %s is not a recognized name " , strindex ) ;
2001-09-11 07:57:10 +08:00
}
}
zend_hash_move_forward_ex ( HASH_OF ( dn ) , & hpos ) ;
}
2001-05-05 07:42:11 +08:00
2001-09-11 07:57:10 +08:00
/* Finally apply defaults from config file */
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < sk_CONF_VALUE_num ( dn_sk ) ; i + + ) {
2001-09-11 07:57:10 +08:00
int len ;
char buffer [ 200 ] ;
v = sk_CONF_VALUE_value ( dn_sk , i ) ;
type = v - > name ;
len = strlen ( type ) ;
2003-01-05 07:31:55 +08:00
if ( len < sizeof ( " _default " ) ) {
2001-09-11 07:57:10 +08:00
continue ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
len - = sizeof ( " _default " ) - 1 ;
2002-12-11 06:18:58 +08:00
if ( strcmp ( " _default " , type + len ) ! = 0 ) {
2001-09-11 07:57:10 +08:00
continue ;
}
memcpy ( buffer , type , len ) ;
buffer [ len ] = ' \0 ' ;
type = buffer ;
/* Skip past any leading X. X: X, etc to allow for multiple
* instances */
2002-12-11 06:18:58 +08:00
for ( str = type ; * str ; str + + ) {
if ( * str = = ' : ' | | * str = = ' , ' | | * str = = ' . ' ) {
2001-09-11 07:57:10 +08:00
str + + ;
2003-01-05 07:31:55 +08:00
if ( * str ) {
2001-09-11 07:57:10 +08:00
type = str ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
break ;
}
}
/* if it is already set, skip this */
nid = OBJ_txt2nid ( type ) ;
2003-01-05 07:31:55 +08:00
if ( X509_NAME_get_index_by_NID ( subj , nid , - 1 ) > = 0 ) {
2001-09-11 07:57:10 +08:00
continue ;
2003-01-05 07:31:55 +08:00
}
if ( ! X509_NAME_add_entry_by_txt ( subj , type , MBSTRING_ASC , ( unsigned char * ) v - > value , - 1 , - 1 , 0 ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " add_entry_by_txt %s -> %s (failed) " , type , v - > value ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
2002-12-11 06:18:58 +08:00
if ( ! X509_NAME_entry_count ( subj ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " no objects specified in config file " ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
}
2002-12-11 06:18:58 +08:00
if ( attribs ) {
2001-09-11 07:57:10 +08:00
zend_hash_internal_pointer_reset_ex ( HASH_OF ( attribs ) , & hpos ) ;
2002-12-11 06:18:58 +08:00
while ( zend_hash_get_current_data_ex ( HASH_OF ( attribs ) , ( void * * ) & item , & hpos ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
char * strindex ; int strindexlen ;
long intindex ;
zend_hash_get_current_key_ex ( HASH_OF ( attribs ) , & strindex , & strindexlen , & intindex , 0 , & hpos ) ;
convert_to_string_ex ( item ) ;
2002-12-11 06:18:58 +08:00
if ( strindex ) {
2001-09-11 07:57:10 +08:00
int nid ;
nid = OBJ_txt2nid ( strindex ) ;
2002-12-11 06:18:58 +08:00
if ( nid ! = NID_undef ) {
2003-01-05 07:31:55 +08:00
if ( ! X509_NAME_add_entry_by_NID ( subj , nid , MBSTRING_ASC , ( unsigned char * ) Z_STRVAL_PP ( item ) , - 1 , - 1 , 0 ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " attribs: add_entry_by_NID %d -> %s (failed) " , nid , Z_STRVAL_PP ( item ) ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
2002-12-11 06:18:58 +08:00
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " dn: %s is not a recognized name " , strindex ) ;
2001-09-11 07:57:10 +08:00
}
}
zend_hash_move_forward_ex ( HASH_OF ( attribs ) , & hpos ) ;
}
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < sk_CONF_VALUE_num ( attr_sk ) ; i + + ) {
2001-09-11 07:57:10 +08:00
v = sk_CONF_VALUE_value ( attr_sk , i ) ;
/* if it is already set, skip this */
nid = OBJ_txt2nid ( v - > name ) ;
2003-01-05 07:31:55 +08:00
if ( X509_REQ_get_attr_by_NID ( csr , nid , - 1 ) > = 0 ) {
2001-09-11 07:57:10 +08:00
continue ;
2003-01-05 07:31:55 +08:00
}
if ( ! X509_REQ_add1_attr_by_txt ( csr , v - > name , MBSTRING_ASC , ( unsigned char * ) v - > value , - 1 ) ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " add1_attr_by_txt %s -> %s (failed) " , v - > name , v - > value ) ;
2001-09-11 07:57:10 +08:00
return FAILURE ;
}
}
}
2001-05-05 07:42:11 +08:00
}
2001-09-11 07:57:10 +08:00
X509_REQ_set_pubkey ( csr , req - > priv_key ) ;
return SUCCESS ;
2001-05-05 07:42:11 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ php_openssl_csr_from_zval */
static X509_REQ * php_openssl_csr_from_zval ( zval * * val , int makeresource , long * resourceval TSRMLS_DC )
2001-05-05 07:42:11 +08:00
{
2001-09-11 07:57:10 +08:00
X509_REQ * csr = NULL ;
2002-04-19 15:56:41 +08:00
char * filename = NULL ;
2001-09-11 07:57:10 +08:00
BIO * in ;
2001-05-05 07:42:11 +08:00
2003-01-05 07:31:55 +08:00
if ( resourceval ) {
2001-09-11 07:57:10 +08:00
* resourceval = - 1 ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_PP ( val ) = = IS_RESOURCE ) {
2001-09-11 07:57:10 +08:00
void * what ;
int type ;
2001-05-05 07:42:11 +08:00
2001-09-11 07:57:10 +08:00
what = zend_fetch_resource ( val TSRMLS_CC , - 1 , " OpenSSL X.509 CSR " , & type , 1 , le_csr ) ;
2002-12-11 06:18:58 +08:00
if ( what ) {
2003-01-05 07:31:55 +08:00
if ( resourceval ) {
2001-09-11 07:57:10 +08:00
* resourceval = Z_LVAL_PP ( val ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
return ( X509_REQ * ) what ;
}
return NULL ;
2003-01-03 05:18:59 +08:00
} else if ( Z_TYPE_PP ( val ) ! = IS_STRING ) {
return NULL ;
2001-05-05 07:42:11 +08:00
}
2003-01-05 07:31:55 +08:00
if ( Z_STRLEN_PP ( val ) > 7 & & memcmp ( Z_STRVAL_PP ( val ) , " file:// " , sizeof ( " file:// " ) - 1 ) = = 0 ) {
filename = Z_STRVAL_PP ( val ) + ( sizeof ( " file:// " ) - 1 ) ;
}
2002-11-10 13:19:40 +08:00
if ( filename ) {
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
return NULL ;
}
2001-09-11 07:57:10 +08:00
in = BIO_new_file ( filename , " r " ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
in = BIO_new_mem_buf ( Z_STRVAL_PP ( val ) , Z_STRLEN_PP ( val ) ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
csr = PEM_read_bio_X509_REQ ( in , NULL , NULL , NULL ) ;
BIO_free ( in ) ;
2001-05-05 07:42:11 +08:00
2001-09-11 07:57:10 +08:00
return csr ;
2001-05-05 07:42:11 +08:00
}
/* }}} */
2001-12-07 01:51:48 +08:00
/* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true])
2002-08-11 04:19:49 +08:00
Exports a CSR to file */
2001-09-11 08:33:25 +08:00
PHP_FUNCTION ( openssl_csr_export_to_file )
2000-11-14 03:47:20 +08:00
{
2001-09-11 07:57:10 +08:00
X509_REQ * csr ;
2001-09-11 08:33:25 +08:00
zval * zcsr = NULL ;
zend_bool notext = 1 ;
2003-03-07 07:07:28 +08:00
char * filename = NULL ; int filename_len ;
2001-09-11 07:57:10 +08:00
BIO * bio_out ;
long csr_resource ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " rs|b " , & zcsr , & filename , & filename_len , & notext ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2000-11-18 03:49:13 +08:00
2001-09-11 07:57:10 +08:00
csr = php_openssl_csr_from_zval ( & zcsr , 0 , & csr_resource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( csr = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get CSR from parameter 1 " ) ;
2001-09-11 07:57:10 +08:00
return ;
2000-11-14 17:54:25 +08:00
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
return ;
}
2001-09-11 08:33:25 +08:00
bio_out = BIO_new_file ( filename , " w " ) ;
2002-12-11 06:18:58 +08:00
if ( bio_out ) {
2003-01-05 07:31:55 +08:00
if ( ! notext ) {
2001-09-11 07:57:10 +08:00
X509_REQ_print ( bio_out , csr ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PEM_write_bio_X509_REQ ( bio_out , csr ) ;
2001-09-11 08:33:25 +08:00
RETVAL_TRUE ;
2002-12-11 06:18:58 +08:00
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening file %s " , filename ) ;
2001-09-11 08:33:25 +08:00
}
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( csr_resource = = - 1 & & csr ) {
2001-09-11 08:33:25 +08:00
X509_REQ_free ( csr ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
BIO_free ( bio_out ) ;
}
/* }}} */
2001-12-07 01:51:48 +08:00
/* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true])
2001-09-11 09:03:59 +08:00
Exports a CSR to file or a var */
2001-09-11 08:33:25 +08:00
PHP_FUNCTION ( openssl_csr_export )
{
X509_REQ * csr ;
zval * zcsr = NULL , * zout = NULL ;
zend_bool notext = 1 ;
BIO * bio_out ;
long csr_resource ;
char * bio_mem_ptr ;
long bio_mem_len ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " rz|b " , & zcsr , & zout , & notext ) = = FAILURE ) {
2001-09-11 08:33:25 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
RETVAL_FALSE ;
csr = php_openssl_csr_from_zval ( & zcsr , 0 , & csr_resource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( csr = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get CSR from parameter 1 " ) ;
2001-09-11 08:33:25 +08:00
return ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 08:33:25 +08:00
/* export to a var */
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
2003-01-05 07:31:55 +08:00
if ( ! notext ) {
2001-09-11 08:33:25 +08:00
X509_REQ_print ( bio_out , csr ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
PEM_write_bio_X509_REQ ( bio_out , csr ) ;
bio_mem_len = BIO_get_mem_data ( bio_out , & bio_mem_ptr ) ;
ZVAL_STRINGL ( zout , bio_mem_ptr , bio_mem_len , 1 ) ;
RETVAL_TRUE ;
2003-01-05 07:31:55 +08:00
if ( csr_resource = = - 1 & & csr ) {
2001-09-11 07:57:10 +08:00
X509_REQ_free ( csr ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
BIO_free ( bio_out ) ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2003-07-13 17:54:42 +08:00
/* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]])
2001-09-11 09:03:59 +08:00
Signs a cert with another CERT */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_csr_sign )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
zval * zcert = NULL , * zcsr , * zpkey , * args = NULL ;
long num_days ;
2003-07-13 17:54:42 +08:00
long serial = 0L ;
2001-09-11 07:57:10 +08:00
X509 * cert = NULL , * new_cert = NULL ;
X509_REQ * csr ;
2003-10-13 19:43:14 +08:00
EVP_PKEY * key = NULL , * priv_key = NULL ;
2001-09-11 07:57:10 +08:00
long csr_resource , certresource , keyresource ;
int i ;
struct php_x509_request req ;
2003-07-13 17:54:42 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zz!zl|a!l " , & zcsr , & zcert , & zpkey , & num_days , & args , & serial ) = = FAILURE )
2001-09-11 07:57:10 +08:00
return ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
PHP_SSL_REQ_INIT ( & req ) ;
csr = php_openssl_csr_from_zval ( & zcsr , 0 , & csr_resource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( csr = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get CSR from parameter 1 " ) ;
2001-09-11 07:57:10 +08:00
return ;
}
2002-12-11 06:18:58 +08:00
if ( zcert ) {
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get cert from parameter 2 " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
}
priv_key = php_openssl_evp_from_zval ( & zpkey , 0 , " " , 1 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( priv_key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get private key from parameter 3 " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
2002-12-11 06:18:58 +08:00
if ( cert & & ! X509_check_private_key ( cert , priv_key ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " private key does not correspond to signing cert " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
2003-01-05 07:31:55 +08:00
if ( PHP_SSL_REQ_PARSE ( & req , args ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
goto cleanup ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
/* Check that the request matches the signature */
key = X509_REQ_get_pubkey ( csr ) ;
2002-12-11 06:18:58 +08:00
if ( key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error unpacking public key " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
i = X509_REQ_verify ( csr , key ) ;
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( i < 0 ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Signature verification problems " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
2003-01-05 07:31:55 +08:00
else if ( i = = 0 ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Signature did not match the certificate request " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
/* Now we can get on with it */
new_cert = X509_new ( ) ;
2002-12-11 06:18:58 +08:00
if ( new_cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " No memory " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
/* Version 3 cert */
2003-07-13 17:38:32 +08:00
if ( ! X509_set_version ( new_cert , 2 ) )
2001-09-11 07:57:10 +08:00
goto cleanup ;
2001-04-02 07:06:15 +08:00
2003-07-13 17:54:42 +08:00
ASN1_INTEGER_set ( X509_get_serialNumber ( new_cert ) , serial ) ;
2001-09-11 07:57:10 +08:00
X509_set_subject_name ( new_cert , X509_REQ_get_subject_name ( csr ) ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-09-11 07:57:10 +08:00
cert = new_cert ;
2003-01-05 07:31:55 +08:00
}
if ( ! X509_set_issuer_name ( new_cert , X509_get_subject_name ( cert ) ) ) {
2001-09-11 07:57:10 +08:00
goto cleanup ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
X509_gmtime_adj ( X509_get_notBefore ( new_cert ) , 0 ) ;
X509_gmtime_adj ( X509_get_notAfter ( new_cert ) , ( long ) 60 * 60 * 24 * num_days ) ;
i = X509_set_pubkey ( new_cert , key ) ;
2003-01-05 07:31:55 +08:00
if ( ! i ) {
2001-09-11 07:57:10 +08:00
goto cleanup ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( req . request_extensions_section ) {
2001-09-11 07:57:10 +08:00
X509V3_CTX ctx ;
X509V3_set_ctx ( & ctx , cert , new_cert , csr , NULL , 0 ) ;
X509V3_set_conf_lhash ( & ctx , req . req_config ) ;
2003-01-05 07:31:55 +08:00
if ( ! X509V3_EXT_add_conf ( req . req_config , & ctx , req . request_extensions_section , new_cert ) ) {
2001-09-11 07:57:10 +08:00
goto cleanup ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* Now sign it */
2002-12-11 06:18:58 +08:00
if ( ! X509_sign ( new_cert , priv_key , req . digest ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " failed to sign it " ) ;
2001-09-11 07:57:10 +08:00
goto cleanup ;
}
/* Succeeded; lets return the cert */
RETVAL_RESOURCE ( zend_list_insert ( new_cert , le_x509 ) ) ;
new_cert = NULL ;
cleanup :
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( cert = = new_cert ) {
2001-09-11 07:57:10 +08:00
cert = NULL ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PHP_SSL_REQ_DISPOSE ( & req ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 & & priv_key ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( priv_key ) ;
2003-01-05 07:31:55 +08:00
}
if ( key ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( key ) ;
2003-01-05 07:31:55 +08:00
}
if ( csr_resource = = - 1 & & csr ) {
2001-09-11 07:57:10 +08:00
X509_REQ_free ( csr ) ;
2003-01-05 07:31:55 +08:00
}
if ( certresource = = - 1 & & cert ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
if ( new_cert ) {
2001-09-11 07:57:10 +08:00
X509_free ( new_cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2000-11-14 17:54:25 +08:00
2003-03-15 21:29:35 +08:00
/* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs, array extraattribs])
2001-09-11 09:03:59 +08:00
Generates a privkey and CSR */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_csr_new )
{
struct php_x509_request req ;
zval * args = NULL , * dn , * attribs = NULL ;
zval * out_pkey ;
X509_REQ * csr = NULL ;
int we_made_the_key = 1 ;
long key_resource ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " az|a!a! " , & dn , & out_pkey , & args , & attribs ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
PHP_SSL_REQ_INIT ( & req ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( PHP_SSL_REQ_PARSE ( & req , args ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
/* Generate or use a private key */
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_P ( out_pkey ) ! = IS_NULL ) {
2001-09-11 07:57:10 +08:00
req . priv_key = php_openssl_evp_from_zval ( & out_pkey , 0 , NULL , 0 , & key_resource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( req . priv_key ! = NULL ) {
2001-09-11 07:57:10 +08:00
we_made_the_key = 0 ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
2003-01-05 07:31:55 +08:00
if ( req . priv_key = = NULL ) {
2001-09-11 07:57:10 +08:00
php_openssl_generate_private_key ( & req TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
}
if ( req . priv_key = = NULL ) {
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unable to generate a private key " ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
csr = X509_REQ_new ( ) ;
2002-12-11 06:18:58 +08:00
if ( csr ) {
if ( php_openssl_make_REQ ( & req , csr , dn , attribs TSRMLS_CC ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
X509V3_CTX ext_ctx ;
X509V3_set_ctx ( & ext_ctx , NULL , NULL , csr , NULL , 0 ) ;
X509V3_set_conf_lhash ( & ext_ctx , req . req_config ) ;
/* Add extensions */
if ( req . request_extensions_section & & ! X509V3_EXT_REQ_add_conf ( req . req_config ,
& ext_ctx , req . request_extensions_section , csr ) )
{
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Error loading extension section %s " , req . request_extensions_section ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
RETVAL_TRUE ;
2002-12-11 06:18:58 +08:00
if ( X509_REQ_sign ( csr , req . priv_key , req . digest ) ) {
2001-09-11 07:57:10 +08:00
RETVAL_RESOURCE ( zend_list_insert ( csr , le_csr ) ) ;
csr = NULL ;
2002-12-11 06:18:58 +08:00
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Error signing request " ) ;
2001-09-11 07:57:10 +08:00
}
2002-12-11 06:18:58 +08:00
if ( we_made_the_key ) {
2001-09-11 07:57:10 +08:00
/* and a resource for the private key */
ZVAL_RESOURCE ( out_pkey , zend_list_insert ( req . priv_key , le_key ) ) ;
2004-10-27 19:07:26 +08:00
req . priv_key = NULL ; /* make sure the cleanup code doesn't zap it! */
2003-01-05 07:31:55 +08:00
} else if ( key_resource ! = - 1 ) {
2001-09-11 07:57:10 +08:00
req . priv_key = NULL ; /* make sure the cleanup code doesn't zap it! */
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
}
2004-10-26 17:24:07 +08:00
else {
if ( ! we_made_the_key ) {
/* if we have not made the key we are not supposed to zap it by calling dispose! */
req . priv_key = NULL ;
}
}
2001-09-11 07:57:10 +08:00
}
}
}
2003-01-05 07:31:55 +08:00
if ( csr ) {
2001-09-11 07:57:10 +08:00
X509_REQ_free ( csr ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
PHP_SSL_REQ_DISPOSE ( & req ) ;
2001-04-02 07:06:15 +08:00
}
2001-05-05 07:42:11 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* }}} */
/* {{{ EVP Public/Private key functions */
/* {{{ php_openssl_evp_from_zval
Given a zval , coerce it into a EVP_PKEY object .
It can be :
1. private key resource from openssl_get_privatekey ( )
2. X509 resource - > public key will be extracted from it
3. if it starts with file : // interpreted as path to key file
4. interpreted as the data from the cert / key file and interpreted in same way as openssl_get_privatekey ( )
5. an array ( 0 = > [ items 2. .4 ] , 1 = > passphrase )
2002-12-12 21:42:23 +08:00
6. if val is a string ( possibly starting with file : ///) and it is not an X509 certificate, then interpret as public key
2001-09-11 07:57:10 +08:00
NOTE : If you are requesting a private key but have not specified a passphrase , you should use an
empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in
the Apache error log !
*/
static EVP_PKEY * php_openssl_evp_from_zval ( zval * * val , int public_key , char * passphrase , int makeresource , long * resourceval TSRMLS_DC )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
EVP_PKEY * key = NULL ;
2001-04-02 07:06:15 +08:00
X509 * cert = NULL ;
2001-09-11 07:57:10 +08:00
int free_cert = 0 ;
long cert_res = - 1 ;
char * filename = NULL ;
2001-09-08 01:09:56 +08:00
2003-01-05 07:31:55 +08:00
if ( resourceval ) {
2001-09-11 07:57:10 +08:00
* resourceval = - 1 ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_PP ( val ) = = IS_ARRAY ) {
2001-09-11 07:57:10 +08:00
zval * * zphrase ;
/* get passphrase */
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
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) " ) ;
2001-09-11 07:57:10 +08:00
return NULL ;
}
convert_to_string_ex ( zphrase ) ;
passphrase = Z_STRVAL_PP ( zphrase ) ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* now set val to be the key param and continue */
2002-12-11 06:18:58 +08:00
if ( zend_hash_index_find ( HASH_OF ( * val ) , 0 , ( void * * ) & val ) = = FAILURE ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key array must be of the form array(0 => key, 1 => phrase) " ) ;
2001-09-11 07:57:10 +08:00
return NULL ;
}
}
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_PP ( val ) = = IS_RESOURCE ) {
2001-09-11 07:57:10 +08:00
void * what ;
int type ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
what = zend_fetch_resource ( val TSRMLS_CC , - 1 , " OpenSSL X.509/key " , & type , 2 , le_x509 , le_key ) ;
2003-01-05 07:31:55 +08:00
if ( ! what ) {
2001-09-11 07:57:10 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
if ( resourceval ) {
2001-09-11 07:57:10 +08:00
* resourceval = Z_LVAL_PP ( val ) ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( type = = le_x509 ) {
2001-09-11 07:57:10 +08:00
/* extract key from cert, depending on public_key param */
cert = ( X509 * ) what ;
free_cert = 0 ;
2003-01-05 07:31:55 +08:00
} else if ( type = = le_key ) {
2003-09-24 00:05:52 +08:00
int is_priv ;
is_priv = php_openssl_is_private_key ( ( EVP_PKEY * ) what TSRMLS_CC ) ;
2002-12-12 21:42:23 +08:00
/* check whether it is actually a private key if requested */
2003-09-24 03:29:34 +08:00
if ( ! public_key & & ! is_priv ) {
2002-12-12 21:42:23 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " supplied key param is a public key " ) ;
return NULL ;
}
2003-09-24 00:05:52 +08:00
if ( public_key & & is_priv ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Don't know how to get public key from this private key " ) ;
return NULL ;
} else {
/* got the key - return it */
return ( EVP_PKEY * ) what ;
}
2001-09-11 07:57:10 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* other types could be used here - eg: file pointers and read in the data from them */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
/* force it to be a string and check if it refers to a file */
2006-07-30 06:39:34 +08:00
if ( Z_TYPE_PP ( val ) = = IS_LONG | | Z_TYPE_PP ( val ) = = IS_BOOL
| | Z_TYPE_PP ( val ) = = IS_ARRAY ) {
2006-07-30 06:10:50 +08:00
return NULL ;
}
2001-09-11 07:57:10 +08:00
convert_to_string_ex ( val ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( Z_STRLEN_PP ( val ) > 7 & & memcmp ( Z_STRVAL_PP ( val ) , " file:// " , sizeof ( " file:// " ) - 1 ) = = 0 ) {
filename = Z_STRVAL_PP ( val ) + ( sizeof ( " file:// " ) - 1 ) ;
}
2001-09-11 07:57:10 +08:00
/* it's an X509 file/cert of some kind, and we need to extract the data from that */
2002-12-11 06:18:58 +08:00
if ( public_key ) {
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( val , 0 , & cert_res TSRMLS_CC ) ;
free_cert = ( cert_res = = - 1 ) ;
/* actual extraction done later */
2002-12-12 21:42:23 +08:00
if ( ! cert ) {
/* not a X509 certificate, try to retrieve public key */
BIO * in ;
2003-01-05 07:31:55 +08:00
if ( filename ) {
2002-12-12 21:42:23 +08:00
in = BIO_new_file ( filename , " r " ) ;
2003-01-05 07:31:55 +08:00
} else {
2002-12-12 21:42:23 +08:00
in = BIO_new_mem_buf ( Z_STRVAL_PP ( val ) , Z_STRLEN_PP ( val ) ) ;
2003-01-05 07:31:55 +08:00
}
if ( in = = NULL ) {
2002-12-12 21:42:23 +08:00
return NULL ;
2003-01-05 07:31:55 +08:00
}
2002-12-12 21:42:23 +08:00
key = PEM_read_bio_PUBKEY ( in , NULL , NULL , NULL ) ;
BIO_free ( in ) ;
}
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
/* we want the private key */
2003-02-01 06:15:56 +08:00
BIO * in ;
2002-12-11 06:18:58 +08:00
if ( filename ) {
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
return NULL ;
}
in = BIO_new_file ( filename , " r " ) ;
2003-01-05 07:31:55 +08:00
} else {
2003-02-01 06:15:56 +08:00
in = BIO_new_mem_buf ( Z_STRVAL_PP ( val ) , Z_STRLEN_PP ( val ) ) ;
}
if ( in = = NULL ) {
return NULL ;
2001-09-11 07:57:10 +08:00
}
2003-02-01 06:15:56 +08:00
key = PEM_read_bio_PrivateKey ( in , NULL , NULL , passphrase ) ;
BIO_free ( in ) ;
2001-09-11 07:57:10 +08:00
}
}
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( public_key & & cert & & key = = NULL ) {
2001-09-11 07:57:10 +08:00
/* extract public key from X509 cert */
key = ( EVP_PKEY * ) X509_get_pubkey ( cert ) ;
2000-11-14 03:47:20 +08:00
}
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( free_cert & & cert ) {
2001-04-02 07:06:15 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( key & & makeresource & & resourceval ) {
2002-03-26 08:03:11 +08:00
* resourceval = ZEND_REGISTER_RESOURCE ( NULL , key , le_key ) ;
2001-09-11 07:57:10 +08:00
}
return key ;
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ php_openssl_generate_private_key */
static EVP_PKEY * php_openssl_generate_private_key ( struct php_x509_request * req TSRMLS_DC )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
char * randfile = NULL ;
int egdsocket , seeded ;
EVP_PKEY * return_val = NULL ;
2002-12-11 06:18:58 +08:00
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 " ,
2001-09-11 07:57:10 +08:00
MIN_KEY_LENGTH , req - > priv_key_bits ) ;
return NULL ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
randfile = CONF_get_string ( req - > req_config , req - > section_name , " RANDFILE " ) ;
php_openssl_load_rand_file ( randfile , & egdsocket , & seeded ) ;
2002-12-11 06:18:58 +08:00
if ( ( req - > priv_key = EVP_PKEY_new ( ) ) ! = NULL ) {
switch ( req - > priv_key_type ) {
2001-09-11 07:57:10 +08:00
case OPENSSL_KEYTYPE_RSA :
if ( EVP_PKEY_assign_RSA ( req - > priv_key , RSA_generate_key ( req - > priv_key_bits , 0x10001 , NULL , NULL ) ) )
return_val = req - > priv_key ;
break ;
default :
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unsupported private key type " ) ;
2001-04-02 07:06:15 +08:00
}
}
2001-09-11 07:57:10 +08:00
php_openssl_write_rand_file ( randfile , egdsocket , seeded ) ;
2002-12-11 06:18:58 +08:00
if ( return_val = = NULL ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( req - > priv_key ) ;
req - > priv_key = NULL ;
return NULL ;
}
return return_val ;
2001-04-02 07:06:15 +08:00
}
2001-05-05 07:42:11 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2002-12-12 21:42:23 +08:00
/* {{{ php_openssl_is_private_key
Check whether the supplied key is a private key by checking if the secret prime factors are set */
static int php_openssl_is_private_key ( EVP_PKEY * pkey TSRMLS_DC )
{
assert ( pkey ! = NULL ) ;
switch ( pkey - > type ) {
# ifndef NO_RSA
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
assert ( pkey - > pkey . rsa ! = NULL ) ;
2003-01-05 07:31:55 +08:00
if ( NULL = = pkey - > pkey . rsa - > p | | NULL = = pkey - > pkey . rsa - > q ) {
2002-12-12 21:42:23 +08:00
return 0 ;
2003-01-05 07:31:55 +08:00
}
2002-12-12 21:42:23 +08:00
break ;
# endif
# ifndef NO_DSA
case EVP_PKEY_DSA :
case EVP_PKEY_DSA1 :
case EVP_PKEY_DSA2 :
case EVP_PKEY_DSA3 :
case EVP_PKEY_DSA4 :
assert ( pkey - > pkey . dsa ! = NULL ) ;
2003-01-05 07:31:55 +08:00
if ( NULL = = pkey - > pkey . dsa - > p | | NULL = = pkey - > pkey . dsa - > q | | NULL = = pkey - > pkey . dsa - > priv_key ) {
2002-12-12 21:42:23 +08:00
return 0 ;
2003-01-05 07:31:55 +08:00
}
2002-12-12 21:42:23 +08:00
break ;
# endif
# ifndef NO_DH
case EVP_PKEY_DH :
assert ( pkey - > pkey . dh ! = NULL ) ;
2003-01-05 07:31:55 +08:00
if ( NULL = = pkey - > pkey . dh - > p | | NULL = = pkey - > pkey . dh - > priv_key ) {
2002-12-12 21:42:23 +08:00
return 0 ;
2003-01-05 07:31:55 +08:00
}
2002-12-12 21:42:23 +08:00
break ;
# endif
default :
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key type not supported in this PHP build! " ) ;
break ;
}
return 1 ;
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ proto resource openssl_pkey_new([array configargs])
2001-09-11 09:03:59 +08:00
Generates a new private key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkey_new )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
struct php_x509_request req ;
zval * args = NULL ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |a! " , & args ) = = FAILURE ) {
return ;
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
PHP_SSL_REQ_INIT ( & req ) ;
if ( PHP_SSL_REQ_PARSE ( & req , args ) = = SUCCESS )
2001-04-02 07:06:15 +08:00
{
2002-12-11 06:18:58 +08:00
if ( php_openssl_generate_private_key ( & req TSRMLS_CC ) ) {
2001-09-11 07:57:10 +08:00
/* pass back a key resource */
RETVAL_RESOURCE ( zend_list_insert ( req . priv_key , le_key ) ) ;
/* make sure the cleanup code doesn't zap it! */
req . priv_key = NULL ;
}
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
PHP_SSL_REQ_DISPOSE ( & req ) ;
2001-04-02 07:06:15 +08:00
}
2001-05-05 07:42:11 +08:00
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 09:03:59 +08:00
/* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
Gets an exportable representation of a key into a file */
2001-09-11 08:33:25 +08:00
PHP_FUNCTION ( openssl_pkey_export_to_file )
{
struct php_x509_request req ;
zval * zpkey , * args = NULL ;
2003-03-07 07:07:28 +08:00
char * passphrase = NULL ; int passphrase_len = 0 ;
char * filename = NULL ; int filename_len = 0 ;
2001-09-11 08:33:25 +08:00
long key_resource = - 1 ;
EVP_PKEY * key ;
BIO * bio_out = NULL ;
2003-03-01 01:26:28 +08:00
const EVP_CIPHER * cipher ;
2001-09-11 08:33:25 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zs|s!a! " , & zpkey , & filename , & filename_len , & passphrase , & passphrase_len , & args ) = = FAILURE ) {
2001-09-11 08:33:25 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
RETVAL_FALSE ;
2001-09-30 21:30:18 +08:00
key = php_openssl_evp_from_zval ( & zpkey , 0 , passphrase , 0 , & key_resource TSRMLS_CC ) ;
2001-09-11 08:33:25 +08:00
2002-12-11 06:18:58 +08:00
if ( key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get key from parameter 1 " ) ;
2001-09-11 08:33:25 +08:00
RETURN_FALSE ;
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
RETURN_FALSE ;
}
2001-09-11 08:33:25 +08:00
PHP_SSL_REQ_INIT ( & req ) ;
2003-01-05 07:31:55 +08:00
if ( PHP_SSL_REQ_PARSE ( & req , args ) = = SUCCESS ) {
2001-09-11 08:33:25 +08:00
bio_out = BIO_new_file ( filename , " w " ) ;
2003-01-05 07:31:55 +08:00
if ( passphrase & & req . priv_key_encrypt ) {
2003-06-09 07:52:29 +08:00
cipher = ( EVP_CIPHER * ) EVP_des_ede3_cbc ( ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 08:33:25 +08:00
cipher = NULL ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( PEM_write_bio_PrivateKey ( bio_out , key , cipher , passphrase , passphrase_len , NULL , NULL ) ) {
2001-09-11 08:33:25 +08:00
/* Success!
* If returning the output as a string , do so now */
RETVAL_TRUE ;
}
}
PHP_SSL_REQ_DISPOSE ( & req ) ;
2002-12-11 06:18:58 +08:00
if ( key_resource = = - 1 & & key ) {
2001-09-11 08:33:25 +08:00
EVP_PKEY_free ( key ) ;
}
2003-01-05 07:31:55 +08:00
if ( bio_out ) {
2001-09-11 08:33:25 +08:00
BIO_free ( bio_out ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 08:33:25 +08:00
}
/* }}} */
2001-09-11 09:03:59 +08:00
/* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
Gets an exportable representation of a key into a string or file */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkey_export )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
struct php_x509_request req ;
zval * zpkey , * args = NULL , * out ;
2003-03-07 07:07:28 +08:00
char * passphrase = NULL ; int passphrase_len = 0 ;
2001-09-11 07:57:10 +08:00
long key_resource = - 1 ;
EVP_PKEY * key ;
BIO * bio_out = NULL ;
2003-03-01 01:26:28 +08:00
const EVP_CIPHER * cipher ;
2001-09-11 07:57:10 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zz|s!a! " , & zpkey , & out , & passphrase , & passphrase_len , & args ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2001-04-02 07:06:15 +08:00
2001-09-30 21:30:18 +08:00
key = php_openssl_evp_from_zval ( & zpkey , 0 , passphrase , 0 , & key_resource TSRMLS_CC ) ;
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get key from parameter 1 " ) ;
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
}
PHP_SSL_REQ_INIT ( & req ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( PHP_SSL_REQ_PARSE ( & req , args ) = = SUCCESS ) {
2001-09-11 08:33:25 +08:00
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
2001-09-11 07:57:10 +08:00
2003-01-05 07:31:55 +08:00
if ( passphrase & & req . priv_key_encrypt ) {
2003-06-09 07:52:29 +08:00
cipher = ( EVP_CIPHER * ) EVP_des_ede3_cbc ( ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
cipher = NULL ;
2003-01-05 07:31:55 +08:00
}
2002-12-11 06:18:58 +08:00
if ( PEM_write_bio_PrivateKey ( bio_out , key , cipher , passphrase , passphrase_len , NULL , NULL ) ) {
2001-09-11 07:57:10 +08:00
/* Success!
* If returning the output as a string , do so now */
2001-09-11 08:33:25 +08:00
char * bio_mem_ptr ;
long bio_mem_len ;
2001-09-11 07:57:10 +08:00
RETVAL_TRUE ;
2001-09-11 08:33:25 +08:00
bio_mem_len = BIO_get_mem_data ( bio_out , & bio_mem_ptr ) ;
ZVAL_STRINGL ( out , bio_mem_ptr , bio_mem_len , 1 ) ;
2001-09-11 07:57:10 +08:00
}
}
PHP_SSL_REQ_DISPOSE ( & req ) ;
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( key_resource = = - 1 & & key ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( key ) ;
}
2003-01-05 07:31:55 +08:00
if ( bio_out ) {
2001-09-11 07:57:10 +08:00
BIO_free ( bio_out ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ proto int openssl_pkey_get_public(mixed cert)
2001-09-11 09:03:59 +08:00
Gets public key from X .509 certificate */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkey_get_public )
2000-11-14 03:47:20 +08:00
{
2001-09-08 01:09:56 +08:00
zval * cert ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " z " , & cert ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
Z_TYPE_P ( return_value ) = IS_RESOURCE ;
2001-09-08 01:09:56 +08:00
pkey = php_openssl_evp_from_zval ( & cert , 1 , NULL , 1 , & Z_LVAL_P ( return_value ) TSRMLS_CC ) ;
2000-11-14 17:54:25 +08:00
2001-04-02 07:06:15 +08:00
if ( pkey = = NULL ) {
2000-11-14 17:54:25 +08:00
RETURN_FALSE ;
}
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ proto void openssl_pkey_free(int key)
2001-09-11 09:03:59 +08:00
Frees a key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkey_free )
2000-11-14 03:47:20 +08:00
{
2001-09-08 01:09:56 +08:00
zval * key ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " r " , & key ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-08 01:09:56 +08:00
ZEND_FETCH_RESOURCE ( pkey , EVP_PKEY * , & key , - 1 , " OpenSSL key " , le_key ) ;
zend_list_delete ( Z_LVAL_P ( key ) ) ;
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
2001-09-11 09:03:59 +08:00
Gets private keys */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkey_get_private )
2001-04-02 07:06:15 +08:00
{
2001-09-08 01:09:56 +08:00
zval * cert ;
2001-09-11 07:57:10 +08:00
EVP_PKEY * pkey ;
char * passphrase = " " ;
2003-03-07 07:07:28 +08:00
int passphrase_len ;
2001-09-11 07:57:10 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " z|s " , & cert , & passphrase , & passphrase_len ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
Z_TYPE_P ( return_value ) = IS_RESOURCE ;
2002-03-26 08:03:11 +08:00
pkey = php_openssl_evp_from_zval ( & cert , 0 , passphrase , 1 , & Z_LVAL_P ( return_value ) TSRMLS_CC ) ;
2001-09-11 07:57:10 +08:00
if ( pkey = = NULL ) {
2000-11-14 17:54:25 +08:00
RETURN_FALSE ;
}
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
/* }}} */
2001-09-11 08:33:25 +08:00
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ PKCS7 S/MIME functions */
2005-06-30 22:25:41 +08:00
/* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
2001-09-11 09:03:59 +08:00
Verifys that the data block is intact , the signer is who they say they are , and returns the CERTs of the signers */
2001-04-02 07:06:15 +08:00
PHP_FUNCTION ( openssl_pkcs7_verify )
{
2002-04-19 15:56:41 +08:00
X509_STORE * store = NULL ;
2001-09-08 01:09:56 +08:00
zval * cainfo = NULL ;
2001-04-03 07:14:01 +08:00
STACK_OF ( X509 ) * signers = NULL ;
STACK_OF ( X509 ) * others = NULL ;
2001-04-02 07:06:15 +08:00
PKCS7 * p7 = NULL ;
2005-06-30 22:25:41 +08:00
BIO * in = NULL , * datain = NULL , * dataout = NULL ;
2001-09-08 01:09:56 +08:00
long flags = 0 ;
2003-03-07 07:07:28 +08:00
char * filename ; int filename_len ;
char * extracerts = NULL ; int extracerts_len ;
char * signersfilename = NULL ; int signersfilename_len ;
2005-06-30 22:25:41 +08:00
char * datafilename = NULL ; int datafilename_len ;
2001-04-03 07:14:01 +08:00
2001-09-08 01:09:56 +08:00
RETVAL_LONG ( - 1 ) ;
2000-11-14 03:47:20 +08:00
2005-06-30 22:25:41 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " sl|sass " , & filename , & filename_len ,
2001-09-08 01:09:56 +08:00
& flags , & signersfilename , & signersfilename_len , & cainfo ,
2005-06-30 22:25:41 +08:00
& extracerts , & extracerts_len , & datafilename , & datafilename_len ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-04-03 07:14:01 +08:00
2002-12-11 06:18:58 +08:00
if ( extracerts ) {
2001-09-08 01:09:56 +08:00
others = load_all_certs_from_file ( extracerts ) ;
2003-01-05 07:31:55 +08:00
if ( others = = NULL ) {
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
2000-11-14 03:47:20 +08:00
2001-09-08 01:09:56 +08:00
flags = flags & ~ PKCS7_DETACHED ;
2001-04-02 07:06:15 +08:00
2001-09-08 01:09:56 +08:00
store = setup_verify ( cainfo TSRMLS_CC ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( ! store ) {
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
goto clean_exit ;
}
2001-09-08 01:09:56 +08:00
in = BIO_new_file ( filename , ( flags & PKCS7_BINARY ) ? " rb " : " r " ) ;
2003-01-05 07:31:55 +08:00
if ( in = = NULL ) {
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
p7 = SMIME_read_PKCS7 ( in , & datain ) ;
2002-12-11 06:18:58 +08:00
if ( p7 = = NULL ) {
2001-09-08 01:09:56 +08:00
# if DEBUG_SMIME
zend_printf ( " SMIME_read_PKCS7 failed \n " ) ;
# endif
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2001-09-08 01:09:56 +08:00
}
2005-06-30 22:25:41 +08:00
if ( datafilename ) {
if ( php_openssl_safe_mode_chk ( datafilename TSRMLS_CC ) ) {
goto clean_exit ;
}
dataout = BIO_new_file ( datafilename , " w " ) ;
if ( dataout = = NULL ) {
goto clean_exit ;
}
}
2001-09-08 01:09:56 +08:00
# if DEBUG_SMIME
zend_printf ( " Calling PKCS7 verify \n " ) ;
# endif
2001-04-02 07:06:15 +08:00
2005-06-30 22:25:41 +08:00
if ( PKCS7_verify ( p7 , others , store , datain , dataout , flags ) ) {
2001-04-02 07:06:15 +08:00
RETVAL_TRUE ;
2002-11-10 13:19:40 +08:00
if ( signersfilename ) {
BIO * certout ;
2005-06-30 22:25:41 +08:00
if ( php_openssl_safe_mode_chk ( signersfilename TSRMLS_CC ) ) {
2002-11-10 13:19:40 +08:00
goto clean_exit ;
}
certout = BIO_new_file ( signersfilename , " w " ) ;
2002-12-11 06:18:58 +08:00
if ( certout ) {
2001-04-02 07:06:15 +08:00
int i ;
signers = PKCS7_get0_signers ( p7 , NULL , flags ) ;
2003-01-05 07:31:55 +08:00
for ( i = 0 ; i < sk_X509_num ( signers ) ; i + + ) {
2001-04-02 07:06:15 +08:00
PEM_write_bio_X509 ( certout , sk_X509_value ( signers , i ) ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
BIO_free ( certout ) ;
sk_X509_free ( signers ) ;
2003-01-05 07:31:55 +08:00
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " signature OK, but cannot open %s for writing " , signersfilename ) ;
2001-04-03 07:14:01 +08:00
RETVAL_LONG ( - 1 ) ;
}
2001-04-02 07:06:15 +08:00
}
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
} else {
2001-04-03 07:14:01 +08:00
RETVAL_FALSE ;
2003-01-05 07:31:55 +08:00
}
2001-04-03 07:14:01 +08:00
clean_exit :
2001-04-02 07:06:15 +08:00
X509_STORE_free ( store ) ;
BIO_free ( datain ) ;
BIO_free ( in ) ;
2005-06-30 22:25:41 +08:00
BIO_free ( dataout ) ;
2001-04-02 07:06:15 +08:00
PKCS7_free ( p7 ) ;
2001-04-03 07:14:01 +08:00
sk_X509_free ( others ) ;
2000-11-14 03:47:20 +08:00
}
/* }}} */
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
/* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
2001-09-11 09:03:59 +08:00
Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
2001-04-02 07:06:15 +08:00
PHP_FUNCTION ( openssl_pkcs7_encrypt )
2000-11-14 03:47:20 +08:00
{
2001-09-08 01:09:56 +08:00
zval * zrecipcerts , * zheaders = NULL ;
2001-04-02 07:06:15 +08:00
STACK_OF ( X509 ) * recipcerts = NULL ;
BIO * infile = NULL , * outfile = NULL ;
2001-09-08 01:09:56 +08:00
long flags = 0 ;
2001-04-02 07:06:15 +08:00
PKCS7 * p7 = NULL ;
HashPosition hpos ;
zval * * zcertval ;
X509 * cert ;
2003-03-01 01:26:28 +08:00
const EVP_CIPHER * cipher = NULL ;
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
long cipherid = PHP_OPENSSL_CIPHER_DEFAULT ;
2001-08-21 20:57:53 +08:00
uint strindexlen ;
ulong intindex ;
2001-04-02 07:06:15 +08:00
char * strindex ;
2003-03-07 07:07:28 +08:00
char * infilename = NULL ; int infilename_len ;
char * outfilename = NULL ; int outfilename_len ;
2001-09-08 01:09:56 +08:00
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ssza!|ll " , & infilename , & infilename_len ,
& outfilename , & outfilename_len , & zrecipcerts , & zheaders , & flags , & cipherid ) = = FAILURE )
2001-09-08 01:09:56 +08:00
return ;
2001-04-02 07:06:15 +08:00
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( infilename TSRMLS_CC ) | | php_openssl_safe_mode_chk ( outfilename TSRMLS_CC ) ) {
return ;
}
2001-09-08 01:09:56 +08:00
infile = BIO_new_file ( infilename , " r " ) ;
2003-01-05 07:31:55 +08:00
if ( infile = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-08 01:09:56 +08:00
outfile = BIO_new_file ( outfilename , " w " ) ;
2003-01-05 07:31:55 +08:00
if ( outfile = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
recipcerts = sk_X509_new_null ( ) ;
/* get certs */
2002-12-11 06:18:58 +08:00
if ( Z_TYPE_P ( zrecipcerts ) = = IS_ARRAY ) {
2001-09-08 01:09:56 +08:00
zend_hash_internal_pointer_reset_ex ( HASH_OF ( zrecipcerts ) , & hpos ) ;
2002-12-11 06:18:58 +08:00
while ( zend_hash_get_current_data_ex ( HASH_OF ( zrecipcerts ) , ( void * * ) & zcertval , & hpos ) = = SUCCESS ) {
2001-04-03 07:14:01 +08:00
long certresource ;
2001-08-01 07:47:35 +08:00
cert = php_openssl_x509_from_zval ( zcertval , 0 , & certresource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-03 07:14:01 +08:00
2002-12-11 06:18:58 +08:00
if ( certresource ! = - 1 ) {
2001-04-03 07:14:01 +08:00
/* we shouldn't free this particular cert, as it is a resource.
make a copy and push that on the stack instead */
cert = X509_dup ( cert ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-04-03 07:14:01 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-03 07:14:01 +08:00
}
sk_X509_push ( recipcerts , cert ) ;
2001-09-08 01:09:56 +08:00
zend_hash_move_forward_ex ( HASH_OF ( zrecipcerts ) , & hpos ) ;
2001-04-03 07:14:01 +08:00
}
2003-01-05 07:31:55 +08:00
} else {
2001-04-03 07:14:01 +08:00
/* a single certificate */
2001-04-02 07:06:15 +08:00
long certresource ;
2001-09-08 01:09:56 +08:00
cert = php_openssl_x509_from_zval ( & zrecipcerts , 0 , & certresource TSRMLS_CC ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( certresource ! = - 1 ) {
2001-04-02 07:06:15 +08:00
/* we shouldn't free this particular cert, as it is a resource.
2001-04-03 07:14:01 +08:00
make a copy and push that on the stack instead */
2001-04-02 07:06:15 +08:00
cert = X509_dup ( cert ) ;
2003-01-05 07:31:55 +08:00
if ( cert = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
sk_X509_push ( recipcerts , cert ) ;
}
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
/* sanity check the cipher */
switch ( cipherid ) {
case PHP_OPENSSL_CIPHER_RC2_40 :
cipher = EVP_rc2_40_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_RC2_64 :
cipher = EVP_rc2_64_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_RC2_128 :
cipher = EVP_rc2_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_DES :
cipher = EVP_des_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_3DES :
cipher = EVP_des_ede3_cbc ( ) ;
break ;
default :
2003-09-01 04:45:51 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Invalid cipher type `%ld' " , cipherid ) ;
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
goto clean_exit ;
}
2003-01-05 07:31:55 +08:00
if ( cipher = = NULL ) {
Add additional optional parameter to openssl_pkcs7_encrypt to specify the
cipher. The cipher can be one of the constants listed below.
Based on a patch from:
stefan at cuba dot ionum dot ch
OPENSSL_CIPHER_RC2_40, (the default)
OPENSSL_CIPHER_RC2_128,
OPENSSL_CIPHER_RC2_64,
OPENSSL_CIPHER_DES,
OPENSSL_CIPHER_3DES,
proto bool openssl_pkcs7_encrypt(string infile, string outfile,
mixed recipcerts, array headers [, long flags [, long cipher]])
2003-02-10 17:49:31 +08:00
/* shouldn't happen */
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Failed to get cipher " ) ;
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
2003-04-01 01:58:29 +08:00
p7 = PKCS7_encrypt ( recipcerts , infile , ( EVP_CIPHER * ) cipher , flags ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( p7 = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
/* tack on extra headers */
2002-12-11 06:18:58 +08:00
if ( zheaders ) {
2001-09-08 01:09:56 +08:00
zend_hash_internal_pointer_reset_ex ( HASH_OF ( zheaders ) , & hpos ) ;
2002-12-11 06:18:58 +08:00
while ( zend_hash_get_current_data_ex ( HASH_OF ( zheaders ) , ( void * * ) & zcertval , & hpos ) = = SUCCESS ) {
2001-09-08 01:09:56 +08:00
zend_hash_get_current_key_ex ( HASH_OF ( zheaders ) , & strindex , & strindexlen , & intindex , 0 , & hpos ) ;
2001-04-02 07:06:15 +08:00
2001-09-08 01:09:56 +08:00
convert_to_string_ex ( zcertval ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( strindex ) {
2001-09-08 01:09:56 +08:00
BIO_printf ( outfile , " %s: %s \n " , strindex , Z_STRVAL_PP ( zcertval ) ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-08 01:09:56 +08:00
BIO_printf ( outfile , " %s \n " , Z_STRVAL_PP ( zcertval ) ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-08 01:09:56 +08:00
zend_hash_move_forward_ex ( HASH_OF ( zheaders ) , & hpos ) ;
}
2001-04-02 07:06:15 +08:00
}
BIO_reset ( infile ) ;
/* write the encrypted data */
SMIME_write_PKCS7 ( outfile , p7 , infile , flags ) ;
RETVAL_TRUE ;
clean_exit :
PKCS7_free ( p7 ) ;
BIO_free ( infile ) ;
BIO_free ( outfile ) ;
2003-01-05 07:31:55 +08:00
if ( recipcerts ) {
2001-04-02 07:06:15 +08:00
sk_X509_pop_free ( recipcerts , X509_free ) ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-09-11 09:03:59 +08:00
/* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
Signs the MIME message in the file named infile with signcert / signkey and output the result to file name outfile . headers lists plain text headers to exclude from the signed portion of the message , and should include to , from and subject as a minimum */
2001-04-02 07:06:15 +08:00
PHP_FUNCTION ( openssl_pkcs7_sign )
{
2001-09-08 01:09:56 +08:00
zval * zcert , * zprivkey , * zheaders ;
2001-04-02 07:06:15 +08:00
zval * * hval ;
X509 * cert = NULL ;
EVP_PKEY * privkey = NULL ;
2001-09-08 01:09:56 +08:00
long flags = PKCS7_DETACHED ;
2001-04-02 07:06:15 +08:00
PKCS7 * p7 = NULL ;
BIO * infile = NULL , * outfile = NULL ;
STACK_OF ( X509 ) * others = NULL ;
long certresource = - 1 , keyresource = - 1 ;
2001-08-21 20:57:53 +08:00
ulong intindex ;
uint strindexlen ;
2001-04-02 07:06:15 +08:00
HashPosition hpos ;
char * strindex ;
2003-03-07 07:07:28 +08:00
char * infilename ; int infilename_len ;
char * outfilename ; int outfilename_len ;
char * extracertsfilename = NULL ; int extracertsfilename_len ;
2001-09-08 01:09:56 +08:00
2001-09-10 22:30:10 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " sszza!|ls " ,
2002-01-31 17:57:28 +08:00
& infilename , & infilename_len , & outfilename , & outfilename_len ,
2001-09-08 01:09:56 +08:00
& zcert , & zprivkey , & zheaders , & flags , & extracertsfilename ,
2003-01-05 07:31:55 +08:00
& extracertsfilename_len ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-08 01:09:56 +08:00
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
2002-12-11 06:18:58 +08:00
if ( extracertsfilename ) {
2001-09-08 01:09:56 +08:00
others = load_all_certs_from_file ( extracertsfilename ) ;
2003-01-05 07:31:55 +08:00
if ( others = = NULL ) {
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
2001-09-08 01:09:56 +08:00
privkey = php_openssl_evp_from_zval ( & zprivkey , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( privkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error getting private key " ) ;
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2001-04-02 09:31:08 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error getting cert " ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( infilename TSRMLS_CC ) | | php_openssl_safe_mode_chk ( outfilename TSRMLS_CC ) ) {
goto clean_exit ;
}
2001-09-11 07:57:10 +08:00
infile = BIO_new_file ( infilename , " r " ) ;
2002-12-11 06:18:58 +08:00
if ( infile = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening input file %s! " , infilename ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
outfile = BIO_new_file ( outfilename , " w " ) ;
2002-12-11 06:18:58 +08:00
if ( outfile = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening output file %s! " , outfilename ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
p7 = PKCS7_sign ( cert , privkey , others , infile , flags ) ;
2002-12-11 06:18:58 +08:00
if ( p7 = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error creating PKCS7 structure! " ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
BIO_reset ( infile ) ;
/* tack on extra headers */
2002-12-11 06:18:58 +08:00
if ( zheaders ) {
2001-09-11 07:57:10 +08:00
zend_hash_internal_pointer_reset_ex ( HASH_OF ( zheaders ) , & hpos ) ;
2002-12-11 06:18:58 +08:00
while ( zend_hash_get_current_data_ex ( HASH_OF ( zheaders ) , ( void * * ) & hval , & hpos ) = = SUCCESS ) {
2001-09-11 07:57:10 +08:00
zend_hash_get_current_key_ex ( HASH_OF ( zheaders ) , & strindex , & strindexlen , & intindex , 0 , & hpos ) ;
convert_to_string_ex ( hval ) ;
2003-01-05 07:31:55 +08:00
if ( strindex ) {
2001-09-11 07:57:10 +08:00
BIO_printf ( outfile , " %s: %s \n " , strindex , Z_STRVAL_PP ( hval ) ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
BIO_printf ( outfile , " %s \n " , Z_STRVAL_PP ( hval ) ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
zend_hash_move_forward_ex ( HASH_OF ( zheaders ) , & hpos ) ;
}
}
/* write the signed data */
SMIME_write_PKCS7 ( outfile , p7 , infile , flags ) ;
RETVAL_TRUE ;
clean_exit :
PKCS7_free ( p7 ) ;
BIO_free ( infile ) ;
BIO_free ( outfile ) ;
2003-01-05 07:31:55 +08:00
if ( others ) {
2001-09-11 07:57:10 +08:00
sk_X509_pop_free ( others , X509_free ) ;
2003-01-05 07:31:55 +08:00
}
if ( privkey & & keyresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( privkey ) ;
2003-01-05 07:31:55 +08:00
}
if ( cert & & certresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2001-09-11 09:03:59 +08:00
/* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
Decrypts the S / MIME message in the file name infilename and output the results to the file name outfilename . recipcert is a CERT for one of the recipients . recipkey specifies the private key matching recipcert , if recipcert does not include the key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_pkcs7_decrypt )
{
zval * recipcert , * recipkey = NULL ;
X509 * cert = NULL ;
EVP_PKEY * key = NULL ;
long certresval , keyresval ;
BIO * in = NULL , * out = NULL , * datain = NULL ;
PKCS7 * p7 = NULL ;
2003-03-07 07:07:28 +08:00
char * infilename ; int infilename_len ;
char * outfilename ; int outfilename_len ;
2001-09-11 07:57:10 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ssz|z " , & infilename , & infilename_len ,
2003-01-05 07:31:55 +08:00
& outfilename , & outfilename_len , & recipcert , & recipkey ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
cert = php_openssl_x509_from_zval ( & recipcert , 0 , & certresval TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to coerce parameter 3 to x509 cert " ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
key = php_openssl_evp_from_zval ( recipkey ? & recipkey : & recipcert , 0 , " " , 0 , & keyresval TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to get private key " ) ;
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
2002-11-10 13:19:40 +08:00
if ( php_openssl_safe_mode_chk ( infilename TSRMLS_CC ) | | php_openssl_safe_mode_chk ( outfilename TSRMLS_CC ) ) {
goto clean_exit ;
}
2001-09-11 07:57:10 +08:00
in = BIO_new_file ( infilename , " r " ) ;
2002-12-11 06:18:58 +08:00
if ( in = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
out = BIO_new_file ( outfilename , " w " ) ;
2002-12-11 06:18:58 +08:00
if ( out = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
}
p7 = SMIME_read_PKCS7 ( in , & datain ) ;
2003-01-05 07:31:55 +08:00
if ( p7 = = NULL ) {
2001-09-11 07:57:10 +08:00
goto clean_exit ;
2003-01-05 07:31:55 +08:00
}
if ( PKCS7_decrypt ( p7 , key , cert , out , PKCS7_DETACHED ) ) {
2001-09-11 07:57:10 +08:00
RETVAL_TRUE ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
clean_exit :
PKCS7_free ( p7 ) ;
BIO_free ( datain ) ;
BIO_free ( in ) ;
BIO_free ( out ) ;
2003-01-05 07:31:55 +08:00
if ( cert & & certresval = = - 1 ) {
2001-09-11 07:57:10 +08:00
X509_free ( cert ) ;
2003-01-05 07:31:55 +08:00
}
if ( key & & keyresval = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( key ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
/* }}} */
/* {{{ proto bool openssl_private_encrypt(string data, string crypted, mixed key [, int padding])
2001-09-11 09:03:59 +08:00
Encrypts data with private key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_private_encrypt )
{
zval * key , * crypted ;
EVP_PKEY * pkey ;
int cryptedlen ;
unsigned char * cryptedbuf = NULL ;
int successful = 0 ;
long keyresource = - 1 ;
char * data ;
2003-03-07 07:07:28 +08:00
int data_len ;
long padding = RSA_PKCS1_PADDING ;
2001-09-11 07:57:10 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szz|l " , & data , & data_len , & crypted , & key , & padding ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
pkey = php_openssl_evp_from_zval ( & key , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key param is not a valid private key " ) ;
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
}
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
cryptedlen = EVP_PKEY_size ( pkey ) ;
cryptedbuf = emalloc ( cryptedlen + 1 ) ;
2005-04-20 06:04:28 +08:00
switch ( pkey - > type ) {
2001-09-11 07:57:10 +08:00
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
successful = ( RSA_private_encrypt ( data_len ,
data ,
cryptedbuf ,
pkey - > pkey . rsa ,
padding ) = = cryptedlen ) ;
break ;
default :
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key type not supported in this PHP build! " ) ;
2001-09-11 07:57:10 +08:00
}
if ( successful ) {
zval_dtor ( crypted ) ;
cryptedbuf [ cryptedlen ] = ' \0 ' ;
ZVAL_STRINGL ( crypted , cryptedbuf , cryptedlen , 0 ) ;
cryptedbuf = NULL ;
RETVAL_TRUE ;
}
2003-01-05 07:31:55 +08:00
if ( cryptedbuf ) {
2001-09-11 07:57:10 +08:00
efree ( cryptedbuf ) ;
2003-01-05 07:31:55 +08:00
}
if ( keyresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2002-05-17 20:42:40 +08:00
/* {{{ proto bool openssl_private_decrypt(string data, string decrypted, mixed key [, int padding])
2001-09-11 09:03:59 +08:00
Decrypts data with private key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_private_decrypt )
{
zval * key , * crypted ;
EVP_PKEY * pkey ;
int cryptedlen ;
2002-04-19 15:56:41 +08:00
unsigned char * cryptedbuf = NULL ;
2001-09-11 07:57:10 +08:00
unsigned char * crypttemp ;
int successful = 0 ;
long padding = RSA_PKCS1_PADDING ;
long keyresource = - 1 ;
char * data ;
2003-03-07 07:07:28 +08:00
int data_len ;
2003-03-31 06:29:22 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szz|l " , & data , & data_len , & crypted , & key , & padding ) = = FAILURE ) {
2001-09-11 07:57:10 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
pkey = php_openssl_evp_from_zval ( & key , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key parameter is not a valid private key " ) ;
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
}
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
cryptedlen = EVP_PKEY_size ( pkey ) ;
crypttemp = emalloc ( cryptedlen + 1 ) ;
2005-04-20 06:04:28 +08:00
switch ( pkey - > type ) {
2001-09-11 07:57:10 +08:00
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
cryptedlen = RSA_private_decrypt ( data_len ,
data ,
crypttemp ,
pkey - > pkey . rsa ,
padding ) ;
if ( cryptedlen ! = - 1 ) {
cryptedbuf = emalloc ( cryptedlen + 1 ) ;
memcpy ( cryptedbuf , crypttemp , cryptedlen ) ;
successful = 1 ;
}
break ;
default :
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key type not supported in this PHP build! " ) ;
2001-04-02 09:31:08 +08:00
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
efree ( crypttemp ) ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
if ( successful ) {
zval_dtor ( crypted ) ;
cryptedbuf [ cryptedlen ] = ' \0 ' ;
ZVAL_STRINGL ( crypted , cryptedbuf , cryptedlen , 0 ) ;
cryptedbuf = NULL ;
RETVAL_TRUE ;
2001-04-02 09:31:08 +08:00
}
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
if ( cryptedbuf ) {
2001-09-11 07:57:10 +08:00
efree ( cryptedbuf ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
/* {{{ proto bool openssl_public_encrypt(string data, string crypted, mixed key [, int padding])
2001-09-11 09:03:59 +08:00
Encrypts data with public key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_public_encrypt )
{
zval * key , * crypted ;
EVP_PKEY * pkey ;
int cryptedlen ;
unsigned char * cryptedbuf ;
int successful = 0 ;
long keyresource = - 1 ;
long padding = RSA_PKCS1_PADDING ;
char * data ;
2003-03-07 07:07:28 +08:00
int data_len ;
2003-03-31 06:29:22 +08:00
2001-09-11 07:57:10 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szz|l " , & data , & data_len , & crypted , & key , & padding ) = = FAILURE )
return ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
pkey = php_openssl_evp_from_zval ( & key , 1 , NULL , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key parameter is not a valid public key " ) ;
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
cryptedlen = EVP_PKEY_size ( pkey ) ;
cryptedbuf = emalloc ( cryptedlen + 1 ) ;
2001-04-02 07:06:15 +08:00
2005-04-20 06:04:28 +08:00
switch ( pkey - > type ) {
2001-09-11 07:57:10 +08:00
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
successful = ( RSA_public_encrypt ( data_len ,
data ,
cryptedbuf ,
pkey - > pkey . rsa ,
padding ) = = cryptedlen ) ;
break ;
default :
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key type not supported in this PHP build! " ) ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
if ( successful ) {
zval_dtor ( crypted ) ;
cryptedbuf [ cryptedlen ] = ' \0 ' ;
ZVAL_STRINGL ( crypted , cryptedbuf , cryptedlen , 0 ) ;
cryptedbuf = NULL ;
RETVAL_TRUE ;
}
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
if ( cryptedbuf ) {
2001-09-11 07:57:10 +08:00
efree ( cryptedbuf ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
}
/* }}} */
2001-09-11 07:57:10 +08:00
/* {{{ proto bool openssl_public_decrypt(string data, string crypted, resource key [, int padding])
2001-09-11 09:03:59 +08:00
Decrypts data with public key */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_public_decrypt )
2001-04-02 07:06:15 +08:00
{
2001-09-11 07:57:10 +08:00
zval * key , * crypted ;
EVP_PKEY * pkey ;
int cryptedlen ;
2002-04-19 15:56:41 +08:00
unsigned char * cryptedbuf = NULL ;
2001-09-11 07:57:10 +08:00
unsigned char * crypttemp ;
int successful = 0 ;
long keyresource = - 1 ;
long padding = RSA_PKCS1_PADDING ;
char * data ;
2003-03-07 07:07:28 +08:00
int data_len ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szz|l " , & data , & data_len , & crypted , & key , & padding ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
2001-09-11 07:57:10 +08:00
pkey = php_openssl_evp_from_zval ( & key , 1 , NULL , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key parameter is not a valid public key " ) ;
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
cryptedlen = EVP_PKEY_size ( pkey ) ;
crypttemp = emalloc ( cryptedlen + 1 ) ;
2001-04-02 07:06:15 +08:00
2005-04-20 06:04:28 +08:00
switch ( pkey - > type ) {
2001-09-11 07:57:10 +08:00
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
cryptedlen = RSA_public_decrypt ( data_len ,
data ,
crypttemp ,
pkey - > pkey . rsa ,
padding ) ;
if ( cryptedlen ! = - 1 ) {
cryptedbuf = emalloc ( cryptedlen + 1 ) ;
memcpy ( cryptedbuf , crypttemp , cryptedlen ) ;
successful = 1 ;
}
break ;
default :
2002-12-11 06:18:58 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " key type not supported in this PHP build! " ) ;
2001-09-11 07:57:10 +08:00
2001-04-02 07:06:15 +08:00
}
2001-09-11 07:57:10 +08:00
efree ( crypttemp ) ;
if ( successful ) {
zval_dtor ( crypted ) ;
cryptedbuf [ cryptedlen ] = ' \0 ' ;
ZVAL_STRINGL ( crypted , cryptedbuf , cryptedlen , 0 ) ;
cryptedbuf = NULL ;
RETVAL_TRUE ;
2001-04-02 07:06:15 +08:00
}
2003-01-05 07:31:55 +08:00
if ( cryptedbuf ) {
2001-09-11 07:57:10 +08:00
efree ( cryptedbuf ) ;
2003-01-05 07:31:55 +08:00
}
if ( keyresource = = - 1 ) {
2001-09-11 07:57:10 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-11 07:57:10 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
2001-09-11 09:03:59 +08:00
/* {{{ proto mixed openssl_error_string(void)
Returns a description of the last error , and alters the index of the error messages . Returns false when the are no more messages */
2001-09-11 07:57:10 +08:00
PHP_FUNCTION ( openssl_error_string )
{
char buf [ 512 ] ;
unsigned long val ;
2001-04-02 07:06:15 +08:00
2002-12-11 06:18:58 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 0 ) {
2001-09-11 07:57:10 +08:00
WRONG_PARAM_COUNT ;
}
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
val = ERR_get_error ( ) ;
2003-01-05 07:31:55 +08:00
if ( val ) {
2001-09-11 07:57:10 +08:00
RETURN_STRING ( ERR_error_string ( val , buf ) , 1 ) ;
2003-01-05 07:31:55 +08:00
} else {
2001-09-11 07:57:10 +08:00
RETURN_FALSE ;
}
2001-04-02 07:06:15 +08:00
}
/* }}} */
2006-07-30 06:10:50 +08:00
/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, int signature_alg])
2001-09-11 09:03:59 +08:00
Signs data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_sign )
{
2001-09-08 01:09:56 +08:00
zval * key , * signature ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
int siglen ;
unsigned char * sigbuf ;
2001-04-02 07:06:15 +08:00
long keyresource = - 1 ;
2003-03-31 06:29:22 +08:00
char * data ;
int data_len ;
2000-11-14 03:47:20 +08:00
EVP_MD_CTX md_ctx ;
2003-03-31 06:25:23 +08:00
long signature_algo = OPENSSL_ALGO_SHA1 ;
EVP_MD * mdtype ;
2000-11-14 03:47:20 +08:00
2003-03-31 06:25:23 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szz|l " , & data , & data_len , & signature , & key , & signature_algo ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-08 01:09:56 +08:00
pkey = php_openssl_evp_from_zval ( & key , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " supplied key param cannot be coerced into a private key " ) ;
2001-04-02 07:06:15 +08:00
RETURN_FALSE ;
}
2006-07-30 06:10:50 +08:00
mdtype = php_openssl_get_evp_md_from_algo ( signature_algo ) ;
if ( ! mdtype ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
2003-03-31 06:25:23 +08:00
}
2003-12-22 02:17:20 +08:00
siglen = EVP_PKEY_size ( pkey ) ;
sigbuf = emalloc ( siglen + 1 ) ;
2003-03-31 06:25:23 +08:00
EVP_SignInit ( & md_ctx , mdtype ) ;
2001-09-08 01:09:56 +08:00
EVP_SignUpdate ( & md_ctx , data , data_len ) ;
2000-11-14 03:47:20 +08:00
if ( EVP_SignFinal ( & md_ctx , sigbuf , & siglen , pkey ) ) {
2001-09-08 01:09:56 +08:00
zval_dtor ( signature ) ;
2000-11-14 03:47:20 +08:00
sigbuf [ siglen ] = ' \0 ' ;
2001-09-08 01:09:56 +08:00
ZVAL_STRINGL ( signature , sigbuf , siglen , 0 ) ;
2001-04-02 07:06:15 +08:00
RETVAL_TRUE ;
2000-11-14 03:47:20 +08:00
} else {
efree ( sigbuf ) ;
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
2000-11-14 03:47:20 +08:00
}
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
/* {{{ proto int openssl_verify(string data, string signature, mixed key)
2001-09-11 09:03:59 +08:00
Verifys data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_verify )
{
2001-09-08 01:09:56 +08:00
zval * key ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
int err ;
EVP_MD_CTX md_ctx ;
2006-07-30 06:10:50 +08:00
EVP_MD * mdtype ;
2001-04-02 07:06:15 +08:00
long keyresource = - 1 ;
2003-03-07 07:07:28 +08:00
char * data ; int data_len ;
char * signature ; int signature_len ;
2006-07-30 06:10:50 +08:00
long signature_algo = OPENSSL_ALGO_SHA1 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ssz|l " , & data , & data_len , & signature , & signature_len , & key , & signature_algo ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2006-07-30 06:10:50 +08:00
mdtype = php_openssl_get_evp_md_from_algo ( signature_algo ) ;
if ( ! mdtype ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
2001-09-08 01:09:56 +08:00
pkey = php_openssl_evp_from_zval ( & key , 1 , NULL , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " supplied key param cannot be coerced into a public key " ) ;
2001-04-02 07:06:15 +08:00
RETURN_FALSE ;
}
2000-11-14 03:47:20 +08:00
2006-07-30 06:10:50 +08:00
EVP_VerifyInit ( & md_ctx , mdtype ) ;
2001-09-08 01:09:56 +08:00
EVP_VerifyUpdate ( & md_ctx , data , data_len ) ;
err = EVP_VerifyFinal ( & md_ctx , signature , signature_len , pkey ) ;
2001-04-02 07:06:15 +08:00
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
RETURN_LONG ( err ) ;
}
/* }}} */
2001-04-02 07:06:15 +08:00
/* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
2001-09-11 09:03:59 +08:00
Seals data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_seal )
{
2001-09-08 01:09:56 +08:00
zval * pubkeys , * * pubkey , * sealdata , * ekeys ;
2000-11-14 03:47:20 +08:00
HashTable * pubkeysht ;
2001-04-02 07:06:15 +08:00
HashPosition pos ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * * pkeys ;
2001-04-02 07:06:15 +08:00
long * key_resources ; /* so we know what to cleanup */
2000-11-14 17:54:25 +08:00
int i , len1 , len2 , * eksl , nkeys ;
2001-04-02 07:06:15 +08:00
unsigned char * buf = NULL , * * eks ;
2003-03-07 07:07:28 +08:00
char * data ; int data_len ;
2000-11-14 03:47:20 +08:00
EVP_CIPHER_CTX ctx ;
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szza/ " , & data , & data_len , & sealdata , & ekeys , & pubkeys ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2001-09-08 01:09:56 +08:00
pubkeysht = HASH_OF ( pubkeys ) ;
2000-11-14 03:47:20 +08:00
nkeys = pubkeysht ? zend_hash_num_elements ( pubkeysht ) : 0 ;
if ( ! nkeys ) {
2003-01-05 07:31:55 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Fourth argument to openssl_seal() must be a non-empty array " ) ;
2001-04-02 07:06:15 +08:00
RETURN_FALSE ;
2000-11-14 03:47:20 +08:00
}
2003-04-29 06:42:22 +08:00
pkeys = safe_emalloc ( nkeys , sizeof ( * pkeys ) , 0 ) ;
eksl = safe_emalloc ( nkeys , sizeof ( * eksl ) , 0 ) ;
eks = safe_emalloc ( nkeys , sizeof ( * eks ) , 0 ) ;
key_resources = safe_emalloc ( nkeys , sizeof ( long ) , 0 ) ;
2001-04-02 07:06:15 +08:00
/* get the public keys we are using to seal this data */
zend_hash_internal_pointer_reset_ex ( pubkeysht , & pos ) ;
2000-11-14 03:47:20 +08:00
i = 0 ;
2001-04-02 07:06:15 +08:00
while ( zend_hash_get_current_data_ex ( pubkeysht , ( void * * ) & pubkey ,
& pos ) = = SUCCESS ) {
2001-07-30 16:24:42 +08:00
pkeys [ i ] = php_openssl_evp_from_zval ( pubkey , 1 , NULL , 0 , & key_resources [ i ] TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkeys [ i ] = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " not a public key (%dth member of pubkeys) " , i ) ;
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
goto clean_exit ;
}
2000-11-14 03:47:20 +08:00
eks [ i ] = emalloc ( EVP_PKEY_size ( pkeys [ i ] ) + 1 ) ;
2001-04-02 07:06:15 +08:00
zend_hash_move_forward_ex ( pubkeysht , & pos ) ;
2000-11-14 03:47:20 +08:00
i + + ;
}
if ( ! EVP_EncryptInit ( & ctx , EVP_rc4 ( ) , NULL , NULL ) ) {
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
goto clean_exit ;
2000-11-14 03:47:20 +08:00
}
2000-11-14 17:54:25 +08:00
#if 0
/* Need this if allow ciphers that require initialization vector */
2000-11-14 03:47:20 +08:00
ivlen = EVP_CIPHER_CTX_iv_length ( & ctx ) ;
2001-01-13 17:16:36 +08:00
iv = ivlen ? emalloc ( ivlen + 1 ) : NULL ;
2000-11-14 17:54:25 +08:00
# endif
2000-11-14 03:47:20 +08:00
/* allocate one byte extra to make room for \0 */
2001-09-08 01:09:56 +08:00
buf = emalloc ( data_len + EVP_CIPHER_CTX_block_size ( & ctx ) ) ;
2000-11-14 03:47:20 +08:00
2003-01-05 07:31:55 +08:00
if ( ! EVP_SealInit ( & ctx , EVP_rc4 ( ) , eks , eksl , NULL , pkeys , nkeys ) | | ! EVP_SealUpdate ( & ctx , buf , & len1 , data , data_len ) ) {
2001-04-02 07:06:15 +08:00
RETVAL_FALSE ;
2000-11-14 03:47:20 +08:00
efree ( buf ) ;
2001-04-02 07:06:15 +08:00
goto clean_exit ;
2000-11-14 03:47:20 +08:00
}
EVP_SealFinal ( & ctx , buf + len1 , & len2 ) ;
if ( len1 + len2 > 0 ) {
2001-09-08 01:09:56 +08:00
zval_dtor ( sealdata ) ;
2000-11-14 03:47:20 +08:00
buf [ len1 + len2 ] = ' \0 ' ;
2001-04-02 07:06:15 +08:00
buf = erealloc ( buf , len1 + len2 + 1 ) ;
2001-09-08 01:09:56 +08:00
ZVAL_STRINGL ( sealdata , buf , len1 + len2 , 0 ) ;
2000-11-14 03:47:20 +08:00
2001-09-08 01:09:56 +08:00
zval_dtor ( ekeys ) ;
2003-01-19 03:41:56 +08:00
array_init ( ekeys ) ;
2000-11-14 03:47:20 +08:00
for ( i = 0 ; i < nkeys ; i + + ) {
eks [ i ] [ eksl [ i ] ] = ' \0 ' ;
2001-09-08 01:09:56 +08:00
add_next_index_stringl ( ekeys , erealloc ( eks [ i ] , eksl [ i ] + 1 ) , eksl [ i ] , 0 ) ;
2001-04-02 07:06:15 +08:00
eks [ i ] = NULL ;
2000-11-14 03:47:20 +08:00
}
2000-11-14 17:54:25 +08:00
#if 0
/* If allow ciphers that need IV, we need this */
2000-11-14 03:47:20 +08:00
zval_dtor ( * ivec ) ;
if ( ivlen ) {
iv [ ivlen ] = ' \0 ' ;
ZVAL_STRINGL ( * ivec , erealloc ( iv , ivlen + 1 ) , ivlen , 0 ) ;
} else {
ZVAL_EMPTY_STRING ( * ivec ) ;
}
2000-11-14 17:54:25 +08:00
# endif
2003-01-05 07:31:55 +08:00
} else {
2000-11-14 03:47:20 +08:00
efree ( buf ) ;
2003-01-05 07:31:55 +08:00
}
2001-04-02 07:06:15 +08:00
RETVAL_LONG ( len1 + len2 ) ;
clean_exit :
for ( i = 0 ; i < nkeys ; i + + ) {
2003-01-05 07:31:55 +08:00
if ( key_resources [ i ] = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkeys [ i ] ) ;
2003-01-05 07:31:55 +08:00
}
if ( eks [ i ] ) {
2000-11-14 03:47:20 +08:00
efree ( eks [ i ] ) ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
}
2001-04-02 07:06:15 +08:00
efree ( eks ) ;
efree ( eksl ) ;
efree ( pkeys ) ;
efree ( key_resources ) ;
2000-11-14 03:47:20 +08:00
}
/* }}} */
2001-04-02 07:06:15 +08:00
/* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
2001-09-11 09:03:59 +08:00
Opens data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_open )
{
2001-09-08 01:09:56 +08:00
zval * privkey , * opendata ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
2001-04-02 07:06:15 +08:00
int len1 , len2 ;
unsigned char * buf ;
long keyresource = - 1 ;
2000-11-14 03:47:20 +08:00
EVP_CIPHER_CTX ctx ;
2003-03-07 07:07:28 +08:00
char * data ; int data_len ;
char * ekey ; int ekey_len ;
2000-11-14 03:47:20 +08:00
2003-01-05 07:31:55 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szsz " , & data , & data_len , & opendata , & ekey , & ekey_len , & privkey ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
2001-09-08 01:09:56 +08:00
pkey = php_openssl_evp_from_zval ( & privkey , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2002-12-11 06:18:58 +08:00
if ( pkey = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " unable to coerce parameter 4 into a private key " ) ;
2001-04-02 07:06:15 +08:00
RETURN_FALSE ;
}
2001-09-08 01:09:56 +08:00
buf = emalloc ( data_len + 1 ) ;
2000-11-14 03:47:20 +08:00
2003-01-05 07:31:55 +08:00
if ( EVP_OpenInit ( & ctx , EVP_rc4 ( ) , ekey , ekey_len , NULL , pkey ) & & EVP_OpenUpdate ( & ctx , buf , & len1 , data , data_len ) ) {
if ( ! EVP_OpenFinal ( & ctx , buf + len1 , & len2 ) | | ( len1 + len2 = = 0 ) ) {
2001-01-07 19:36:15 +08:00
efree ( buf ) ;
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2001-01-07 19:36:15 +08:00
RETURN_FALSE ;
}
} else {
2000-11-14 03:47:20 +08:00
efree ( buf ) ;
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2000-11-14 03:47:20 +08:00
RETURN_FALSE ;
}
2003-01-05 07:31:55 +08:00
if ( keyresource = = - 1 ) {
2001-04-02 07:06:15 +08:00
EVP_PKEY_free ( pkey ) ;
2003-01-05 07:31:55 +08:00
}
2001-09-08 01:09:56 +08:00
zval_dtor ( opendata ) ;
2000-11-14 03:47:20 +08:00
buf [ len1 + len2 ] = ' \0 ' ;
2001-09-08 01:09:56 +08:00
ZVAL_STRINGL ( opendata , erealloc ( buf , len1 + len2 + 1 ) , len1 + len2 , 0 ) ;
2000-11-14 03:47:20 +08:00
RETURN_TRUE ;
}
/* }}} */
2003-11-28 01:40:16 +08:00
/* SSL verification functions */
# define GET_VER_OPT(name) (stream->context && SUCCESS == php_stream_context_get_option(stream->context, "ssl", name, &val))
# define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_PP(val); }
2006-07-30 06:52:49 +08:00
static int verify_callback ( int preverify_ok , X509_STORE_CTX * ctx ) /* { { { */
2003-11-28 01:40:16 +08:00
{
php_stream * stream ;
SSL * ssl ;
X509 * err_cert ;
int err , depth , ret ;
zval * * val ;
ret = preverify_ok ;
/* determine the status for the current cert */
err_cert = X509_STORE_CTX_get_current_cert ( ctx ) ;
err = X509_STORE_CTX_get_error ( ctx ) ;
depth = X509_STORE_CTX_get_error_depth ( ctx ) ;
/* conjure the stream & context to use */
ssl = X509_STORE_CTX_get_ex_data ( ctx , SSL_get_ex_data_X509_STORE_CTX_idx ( ) ) ;
stream = ( php_stream * ) SSL_get_ex_data ( ssl , ssl_stream_data_index ) ;
/* if allow_self_signed is set, make sure that verification succeeds */
if ( err = = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT & & GET_VER_OPT ( " allow_self_signed " ) & & zval_is_true ( * val ) ) {
ret = 1 ;
}
/* check the depth */
if ( GET_VER_OPT ( " verify_depth " ) ) {
convert_to_long_ex ( val ) ;
if ( depth > Z_LVAL_PP ( val ) ) {
ret = 0 ;
X509_STORE_CTX_set_error ( ctx , X509_V_ERR_CERT_CHAIN_TOO_LONG ) ;
}
}
return ret ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2003-11-28 01:40:16 +08:00
2006-07-30 06:52:49 +08:00
int php_openssl_apply_verification_policy ( SSL * ssl , X509 * peer , php_stream * stream TSRMLS_DC ) /* { { { */
2003-11-28 01:40:16 +08:00
{
zval * * val = NULL ;
char * cnmatch = NULL ;
X509_NAME * name ;
char buf [ 1024 ] ;
int err ;
/* verification is turned off */
if ( ! ( GET_VER_OPT ( " verify_peer " ) & & zval_is_true ( * val ) ) ) {
return SUCCESS ;
}
if ( peer = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Could not get peer certificate " ) ;
return FAILURE ;
}
err = SSL_get_verify_result ( ssl ) ;
switch ( err ) {
case X509_V_OK :
/* fine */
break ;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT :
if ( GET_VER_OPT ( " allow_self_signed " ) & & zval_is_true ( * val ) ) {
/* allowed */
break ;
}
/* not allowed, so fall through */
default :
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Could not verify peer: code:%d %s " , err , X509_verify_cert_error_string ( err ) ) ;
return FAILURE ;
}
/* if the cert passed the usual checks, apply our own local policies now */
name = X509_get_subject_name ( peer ) ;
/* Does the common name match ? (used primarily for https://) */
GET_VER_OPT_STRING ( " CN_match " , cnmatch ) ;
if ( cnmatch ) {
int match = 0 ;
X509_NAME_get_text_by_NID ( name , NID_commonName , buf , sizeof ( buf ) ) ;
match = strcmp ( cnmatch , buf ) = = 0 ;
if ( ! match & & strlen ( buf ) > 3 & & buf [ 0 ] = = ' * ' & & buf [ 1 ] = = ' . ' ) {
/* Try wildcard */
if ( strchr ( buf + 2 , ' . ' ) ) {
char * tmp = strstr ( cnmatch , buf + 1 ) ;
match = tmp & & strcmp ( tmp , buf + 2 ) & & tmp = = strchr ( cnmatch , ' . ' ) ;
}
}
if ( ! match ) {
/* didn't match */
php_error_docref ( NULL TSRMLS_CC , E_WARNING ,
" Peer certificate CN=`%s' did not match expected CN=`%s' " ,
buf , cnmatch ) ;
return FAILURE ;
}
}
return SUCCESS ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2003-11-28 01:40:16 +08:00
2006-07-30 06:52:49 +08:00
static int passwd_callback ( char * buf , int num , int verify , void * data ) /* { { { */
2003-11-28 01:40:16 +08:00
{
php_stream * stream = ( php_stream * ) data ;
zval * * val = NULL ;
char * passphrase = NULL ;
/* TODO: could expand this to make a callback into PHP user-space */
GET_VER_OPT_STRING ( " passphrase " , passphrase ) ;
if ( passphrase ) {
if ( Z_STRLEN_PP ( val ) < num - 1 ) {
memcpy ( buf , Z_STRVAL_PP ( val ) , Z_STRLEN_PP ( val ) + 1 ) ;
return Z_STRLEN_PP ( val ) ;
}
}
return 0 ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2003-11-28 01:40:16 +08:00
2006-07-30 06:52:49 +08:00
SSL * php_SSL_new_from_context ( SSL_CTX * ctx , php_stream * stream TSRMLS_DC ) /* { { { */
2003-11-28 01:40:16 +08:00
{
zval * * val = NULL ;
char * cafile = NULL ;
char * capath = NULL ;
char * certfile = NULL ;
2004-04-22 07:02:06 +08:00
char * cipherlist = NULL ;
2003-11-28 01:40:16 +08:00
int ok = 1 ;
/* look at context options in the stream and set appropriate verification flags */
if ( GET_VER_OPT ( " verify_peer " ) & & zval_is_true ( * val ) ) {
/* turn on verification callback */
SSL_CTX_set_verify ( ctx , SSL_VERIFY_PEER , verify_callback ) ;
/* CA stuff */
GET_VER_OPT_STRING ( " cafile " , cafile ) ;
GET_VER_OPT_STRING ( " capath " , capath ) ;
if ( cafile | | capath ) {
if ( ! SSL_CTX_load_verify_locations ( ctx , cafile , capath ) ) {
2005-08-18 21:34:41 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unable to set verify locations `%s' `%s' " , cafile , capath ) ;
2003-11-28 01:40:16 +08:00
return NULL ;
}
}
if ( GET_VER_OPT ( " verify_depth " ) ) {
convert_to_long_ex ( val ) ;
SSL_CTX_set_verify_depth ( ctx , Z_LVAL_PP ( val ) ) ;
}
} else {
SSL_CTX_set_verify ( ctx , SSL_VERIFY_NONE , NULL ) ;
}
/* callback for the passphrase (for localcert) */
if ( GET_VER_OPT ( " passphrase " ) ) {
SSL_CTX_set_default_passwd_cb_userdata ( ctx , stream ) ;
SSL_CTX_set_default_passwd_cb ( ctx , passwd_callback ) ;
}
2004-04-22 07:02:06 +08:00
GET_VER_OPT_STRING ( " ciphers " , cipherlist ) ;
if ( ! cipherlist ) {
cipherlist = " DEFAULT " ;
}
SSL_CTX_set_cipher_list ( ctx , cipherlist ) ;
2003-11-28 01:40:16 +08:00
GET_VER_OPT_STRING ( " local_cert " , certfile ) ;
if ( certfile ) {
X509 * cert = NULL ;
EVP_PKEY * key = NULL ;
SSL * tmpssl ;
/* a certificate to use for authentication */
if ( SSL_CTX_use_certificate_chain_file ( ctx , certfile ) ! = 1 ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer " , certfile ) ;
return NULL ;
}
if ( SSL_CTX_use_PrivateKey_file ( ctx , certfile , SSL_FILETYPE_PEM ) ! = 1 ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unable to set private key file `%s' " , certfile ) ;
return NULL ;
}
tmpssl = SSL_new ( ctx ) ;
cert = SSL_get_certificate ( tmpssl ) ;
if ( cert ) {
key = X509_get_pubkey ( cert ) ;
EVP_PKEY_copy_parameters ( key , SSL_get_privatekey ( tmpssl ) ) ;
EVP_PKEY_free ( key ) ;
}
SSL_free ( tmpssl ) ;
if ( ! SSL_CTX_check_private_key ( ctx ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Private key does not match certificate! " ) ;
}
}
if ( ok ) {
SSL * ssl = SSL_new ( ctx ) ;
if ( ssl ) {
/* map SSL => stream */
SSL_set_ex_data ( ssl , ssl_stream_data_index , stream ) ;
}
return ssl ;
}
return NULL ;
}
2006-07-30 06:52:49 +08:00
/* }}} */
2003-11-28 01:40:16 +08:00
2000-11-14 03:47:20 +08:00
/*
* Local variables :
* tab - width : 8
* c - basic - offset : 8
* End :
2001-09-09 21:29:31 +08:00
* vim600 : sw = 4 ts = 4 fdm = marker
* vim < 600 : sw = 4 ts = 4
2000-11-14 03:47:20 +08:00
*/