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
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2007-12-31 15:17:19 +08:00
| Copyright ( c ) 1997 - 2008 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 > |
2007-04-05 05:24:01 +08:00
| Pierre - Alain Joye < pierre @ php . net > |
| Marc Delling < delling @ silpion . de > ( PKCS12 functions ) |
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"
2007-09-27 16:46:00 +08:00
# include "ext/standard/md5.h"
# include "ext/standard/base64.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>
2007-04-05 05:24:01 +08:00
# include <openssl/pkcs12.h>
2001-09-11 07:57:10 +08:00
2007-10-31 21:22:45 +08:00
/* Common */
# include <time.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
2006-08-15 08:38:05 +08:00
/* FIXME: Use the openssl constants instead of
* enum . It is now impossible to match real values
* against php constants . Also sorry to break the
* enum principles here , BC . . .
*/
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 ,
2006-08-15 08:38:05 +08:00
OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA ,
2006-08-18 21:02:38 +08:00
# ifdef EVP_PKEY_EC
2006-08-15 08:38:05 +08:00
OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH + 1
2006-08-18 21:02:38 +08:00
# endif
2001-09-11 07:57:10 +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_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
} ;
2007-09-27 16:46:00 +08:00
PHP_FUNCTION ( openssl_get_md_methods ) ;
PHP_FUNCTION ( openssl_get_cipher_methods ) ;
PHP_FUNCTION ( openssl_digest ) ;
PHP_FUNCTION ( openssl_encrypt ) ;
PHP_FUNCTION ( openssl_decrypt ) ;
PHP_FUNCTION ( openssl_dh_compute_key ) ;
2008-06-02 01:54:02 +08:00
/* {{{ arginfo */
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_x509_export_to_file , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 0 , outfilename )
ZEND_ARG_INFO ( 0 , notext )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_x509_export , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 1 , out )
ZEND_ARG_INFO ( 0 , notext )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_x509_check_private_key , 0 )
ZEND_ARG_INFO ( 0 , cert )
ZEND_ARG_INFO ( 0 , key )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_x509_parse , 0 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 0 , shortname )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_x509_checkpurpose , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , x509cert )
ZEND_ARG_INFO ( 0 , purpose )
ZEND_ARG_INFO ( 0 , cainfo ) /* array */
ZEND_ARG_INFO ( 0 , untrustedfile )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_x509_read , 0 )
ZEND_ARG_INFO ( 0 , cert )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_x509_free , 0 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkcs12_export_to_file , 0 , 0 , 4 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 0 , filename )
ZEND_ARG_INFO ( 0 , priv_key )
ZEND_ARG_INFO ( 0 , pass )
ZEND_ARG_INFO ( 0 , args ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_pkcs12_export , 0 )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 1 , out )
ZEND_ARG_INFO ( 0 , priv_key )
ZEND_ARG_INFO ( 0 , pass )
ZEND_ARG_INFO ( 0 , args ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_pkcs12_read , 0 )
ZEND_ARG_INFO ( 0 , PKCS12 )
ZEND_ARG_INFO ( 1 , certs ) /* array */
ZEND_ARG_INFO ( 0 , pass )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_csr_export_to_file , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , csr )
ZEND_ARG_INFO ( 0 , outfilename )
ZEND_ARG_INFO ( 0 , notext )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_csr_export , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , csr )
ZEND_ARG_INFO ( 1 , out )
ZEND_ARG_INFO ( 0 , notext )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_csr_sign , 0 , 0 , 4 )
ZEND_ARG_INFO ( 0 , csr )
ZEND_ARG_INFO ( 0 , x509 )
ZEND_ARG_INFO ( 0 , priv_key )
ZEND_ARG_INFO ( 0 , days )
ZEND_ARG_INFO ( 0 , config_args ) /* array */
ZEND_ARG_INFO ( 0 , serial )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_csr_new , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , dn ) /* array */
ZEND_ARG_INFO ( 1 , privkey )
ZEND_ARG_INFO ( 0 , configargs )
ZEND_ARG_INFO ( 0 , extraattribs )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_csr_get_subject , 0 )
ZEND_ARG_INFO ( 0 , csr )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_csr_get_public_key , 0 )
ZEND_ARG_INFO ( 0 , csr )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkey_new , 0 , 0 , 0 )
ZEND_ARG_INFO ( 0 , configargs ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkey_export_to_file , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , outfilename )
ZEND_ARG_INFO ( 0 , passphrase )
ZEND_ARG_INFO ( 0 , config_args ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkey_export , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 1 , out )
ZEND_ARG_INFO ( 0 , passphrase )
ZEND_ARG_INFO ( 0 , config_args ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_pkey_get_public , 0 )
ZEND_ARG_INFO ( 0 , cert )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_pkey_free , 0 )
ZEND_ARG_INFO ( 0 , key )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkey_get_private , 0 , 0 , 1 )
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , passphrase )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_pkey_get_details , 0 )
ZEND_ARG_INFO ( 0 , key )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkcs7_verify , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , filename )
ZEND_ARG_INFO ( 0 , flags )
ZEND_ARG_INFO ( 0 , signerscerts )
ZEND_ARG_INFO ( 0 , cainfo ) /* array */
ZEND_ARG_INFO ( 0 , extracerts )
ZEND_ARG_INFO ( 0 , content )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkcs7_encrypt , 0 , 0 , 4 )
ZEND_ARG_INFO ( 0 , infile )
ZEND_ARG_INFO ( 0 , outfile )
ZEND_ARG_INFO ( 0 , recipcerts )
ZEND_ARG_INFO ( 0 , headers ) /* array */
ZEND_ARG_INFO ( 0 , flags )
ZEND_ARG_INFO ( 0 , cipher )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkcs7_sign , 0 , 0 , 5 )
ZEND_ARG_INFO ( 0 , infile )
ZEND_ARG_INFO ( 0 , outfile )
ZEND_ARG_INFO ( 0 , signcert )
ZEND_ARG_INFO ( 0 , signkey )
ZEND_ARG_INFO ( 0 , headers ) /* array */
ZEND_ARG_INFO ( 0 , flags )
ZEND_ARG_INFO ( 0 , extracertsfilename )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_pkcs7_decrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , infilename )
ZEND_ARG_INFO ( 0 , outfilename )
ZEND_ARG_INFO ( 0 , recipcert )
ZEND_ARG_INFO ( 0 , recipkey )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_private_encrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
2008-06-02 02:24:38 +08:00
ZEND_ARG_INFO ( 1 , crypted )
2008-06-02 01:54:02 +08:00
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , padding )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_private_decrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
2008-06-02 02:24:38 +08:00
ZEND_ARG_INFO ( 1 , crypted )
2008-06-02 01:54:02 +08:00
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , padding )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_public_encrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
2008-06-02 02:24:38 +08:00
ZEND_ARG_INFO ( 1 , crypted )
2008-06-02 01:54:02 +08:00
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , padding )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_public_decrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
2008-06-02 02:24:38 +08:00
ZEND_ARG_INFO ( 1 , crypted )
2008-06-02 01:54:02 +08:00
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , padding )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_error_string , 0 )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_sign , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 1 , signature )
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , method )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_verify , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 0 , signature )
ZEND_ARG_INFO ( 0 , key )
ZEND_ARG_INFO ( 0 , method )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_seal , 0 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 1 , sealdata )
ZEND_ARG_INFO ( 1 , ekeys ) /* arary */
ZEND_ARG_INFO ( 0 , pubkeys ) /* array */
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_open , 0 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 1 , opendata )
ZEND_ARG_INFO ( 0 , ekey )
ZEND_ARG_INFO ( 0 , privkey )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_get_md_methods , 0 , 0 , 0 )
ZEND_ARG_INFO ( 0 , aliases )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_get_cipher_methods , 0 , 0 , 0 )
ZEND_ARG_INFO ( 0 , aliases )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_digest , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 0 , method )
ZEND_ARG_INFO ( 0 , raw_output )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_encrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 0 , method )
ZEND_ARG_INFO ( 0 , password )
ZEND_ARG_INFO ( 0 , raw_output )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_openssl_decrypt , 0 , 0 , 3 )
ZEND_ARG_INFO ( 0 , data )
ZEND_ARG_INFO ( 0 , method )
ZEND_ARG_INFO ( 0 , password )
ZEND_ARG_INFO ( 0 , raw_input )
ZEND_END_ARG_INFO ( )
static
ZEND_BEGIN_ARG_INFO ( arginfo_openssl_dh_compute_key , 0 )
ZEND_ARG_INFO ( 0 , pub_key )
ZEND_ARG_INFO ( 0 , dh_key )
ZEND_END_ARG_INFO ( )
/* }}} */
2001-06-05 21:12:10 +08:00
/* {{{ openssl_functions[]
*/
2007-09-28 02:00:48 +08:00
const zend_function_entry openssl_functions [ ] = {
2001-09-11 07:57:10 +08:00
/* public/private key functions */
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_pkey_free , arginfo_openssl_pkey_free )
PHP_FE ( openssl_pkey_new , arginfo_openssl_pkey_new )
PHP_FE ( openssl_pkey_export , arginfo_openssl_pkey_export )
PHP_FE ( openssl_pkey_export_to_file , arginfo_openssl_pkey_export_to_file )
PHP_FE ( openssl_pkey_get_private , arginfo_openssl_pkey_get_private )
PHP_FE ( openssl_pkey_get_public , arginfo_openssl_pkey_get_public )
PHP_FE ( openssl_pkey_get_details , arginfo_openssl_pkey_get_details )
2001-09-11 07:57:10 +08:00
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 */
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_x509_read , arginfo_openssl_x509_read )
PHP_FE ( openssl_x509_free , arginfo_openssl_x509_free )
PHP_FE ( openssl_x509_parse , arginfo_openssl_x509_parse )
PHP_FE ( openssl_x509_checkpurpose , arginfo_openssl_x509_checkpurpose )
PHP_FE ( openssl_x509_check_private_key , arginfo_openssl_x509_check_private_key )
PHP_FE ( openssl_x509_export , arginfo_openssl_x509_export )
PHP_FE ( openssl_x509_export_to_file , arginfo_openssl_x509_export_to_file )
2001-04-02 07:06:15 +08:00
2007-04-05 05:24:01 +08:00
/* PKCS12 funcs */
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_pkcs12_export , arginfo_openssl_pkcs12_export )
PHP_FE ( openssl_pkcs12_export_to_file , arginfo_openssl_pkcs12_export_to_file )
PHP_FE ( openssl_pkcs12_read , arginfo_openssl_pkcs12_read )
2007-04-05 05:24:01 +08:00
2001-09-11 07:57:10 +08:00
/* CSR funcs */
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_csr_new , arginfo_openssl_csr_new )
PHP_FE ( openssl_csr_export , arginfo_openssl_csr_export )
PHP_FE ( openssl_csr_export_to_file , arginfo_openssl_csr_export_to_file )
PHP_FE ( openssl_csr_sign , arginfo_openssl_csr_sign )
PHP_FE ( openssl_csr_get_subject , arginfo_openssl_csr_get_subject )
PHP_FE ( openssl_csr_get_public_key , arginfo_openssl_csr_get_public_key )
PHP_FE ( openssl_digest , arginfo_openssl_digest )
PHP_FE ( openssl_encrypt , arginfo_openssl_encrypt )
PHP_FE ( openssl_decrypt , arginfo_openssl_decrypt )
PHP_FE ( openssl_sign , arginfo_openssl_sign )
PHP_FE ( openssl_verify , arginfo_openssl_verify )
PHP_FE ( openssl_seal , arginfo_openssl_seal )
PHP_FE ( openssl_open , arginfo_openssl_open )
2001-09-11 07:57:10 +08:00
2001-04-02 07:06:15 +08:00
/* for S/MIME handling */
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_pkcs7_verify , arginfo_openssl_pkcs7_verify )
PHP_FE ( openssl_pkcs7_decrypt , arginfo_openssl_pkcs7_decrypt )
PHP_FE ( openssl_pkcs7_sign , arginfo_openssl_pkcs7_sign )
PHP_FE ( openssl_pkcs7_encrypt , arginfo_openssl_pkcs7_encrypt )
2001-04-02 07:06:15 +08:00
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_private_encrypt , arginfo_openssl_private_encrypt )
PHP_FE ( openssl_private_decrypt , arginfo_openssl_private_decrypt )
PHP_FE ( openssl_public_encrypt , arginfo_openssl_public_encrypt )
PHP_FE ( openssl_public_decrypt , arginfo_openssl_public_decrypt )
2001-05-05 07:42:11 +08:00
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_get_md_methods , arginfo_openssl_get_md_methods )
PHP_FE ( openssl_get_cipher_methods , arginfo_openssl_get_cipher_methods )
2007-09-27 16:46:00 +08:00
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_dh_compute_key , arginfo_openssl_dh_compute_key )
2007-09-27 16:46:00 +08:00
2008-06-02 01:54:02 +08:00
PHP_FE ( openssl_error_string , arginfo_openssl_error_string )
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 )
# 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 ;
2006-07-31 11:41:20 +08:00
ASN1_STRING * str = NULL ;
2001-09-11 07:57:10 +08:00
ASN1_OBJECT * obj ;
2006-08-16 04:27:22 +08:00
if ( key ! = NULL ) {
MAKE_STD_ZVAL ( subitem ) ;
array_init ( subitem ) ;
} else {
subitem = val ;
}
2002-12-11 06:18:58 +08:00
for ( i = 0 ; i < X509_NAME_entry_count ( name ) ; i + + ) {
2007-04-05 05:24:01 +08:00
unsigned char * to_add ;
int to_add_len ;
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 ) ;
2007-04-05 05:24:01 +08:00
if ( ASN1_STRING_type ( str ) ! = V_ASN1_UTF8STRING ) {
to_add_len = ASN1_STRING_to_UTF8 ( & to_add , str ) ;
add_next_index_stringl ( subentries , ( char * ) to_add , to_add_len , 1 ) ;
} else {
to_add = ASN1_STRING_data ( str ) ;
to_add_len = ASN1_STRING_length ( str ) ;
add_next_index_stringl ( subentries , ( char * ) to_add , to_add_len , 1 ) ;
}
2005-03-15 05:00:03 +08:00
}
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 ) ;
2006-07-31 11:41:20 +08:00
if ( obj_cnt & & str ) {
2007-04-05 05:24:01 +08:00
add_assoc_stringl ( subitem , sname , ( char * ) to_add , to_add_len , 1 ) ;
2005-03-15 08:27:52 +08:00
}
2001-09-11 07:57:10 +08:00
}
}
2006-08-16 04:27:22 +08:00
if ( key ! = NULL ) {
zend_hash_update ( HASH_OF ( val ) , key , strlen ( key ) + 1 , ( void * ) & subitem , sizeof ( subitem ) , NULL ) ;
}
2001-09-11 07:57:10 +08:00
}
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
{
2006-07-30 17:18:07 +08:00
add_assoc_stringl ( val , key , ( char * ) str - > data , str - > length , 1 ) ;
2001-09-11 07:57:10 +08:00
}
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 :
2007-02-24 10:17:47 +08:00
snprintf ( p , sizeof ( p ) , " %02d%02d%02d%02d%02d%02dZ " , ts - > tm_year % 100 ,
2001-09-11 07:57:10 +08:00
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 ;
}
2006-07-30 17:18:07 +08:00
strbuf = estrdup ( ( char * ) timestr - > data ) ;
2001-09-11 07:57:10 +08:00
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 " ) ) ;
2006-07-31 08:33:42 +08:00
SET_OPTIONAL_STRING_ARG ( " req_extensions " , req - > request_extensions_section ,
CONF_get_string ( req - > req_config , req - > section_name , " 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 ;
}
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 ;
}
/* }}} */
2007-09-27 16:46:00 +08:00
static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo ( long algo ) { /* {{{ */
switch ( algo ) {
# ifndef OPENSSL_NO_RC2
case PHP_OPENSSL_CIPHER_RC2_40 :
return EVP_rc2_40_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_RC2_64 :
return EVP_rc2_64_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_RC2_128 :
return EVP_rc2_cbc ( ) ;
break ;
# endif
# ifndef OPENSSL_NO_DES
case PHP_OPENSSL_CIPHER_DES :
return EVP_des_cbc ( ) ;
break ;
case PHP_OPENSSL_CIPHER_3DES :
return EVP_des_ede3_cbc ( ) ;
break ;
# endif
default :
return NULL ;
break ;
}
}
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 ) ;
2006-09-03 23:31:01 +08:00
REGISTER_STRING_CONSTANT ( " OPENSSL_VERSION_TEXT " , OPENSSL_VERSION_TEXT , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " OPENSSL_VERSION_NUMBER " , OPENSSL_VERSION_NUMBER , CONST_CS | CONST_PERSISTENT ) ;
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 */
2007-05-20 06:05:08 +08:00
# ifndef OPENSSL_NO_RC2
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 ) ;
2007-05-20 06:05:08 +08:00
# endif
# ifndef OPENSSL_NO_DES
2003-03-31 06:29:22 +08:00
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 ) ;
2007-05-20 06:05:08 +08:00
# endif
2003-03-31 06:29:22 +08:00
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 ) ;
2006-08-18 21:02:38 +08:00
# ifdef EVP_PKEY_EC
2006-08-15 08:38:05 +08:00
REGISTER_LONG_CONSTANT ( " OPENSSL_KEYTYPE_EC " , OPENSSL_KEYTYPE_EC , CONST_CS | CONST_PERSISTENT ) ;
2006-08-18 21:02:38 +08:00
# endif
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 ;
}
2006-07-31 00:26:20 +08:00
if ( ! ( Z_TYPE_PP ( val ) = = IS_STRING | | Z_TYPE_PP ( val ) = = IS_OBJECT ) ) {
return NULL ;
}
2001-04-02 07:06:15 +08:00
/* force it to be a string and check if it refers to a file */
2006-08-31 21:48:17 +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 ) {
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 ;
2006-08-31 21:48:17 +08:00
zval * * zcert ;
2001-09-11 08:33:25 +08:00
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
2006-08-31 21:48:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " Zs|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
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +08:00
zval * * zcert , * zout ;
2001-09-11 08:33:25 +08:00
zend_bool notext = 1 ;
BIO * bio_out ;
long certresource ;
2006-08-31 21:48:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " Zz|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 ;
2006-08-31 21:48:17 +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 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
}
2006-07-31 08:33:42 +08:00
if ( PEM_write_bio_X509 ( bio_out , cert ) ) {
BUF_MEM * bio_buf ;
2001-09-11 08:33:25 +08:00
2006-07-31 08:33:42 +08:00
zval_dtor ( zout ) ;
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
ZVAL_STRINGL ( zout , bio_buf - > data , bio_buf - > length , 1 ) ;
2001-09-11 08:33:25 +08:00
2006-07-31 08:33:42 +08:00
RETVAL_TRUE ;
}
2001-09-11 08:33:25 +08:00
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 )
{
2006-08-31 21:48:17 +08:00
zval * * zcert , * * zkey ;
2001-09-11 07:57:10 +08:00
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 ;
2006-08-31 21:48:17 +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
}
2006-08-31 21:48:17 +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
}
2006-08-31 21:48:17 +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 )
{
2006-08-31 21:48:17 +08:00
zval * * zcert ;
2001-09-11 07:57:10 +08:00
X509 * cert = NULL ;
long certresource = - 1 ;
int i ;
zend_bool useshortnames = 1 ;
char * tmpstr ;
zval * subitem ;
2006-07-31 01:03:13 +08:00
X509_EXTENSION * extension ;
char * extname ;
2007-07-11 20:18:14 +08:00
BIO * bio_out ;
BUF_MEM * bio_buf ;
char buf [ 256 ] ;
2001-04-02 07:06:15 +08:00
2006-08-31 21:48:17 +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
}
2006-08-31 21:48:17 +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 ) ) ;
2006-11-16 07:28:06 +08:00
add_assoc_string ( return_value , " serialNumber " , i2s_ASN1_INTEGER ( NULL , X509_get_serialNumber ( cert ) ) , 1 ) ;
2001-09-11 07:57:10 +08:00
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 ) ) ;
2006-07-30 17:18:07 +08:00
tmpstr = ( char * ) 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 ) ;
2006-07-31 01:03:13 +08:00
MAKE_STD_ZVAL ( subitem ) ;
array_init ( subitem ) ;
for ( i = 0 ; i < X509_get_ext_count ( cert ) ; i + + ) {
extension = X509_get_ext ( cert , i ) ;
2007-07-11 20:18:14 +08:00
if ( OBJ_obj2nid ( X509_EXTENSION_get_object ( extension ) ) ! = NID_undef ) {
extname = ( char * ) OBJ_nid2sn ( OBJ_obj2nid ( X509_EXTENSION_get_object ( extension ) ) ) ;
} else {
OBJ_obj2txt ( buf , sizeof ( buf ) - 1 , X509_EXTENSION_get_object ( extension ) , 1 ) ;
extname = buf ;
}
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
if ( X509V3_EXT_print ( bio_out , extension , 0 , 0 ) ) {
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
add_assoc_stringl ( subitem , extname , bio_buf - > data , bio_buf - > length , 1 ) ;
} else {
add_assoc_asn1_string ( subitem , extname , X509_EXTENSION_get_data ( extension ) ) ;
}
BIO_free ( bio_out ) ;
2006-07-31 01:03:13 +08:00
}
add_assoc_zval ( return_value , " extensions " , 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 ) ) {
2007-06-20 06:09:49 +08:00
sk_X509_free ( stack ) ;
2002-11-10 13:19:40 +08:00
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 ) ;
2007-06-20 06:09:49 +08:00
sk_X509_free ( stack ) ;
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 ) ;
2007-06-20 06:09:49 +08:00
sk_X509_free ( stack ) ;
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 ;
}
/* }}} */
2008-06-02 02:24:38 +08:00
/* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
2001-09-11 09:03:59 +08:00
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 )
{
2006-08-31 21:48:17 +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 ;
2007-10-31 21:22:45 +08:00
int untrusted_len , ret ;
2001-09-11 07:57:10 +08:00
2007-10-31 21:22:45 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " Zl|a!s " , & zcert , & purpose , & zcainfo , & untrusted , & untrusted_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
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
}
2006-08-31 21:48:17 +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
}
2007-10-31 21:22:45 +08:00
ret = check_cert ( cainfo , cert , untrustedchain , purpose ) ;
if ( ret ! = 0 & & ret ! = 1 ) {
RETVAL_LONG ( ret ) ;
} else {
RETVAL_BOOL ( ret ) ;
}
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
{
2006-08-31 21:48:17 +08:00
zval * * cert ;
2001-09-11 07:57:10 +08:00
X509 * x509 ;
2001-05-05 07:42:11 +08:00
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +08:00
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
/* }}} */
2007-04-05 05:24:01 +08:00
/* Pop all X509 from Stack and free them, free the stack afterwards */
static void php_sk_X509_free ( STACK_OF ( X509 ) * sk )
{
for ( ; ; ) {
X509 * x = sk_X509_pop ( sk ) ;
if ( ! x ) break ;
X509_free ( x ) ;
}
sk_X509_free ( sk ) ;
}
2007-04-05 15:10:07 +08:00
static STACK_OF ( X509 ) * php_array_to_X509_sk ( zval * * zcerts TSRMLS_DC )
2007-04-05 05:24:01 +08:00
{
HashPosition hpos ;
zval * * zcertval ;
STACK_OF ( X509 ) * sk = NULL ;
X509 * cert ;
long certresource ;
sk = sk_X509_new_null ( ) ;
/* get certs */
if ( Z_TYPE_PP ( zcerts ) = = IS_ARRAY ) {
zend_hash_internal_pointer_reset_ex ( HASH_OF ( * zcerts ) , & hpos ) ;
while ( zend_hash_get_current_data_ex ( HASH_OF ( * zcerts ) , ( void * * ) & zcertval , & hpos ) = = SUCCESS ) {
cert = php_openssl_x509_from_zval ( zcertval , 0 , & certresource TSRMLS_CC ) ;
if ( cert = = NULL ) {
goto clean_exit ;
}
if ( certresource ! = - 1 ) {
cert = X509_dup ( cert ) ;
if ( cert = = NULL ) {
goto clean_exit ;
}
}
sk_X509_push ( sk , cert ) ;
zend_hash_move_forward_ex ( HASH_OF ( * zcerts ) , & hpos ) ;
}
} else {
/* a single certificate */
cert = php_openssl_x509_from_zval ( zcerts , 0 , & certresource TSRMLS_CC ) ;
if ( cert = = NULL ) {
goto clean_exit ;
}
if ( certresource ! = - 1 ) {
cert = X509_dup ( cert ) ;
if ( cert = = NULL ) {
goto clean_exit ;
}
}
sk_X509_push ( sk , cert ) ;
}
clean_exit :
return sk ;
}
/* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args])
Creates and exports a PKCS to file */
PHP_FUNCTION ( openssl_pkcs12_export_to_file )
{
X509 * cert = NULL ;
BIO * bio_out = NULL ;
PKCS12 * p12 = NULL ;
char * filename ;
char * friendly_name = NULL ;
int filename_len ;
char * pass ;
int pass_len ;
zval * zcert = NULL , * zpkey = NULL , * args = NULL ;
EVP_PKEY * priv_key = NULL ;
long certresource , keyresource ;
zval * * item ;
STACK_OF ( X509 ) * ca = NULL ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zszs|a " , & zcert , & filename , & filename_len , & zpkey , & pass , & pass_len , & args ) = = FAILURE )
return ;
RETVAL_FALSE ;
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get cert from parameter 1 " ) ;
return ;
}
priv_key = php_openssl_evp_from_zval ( & zpkey , 0 , " " , 1 , & keyresource TSRMLS_CC ) ;
if ( priv_key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get private key from parameter 3 " ) ;
goto cleanup ;
}
if ( cert & & ! X509_check_private_key ( cert , priv_key ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " private key does not correspond to cert " ) ;
goto cleanup ;
}
if ( php_openssl_safe_mode_chk ( filename TSRMLS_CC ) ) {
goto cleanup ;
}
/* parse extra config from args array, promote this to an extra function */
if ( args & & zend_hash_find ( Z_ARRVAL_P ( args ) , " friendly_name " , sizeof ( " friendly_name " ) , ( void * * ) & item ) = = SUCCESS )
friendly_name = Z_STRVAL_PP ( item ) ;
2007-04-05 06:00:51 +08:00
/* certpbe (default RC2-40)
keypbe ( default 3 DES )
friendly_caname
*/
2007-04-05 05:24:01 +08:00
if ( args & & zend_hash_find ( Z_ARRVAL_P ( args ) , " extracerts " , sizeof ( " extracerts " ) , ( void * * ) & item ) = = SUCCESS )
2007-04-05 15:10:07 +08:00
ca = php_array_to_X509_sk ( item TSRMLS_CC ) ;
2007-04-05 05:24:01 +08:00
/* end parse extra config */
2007-04-05 06:00:51 +08:00
/*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
int nid_key , int nid_cert , int iter , int mac_iter , int keytype ) ; */
2007-04-05 05:24:01 +08:00
p12 = PKCS12_create ( pass , friendly_name , priv_key , cert , ca , 0 , 0 , 0 , 0 , 0 ) ;
bio_out = BIO_new_file ( filename , " w " ) ;
if ( bio_out ) {
i2d_PKCS12_bio ( bio_out , p12 ) ;
RETVAL_TRUE ;
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " error opening file %s " , filename ) ;
}
BIO_free ( bio_out ) ;
PKCS12_free ( p12 ) ;
php_sk_X509_free ( ca ) ;
cleanup :
if ( keyresource = = - 1 & & priv_key ) {
EVP_PKEY_free ( priv_key ) ;
}
if ( certresource = = - 1 & & cert ) {
X509_free ( cert ) ;
}
}
/* }}} */
/* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
Creates and exports a PKCS12 to a var */
PHP_FUNCTION ( openssl_pkcs12_export )
{
X509 * cert = NULL ;
BIO * bio_out ;
PKCS12 * p12 = NULL ;
zval * zcert = NULL , * zout = NULL , * zpkey , * args = NULL ;
EVP_PKEY * priv_key = NULL ;
long certresource , keyresource ;
char * pass ;
int pass_len ;
char * friendly_name = NULL ;
zval * * item ;
STACK_OF ( X509 ) * ca = NULL ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " zzzs|a " , & zcert , & zout , & zpkey , & pass , & pass_len , & args ) = = FAILURE )
return ;
RETVAL_FALSE ;
cert = php_openssl_x509_from_zval ( & zcert , 0 , & certresource TSRMLS_CC ) ;
if ( cert = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get cert from parameter 1 " ) ;
return ;
}
priv_key = php_openssl_evp_from_zval ( & zpkey , 0 , " " , 1 , & keyresource TSRMLS_CC ) ;
if ( priv_key = = NULL ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot get private key from parameter 3 " ) ;
goto cleanup ;
}
if ( cert & & ! X509_check_private_key ( cert , priv_key ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " private key does not correspond to cert " ) ;
goto cleanup ;
}
/* parse extra config from args array, promote this to an extra function */
if ( args & & zend_hash_find ( Z_ARRVAL_P ( args ) , " friendly_name " , sizeof ( " friendly_name " ) , ( void * * ) & item ) = = SUCCESS )
friendly_name = Z_STRVAL_PP ( item ) ;
if ( args & & zend_hash_find ( Z_ARRVAL_P ( args ) , " extracerts " , sizeof ( " extracerts " ) , ( void * * ) & item ) = = SUCCESS )
2007-04-05 15:10:07 +08:00
ca = php_array_to_X509_sk ( item TSRMLS_CC ) ;
2007-04-05 05:24:01 +08:00
/* end parse extra config */
p12 = PKCS12_create ( pass , friendly_name , priv_key , cert , ca , 0 , 0 , 0 , 0 , 0 ) ;
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
if ( i2d_PKCS12_bio ( bio_out , p12 ) ) {
BUF_MEM * bio_buf ;
zval_dtor ( zout ) ;
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
ZVAL_STRINGL ( zout , bio_buf - > data , bio_buf - > length , 1 ) ;
RETVAL_TRUE ;
}
BIO_free ( bio_out ) ;
PKCS12_free ( p12 ) ;
php_sk_X509_free ( ca ) ;
cleanup :
if ( keyresource = = - 1 & & priv_key ) {
EVP_PKEY_free ( priv_key ) ;
}
if ( certresource = = - 1 & & cert ) {
X509_free ( cert ) ;
}
}
/* }}} */
2007-05-14 01:37:32 +08:00
/* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass)
2007-04-05 05:24:01 +08:00
Parses a PKCS12 to an array */
PHP_FUNCTION ( openssl_pkcs12_read )
{
2007-05-14 01:37:32 +08:00
zval * zout = NULL , * zextracerts , * zcert , * zpkey ;
char * pass , * zp12 ;
int pass_len , zp12_len ;
2007-04-05 05:24:01 +08:00
PKCS12 * p12 = NULL ;
EVP_PKEY * pkey = NULL ;
X509 * cert = NULL ;
STACK_OF ( X509 ) * ca = NULL ;
BIO * bio_in = NULL ;
int i ;
2007-05-14 01:37:32 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szs " , & zp12 , & zp12_len , & zout , & pass , & pass_len ) = = FAILURE )
2007-04-05 05:24:01 +08:00
return ;
RETVAL_FALSE ;
bio_in = BIO_new ( BIO_s_mem ( ) ) ;
2007-05-14 01:37:32 +08:00
if ( ! BIO_write ( bio_in , zp12 , zp12_len ) )
2007-04-05 05:24:01 +08:00
goto cleanup ;
if ( d2i_PKCS12_bio ( bio_in , & p12 ) ) {
if ( PKCS12_parse ( p12 , pass , & pkey , & cert , & ca ) ) {
2007-04-06 02:08:42 +08:00
BIO * bio_out ;
2007-04-05 05:24:01 +08:00
zval_dtor ( zout ) ;
array_init ( zout ) ;
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
if ( PEM_write_bio_X509 ( bio_out , cert ) ) {
BUF_MEM * bio_buf ;
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
MAKE_STD_ZVAL ( zcert ) ;
ZVAL_STRINGL ( zcert , bio_buf - > data , bio_buf - > length , 1 ) ;
add_assoc_zval ( zout , " cert " , zcert ) ;
}
BIO_free ( bio_out ) ;
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
if ( PEM_write_bio_PrivateKey ( bio_out , pkey , NULL , NULL , 0 , 0 , NULL ) ) {
BUF_MEM * bio_buf ;
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
MAKE_STD_ZVAL ( zpkey ) ;
ZVAL_STRINGL ( zpkey , bio_buf - > data , bio_buf - > length , 1 ) ;
add_assoc_zval ( zout , " pkey " , zpkey ) ;
}
BIO_free ( bio_out ) ;
MAKE_STD_ZVAL ( zextracerts ) ;
array_init ( zextracerts ) ;
for ( i = 0 ; ; i + + ) {
zval * zextracert ;
X509 * aCA = sk_X509_pop ( ca ) ;
if ( ! aCA ) break ;
bio_out = BIO_new ( BIO_s_mem ( ) ) ;
if ( PEM_write_bio_X509 ( bio_out , aCA ) ) {
BUF_MEM * bio_buf ;
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
MAKE_STD_ZVAL ( zextracert ) ;
ZVAL_STRINGL ( zextracert , bio_buf - > data , bio_buf - > length , 1 ) ;
add_index_zval ( zextracerts , i , zextracert ) ;
}
BIO_free ( bio_out ) ;
X509_free ( aCA ) ;
}
if ( ca ) {
sk_X509_free ( ca ) ;
add_assoc_zval ( zout , " extracerts " , zextracerts ) ;
} else {
zval_dtor ( zextracerts ) ;
}
RETVAL_TRUE ;
PKCS12_free ( p12 ) ;
}
}
cleanup :
if ( bio_in ) {
BIO_free ( bio_in ) ;
}
if ( pkey ) {
EVP_PKEY_free ( pkey ) ;
}
if ( cert ) {
X509_free ( cert ) ;
}
}
/* }}} */
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 ) {
2006-09-05 21:59:26 +08:00
char * strindex = NULL ;
uint strindexlen = 0 ;
2006-07-30 17:18:07 +08:00
ulong intindex ;
2001-09-11 07:57:10 +08:00
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 ;
2007-08-08 14:29:46 +08:00
char buffer [ 200 + 1 ] ; /*200 + \0 !*/
2001-09-11 07:57:10 +08:00
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 ;
}
2007-08-07 03:11:20 +08:00
if ( len > 200 ) {
len = 200 ;
}
2001-09-11 07:57:10 +08:00
memcpy ( buffer , type , len ) ;
2007-08-08 14:29:46 +08:00
buffer [ len ] = ' \0 ' ;
2001-09-11 07:57:10 +08:00
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 ) {
2006-07-30 17:18:07 +08:00
char * strindex ; uint strindexlen ;
ulong intindex ;
2001-09-11 07:57:10 +08:00
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 ;
2006-07-31 08:33:42 +08:00
2001-09-11 08:33:25 +08:00
long csr_resource ;
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
2006-07-31 08:33:42 +08:00
if ( PEM_write_bio_X509_REQ ( bio_out , csr ) ) {
BUF_MEM * bio_buf ;
2001-09-11 08:33:25 +08:00
2006-07-31 08:33:42 +08:00
BIO_get_mem_ptr ( bio_out , & bio_buf ) ;
zval_dtor ( zout ) ;
ZVAL_STRINGL ( zout , bio_buf - > data , bio_buf - > length , 1 ) ;
RETVAL_TRUE ;
}
2001-09-11 08:33:25 +08:00
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
{
2006-08-31 21:48:17 +08:00
zval * * zcert = NULL , * * zcsr , * * zpkey , * args = NULL ;
2001-09-11 07:57:10 +08:00
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 ;
2008-04-02 22:35:29 +08:00
long csr_resource , certresource = 0 , keyresource ;
2001-09-11 07:57:10 +08:00
int i ;
struct php_x509_request req ;
2006-08-31 21:48:17 +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 ) ;
2006-08-31 21:48:17 +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 ;
}
2002-12-11 06:18:58 +08:00
if ( zcert ) {
2006-08-31 21:48:17 +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 ;
}
}
2006-08-31 21:48:17 +08:00
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
}
2006-07-31 08:33:42 +08:00
if ( req . 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 ) ;
2006-07-31 08:33:42 +08:00
if ( ! X509V3_EXT_add_conf ( req . req_config , & ctx , req . 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
2008-05-05 05:17:33 +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 */
2006-09-07 22:11:06 +08:00
zval_dtor ( out_pkey ) ;
2001-09-11 07:57:10 +08:00
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
2006-08-16 04:27:22 +08:00
/* {{{ proto mixed openssl_csr_get_subject(mixed csr)
Returns the subject of a CERT or FALSE on error */
PHP_FUNCTION ( openssl_csr_get_subject )
{
2006-08-31 21:48:17 +08:00
zval * * zcsr ;
2006-08-16 04:27:22 +08:00
zend_bool use_shortnames = 1 ;
long csr_resource ;
X509_NAME * subject ;
X509_REQ * csr ;
2006-08-31 21:48:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " Z|b " , & zcsr , & use_shortnames ) = = FAILURE ) {
2006-08-16 04:27:22 +08:00
return ;
}
2006-08-31 21:48:17 +08:00
csr = php_openssl_csr_from_zval ( zcsr , 0 , & csr_resource TSRMLS_CC ) ;
2006-08-16 04:27:22 +08:00
if ( csr = = NULL ) {
RETURN_FALSE ;
}
subject = X509_REQ_get_subject_name ( csr ) ;
array_init ( return_value ) ;
add_assoc_name_entry ( return_value , NULL , subject , use_shortnames TSRMLS_CC ) ;
return ;
}
/* }}} */
/* {{{ proto mixed openssl_csr_get_public_key(mixed csr)
Returns the subject of a CERT or FALSE on error */
PHP_FUNCTION ( openssl_csr_get_public_key )
{
2006-08-31 21:48:17 +08:00
zval * * zcsr ;
2006-08-16 04:27:22 +08:00
zend_bool use_shortnames = 1 ;
long csr_resource ;
X509_REQ * csr ;
EVP_PKEY * tpubkey ;
2006-08-31 21:48:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " Z|b " , & zcsr , & use_shortnames ) = = FAILURE ) {
2006-08-16 04:27:22 +08:00
return ;
}
2006-08-31 21:48:17 +08:00
csr = php_openssl_csr_from_zval ( zcsr , 0 , & csr_resource TSRMLS_CC ) ;
2006-08-16 04:27:22 +08:00
if ( csr = = NULL ) {
RETURN_FALSE ;
}
tpubkey = X509_REQ_get_pubkey ( csr ) ;
RETVAL_RESOURCE ( zend_list_insert ( tpubkey , le_key ) ) ;
return ;
}
/* }}} */
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 ;
2006-09-07 22:11:06 +08:00
zval tmp ;
Z_TYPE ( tmp ) = IS_NULL ;
# define TMP_CLEAN \
if ( Z_TYPE ( tmp ) = = IS_STRING ) { \
zval_dtor ( & tmp ) ; \
2006-10-09 08:04:11 +08:00
} \
return NULL ;
2006-09-07 22:11:06 +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 ;
}
2006-09-12 18:54:01 +08:00
2006-09-07 22:11:06 +08:00
if ( Z_TYPE_PP ( zphrase ) = = IS_STRING ) {
passphrase = Z_STRVAL_PP ( zphrase ) ;
} else {
tmp = * * zphrase ;
zval_copy_ctor ( & tmp ) ;
2007-07-11 15:26:52 +08:00
convert_to_string ( & tmp ) ;
2006-09-07 22:11:06 +08:00
passphrase = Z_STRVAL ( tmp ) ;
}
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) " ) ;
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
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 ( 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 ) {
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
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 " ) ;
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
2002-12-12 21:42:23 +08:00
}
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 " ) ;
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
2003-09-24 00:05:52 +08:00
} else {
2006-09-07 22:11:06 +08:00
if ( Z_TYPE ( tmp ) = = IS_STRING ) {
zval_dtor ( & tmp ) ;
}
2003-09-24 00:05:52 +08:00
/* got the key - return it */
return ( EVP_PKEY * ) what ;
}
2007-01-21 06:08:29 +08:00
} else {
/* other types could be used here - eg: file pointers and read in the data from them */
TMP_CLEAN ;
2001-09-11 07:57:10 +08:00
}
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 07:03:56 +08:00
/* passing non string values leaks, object uses toString, it returns NULL
* See bug38255 . phpt
*/
if ( ! ( Z_TYPE_PP ( val ) = = IS_STRING | | Z_TYPE_PP ( val ) = = IS_OBJECT ) ) {
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
2006-07-30 06:10:50 +08:00
}
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 ) {
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
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 ) ) {
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
2002-11-10 13:19:40 +08:00
}
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 ) {
2006-09-07 22:11:06 +08:00
TMP_CLEAN ;
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
}
2006-09-07 22:11:06 +08:00
if ( Z_TYPE ( tmp ) = = IS_STRING ) {
zval_dtor ( & tmp ) ;
}
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 :
2006-09-09 04:10:47 +08:00
if ( EVP_PKEY_assign_RSA ( req - > priv_key , RSA_generate_key ( req - > priv_key_bits , 0x10001 , NULL , NULL ) ) ) {
2001-09-11 07:57:10 +08:00
return_val = req - > priv_key ;
2006-09-09 04:10:47 +08:00
}
break ;
2007-01-08 02:38:22 +08:00
# if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD)
2006-09-09 04:10:47 +08:00
case OPENSSL_KEYTYPE_DSA :
{
DSA * dsapar = DSA_generate_parameters ( req - > priv_key_bits , NULL , 0 , NULL , NULL , NULL , NULL ) ;
if ( dsapar ) {
DSA_set_method ( dsapar , DSA_get_default_method ( ) ) ;
if ( DSA_generate_key ( dsapar ) ) {
if ( EVP_PKEY_assign_DSA ( req - > priv_key , dsapar ) ) {
return_val = req - > priv_key ;
}
} else {
DSA_free ( dsapar ) ;
}
}
}
2001-09-11 07:57:10 +08:00
break ;
2007-09-27 16:46:00 +08:00
# endif
# if !defined(NO_DH)
case OPENSSL_KEYTYPE_DH :
{
DH * dhpar = DH_generate_parameters ( req - > priv_key_bits , 2 , NULL , NULL ) ;
int codes = 0 ;
if ( dhpar ) {
DH_set_method ( dhpar , DH_get_default_method ( ) ) ;
if ( DH_check ( dhpar , & codes ) & & codes = = 0 & & DH_generate_key ( dhpar ) ) {
if ( EVP_PKEY_assign_DH ( req - > priv_key , dhpar ) ) {
return_val = req - > priv_key ;
}
} else {
DH_free ( dhpar ) ;
}
}
}
break ;
2006-09-09 04:10:47 +08:00
# endif
2001-09-11 07:57:10 +08:00
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 ;
}
/* }}} */
2007-09-27 16:46:00 +08:00
# define OPENSSL_PKEY_GET_BN(_type, _name) do { \
if ( pkey - > pkey . _type - > _name ! = NULL ) { \
int len = BN_num_bytes ( pkey - > pkey . _type - > _name ) ; \
char * str = emalloc ( len + 1 ) ; \
BN_bn2bin ( pkey - > pkey . _type - > _name , ( unsigned char * ) str ) ; \
str [ len ] = 0 ; \
add_assoc_stringl ( _type , # _name , str , len , 0 ) ; \
} \
} while ( 0 )
# define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \
zval * * bn ; \
if ( zend_hash_find ( _ht , # _name , sizeof ( # _name ) , ( void * * ) & bn ) = = SUCCESS & & \
Z_TYPE_PP ( bn ) = = IS_STRING ) { \
_type - > _name = BN_bin2bn ( \
( unsigned char * ) Z_STRVAL_PP ( bn ) , \
Z_STRLEN_PP ( bn ) , NULL ) ; \
} \
} while ( 0 ) ;
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 ;
2007-09-27 16:46:00 +08:00
zval * * data ;
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 ;
2007-09-27 16:46:00 +08:00
if ( args & & Z_TYPE_P ( args ) = = IS_ARRAY ) {
EVP_PKEY * pkey ;
if ( zend_hash_find ( Z_ARRVAL_P ( args ) , " rsa " , sizeof ( " rsa " ) , ( void * * ) & data ) = = SUCCESS & &
Z_TYPE_PP ( data ) = = IS_ARRAY ) {
pkey = EVP_PKEY_new ( ) ;
if ( pkey ) {
RSA * rsa = RSA_new ( ) ;
if ( rsa ) {
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , n ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , e ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , d ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , p ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , q ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , dmp1 ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , dmq1 ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , rsa , iqmp ) ;
if ( EVP_PKEY_assign_RSA ( pkey , rsa ) ) {
RETURN_RESOURCE ( zend_list_insert ( pkey , le_key ) ) ;
}
RSA_free ( rsa ) ;
}
EVP_PKEY_free ( pkey ) ;
}
RETURN_FALSE ;
} else if ( zend_hash_find ( Z_ARRVAL_P ( args ) , " dsa " , sizeof ( " dsa " ) , ( void * * ) & data ) = = SUCCESS & &
Z_TYPE_PP ( data ) = = IS_ARRAY ) {
pkey = EVP_PKEY_new ( ) ;
if ( pkey ) {
DSA * dsa = DSA_new ( ) ;
if ( dsa ) {
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dsa , p ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dsa , q ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dsa , g ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dsa , priv_key ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dsa , pub_key ) ;
if ( ! dsa - > priv_key & & ! dsa - > pub_key ) {
DSA_generate_key ( dsa ) ;
}
if ( EVP_PKEY_assign_DSA ( pkey , dsa ) ) {
RETURN_RESOURCE ( zend_list_insert ( pkey , le_key ) ) ;
}
DSA_free ( dsa ) ;
}
EVP_PKEY_free ( pkey ) ;
}
RETURN_FALSE ;
} else if ( zend_hash_find ( Z_ARRVAL_P ( args ) , " dh " , sizeof ( " dh " ) , ( void * * ) & data ) = = SUCCESS & &
Z_TYPE_PP ( data ) = = IS_ARRAY ) {
pkey = EVP_PKEY_new ( ) ;
if ( pkey ) {
DH * dh = DH_new ( ) ;
if ( dh ) {
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dh , p ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dh , g ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dh , priv_key ) ;
OPENSSL_PKEY_SET_BN ( Z_ARRVAL_PP ( data ) , dh , pub_key ) ;
if ( ! dh - > pub_key ) {
DH_generate_key ( dh ) ;
}
if ( EVP_PKEY_assign_DH ( pkey , dh ) ) {
RETURN_RESOURCE ( zend_list_insert ( pkey , le_key ) ) ;
}
DH_free ( dh ) ;
}
EVP_PKEY_free ( pkey ) ;
}
RETURN_FALSE ;
}
}
2001-09-11 07:57:10 +08:00
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 ;
2006-08-31 21:48:17 +08:00
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
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +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
}
2006-07-30 17:18:07 +08:00
if ( PEM_write_bio_PrivateKey ( bio_out , key , cipher , ( unsigned char * ) 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 ;
2006-08-31 21:48:17 +08:00
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
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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
}
2006-07-30 17:18:07 +08:00
if ( PEM_write_bio_PrivateKey ( bio_out , key , cipher , ( unsigned char * ) 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 ) ;
2007-07-11 15:36:12 +08:00
zval_dtor ( out ) ;
2001-09-11 08:33:25 +08:00
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
{
2006-08-31 21:48:17 +08:00
zval * * cert ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +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
{
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +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
/* }}} */
2006-08-15 08:38:05 +08:00
/* {{{ proto resource openssl_pkey_get_details(resource key)
returns an array with the key details ( bits , pkey , type ) */
PHP_FUNCTION ( openssl_pkey_get_details )
{
zval * key ;
EVP_PKEY * pkey ;
BIO * out ;
unsigned int pbio_len ;
char * pbio ;
long ktype ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " r " , & key ) = = FAILURE ) {
return ;
}
ZEND_FETCH_RESOURCE ( pkey , EVP_PKEY * , & key , - 1 , " OpenSSL key " , le_key ) ;
if ( ! pkey ) {
RETURN_FALSE ;
}
out = BIO_new ( BIO_s_mem ( ) ) ;
PEM_write_bio_PUBKEY ( out , pkey ) ;
pbio_len = BIO_get_mem_data ( out , & pbio ) ;
array_init ( return_value ) ;
add_assoc_long ( return_value , " bits " , EVP_PKEY_bits ( pkey ) ) ;
add_assoc_stringl ( return_value , " key " , pbio , pbio_len , 1 ) ;
/*TODO: Use the real values once the openssl constants are used
* See the enum at the top of this file
*/
switch ( EVP_PKEY_type ( pkey - > type ) ) {
case EVP_PKEY_RSA :
case EVP_PKEY_RSA2 :
ktype = OPENSSL_KEYTYPE_RSA ;
2007-09-27 16:46:00 +08:00
if ( pkey - > pkey . rsa ! = NULL ) {
zval * rsa ;
ALLOC_INIT_ZVAL ( rsa ) ;
array_init ( rsa ) ;
OPENSSL_PKEY_GET_BN ( rsa , n ) ;
OPENSSL_PKEY_GET_BN ( rsa , e ) ;
OPENSSL_PKEY_GET_BN ( rsa , d ) ;
OPENSSL_PKEY_GET_BN ( rsa , p ) ;
OPENSSL_PKEY_GET_BN ( rsa , q ) ;
OPENSSL_PKEY_GET_BN ( rsa , dmp1 ) ;
OPENSSL_PKEY_GET_BN ( rsa , dmq1 ) ;
OPENSSL_PKEY_GET_BN ( rsa , iqmp ) ;
add_assoc_zval ( return_value , " rsa " , rsa ) ;
}
2006-08-15 08:38:05 +08:00
break ;
case EVP_PKEY_DSA :
case EVP_PKEY_DSA2 :
case EVP_PKEY_DSA3 :
case EVP_PKEY_DSA4 :
ktype = OPENSSL_KEYTYPE_DSA ;
2007-09-27 16:46:00 +08:00
if ( pkey - > pkey . dsa ! = NULL ) {
zval * dsa ;
ALLOC_INIT_ZVAL ( dsa ) ;
array_init ( dsa ) ;
OPENSSL_PKEY_GET_BN ( dsa , p ) ;
OPENSSL_PKEY_GET_BN ( dsa , q ) ;
OPENSSL_PKEY_GET_BN ( dsa , g ) ;
OPENSSL_PKEY_GET_BN ( dsa , priv_key ) ;
OPENSSL_PKEY_GET_BN ( dsa , pub_key ) ;
add_assoc_zval ( return_value , " dsa " , dsa ) ;
}
2006-08-15 08:38:05 +08:00
break ;
case EVP_PKEY_DH :
2007-09-27 16:46:00 +08:00
2006-08-15 08:38:05 +08:00
ktype = OPENSSL_KEYTYPE_DH ;
2007-09-27 16:46:00 +08:00
if ( pkey - > pkey . dh ! = NULL ) {
zval * dh ;
ALLOC_INIT_ZVAL ( dh ) ;
array_init ( dh ) ;
OPENSSL_PKEY_GET_BN ( dh , p ) ;
OPENSSL_PKEY_GET_BN ( dh , g ) ;
OPENSSL_PKEY_GET_BN ( dh , priv_key ) ;
OPENSSL_PKEY_GET_BN ( dh , pub_key ) ;
add_assoc_zval ( return_value , " dh " , dh ) ;
}
2006-08-15 08:38:05 +08:00
break ;
2006-08-18 21:02:38 +08:00
# ifdef EVP_PKEY_EC
2006-08-15 08:38:05 +08:00
case EVP_PKEY_EC :
ktype = OPENSSL_KEYTYPE_EC ;
break ;
2006-08-18 21:02:38 +08:00
# endif
2006-08-15 08:38:05 +08:00
default :
ktype = - 1 ;
break ;
}
add_assoc_long ( return_value , " type " , ktype ) ;
BIO_free ( out ) ;
}
/* }}} */
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
{
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ssZa!|ll " , & infilename , & infilename_len ,
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
& 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 */
2006-08-31 21:48:17 +08:00
if ( Z_TYPE_PP ( zrecipcerts ) = = IS_ARRAY ) {
zend_hash_internal_pointer_reset_ex ( HASH_OF ( * zrecipcerts ) , & hpos ) ;
while ( zend_hash_get_current_data_ex ( HASH_OF ( * zrecipcerts ) , ( void * * ) & zcertval , & hpos ) = = SUCCESS ) {
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 ) ;
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +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 */
2007-09-27 16:46:00 +08:00
cipher = php_openssl_get_evp_cipher_from_algo ( cipherid ) ;
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 )
{
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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
}
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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 )
{
2006-08-31 21:48:17 +08:00
zval * * recipcert , * * recipkey = NULL ;
2001-09-11 07:57:10 +08:00
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
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +08:00
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 ;
}
2006-08-31 21:48:17 +08:00
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
}
/* }}} */
/* }}} */
2008-06-02 01:54:02 +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 )
{
2006-08-31 21:48:17 +08:00
zval * * key , * crypted ;
2001-09-11 07:57:10 +08:00
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
2006-08-31 21:48:17 +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 ;
2006-08-31 21:48:17 +08:00
pkey = php_openssl_evp_from_zval ( key , 0 , " " , 0 , & keyresource TSRMLS_CC ) ;
2001-09-11 07:57:10 +08:00
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 ,
2006-07-30 17:18:07 +08:00
( unsigned char * ) data ,
2001-09-11 07:57:10 +08:00
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 ' ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( crypted , ( char * ) cryptedbuf , cryptedlen , 0 ) ;
2001-09-11 07:57:10 +08:00
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
}
/* }}} */
2008-06-02 01:54:02 +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 )
{
2006-08-31 21:48:17 +08:00
zval * * key , * crypted ;
2001-09-11 07:57:10 +08:00
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
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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 ,
2006-07-30 17:18:07 +08:00
( unsigned char * ) data ,
2001-09-11 07:57:10 +08:00
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 ' ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( crypted , ( char * ) cryptedbuf , cryptedlen , 0 ) ;
2001-09-11 07:57:10 +08:00
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
2008-06-02 01:54:02 +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 )
{
2006-08-31 21:48:17 +08:00
zval * * key , * crypted ;
2001-09-11 07:57:10 +08:00
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
2006-08-31 21:48:17 +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 ;
2001-04-02 07:06:15 +08:00
2001-09-11 07:57:10 +08:00
RETVAL_FALSE ;
2006-08-31 21:48:17 +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 ) ;
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 ,
2006-07-30 17:18:07 +08:00
( unsigned char * ) data ,
2001-09-11 07:57:10 +08:00
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 ' ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( crypted , ( char * ) cryptedbuf , cryptedlen , 0 ) ;
2001-09-11 07:57:10 +08:00
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
}
/* }}} */
2008-06-02 01:54:02 +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
{
2006-08-31 21:48:17 +08:00
zval * * key , * crypted ;
2001-09-11 07:57:10 +08:00
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
2006-08-31 21:48:17 +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
2006-08-31 21:48:17 +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 ,
2006-07-30 17:18:07 +08:00
( unsigned char * ) data ,
2001-09-11 07:57:10 +08:00
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 ' ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( crypted , ( char * ) cryptedbuf , cryptedlen , 0 ) ;
2001-09-11 07:57:10 +08:00
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
2008-03-11 06:15:36 +08:00
if ( zend_parse_parameters_none ( ) = = FAILURE ) {
return ;
2001-09-11 07:57:10 +08:00
}
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
}
/* }}} */
2007-09-27 16:46:00 +08:00
/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
2001-09-11 09:03:59 +08:00
Signs data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_sign )
{
2006-08-31 21:48:17 +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 ;
2007-09-27 16:46:00 +08:00
zval * method = NULL ;
2003-03-31 06:25:23 +08:00
long signature_algo = OPENSSL_ALGO_SHA1 ;
2007-09-27 16:46:00 +08:00
const EVP_MD * mdtype ;
2000-11-14 03:47:20 +08:00
2007-09-27 16:46:00 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szZ|z " , & data , & data_len , & signature , & key , & method ) = = FAILURE ) {
2001-09-08 01:09:56 +08:00
return ;
2003-01-05 07:31:55 +08:00
}
2006-08-31 21:48:17 +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 ;
}
2007-09-27 16:46:00 +08:00
if ( method = = NULL | | Z_TYPE_P ( method ) = = IS_LONG ) {
2008-01-10 00:47:25 +08:00
if ( method ! = NULL ) {
2007-09-27 16:46:00 +08:00
signature_algo = Z_LVAL_P ( method ) ;
}
mdtype = php_openssl_get_evp_md_from_algo ( signature_algo ) ;
} else if ( Z_TYPE_P ( method ) = = IS_STRING ) {
mdtype = EVP_get_digestbyname ( Z_STRVAL_P ( method ) ) ;
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
2006-07-30 06:10:50 +08:00
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 ) ;
2006-07-30 17:18:07 +08:00
if ( EVP_SignFinal ( & md_ctx , sigbuf , ( unsigned int * ) & siglen , pkey ) ) {
2001-09-08 01:09:56 +08:00
zval_dtor ( signature ) ;
2000-11-14 03:47:20 +08:00
sigbuf [ siglen ] = ' \0 ' ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( signature , ( char * ) 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
}
2008-01-15 23:12:47 +08:00
EVP_MD_CTX_cleanup ( & md_ctx ) ;
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
}
/* }}} */
2007-09-27 16:46:00 +08:00
/* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
2001-09-11 09:03:59 +08:00
Verifys data */
2000-11-14 03:47:20 +08:00
PHP_FUNCTION ( openssl_verify )
{
2006-08-31 21:48:17 +08:00
zval * * key ;
2000-11-14 03:47:20 +08:00
EVP_PKEY * pkey ;
int err ;
EVP_MD_CTX md_ctx ;
2007-09-27 16:46:00 +08:00
const 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 ;
2007-09-27 16:46:00 +08:00
zval * method = NULL ;
2006-07-30 06:10:50 +08:00
long signature_algo = OPENSSL_ALGO_SHA1 ;
2007-09-27 16:46:00 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ssZ|z " , & data , & data_len , & signature , & signature_len , & key , & method ) = = 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
2007-09-27 16:46:00 +08:00
if ( method = = NULL | | Z_TYPE_P ( method ) = = IS_LONG ) {
2008-01-10 00:47:25 +08:00
if ( method ! = NULL ) {
2007-09-27 16:46:00 +08:00
signature_algo = Z_LVAL_P ( method ) ;
}
mdtype = php_openssl_get_evp_md_from_algo ( signature_algo ) ;
} else if ( Z_TYPE_P ( method ) = = IS_STRING ) {
mdtype = EVP_get_digestbyname ( Z_STRVAL_P ( method ) ) ;
} else {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
2006-07-30 06:10:50 +08:00
if ( ! mdtype ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
2006-08-31 21:48:17 +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 ) ;
2006-07-30 17:18:07 +08:00
err = EVP_VerifyFinal ( & md_ctx , ( unsigned char * ) signature , signature_len , pkey ) ;
2008-01-15 23:12:47 +08:00
EVP_MD_CTX_cleanup ( & md_ctx ) ;
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 ;
2007-09-27 16:46:00 +08:00
char * method = NULL ;
int method_len ;
const EVP_CIPHER * cipher ;
2000-11-14 03:47:20 +08:00
EVP_CIPHER_CTX ctx ;
2007-09-27 16:46:00 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szza/|s " , & data , & data_len , & sealdata , & ekeys , & pubkeys , & method , & method_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
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
}
2007-09-27 16:46:00 +08:00
if ( method ) {
cipher = EVP_get_cipherbyname ( method ) ;
if ( ! cipher ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
} else {
cipher = EVP_rc4 ( ) ;
}
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 ) ;
2006-08-31 04:50:04 +08:00
memset ( eks , 0 , sizeof ( * eks ) * nkeys ) ;
2003-04-29 06:42:22 +08:00
key_resources = safe_emalloc ( nkeys , sizeof ( long ) , 0 ) ;
2006-08-31 04:50:04 +08:00
memset ( key_resources , 0 , sizeof ( * key_resources ) * nkeys ) ;
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 + + ;
}
2007-09-27 16:46:00 +08:00
if ( ! EVP_EncryptInit ( & ctx , cipher , 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
2007-09-27 16:46:00 +08:00
if ( ! EVP_SealInit ( & ctx , cipher , eks , eksl , NULL , pkeys , nkeys ) | | ! EVP_SealUpdate ( & ctx , buf , & len1 , ( unsigned char * ) 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 ) ;
2006-07-30 17:18:07 +08:00
ZVAL_STRINGL ( sealdata , ( char * ) 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 )
{
2006-08-31 21:48:17 +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 ;
2007-09-27 16:46:00 +08:00
char * method = NULL ;
int method_len ;
const EVP_CIPHER * cipher ;
2000-11-14 03:47:20 +08:00
2007-09-27 16:46:00 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " szsZ|s " , & data , & data_len , & opendata , & ekey , & ekey_len , & privkey , & method , & method_len ) = = 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
2006-08-31 21:48:17 +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 ;
}
2007-09-27 16:46:00 +08:00
if ( method ) {
cipher = EVP_get_cipherbyname ( method ) ;
if ( ! cipher ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm. " ) ;
RETURN_FALSE ;
}
} else {
cipher = EVP_rc4 ( ) ;
}
2001-09-08 01:09:56 +08:00
buf = emalloc ( data_len + 1 ) ;
2000-11-14 03:47:20 +08:00
2007-09-27 16:46:00 +08:00
if ( EVP_OpenInit ( & ctx , cipher , ( unsigned char * ) ekey , ekey_len , NULL , pkey ) & & EVP_OpenUpdate ( & ctx , buf , & len1 , ( unsigned char * ) data , data_len ) ) {
2003-01-05 07:31:55 +08:00
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
2007-09-27 16:46:00 +08:00
static void openssl_add_method_or_alias ( const OBJ_NAME * name , void * arg ) /* { { { */
{
add_next_index_string ( ( zval * ) arg , ( char * ) name - > name , 1 ) ;
}
/* }}} */
static void openssl_add_method ( const OBJ_NAME * name , void * arg ) /* { { { */
{
if ( name - > alias = = 0 ) {
add_next_index_string ( ( zval * ) arg , ( char * ) name - > name , 1 ) ;
}
}
/* }}} */
/* {{{ proto array openssl_get_md_methods([bool aliases = false])
Return array of available digest methods */
PHP_FUNCTION ( openssl_get_md_methods )
{
zend_bool aliases = 0 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |b " , & aliases ) = = FAILURE ) {
return ;
}
array_init ( return_value ) ;
OBJ_NAME_do_all_sorted ( OBJ_NAME_TYPE_MD_METH ,
aliases ? openssl_add_method_or_alias : openssl_add_method ,
return_value ) ;
}
/* }}} */
/* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
Return array of available cipher methods */
PHP_FUNCTION ( openssl_get_cipher_methods )
{
zend_bool aliases = 0 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |b " , & aliases ) = = FAILURE ) {
return ;
}
array_init ( return_value ) ;
OBJ_NAME_do_all_sorted ( OBJ_NAME_TYPE_CIPHER_METH ,
aliases ? openssl_add_method_or_alias : openssl_add_method ,
return_value ) ;
}
/* }}} */
/* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
Computes digest hash value for given data using given method , returns raw or binhex encoded string */
PHP_FUNCTION ( openssl_digest )
{
zend_bool raw_output = 0 ;
char * data , * method ;
int data_len , method_len ;
const EVP_MD * mdtype ;
EVP_MD_CTX md_ctx ;
int siglen ;
unsigned char * sigbuf ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ss|b " , & data , & data_len , & method , & method_len , & raw_output ) = = FAILURE ) {
return ;
}
mdtype = EVP_get_digestbyname ( method ) ;
if ( ! mdtype ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown signature algorithm " ) ;
RETURN_FALSE ;
}
siglen = EVP_MD_size ( mdtype ) ;
sigbuf = emalloc ( siglen + 1 ) ;
EVP_DigestInit ( & md_ctx , mdtype ) ;
EVP_DigestUpdate ( & md_ctx , ( unsigned char * ) data , data_len ) ;
if ( EVP_DigestFinal ( & md_ctx , ( unsigned char * ) sigbuf , ( unsigned int * ) & siglen ) ) {
if ( raw_output ) {
sigbuf [ siglen ] = ' \0 ' ;
RETVAL_STRINGL ( ( char * ) sigbuf , siglen , 0 ) ;
} else {
int digest_str_len = siglen * 2 ;
char * digest_str = emalloc ( digest_str_len + 1 ) ;
make_digest_ex ( digest_str , sigbuf , siglen ) ;
efree ( sigbuf ) ;
RETVAL_STRINGL ( digest_str , digest_str_len , 0 ) ;
}
} else {
efree ( sigbuf ) ;
RETVAL_FALSE ;
}
}
/* }}} */
/* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false])
Encrypts given data with given method and key , returns raw or base64 encoded string */
PHP_FUNCTION ( openssl_encrypt )
{
zend_bool raw_output = 0 ;
char * data , * method , * password ;
int data_len , method_len , password_len ;
const EVP_CIPHER * cipher_type ;
EVP_CIPHER_CTX cipher_ctx ;
int i , outlen , keylen , ivlen ;
unsigned char * outbuf , * key , * iv ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " sss|b " , & data , & data_len , & method , & method_len , & password , & password_len , & raw_output ) = = FAILURE ) {
return ;
}
cipher_type = EVP_get_cipherbyname ( method ) ;
if ( ! cipher_type ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown cipher algorithm " ) ;
RETURN_FALSE ;
}
keylen = EVP_CIPHER_key_length ( cipher_type ) ;
if ( keylen > password_len ) {
key = emalloc ( keylen ) ;
memset ( key , 0 , keylen ) ;
memcpy ( key , password , password_len ) ;
} else {
key = ( unsigned char * ) password ;
}
ivlen = EVP_CIPHER_iv_length ( cipher_type ) ;
iv = emalloc ( ivlen ) ;
memset ( iv , 0 , ivlen ) ;
outlen = data_len + EVP_CIPHER_block_size ( cipher_type ) ;
outbuf = emalloc ( outlen + 1 ) ;
EVP_EncryptInit ( & cipher_ctx , cipher_type , key , iv ) ;
EVP_EncryptUpdate ( & cipher_ctx , outbuf , & i , ( unsigned char * ) data , data_len ) ;
outlen = i ;
if ( EVP_EncryptFinal ( & cipher_ctx , ( unsigned char * ) outbuf + i , & i ) ) {
outlen + = i ;
if ( raw_output ) {
outbuf [ outlen ] = ' \0 ' ;
RETVAL_STRINGL ( ( char * ) outbuf , outlen , 0 ) ;
} else {
int base64_str_len ;
char * base64_str ;
base64_str = ( char * ) php_base64_encode ( outbuf , outlen , & base64_str_len ) ;
efree ( outbuf ) ;
RETVAL_STRINGL ( base64_str , base64_str_len , 0 ) ;
}
} else {
efree ( outbuf ) ;
RETVAL_FALSE ;
}
if ( key ! = ( unsigned char * ) password ) {
efree ( key ) ;
}
efree ( iv ) ;
}
/* }}} */
/* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false])
Takes raw or base64 encoded string and dectupt it using given method and key */
PHP_FUNCTION ( openssl_decrypt )
{
zend_bool raw_input = 0 ;
char * data , * method , * password ;
int data_len , method_len , password_len ;
const EVP_CIPHER * cipher_type ;
EVP_CIPHER_CTX cipher_ctx ;
int i , outlen , keylen , ivlen ;
unsigned char * outbuf , * key , * iv ;
int base64_str_len ;
char * base64_str = NULL ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " sss|b " , & data , & data_len , & method , & method_len , & password , & password_len , & raw_input ) = = FAILURE ) {
return ;
}
if ( ! raw_input ) {
base64_str = ( char * ) php_base64_decode ( ( unsigned char * ) data , data_len , & base64_str_len ) ;
data_len = base64_str_len ;
data = base64_str ;
}
cipher_type = EVP_get_cipherbyname ( method ) ;
if ( ! cipher_type ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Unknown cipher algorithm " ) ;
RETURN_FALSE ;
}
keylen = EVP_CIPHER_key_length ( cipher_type ) ;
if ( keylen > password_len ) {
key = emalloc ( keylen ) ;
memset ( key , 0 , keylen ) ;
memcpy ( key , password , password_len ) ;
} else {
key = ( unsigned char * ) password ;
}
ivlen = EVP_CIPHER_iv_length ( cipher_type ) ;
iv = emalloc ( ivlen ) ;
memset ( iv , 0 , ivlen ) ;
outlen = data_len + EVP_CIPHER_block_size ( cipher_type ) ;
outbuf = emalloc ( outlen + 1 ) ;
EVP_DecryptInit ( & cipher_ctx , cipher_type , key , iv ) ;
EVP_DecryptUpdate ( & cipher_ctx , outbuf , & i , ( unsigned char * ) data , data_len ) ;
outlen = i ;
if ( EVP_DecryptFinal ( & cipher_ctx , ( unsigned char * ) outbuf + i , & i ) ) {
outlen + = i ;
outbuf [ outlen ] = ' \0 ' ;
RETVAL_STRINGL ( ( char * ) outbuf , outlen , 0 ) ;
} else {
efree ( outbuf ) ;
RETVAL_FALSE ;
}
if ( key ! = ( unsigned char * ) password ) {
efree ( key ) ;
}
efree ( iv ) ;
if ( base64_str ) {
efree ( base64_str ) ;
}
}
/* }}} */
/* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
Computes shared sicret for public value of remote DH key and local DH key */
PHP_FUNCTION ( openssl_dh_compute_key )
{
zval * key ;
char * pub_str ;
int pub_len ;
EVP_PKEY * pkey ;
BIGNUM * pub ;
char * data ;
int len ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " sr " , & pub_str , & pub_len , & key ) = = FAILURE ) {
return ;
}
ZEND_FETCH_RESOURCE ( pkey , EVP_PKEY * , & key , - 1 , " OpenSSL key " , le_key ) ;
if ( ! pkey | | EVP_PKEY_type ( pkey - > type ) ! = EVP_PKEY_DH | | ! pkey - > pkey . dh ) {
RETURN_FALSE ;
}
pub = BN_bin2bn ( ( unsigned char * ) pub_str , pub_len , NULL ) ;
data = emalloc ( DH_size ( pkey - > pkey . dh ) + 1 ) ;
len = DH_compute_key ( ( unsigned char * ) data , pub , pkey - > pkey . dh ) ;
if ( len > = 0 ) {
data [ len ] = 0 ;
RETVAL_STRINGL ( data , len , 0 ) ;
} else {
efree ( data ) ;
RETVAL_FALSE ;
}
BN_free ( pub ) ;
}
/* }}} */
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
*/