PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - openssl - openssl.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 1856
Code covered: 43.4 % Executed lines: 806
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Stig Venaas <venaas@php.net>                                |
      16                 :    |          Wez Furlong <wez@thebrainroom.com>                          |
      17                 :    |          Sascha Kettler <kettler@gmx.net>                            |
      18                 :    |          Pierre-Alain Joye <pierre@php.net>                          |
      19                 :    |          Marc Delling <delling@silpion.de> (PKCS12 functions)        |               
      20                 :    +----------------------------------------------------------------------+
      21                 :  */
      22                 : 
      23                 : /* $Id: openssl.c 290180 2009-11-03 18:24:57Z guenter $ */
      24                 : 
      25                 : #ifdef HAVE_CONFIG_H
      26                 : #include "config.h"
      27                 : #endif
      28                 : 
      29                 : #include "php.h"
      30                 : #include "php_openssl.h"
      31                 : 
      32                 : /* PHP Includes */
      33                 : #include "ext/standard/file.h"
      34                 : #include "ext/standard/info.h"
      35                 : #include "ext/standard/php_fopen_wrappers.h"
      36                 : 
      37                 : /* OpenSSL includes */
      38                 : #include <openssl/evp.h>
      39                 : #include <openssl/x509.h>
      40                 : #include <openssl/x509v3.h>
      41                 : #include <openssl/crypto.h>
      42                 : #include <openssl/pem.h>
      43                 : #include <openssl/err.h>
      44                 : #include <openssl/conf.h>
      45                 : #include <openssl/rand.h>
      46                 : #include <openssl/ssl.h>
      47                 : #include <openssl/pkcs12.h>
      48                 : 
      49                 : /* Common */
      50                 : #include <time.h>
      51                 : 
      52                 : #ifdef NETWARE
      53                 : #define timezone _timezone      /* timezone is called _timezone in LibC */
      54                 : #endif
      55                 : 
      56                 : #define DEFAULT_KEY_LENGTH      512
      57                 : #define MIN_KEY_LENGTH          384
      58                 : 
      59                 : #define OPENSSL_ALGO_SHA1       1
      60                 : #define OPENSSL_ALGO_MD5        2
      61                 : #define OPENSSL_ALGO_MD4        3
      62                 : #define OPENSSL_ALGO_MD2        4
      63                 : #define OPENSSL_ALGO_DSS1       5
      64                 : 
      65                 : #define DEBUG_SMIME     0
      66                 : 
      67                 : static 
      68                 :         ZEND_BEGIN_ARG_INFO(arg2and3_force_ref, 0)
      69                 :                 ZEND_ARG_PASS_INFO(0)
      70                 :                 ZEND_ARG_PASS_INFO(1)
      71                 :                 ZEND_ARG_PASS_INFO(1)
      72                 :         ZEND_END_ARG_INFO();
      73                 : 
      74                 : /* FIXME: Use the openssl constants instead of
      75                 :  * enum. It is now impossible to match real values
      76                 :  * against php constants. Also sorry to break the
      77                 :  * enum principles here, BC...
      78                 :  */
      79                 : enum php_openssl_key_type {
      80                 :         OPENSSL_KEYTYPE_RSA,
      81                 :         OPENSSL_KEYTYPE_DSA,
      82                 :         OPENSSL_KEYTYPE_DH,
      83                 :         OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
      84                 : #ifdef EVP_PKEY_EC
      85                 :         OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
      86                 : #endif
      87                 : };
      88                 : 
      89                 : enum php_openssl_cipher_type {
      90                 :         PHP_OPENSSL_CIPHER_RC2_40,
      91                 :         PHP_OPENSSL_CIPHER_RC2_128,
      92                 :         PHP_OPENSSL_CIPHER_RC2_64,
      93                 :         PHP_OPENSSL_CIPHER_DES,
      94                 :         PHP_OPENSSL_CIPHER_3DES,
      95                 : 
      96                 :         PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
      97                 : };
      98                 : 
      99                 : /* {{{ openssl_functions[]
     100                 :  */
     101                 : zend_function_entry openssl_functions[] = {
     102                 : /* public/private key functions */
     103                 :         PHP_FE(openssl_pkey_free,                       NULL)
     104                 :         PHP_FE(openssl_pkey_new,                        NULL)
     105                 :         PHP_FE(openssl_pkey_export,                     second_arg_force_ref)
     106                 :         PHP_FE(openssl_pkey_export_to_file,     NULL)
     107                 :         PHP_FE(openssl_pkey_get_private,        NULL)
     108                 :         PHP_FE(openssl_pkey_get_public,         NULL)
     109                 :         PHP_FE(openssl_pkey_get_details,        NULL)
     110                 : 
     111                 :         PHP_FALIAS(openssl_free_key,            openssl_pkey_free,                      NULL)
     112                 :         PHP_FALIAS(openssl_get_privatekey,      openssl_pkey_get_private,       NULL)
     113                 :         PHP_FALIAS(openssl_get_publickey,       openssl_pkey_get_public,        NULL)
     114                 : 
     115                 : /* x.509 cert funcs */
     116                 :         PHP_FE(openssl_x509_read,                               NULL)
     117                 :         PHP_FE(openssl_x509_free,                       NULL)
     118                 :         PHP_FE(openssl_x509_parse,                              NULL)
     119                 :         PHP_FE(openssl_x509_checkpurpose,               NULL)
     120                 :         PHP_FE(openssl_x509_check_private_key,  NULL)
     121                 :         PHP_FE(openssl_x509_export,                             second_arg_force_ref)
     122                 :         PHP_FE(openssl_x509_export_to_file,             NULL)
     123                 : 
     124                 : /* PKCS12 funcs */
     125                 :         PHP_FE(openssl_pkcs12_export,                   second_arg_force_ref)
     126                 :         PHP_FE(openssl_pkcs12_export_to_file,   NULL)
     127                 :         PHP_FE(openssl_pkcs12_read,                             second_arg_force_ref)
     128                 : 
     129                 : /* CSR funcs */
     130                 :         PHP_FE(openssl_csr_new,                         second_arg_force_ref)
     131                 :         PHP_FE(openssl_csr_export,                      second_arg_force_ref)
     132                 :         PHP_FE(openssl_csr_export_to_file,      NULL)
     133                 :         PHP_FE(openssl_csr_sign,                        NULL)
     134                 :         PHP_FE(openssl_csr_get_subject,         NULL)
     135                 :         PHP_FE(openssl_csr_get_public_key,      NULL)
     136                 : 
     137                 :         PHP_FE(openssl_sign,            second_arg_force_ref)
     138                 :         PHP_FE(openssl_verify,          NULL)
     139                 :         PHP_FE(openssl_seal,            arg2and3_force_ref)
     140                 :         PHP_FE(openssl_open,            second_arg_force_ref)
     141                 : 
     142                 : /* for S/MIME handling */
     143                 :         PHP_FE(openssl_pkcs7_verify,            NULL)
     144                 :         PHP_FE(openssl_pkcs7_decrypt,           NULL)
     145                 :         PHP_FE(openssl_pkcs7_sign,                      NULL)
     146                 :         PHP_FE(openssl_pkcs7_encrypt,           NULL)
     147                 : 
     148                 :         PHP_FE(openssl_private_encrypt,         second_arg_force_ref)
     149                 :         PHP_FE(openssl_private_decrypt,         second_arg_force_ref)
     150                 :         PHP_FE(openssl_public_encrypt,          second_arg_force_ref)
     151                 :         PHP_FE(openssl_public_decrypt,          second_arg_force_ref)
     152                 : 
     153                 :         PHP_FE(openssl_error_string, NULL)
     154                 :         {NULL, NULL, NULL}
     155                 : };
     156                 : /* }}} */
     157                 : 
     158                 : /* {{{ openssl_module_entry
     159                 :  */
     160                 : zend_module_entry openssl_module_entry = {
     161                 :         STANDARD_MODULE_HEADER,
     162                 :         "openssl",
     163                 :         openssl_functions,
     164                 :         PHP_MINIT(openssl),
     165                 :         PHP_MSHUTDOWN(openssl),
     166                 :         NULL,
     167                 :         NULL,
     168                 :         PHP_MINFO(openssl),
     169                 :         NO_VERSION_YET,
     170                 :         STANDARD_MODULE_PROPERTIES
     171                 : };
     172                 : /* }}} */
     173                 : 
     174                 : #ifdef COMPILE_DL_OPENSSL
     175                 : ZEND_GET_MODULE(openssl)
     176                 : # ifdef PHP_WIN32
     177                 : # include "zend_arg_defs.c"
     178                 : # endif
     179                 : #endif
     180                 : 
     181                 : static int le_key;
     182                 : static int le_x509;
     183                 : static int le_csr;
     184                 : static int ssl_stream_data_index;
     185                 : 
     186                 : int php_openssl_get_x509_list_id(void) /* {{{ */
     187               0 : {
     188               0 :         return le_x509;
     189                 : }
     190                 : /* }}} */
     191                 : 
     192                 : /* {{{ resource destructors */
     193                 : static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     194              13 : {
     195              13 :         EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
     196                 : 
     197                 :         assert(pkey != NULL);
     198                 : 
     199              13 :         EVP_PKEY_free(pkey);
     200              13 : }
     201                 : 
     202                 : static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     203               1 : {
     204               1 :         X509 *x509 = (X509 *)rsrc->ptr;
     205               1 :         X509_free(x509);
     206               1 : }
     207                 : 
     208                 : static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     209               2 : {
     210               2 :         X509_REQ * csr = (X509_REQ*)rsrc->ptr;
     211               2 :         X509_REQ_free(csr);
     212               2 : }
     213                 : /* }}} */
     214                 : 
     215                 : /* {{{ openssl safe_mode & open_basedir checks */
     216                 : inline static int php_openssl_safe_mode_chk(char *filename TSRMLS_DC)
     217               5 : {
     218               5 :         if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
     219               0 :                 return -1;
     220                 :         }
     221               5 :         if (php_check_open_basedir(filename TSRMLS_CC)) {
     222               0 :                 return -1;
     223                 :         }
     224                 :         
     225               5 :         return 0;
     226                 : }
     227                 : /* }}} */
     228                 : 
     229                 : /* {{{ openssl -> PHP "bridging" */
     230                 : /* true global; readonly after module startup */
     231                 : static char default_ssl_conf_filename[MAXPATHLEN];
     232                 : 
     233                 : struct php_x509_request { /* {{{ */
     234                 : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
     235                 :         LHASH_OF(CONF_VALUE) * global_config;   /* Global SSL config */
     236                 :         LHASH_OF(CONF_VALUE) * req_config;              /* SSL config for this request */
     237                 : #else
     238                 :         LHASH * global_config;  /* Global SSL config */
     239                 :         LHASH * req_config;             /* SSL config for this request */
     240                 : #endif
     241                 :         const EVP_MD * md_alg;
     242                 :         const EVP_MD * digest;
     243                 :         char    * section_name,
     244                 :                         * config_filename,
     245                 :                         * digest_name,
     246                 :                         * extensions_section,
     247                 :                         * request_extensions_section;
     248                 :         int priv_key_bits;
     249                 :         int priv_key_type;
     250                 : 
     251                 :         int priv_key_encrypt;
     252                 : 
     253                 :         EVP_PKEY * priv_key;
     254                 : };
     255                 : /* }}} */
     256                 : 
     257                 : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
     258                 : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC);
     259                 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);
     260                 : static X509_STORE     * setup_verify(zval * calist TSRMLS_DC);
     261                 : static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
     262                 : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
     263                 : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC);
     264                 : 
     265                 : 
     266                 : static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */
     267               9 : {
     268                 :         zval *subitem, *subentries;
     269               9 :         int i, j = -1, last = -1, obj_cnt = 0;
     270                 :         char *sname;
     271                 :         int nid;
     272                 :         X509_NAME_ENTRY * ne;
     273               9 :         ASN1_STRING * str = NULL;
     274                 :         ASN1_OBJECT * obj;
     275                 : 
     276               9 :         if (key != NULL) {
     277               8 :                 MAKE_STD_ZVAL(subitem);
     278               8 :                 array_init(subitem);
     279                 :         } else {
     280               1 :                 subitem = val;
     281                 :         }
     282                 :         
     283              63 :         for (i = 0; i < X509_NAME_entry_count(name); i++) {
     284                 :                 unsigned char *to_add;
     285                 :                 int to_add_len;
     286                 : 
     287                 : 
     288              54 :                 ne  = X509_NAME_get_entry(name, i);
     289              54 :                 obj = X509_NAME_ENTRY_get_object(ne);
     290              54 :                 nid = OBJ_obj2nid(obj);
     291              54 :                 obj_cnt = 0;
     292                 : 
     293              54 :                 if (shortname) {
     294              54 :                         sname = (char *) OBJ_nid2sn(nid);
     295                 :                 } else {
     296               0 :                         sname = (char *) OBJ_nid2ln(nid);
     297                 :                 }
     298                 : 
     299              54 :                 MAKE_STD_ZVAL(subentries);
     300              54 :                 array_init(subentries);
     301                 : 
     302              54 :                 last = -1;
     303                 :                 for (;;) {
     304             110 :                         j = X509_NAME_get_index_by_OBJ(name, obj, last);
     305             110 :                         if (j < 0) {
     306              54 :                                 if (last != -1) break;
     307                 :                         } else {
     308              56 :                                 obj_cnt++;
     309              56 :                                 ne  = X509_NAME_get_entry(name, j);
     310              56 :                                 str = X509_NAME_ENTRY_get_data(ne);
     311              56 :                                 if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
     312              56 :                                         to_add_len = ASN1_STRING_to_UTF8(&to_add, str);
     313              56 :                                         if (to_add_len != -1) {
     314              54 :                                                 add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
     315                 :                                         }
     316                 :                                 } else {
     317               0 :                                         to_add = ASN1_STRING_data(str);
     318               0 :                                         to_add_len = ASN1_STRING_length(str);
     319               0 :                                         add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
     320                 :                                 }
     321                 :                         }
     322              56 :                         last = j;
     323              56 :                 }
     324              54 :                 i = last;
     325                 :                 
     326              54 :                 if (obj_cnt > 1) {
     327               2 :                         add_assoc_zval_ex(subitem, sname, strlen(sname) + 1, subentries);
     328                 :                 } else {
     329              52 :                         zval_dtor(subentries);
     330              52 :                         FREE_ZVAL(subentries);
     331              52 :                         if (obj_cnt && str && to_add_len > -1) {
     332              50 :                                 add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1);
     333                 :                         }
     334                 :                 }
     335                 :         }
     336               9 :         if (key != NULL) {
     337               8 :                 zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL);
     338                 :         }
     339               9 : }
     340                 : /* }}} */
     341                 : 
     342                 : static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
     343              10 : {
     344              10 :         add_assoc_stringl(val, key, (char *)str->data, str->length, 1);
     345              10 : }
     346                 : /* }}} */
     347                 : 
     348                 : static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
     349               8 : {
     350                 : /*
     351                 :         This is how the time string is formatted:
     352                 : 
     353                 :    snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
     354                 :       ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
     355                 : */
     356                 : 
     357                 :         time_t ret;
     358                 :         struct tm thetime;
     359                 :         char * strbuf;
     360                 :         char * thestr;
     361               8 :         long gmadjust = 0;
     362                 : 
     363               8 :         if (timestr->length < 13) {
     364               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data);
     365               0 :                 return (time_t)-1;
     366                 :         }
     367                 : 
     368               8 :         strbuf = estrdup((char *)timestr->data);
     369                 : 
     370               8 :         memset(&thetime, 0, sizeof(thetime));
     371                 : 
     372                 :         /* we work backwards so that we can use atoi more easily */
     373                 : 
     374               8 :         thestr = strbuf + timestr->length - 3;
     375                 : 
     376               8 :         thetime.tm_sec = atoi(thestr);
     377               8 :         *thestr = '\0';
     378               8 :         thestr -= 2;
     379               8 :         thetime.tm_min = atoi(thestr);
     380               8 :         *thestr = '\0';
     381               8 :         thestr -= 2;
     382               8 :         thetime.tm_hour = atoi(thestr);
     383               8 :         *thestr = '\0';
     384               8 :         thestr -= 2;
     385               8 :         thetime.tm_mday = atoi(thestr);
     386               8 :         *thestr = '\0';
     387               8 :         thestr -= 2;
     388               8 :         thetime.tm_mon = atoi(thestr)-1;
     389               8 :         *thestr = '\0';
     390               8 :         thestr -= 2;
     391               8 :         thetime.tm_year = atoi(thestr);
     392                 : 
     393               8 :         if (thetime.tm_year < 68) {
     394               8 :                 thetime.tm_year += 100;
     395                 :         }
     396                 : 
     397               8 :         thetime.tm_isdst = -1;
     398               8 :         ret = mktime(&thetime);
     399                 : 
     400                 : #if HAVE_TM_GMTOFF
     401               8 :         gmadjust = thetime.tm_gmtoff;
     402                 : #else
     403                 :         /*
     404                 :         ** If correcting for daylight savings time, we set the adjustment to
     405                 :         ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
     406                 :         ** set the adjustment to the main timezone + 3600 seconds.
     407                 :         */
     408                 :         gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
     409                 : #endif
     410               8 :         ret += gmadjust;
     411                 : 
     412               8 :         efree(strbuf);
     413                 : 
     414               8 :         return ret;
     415                 : }
     416                 : /* }}} */
     417                 : 
     418                 : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
     419                 : static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config TSRMLS_DC) /* {{{ */
     420                 : #else
     421                 : static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config TSRMLS_DC) /* {{{ */
     422                 : #endif
     423              12 : {
     424                 :         X509V3_CTX ctx;
     425                 :         
     426              12 :         X509V3_set_ctx_test(&ctx);
     427              12 :         X509V3_set_conf_lhash(&ctx, config);
     428              12 :         if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
     429               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s",
     430                 :                                 section_label,
     431                 :                                 section,
     432                 :                                 config_filename);
     433               0 :                 return FAILURE;
     434                 :         }
     435              12 :         return SUCCESS;
     436                 : }
     437                 : /* }}} */
     438                 : 
     439                 : static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
     440              10 : {
     441                 :         char * str;
     442                 :         STACK_OF(CONF_VALUE) * sktmp;
     443                 :         CONF_VALUE * cnf;
     444                 :         int i;
     445                 : 
     446              10 :         str = CONF_get_string(req->req_config, NULL, "oid_section");
     447              10 :         if (str == NULL) {
     448              10 :                 return SUCCESS;
     449                 :         }
     450               0 :         sktmp = CONF_get_section(req->req_config, str);
     451               0 :         if (sktmp == NULL) {
     452               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str);
     453               0 :                 return FAILURE;
     454                 :         }
     455               0 :         for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
     456               0 :                 cnf = sk_CONF_VALUE_value(sktmp, i);
     457               0 :                 if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
     458               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
     459               0 :                         return FAILURE;
     460                 :                 }
     461                 :         }
     462               0 :         return SUCCESS;
     463                 : }
     464                 : /* }}} */
     465                 : 
     466                 : #define PHP_SSL_REQ_INIT(req)           memset(req, 0, sizeof(*req))
     467                 : #define PHP_SSL_REQ_DISPOSE(req)        php_openssl_dispose_config(req TSRMLS_CC)
     468                 : #define PHP_SSL_REQ_PARSE(req, zval)    php_openssl_parse_config(req, zval TSRMLS_CC)
     469                 : 
     470                 : #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
     471                 :                         req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE
     472                 : 
     473                 : #define SET_OPTIONAL_STRING_ARG(key, varname, defval)   \
     474                 :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
     475                 :                 varname = Z_STRVAL_PP(item); \
     476                 :         else \
     477                 :                 varname = defval
     478                 : 
     479                 : #define SET_OPTIONAL_LONG_ARG(key, varname, defval)     \
     480                 :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
     481                 :                 varname = Z_LVAL_PP(item); \
     482                 :         else \
     483                 :                 varname = defval
     484                 : 
     485                 : 
     486                 : 
     487                 : static int php_openssl_parse_config(
     488                 :                 struct php_x509_request * req,
     489                 :                 zval * optional_args
     490                 :                 TSRMLS_DC
     491                 :                 ) /* {{{ */
     492              10 : {
     493                 :         char * str;
     494                 :         zval ** item;
     495                 : 
     496              10 :         SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
     497              10 :         SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
     498              10 :         req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
     499              10 :         req->req_config = CONF_load(NULL, req->config_filename, NULL);
     500                 : 
     501              10 :         if (req->req_config == NULL) {
     502               0 :                 return FAILURE;
     503                 :         }
     504                 : 
     505                 :         /* read in the oids */
     506              10 :         str = CONF_get_string(req->req_config, NULL, "oid_file");
     507              10 :         if (str && !php_openssl_safe_mode_chk(str TSRMLS_CC)) {
     508               0 :                 BIO *oid_bio = BIO_new_file(str, "r");
     509               0 :                 if (oid_bio) {
     510               0 :                         OBJ_create_objects(oid_bio);
     511               0 :                         BIO_free(oid_bio);
     512                 :                 }
     513                 :         }
     514              10 :         if (add_oid_section(req TSRMLS_CC) == FAILURE) {
     515               0 :                 return FAILURE;
     516                 :         }
     517              10 :         SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
     518                 :                 CONF_get_string(req->req_config, req->section_name, "default_md"));
     519              10 :         SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
     520                 :                 CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
     521              10 :         SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
     522                 :                 CONF_get_string(req->req_config, req->section_name, "req_extensions"));
     523              10 :         SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
     524                 :                 CONF_get_number(req->req_config, req->section_name, "default_bits"));
     525                 : 
     526              10 :         SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
     527                 : 
     528              10 :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) {
     529               0 :                 req->priv_key_encrypt = Z_BVAL_PP(item);
     530                 :         } else {
     531              10 :                 str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
     532              10 :                 if (str == NULL) {
     533              10 :                         str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
     534                 :                 }
     535              10 :                 if (str && strcmp(str, "no") == 0) {
     536               0 :                         req->priv_key_encrypt = 0;
     537                 :                 } else {
     538              10 :                         req->priv_key_encrypt = 1;
     539                 :                 }
     540                 :         }
     541                 :         
     542                 :         /* digest alg */
     543              10 :         if (req->digest_name == NULL) {
     544               0 :                 req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
     545                 :         }
     546              10 :         if (req->digest_name) {
     547              10 :                 req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
     548                 :         }
     549              10 :         if (req->md_alg == NULL) {
     550               0 :                 req->md_alg = req->digest = EVP_md5();
     551                 :         }
     552                 : 
     553              10 :         PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
     554                 : 
     555                 :         /* set the string mask */
     556              10 :         str = CONF_get_string(req->req_config, req->section_name, "string_mask");
     557              10 :         if (str && !ASN1_STRING_set_default_mask_asc(str)) {
     558               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid global string mask setting %s", str);
     559               0 :                 return FAILURE;
     560                 :         }
     561                 : 
     562              10 :         PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
     563                 :         
     564              10 :         return SUCCESS;
     565                 : }
     566                 : /* }}} */
     567                 : 
     568                 : static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */
     569              10 : {
     570              10 :         if (req->priv_key) {
     571               1 :                 EVP_PKEY_free(req->priv_key);
     572               1 :                 req->priv_key = NULL;
     573                 :         }
     574              10 :         if (req->global_config) {
     575              10 :                 CONF_free(req->global_config);
     576              10 :                 req->global_config = NULL;
     577                 :         }
     578              10 :         if (req->req_config) {
     579              10 :                 CONF_free(req->req_config);
     580              10 :                 req->req_config = NULL;
     581                 :         }
     582              10 : }
     583                 : /* }}} */
     584                 : 
     585                 : static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
     586               7 : {
     587                 :         char buffer[MAXPATHLEN];
     588                 : 
     589                 :         TSRMLS_FETCH();
     590                 : 
     591               7 :         *egdsocket = 0;
     592               7 :         *seeded = 0;
     593                 :         
     594                 : #ifdef WINDOWS
     595                 :         RAND_screen();
     596                 : #endif
     597               7 :         if (file == NULL) {
     598               0 :                 file = RAND_file_name(buffer, sizeof(buffer));
     599               7 :         } else if (RAND_egd(file) > 0) {
     600                 :                 /* if the given filename is an EGD socket, don't
     601                 :                  * write anything back to it */
     602               0 :                 *egdsocket = 1;
     603               0 :                 return SUCCESS;
     604                 :         }
     605               7 :         if (file == NULL || !RAND_load_file(file, -1)) {
     606               7 :                 if (RAND_status() == 0) {
     607               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to load random state; not enough random data!");
     608               0 :                         return FAILURE;
     609                 :                 }
     610               7 :                 return FAILURE;
     611                 :         }
     612               0 :         *seeded = 1;
     613               0 :         return SUCCESS;
     614                 : }
     615                 : /* }}} */
     616                 : 
     617                 : static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
     618               7 : {
     619                 :         char buffer[MAXPATHLEN];
     620                 : 
     621                 :         TSRMLS_FETCH();
     622                 : 
     623               7 :         if (egdsocket || !seeded) {
     624                 :                 /* if we did not manage to read the seed file, we should not write
     625                 :                  * a low-entropy seed file back */
     626               7 :                 return FAILURE;
     627                 :         }
     628               0 :         if (file == NULL) {
     629               0 :                 file = RAND_file_name(buffer, sizeof(buffer));
     630                 :         }
     631               0 :         if (file == NULL || !RAND_write_file(file)) {
     632               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to write random state");
     633               0 :                 return FAILURE;
     634                 :         }
     635               0 :         return SUCCESS;
     636                 : }
     637                 : /* }}} */
     638                 : 
     639               7 : static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
     640                 :         EVP_MD *mdtype;
     641                 : 
     642               7 :         switch (algo) {
     643                 :                 case OPENSSL_ALGO_SHA1:
     644               0 :                         mdtype = (EVP_MD *) EVP_sha1();
     645               0 :                         break;
     646                 :                 case OPENSSL_ALGO_MD5:
     647               5 :                         mdtype = (EVP_MD *) EVP_md5();
     648               5 :                         break;
     649                 :                 case OPENSSL_ALGO_MD4:
     650               0 :                         mdtype = (EVP_MD *) EVP_md4();
     651               0 :                         break;
     652                 :                 case OPENSSL_ALGO_MD2:
     653               0 :                         mdtype = (EVP_MD *) EVP_md2();
     654               0 :                         break;
     655                 :                 case OPENSSL_ALGO_DSS1:
     656               2 :                         mdtype = (EVP_MD *) EVP_dss1();
     657               2 :                         break;
     658                 :                 default:
     659               0 :                         return NULL;
     660                 :                         break;
     661                 :         }
     662               7 :         return mdtype;
     663                 : }
     664                 : /* }}} */
     665                 : /* }}} */
     666                 : 
     667                 : /* {{{ PHP_MINIT_FUNCTION
     668                 :  */
     669                 : PHP_MINIT_FUNCTION(openssl)
     670           13565 : {
     671                 :         char * config_filename;
     672                 : 
     673           13565 :         le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
     674           13565 :         le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
     675           13565 :         le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
     676                 : 
     677           13565 :         SSL_library_init();
     678           13565 :         OpenSSL_add_all_ciphers();
     679           13565 :         OpenSSL_add_all_digests();
     680           13565 :         OpenSSL_add_all_algorithms();
     681                 : 
     682           13565 :         ERR_load_ERR_strings();
     683           13565 :         ERR_load_crypto_strings();
     684           13565 :         ERR_load_EVP_strings();
     685                 : 
     686                 :         /* register a resource id number with openSSL so that we can map SSL -> stream structures in
     687                 :          * openSSL callbacks */
     688           13565 :         ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
     689                 :         
     690           13565 :         REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
     691           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
     692                 :         
     693                 :         /* purposes for cert purpose checking */
     694           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
     695           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
     696           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
     697           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
     698           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
     699           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
     700                 : #ifdef X509_PURPOSE_ANY
     701           13565 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
     702                 : #endif
     703                 : 
     704                 :         /* signature algorithm constants */
     705           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
     706           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
     707           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
     708           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
     709           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
     710                 : 
     711                 :         /* flags for S/MIME */
     712           13565 :         REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
     713           13565 :         REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
     714           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
     715           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
     716           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
     717           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
     718           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
     719           13565 :         REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
     720           13565 :         REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
     721                 : 
     722           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
     723           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
     724           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
     725           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
     726                 : 
     727                 :         /* Ciphers */
     728                 : #ifndef OPENSSL_NO_RC2
     729           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
     730           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
     731           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
     732                 : #endif
     733                 : #ifndef OPENSSL_NO_DES
     734           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
     735           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
     736                 : #endif
     737                 : 
     738                 :         /* Values for key types */
     739           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
     740                 : #ifndef NO_DSA
     741           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
     742                 : #endif
     743           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
     744                 : #ifdef EVP_PKEY_EC
     745           13565 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
     746                 : #endif
     747                 : 
     748                 :         /* Determine default SSL configuration file */
     749           13565 :         config_filename = getenv("OPENSSL_CONF");
     750           13565 :         if (config_filename == NULL) {
     751           13565 :                 config_filename = getenv("SSLEAY_CONF");
     752                 :         }
     753                 : 
     754                 :         /* default to 'openssl.cnf' if no environment variable is set */
     755           13565 :         if (config_filename == NULL) {
     756           13565 :                 snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
     757                 :                                 X509_get_default_cert_area(),
     758                 :                                 "openssl.cnf");
     759                 :         } else {
     760               0 :                 strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
     761                 :         }
     762                 : 
     763           13565 :         php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC);
     764           13565 :         php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC);
     765           13565 :         php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
     766           13565 :         php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC);
     767                 : 
     768                 :         /* override the default tcp socket provider */
     769           13565 :         php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
     770                 : 
     771           13565 :         php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC);
     772           13565 :         php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC);
     773                 :         
     774           13565 :         return SUCCESS;
     775                 : }
     776                 : /* }}} */
     777                 : 
     778                 : /* {{{ PHP_MINFO_FUNCTION
     779                 :  */
     780                 : PHP_MINFO_FUNCTION(openssl)
     781               6 : {
     782               6 :         php_info_print_table_start();
     783               6 :         php_info_print_table_row(2, "OpenSSL support", "enabled");
     784               6 :         php_info_print_table_row(2, "OpenSSL Version", OPENSSL_VERSION_TEXT);
     785               6 :         php_info_print_table_end();
     786               6 : }
     787                 : /* }}} */
     788                 : 
     789                 : /* {{{ PHP_MSHUTDOWN_FUNCTION
     790                 :  */
     791                 : PHP_MSHUTDOWN_FUNCTION(openssl)
     792           13597 : {
     793           13597 :         EVP_cleanup();
     794                 : 
     795           13597 :         php_unregister_url_stream_wrapper("https" TSRMLS_CC);
     796           13597 :         php_unregister_url_stream_wrapper("ftps" TSRMLS_CC);
     797                 : 
     798           13597 :         php_stream_xport_unregister("ssl" TSRMLS_CC);
     799           13597 :         php_stream_xport_unregister("sslv2" TSRMLS_CC);
     800           13597 :         php_stream_xport_unregister("sslv3" TSRMLS_CC);
     801           13597 :         php_stream_xport_unregister("tls" TSRMLS_CC);
     802                 : 
     803                 :         /* reinstate the default tcp handler */
     804           13597 :         php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
     805                 : 
     806           13597 :         return SUCCESS;
     807                 : }
     808                 : /* }}} */
     809                 : 
     810                 : /* {{{ x509 cert functions */
     811                 : 
     812                 : /* {{{ php_openssl_x509_from_zval
     813                 :         Given a zval, coerce it into an X509 object.
     814                 :         The zval can be:
     815                 :                 . X509 resource created using openssl_read_x509()
     816                 :                 . if it starts with file:// then it will be interpreted as the path to that cert
     817                 :                 . it will be interpreted as the cert data
     818                 :         If you supply makeresource, the result will be registered as an x509 resource and
     819                 :         it's value returned in makeresource.
     820                 : */
     821                 : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
     822              17 : {
     823              17 :         X509 *cert = NULL;
     824                 : 
     825              17 :         if (resourceval) {
     826              17 :                 *resourceval = -1;
     827                 :         }
     828              17 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
     829                 :                 /* is it an x509 resource ? */
     830                 :                 void * what;
     831                 :                 int type;
     832                 : 
     833               1 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509", &type, 1, le_x509);
     834               1 :                 if (!what) {
     835               0 :                         return NULL;
     836                 :                 }
     837                 :                 /* this is so callers can decide if they should free the X509 */
     838               1 :                 if (resourceval) {
     839               1 :                         *resourceval = Z_LVAL_PP(val);
     840                 :                 }
     841               1 :                 if (type == le_x509) {
     842               1 :                         return (X509*)what;
     843                 :                 }
     844                 :                 /* other types could be used here - eg: file pointers and read in the data from them */
     845                 : 
     846               0 :                 return NULL;
     847                 :         }
     848                 : 
     849              16 :         if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
     850               5 :                 return NULL;
     851                 :         }
     852                 : 
     853                 :         /* force it to be a string and check if it refers to a file */
     854              11 :         convert_to_string_ex(val);
     855                 : 
     856              11 :         if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
     857                 :                 /* read cert from the named file */
     858                 :                 BIO *in;
     859                 : 
     860               1 :                 if (php_openssl_safe_mode_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) {
     861               0 :                         return NULL;
     862                 :                 }
     863                 : 
     864               1 :                 in = BIO_new_file(Z_STRVAL_PP(val) + (sizeof("file://") - 1), "r");
     865               1 :                 if (in == NULL) {
     866               0 :                         return NULL;
     867                 :                 }
     868               1 :                 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
     869               1 :                 BIO_free(in);
     870                 :         } else {
     871                 :                 BIO *in;
     872                 : 
     873               9 :                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
     874               9 :                 if (in == NULL) {
     875               0 :                         return NULL;
     876                 :                 }
     877                 : #ifdef TYPEDEF_D2I_OF
     878               9 :                 cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
     879                 : #else
     880                 :                 cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
     881                 : #endif
     882               9 :                 BIO_free(in);
     883                 :         }
     884                 : 
     885              10 :         if (cert && makeresource && resourceval) {
     886               0 :                 *resourceval = zend_list_insert(cert, le_x509);
     887                 :         }
     888              10 :         return cert;
     889                 : }
     890                 : 
     891                 : /* }}} */
     892                 : 
     893                 : /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
     894                 :    Exports a CERT to file or a var */
     895                 : PHP_FUNCTION(openssl_x509_export_to_file)
     896               0 : {
     897                 :         X509 * cert;
     898                 :         zval ** zcert;
     899               0 :         zend_bool notext = 1;
     900                 :         BIO * bio_out;
     901                 :         long certresource;
     902                 :         char * filename;
     903                 :         int filename_len;
     904                 : 
     905               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|b", &zcert, &filename, &filename_len, &notext) == FAILURE) {
     906               0 :                 return;
     907                 :         }
     908               0 :         RETVAL_FALSE;
     909                 : 
     910               0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
     911               0 :         if (cert == NULL) {
     912               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
     913               0 :                 return;
     914                 :         }
     915                 : 
     916               0 :         if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
     917               0 :                 return;
     918                 :         }
     919                 : 
     920               0 :         bio_out = BIO_new_file(filename, "w");
     921               0 :         if (bio_out) {
     922               0 :                 if (!notext) {
     923               0 :                         X509_print(bio_out, cert);
     924                 :                 }
     925               0 :                 PEM_write_bio_X509(bio_out, cert);
     926                 : 
     927               0 :                 RETVAL_TRUE;
     928                 :         } else {
     929               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
     930                 :         }
     931               0 :         if (certresource == -1 && cert) {
     932               0 :                 X509_free(cert);
     933                 :         }
     934               0 :         BIO_free(bio_out);
     935                 : }
     936                 : /* }}} */
     937                 : 
     938                 : /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
     939                 :    Exports a CERT to file or a var */
     940                 : PHP_FUNCTION(openssl_x509_export)
     941               1 : {
     942                 :         X509 * cert;
     943                 :         zval ** zcert, *zout;
     944               1 :         zend_bool notext = 1;
     945                 :         BIO * bio_out;
     946                 :         long certresource;
     947                 : 
     948               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|b", &zcert, &zout, &notext) == FAILURE) {
     949               0 :                 return;
     950                 :         }
     951               1 :         RETVAL_FALSE;
     952                 : 
     953               1 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
     954               1 :         if (cert == NULL) {
     955               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
     956               0 :                 return;
     957                 :         }
     958                 : 
     959               1 :         bio_out = BIO_new(BIO_s_mem());
     960               1 :         if (!notext) {
     961               1 :                 X509_print(bio_out, cert);
     962                 :         }
     963               1 :         if (PEM_write_bio_X509(bio_out, cert))  {
     964                 :                 BUF_MEM *bio_buf;
     965                 : 
     966               1 :                 zval_dtor(zout);
     967               1 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
     968               1 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
     969                 : 
     970               1 :                 RETVAL_TRUE;
     971                 :         }
     972                 : 
     973               1 :         if (certresource == -1 && cert) {
     974               0 :                 X509_free(cert);
     975                 :         }
     976               1 :         BIO_free(bio_out);
     977                 : }
     978                 : /* }}} */
     979                 : 
     980                 : /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
     981                 :    Checks if a private key corresponds to a CERT */
     982                 : PHP_FUNCTION(openssl_x509_check_private_key)
     983               0 : {
     984                 :         zval ** zcert, **zkey;
     985               0 :         X509 * cert = NULL;
     986               0 :         EVP_PKEY * key = NULL;
     987               0 :         long certresource = -1, keyresource = -1;
     988                 : 
     989               0 :         RETVAL_FALSE;
     990                 :         
     991               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) {
     992               0 :                 return;
     993                 :         }
     994               0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
     995               0 :         if (cert == NULL) {
     996               0 :                 RETURN_FALSE;
     997                 :         }       
     998               0 :         key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC);
     999               0 :         if (key) {
    1000               0 :                 RETVAL_BOOL(X509_check_private_key(cert, key));
    1001                 :         }
    1002                 : 
    1003               0 :         if (keyresource == -1 && key) {
    1004               0 :                 EVP_PKEY_free(key);
    1005                 :         }
    1006               0 :         if (certresource == -1 && cert) {
    1007               0 :                 X509_free(cert);
    1008                 :         }
    1009                 : }
    1010                 : /* }}} */
    1011                 : 
    1012                 : /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
    1013                 :    Returns an array of the fields/values of the CERT */
    1014                 : PHP_FUNCTION(openssl_x509_parse)
    1015              10 : {
    1016                 :         zval ** zcert;
    1017              10 :         X509 * cert = NULL;
    1018              10 :         long certresource = -1;
    1019                 :         int i;
    1020              10 :         zend_bool useshortnames = 1;
    1021                 :         char * tmpstr;
    1022                 :         zval * subitem;
    1023                 :         X509_EXTENSION *extension;
    1024                 :         char *extname;
    1025                 :         BIO  *bio_out;
    1026                 :         BUF_MEM *bio_buf;
    1027                 :         char buf[256];
    1028                 : 
    1029              10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) {
    1030               1 :                 return;
    1031                 :         }
    1032               9 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1033               8 :         if (cert == NULL) {
    1034               4 :                 RETURN_FALSE;
    1035                 :         }
    1036               4 :         array_init(return_value);
    1037                 : 
    1038               4 :         if (cert->name) {
    1039               4 :                 add_assoc_string(return_value, "name", cert->name, 1);
    1040                 :         }
    1041                 : /*      add_assoc_bool(return_value, "valid", cert->valid); */
    1042                 : 
    1043               4 :         add_assoc_name_entry(return_value, "subject",                 X509_get_subject_name(cert), useshortnames TSRMLS_CC);
    1044                 :         /* hash as used in CA directories to lookup cert by subject name */
    1045                 :         {
    1046                 :                 char buf[32];
    1047               4 :                 snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
    1048               4 :                 add_assoc_string(return_value, "hash", buf, 1);
    1049                 :         }
    1050                 :         
    1051               4 :         add_assoc_name_entry(return_value, "issuer",          X509_get_issuer_name(cert), useshortnames TSRMLS_CC);
    1052               4 :         add_assoc_long(return_value, "version",                       X509_get_version(cert));
    1053                 : 
    1054               4 :         add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1); 
    1055                 : 
    1056               4 :         add_assoc_asn1_string(return_value, "validFrom",      X509_get_notBefore(cert));
    1057               4 :         add_assoc_asn1_string(return_value, "validTo",                X509_get_notAfter(cert));
    1058                 : 
    1059               4 :         add_assoc_long(return_value, "validFrom_time_t",      asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC));
    1060               4 :         add_assoc_long(return_value, "validTo_time_t",                asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC));
    1061                 : 
    1062               4 :         tmpstr = (char *)X509_alias_get0(cert, NULL);
    1063               4 :         if (tmpstr) {
    1064               0 :                 add_assoc_string(return_value, "alias", tmpstr, 1);
    1065                 :         }
    1066                 : /*
    1067                 :         add_assoc_long(return_value, "signaturetypeLONG", X509_get_signature_type(cert));
    1068                 :         add_assoc_string(return_value, "signaturetype", OBJ_nid2sn(X509_get_signature_type(cert)), 1);
    1069                 :         add_assoc_string(return_value, "signaturetypeLN", OBJ_nid2ln(X509_get_signature_type(cert)), 1);
    1070                 : */
    1071               4 :         MAKE_STD_ZVAL(subitem);
    1072               4 :         array_init(subitem);
    1073                 : 
    1074                 :         /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
    1075                 :            in x509v3.h */
    1076              36 :         for (i = 0; i < X509_PURPOSE_get_count(); i++) {
    1077                 :                 int id, purpset;
    1078                 :                 char * pname;
    1079                 :                 X509_PURPOSE * purp;
    1080                 :                 zval * subsub;
    1081                 : 
    1082              32 :                 MAKE_STD_ZVAL(subsub);
    1083              32 :                 array_init(subsub);
    1084                 : 
    1085              32 :                 purp = X509_PURPOSE_get0(i);
    1086              32 :                 id = X509_PURPOSE_get_id(purp);
    1087                 : 
    1088              32 :                 purpset = X509_check_purpose(cert, id, 0);
    1089              32 :                 add_index_bool(subsub, 0, purpset);
    1090                 : 
    1091              32 :                 purpset = X509_check_purpose(cert, id, 1);
    1092              32 :                 add_index_bool(subsub, 1, purpset);
    1093                 : 
    1094              32 :                 pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
    1095              32 :                 add_index_string(subsub, 2, pname, 1);
    1096                 : 
    1097                 :                 /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
    1098                 : 
    1099              32 :                 add_index_zval(subitem, id, subsub);
    1100                 :         }
    1101               4 :         add_assoc_zval(return_value, "purposes", subitem);
    1102                 : 
    1103               4 :         MAKE_STD_ZVAL(subitem);
    1104               4 :         array_init(subitem);
    1105                 : 
    1106                 : 
    1107              27 :         for (i = 0; i < X509_get_ext_count(cert); i++) {
    1108              23 :                 extension = X509_get_ext(cert, i);
    1109              23 :                 if (OBJ_obj2nid(X509_EXTENSION_get_object(extension)) != NID_undef) {
    1110              21 :                         extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
    1111                 :                 } else {
    1112               2 :                         OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
    1113               2 :                         extname = buf;
    1114                 :                 }
    1115              23 :                 bio_out = BIO_new(BIO_s_mem());
    1116              23 :                 if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
    1117              21 :                         BIO_get_mem_ptr(bio_out, &bio_buf);
    1118              21 :                         add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1);
    1119                 :                 } else {
    1120               2 :                         add_assoc_asn1_string(subitem, extname, X509_EXTENSION_get_data(extension));
    1121                 :                 }
    1122              23 :                 BIO_free(bio_out);
    1123                 :         }
    1124               4 :         add_assoc_zval(return_value, "extensions", subitem);
    1125                 : 
    1126               4 :         if (certresource == -1 && cert) {
    1127               4 :                 X509_free(cert);
    1128                 :         }
    1129                 : }
    1130                 : /* }}} */
    1131                 : 
    1132                 : /* {{{ load_all_certs_from_file */
    1133                 : static STACK_OF(X509) * load_all_certs_from_file(char *certfile)
    1134               0 : {
    1135               0 :         STACK_OF(X509_INFO) *sk=NULL;
    1136               0 :         STACK_OF(X509) *stack=NULL, *ret=NULL;
    1137               0 :         BIO *in=NULL;
    1138                 :         X509_INFO *xi;
    1139                 :         TSRMLS_FETCH();
    1140                 : 
    1141               0 :         if(!(stack = sk_X509_new_null())) {
    1142               0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
    1143               0 :                 goto end;
    1144                 :         }
    1145                 : 
    1146               0 :         if (php_openssl_safe_mode_chk(certfile TSRMLS_CC)) {
    1147               0 :                 sk_X509_free(stack);
    1148               0 :                 goto end;
    1149                 :         }
    1150                 : 
    1151               0 :         if(!(in=BIO_new_file(certfile, "r"))) {
    1152               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile);
    1153               0 :                 sk_X509_free(stack);
    1154               0 :                 goto end;
    1155                 :         }
    1156                 : 
    1157                 :         /* This loads from a file, a stack of x509/crl/pkey sets */
    1158               0 :         if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
    1159               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile);
    1160               0 :                 sk_X509_free(stack);
    1161               0 :                 goto end;
    1162                 :         }
    1163                 : 
    1164                 :         /* scan over it and pull out the certs */
    1165               0 :         while (sk_X509_INFO_num(sk)) {
    1166               0 :                 xi=sk_X509_INFO_shift(sk);
    1167               0 :                 if (xi->x509 != NULL) {
    1168               0 :                         sk_X509_push(stack,xi->x509);
    1169               0 :                         xi->x509=NULL;
    1170                 :                 }
    1171               0 :                 X509_INFO_free(xi);
    1172                 :         }
    1173               0 :         if(!sk_X509_num(stack)) {
    1174               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile);
    1175               0 :                 sk_X509_free(stack);
    1176               0 :                 goto end;
    1177                 :         }
    1178               0 :         ret=stack;
    1179               0 : end:
    1180               0 :         BIO_free(in);
    1181               0 :         sk_X509_INFO_free(sk);
    1182                 : 
    1183               0 :         return ret;
    1184                 : }
    1185                 : /* }}} */
    1186                 : 
    1187                 : /* {{{ check_cert */
    1188                 : static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
    1189               0 : {
    1190               0 :         int ret=0;
    1191                 :         X509_STORE_CTX *csc;
    1192                 :         TSRMLS_FETCH();
    1193                 : 
    1194               0 :         csc = X509_STORE_CTX_new();
    1195               0 :         if (csc == NULL) {
    1196               0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
    1197               0 :                 return 0;
    1198                 :         }
    1199               0 :         X509_STORE_CTX_init(csc, ctx, x, untrustedchain);
    1200                 : 
    1201               0 :         if(purpose >= 0) {
    1202               0 :                 X509_STORE_CTX_set_purpose(csc, purpose);
    1203                 :         }
    1204               0 :         ret = X509_verify_cert(csc);
    1205               0 :         X509_STORE_CTX_free(csc);
    1206                 : 
    1207               0 :         return ret;
    1208                 : }
    1209                 : /* }}} */
    1210                 : 
    1211                 : /* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
    1212                 :    Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */
    1213                 : PHP_FUNCTION(openssl_x509_checkpurpose)
    1214               0 : {
    1215               0 :         zval ** zcert, * zcainfo = NULL;
    1216               0 :         X509_STORE * cainfo = NULL;
    1217               0 :         X509 * cert = NULL;
    1218               0 :         long certresource = -1;
    1219               0 :         STACK_OF(X509) * untrustedchain = NULL;
    1220                 :         long purpose;
    1221               0 :         char * untrusted = NULL;
    1222                 :         int untrusted_len, ret;
    1223                 : 
    1224               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len)
    1225                 :                         == FAILURE) {
    1226               0 :                 return;
    1227                 :         }
    1228                 : 
    1229               0 :         RETVAL_LONG(-1);
    1230                 : 
    1231               0 :         if (untrusted) {
    1232               0 :                 untrustedchain = load_all_certs_from_file(untrusted);
    1233               0 :                 if (untrustedchain == NULL) {
    1234               0 :                         goto clean_exit;
    1235                 :                 }
    1236                 :         }
    1237                 : 
    1238               0 :         cainfo = setup_verify(zcainfo TSRMLS_CC);
    1239               0 :         if (cainfo == NULL) {
    1240               0 :                 goto clean_exit;
    1241                 :         }
    1242               0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1243               0 :         if (cert == NULL) {
    1244               0 :                 goto clean_exit;
    1245                 :         }
    1246                 : 
    1247               0 :         ret = check_cert(cainfo, cert, untrustedchain, purpose);
    1248                 : 
    1249               0 :         if (ret != 0 && ret != 1) {
    1250               0 :                 RETVAL_LONG(ret);
    1251                 :         } else {
    1252               0 :                 RETVAL_BOOL(ret);
    1253                 :         }
    1254                 : 
    1255                 : 
    1256               0 : clean_exit:
    1257               0 :         if (certresource == 1 && cert) {
    1258               0 :                 X509_free(cert);
    1259                 :         }
    1260               0 :         if (cainfo) { 
    1261               0 :                 X509_STORE_free(cainfo); 
    1262                 :         }
    1263               0 :         if (untrustedchain) {
    1264               0 :                 sk_X509_pop_free(untrustedchain, X509_free);
    1265                 :         }
    1266                 : }
    1267                 : /* }}} */
    1268                 : 
    1269                 : /* {{{ setup_verify
    1270                 :  * calist is an array containing file and directory names.  create a
    1271                 :  * certificate store and add those certs to it for use in verification.
    1272                 : */
    1273                 : static X509_STORE * setup_verify(zval * calist TSRMLS_DC)
    1274               0 : {
    1275                 :         X509_STORE *store;
    1276                 :         X509_LOOKUP * dir_lookup, * file_lookup;
    1277                 :         HashPosition pos;
    1278               0 :         int ndirs = 0, nfiles = 0;
    1279                 : 
    1280               0 :         store = X509_STORE_new();
    1281                 : 
    1282               0 :         if (store == NULL) {
    1283               0 :                 return NULL;
    1284                 :         }
    1285                 : 
    1286               0 :         if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
    1287               0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos);
    1288               0 :                 for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) {
    1289                 :                         zval ** item;
    1290                 :                         struct stat sb;
    1291                 : 
    1292               0 :                         if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) {
    1293               0 :                                 break;
    1294                 :                         }
    1295               0 :                         convert_to_string_ex(item);
    1296                 : 
    1297               0 :                         if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) {
    1298               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item));
    1299               0 :                                 continue;
    1300                 :                         }
    1301                 : 
    1302               0 :                         if ((sb.st_mode & S_IFREG) == S_IFREG) {
    1303               0 :                                 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    1304               0 :                                 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
    1305               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item));
    1306                 :                                 } else {
    1307               0 :                                         nfiles++;
    1308                 :                                 }
    1309               0 :                                 file_lookup = NULL;
    1310                 :                         } else {
    1311               0 :                                 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    1312               0 :                                 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
    1313               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item));
    1314                 :                                 } else { 
    1315               0 :                                         ndirs++;
    1316                 :                                 }
    1317               0 :                                 dir_lookup = NULL;
    1318                 :                         }
    1319               0 :                 }
    1320                 :         }
    1321               0 :         if (nfiles == 0) {
    1322               0 :                 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    1323               0 :                 if (file_lookup) {
    1324               0 :                         X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT);
    1325                 :                 }
    1326                 :         }
    1327               0 :         if (ndirs == 0) {
    1328               0 :                 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    1329               0 :                 if (dir_lookup) {
    1330               0 :                         X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT);
    1331                 :                 }
    1332                 :         }
    1333               0 :         return store;
    1334                 : }
    1335                 : /* }}} */
    1336                 : 
    1337                 : /* {{{ proto resource openssl_x509_read(mixed cert)
    1338                 :    Reads X.509 certificates */
    1339                 : PHP_FUNCTION(openssl_x509_read)
    1340               0 : {
    1341                 :         zval **cert;
    1342                 :         X509 *x509;
    1343                 : 
    1344               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
    1345               0 :                 return;
    1346                 :         }
    1347               0 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    1348               0 :         x509 = php_openssl_x509_from_zval(cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    1349                 : 
    1350               0 :         if (x509 == NULL) {
    1351               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
    1352               0 :                 RETURN_FALSE;
    1353                 :         }
    1354                 : }
    1355                 : /* }}} */
    1356                 : 
    1357                 : /* {{{ proto void openssl_x509_free(resource x509)
    1358                 :    Frees X.509 certificates */
    1359                 : PHP_FUNCTION(openssl_x509_free)
    1360               0 : {
    1361                 :         zval *x509;
    1362                 :         X509 *cert;
    1363                 : 
    1364               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) {
    1365               0 :                 return;
    1366                 :         }
    1367               0 :         ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509);
    1368               0 :         zend_list_delete(Z_LVAL_P(x509));
    1369                 : }
    1370                 : /* }}} */
    1371                 : 
    1372                 : /* }}} */
    1373                 : 
    1374                 : 
    1375                 : /* Pop all X509 from Stack and free them, free the stack afterwards */
    1376                 : static void php_sk_X509_free(STACK_OF(X509) * sk)
    1377               0 : {
    1378                 :         for (;;) {
    1379               0 :                 X509* x = sk_X509_pop(sk);
    1380               0 :                 if (!x) break;
    1381               0 :                 X509_free(x);
    1382               0 :         }
    1383               0 :         sk_X509_free(sk);
    1384               0 : }
    1385                 : 
    1386                 : static STACK_OF(X509) * php_array_to_X509_sk(zval ** zcerts TSRMLS_DC)
    1387               0 : {
    1388                 :         HashPosition hpos;
    1389                 :         zval ** zcertval;
    1390               0 :         STACK_OF(X509) * sk = NULL;
    1391                 :     X509 * cert;
    1392                 :     long certresource;
    1393                 : 
    1394               0 :         sk = sk_X509_new_null();
    1395                 : 
    1396                 :         /* get certs */
    1397               0 :         if (Z_TYPE_PP(zcerts) == IS_ARRAY) {
    1398               0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(*zcerts), &hpos);
    1399               0 :                 while(zend_hash_get_current_data_ex(HASH_OF(*zcerts), (void**)&zcertval, &hpos) == SUCCESS) {
    1400                 : 
    1401               0 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
    1402               0 :                         if (cert == NULL) {
    1403               0 :                                 goto clean_exit;
    1404                 :                         }
    1405                 : 
    1406               0 :                         if (certresource != -1) {
    1407               0 :                                 cert = X509_dup(cert);
    1408                 :                                 
    1409               0 :                                 if (cert == NULL) {
    1410               0 :                                         goto clean_exit;
    1411                 :                                 }
    1412                 :                                 
    1413                 :                         }
    1414               0 :                         sk_X509_push(sk, cert);
    1415                 : 
    1416               0 :                         zend_hash_move_forward_ex(HASH_OF(*zcerts), &hpos);
    1417                 :                 }
    1418                 :         } else {
    1419                 :                 /* a single certificate */
    1420               0 :                 cert = php_openssl_x509_from_zval(zcerts, 0, &certresource TSRMLS_CC);
    1421                 :                 
    1422               0 :                 if (cert == NULL) {
    1423               0 :                         goto clean_exit;
    1424                 :                 }
    1425                 : 
    1426               0 :                 if (certresource != -1) {
    1427               0 :                         cert = X509_dup(cert);
    1428               0 :                         if (cert == NULL) {
    1429               0 :                                 goto clean_exit;
    1430                 :                         }
    1431                 :                 }
    1432               0 :                 sk_X509_push(sk, cert);
    1433                 :         }
    1434                 : 
    1435               0 :   clean_exit:
    1436               0 :     return sk;
    1437                 : }
    1438                 : 
    1439                 : /* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args])
    1440                 :    Creates and exports a PKCS to file */
    1441                 : PHP_FUNCTION(openssl_pkcs12_export_to_file)
    1442               0 : {
    1443               0 :         X509 * cert = NULL;
    1444               0 :         BIO * bio_out = NULL;
    1445               0 :         PKCS12 * p12 = NULL;
    1446                 :         char * filename;
    1447               0 :         char * friendly_name = NULL;
    1448                 :         int filename_len;
    1449                 :         char * pass;
    1450                 :         int pass_len;
    1451               0 :         zval **zcert = NULL, *zpkey = NULL, *args = NULL;
    1452               0 :         EVP_PKEY *priv_key = NULL;
    1453                 :         long certresource, keyresource;
    1454                 :         zval ** item;
    1455               0 :         STACK_OF(X509) *ca = NULL;
    1456                 : 
    1457               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zszs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE)
    1458               0 :                 return;
    1459                 : 
    1460               0 :         RETVAL_FALSE;
    1461                 :         
    1462               0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1463               0 :         if (cert == NULL) {
    1464               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    1465               0 :                 return;
    1466                 :         }
    1467               0 :         priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    1468               0 :         if (priv_key == NULL) {
    1469               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    1470               0 :                 goto cleanup;
    1471                 :         }
    1472               0 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    1473               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
    1474               0 :                 goto cleanup;
    1475                 :         }
    1476               0 :         if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    1477               0 :                 goto cleanup;
    1478                 :         }
    1479                 : 
    1480                 :         /* parse extra config from args array, promote this to an extra function */
    1481               0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
    1482               0 :                 friendly_name = Z_STRVAL_PP(item);
    1483                 :         /* certpbe (default RC2-40)
    1484                 :            keypbe (default 3DES)
    1485                 :            friendly_caname
    1486                 :         */
    1487                 : 
    1488               0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
    1489               0 :                 ca = php_array_to_X509_sk(item TSRMLS_CC);
    1490                 :         /* end parse extra config */
    1491                 : 
    1492                 :         /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
    1493                 :                                        int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/
    1494                 : 
    1495               0 :         p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
    1496                 : 
    1497               0 :         bio_out = BIO_new_file(filename, "w"); 
    1498               0 :         if (bio_out) {
    1499                 :                 
    1500               0 :                 i2d_PKCS12_bio(bio_out, p12);
    1501                 : 
    1502               0 :                 RETVAL_TRUE;
    1503                 :         } else {
    1504               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
    1505                 :         }
    1506                 : 
    1507               0 :         BIO_free(bio_out);
    1508               0 :         PKCS12_free(p12);
    1509               0 :         php_sk_X509_free(ca);
    1510                 :         
    1511               0 : cleanup:
    1512                 : 
    1513               0 :         if (keyresource == -1 && priv_key) {
    1514               0 :                 EVP_PKEY_free(priv_key);
    1515                 :         }
    1516               0 :         if (certresource == -1 && cert) { 
    1517               0 :                 X509_free(cert);
    1518                 :         }
    1519                 : }
    1520                 : /* }}} */
    1521                 : 
    1522                 : /* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
    1523                 :    Creates and exports a PKCS12 to a var */
    1524                 : PHP_FUNCTION(openssl_pkcs12_export)
    1525               0 : {
    1526               0 :         X509 * cert = NULL;
    1527                 :         BIO * bio_out;
    1528               0 :         PKCS12 * p12 = NULL;
    1529               0 :         zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
    1530               0 :         EVP_PKEY *priv_key = NULL;
    1531                 :         long certresource, keyresource;
    1532                 :         char * pass;
    1533                 :         int pass_len;
    1534               0 :         char * friendly_name = NULL;
    1535                 :         zval ** item;
    1536               0 :         STACK_OF(X509) *ca = NULL;
    1537                 : 
    1538               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
    1539               0 :                 return;
    1540                 : 
    1541               0 :         RETVAL_FALSE;
    1542                 :         
    1543               0 :         cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC);
    1544               0 :         if (cert == NULL) {
    1545               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    1546               0 :                 return;
    1547                 :         }
    1548               0 :         priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    1549               0 :         if (priv_key == NULL) {
    1550               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    1551               0 :                 goto cleanup;
    1552                 :         }
    1553               0 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    1554               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
    1555               0 :                 goto cleanup;
    1556                 :         }
    1557                 : 
    1558                 :         /* parse extra config from args array, promote this to an extra function */
    1559               0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
    1560               0 :                 friendly_name = Z_STRVAL_PP(item);
    1561                 : 
    1562               0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
    1563               0 :                 ca = php_array_to_X509_sk(item TSRMLS_CC);
    1564                 :         /* end parse extra config */
    1565                 :         
    1566               0 :         p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
    1567                 : 
    1568               0 :         bio_out = BIO_new(BIO_s_mem());
    1569               0 :         if (i2d_PKCS12_bio(bio_out, p12))  {
    1570                 :                 BUF_MEM *bio_buf;
    1571                 : 
    1572               0 :                 zval_dtor(zout);
    1573               0 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1574               0 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
    1575                 : 
    1576               0 :                 RETVAL_TRUE;
    1577                 :         }
    1578                 : 
    1579               0 :         BIO_free(bio_out);
    1580               0 :         PKCS12_free(p12);
    1581               0 :         php_sk_X509_free(ca);
    1582                 :         
    1583               0 : cleanup:
    1584                 : 
    1585               0 :         if (keyresource == -1 && priv_key) {
    1586               0 :                 EVP_PKEY_free(priv_key);
    1587                 :         }
    1588               0 :         if (certresource == -1 && cert) { 
    1589               0 :                 X509_free(cert);
    1590                 :         }
    1591                 : }
    1592                 : /* }}} */
    1593                 : 
    1594                 : /* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass)
    1595                 :    Parses a PKCS12 to an array */
    1596                 : PHP_FUNCTION(openssl_pkcs12_read)
    1597               1 : {
    1598               1 :         zval *zout = NULL, *zextracerts, *zcert, *zpkey;
    1599                 :         char *pass, *zp12;
    1600                 :         int pass_len, zp12_len;
    1601               1 :         PKCS12 * p12 = NULL;
    1602               1 :         EVP_PKEY * pkey = NULL;
    1603               1 :         X509 * cert = NULL;
    1604               1 :         STACK_OF(X509) * ca = NULL;
    1605               1 :         BIO * bio_in = NULL;
    1606                 :         int i;
    1607                 : 
    1608               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szs", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE)
    1609               0 :                 return;
    1610                 : 
    1611               1 :         RETVAL_FALSE;
    1612                 :         
    1613               1 :         bio_in = BIO_new(BIO_s_mem());
    1614                 :         
    1615               1 :         if(!BIO_write(bio_in, zp12, zp12_len))
    1616               0 :                 goto cleanup;
    1617                 :         
    1618               1 :         if(d2i_PKCS12_bio(bio_in, &p12)) {
    1619               0 :                 if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
    1620                 :                         BIO * bio_out;
    1621                 : 
    1622               0 :                         zval_dtor(zout);
    1623               0 :                         array_init(zout);
    1624                 : 
    1625               0 :                         bio_out = BIO_new(BIO_s_mem());
    1626               0 :                         if (PEM_write_bio_X509(bio_out, cert)) {
    1627                 :                                 BUF_MEM *bio_buf;
    1628               0 :                                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1629               0 :                                 MAKE_STD_ZVAL(zcert);
    1630               0 :                                 ZVAL_STRINGL(zcert, bio_buf->data, bio_buf->length, 1);
    1631               0 :                                 add_assoc_zval(zout, "cert", zcert);
    1632                 :                         }
    1633               0 :                         BIO_free(bio_out);
    1634                 : 
    1635               0 :                         bio_out = BIO_new(BIO_s_mem());
    1636               0 :                         if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) {
    1637                 :                                 BUF_MEM *bio_buf;
    1638               0 :                                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1639               0 :                                 MAKE_STD_ZVAL(zpkey);
    1640               0 :                                 ZVAL_STRINGL(zpkey, bio_buf->data, bio_buf->length, 1);
    1641               0 :                                 add_assoc_zval(zout, "pkey", zpkey);
    1642                 :                         }
    1643               0 :                         BIO_free(bio_out);
    1644                 : 
    1645               0 :                         MAKE_STD_ZVAL(zextracerts);
    1646               0 :                         array_init(zextracerts);
    1647                 :                         
    1648               0 :                         for (i=0;;i++) {
    1649                 :                                 zval * zextracert;
    1650               0 :                                 X509* aCA = sk_X509_pop(ca);
    1651               0 :                                 if (!aCA) break;
    1652                 :                                 
    1653               0 :                                 bio_out = BIO_new(BIO_s_mem());
    1654               0 :                                 if (PEM_write_bio_X509(bio_out, aCA)) {
    1655                 :                                         BUF_MEM *bio_buf;
    1656               0 :                                         BIO_get_mem_ptr(bio_out, &bio_buf);
    1657               0 :                                         MAKE_STD_ZVAL(zextracert);
    1658               0 :                                         ZVAL_STRINGL(zextracert, bio_buf->data, bio_buf->length, 1);
    1659               0 :                                         add_index_zval(zextracerts, i, zextracert);
    1660                 :                                         
    1661                 :                                 }
    1662               0 :                                 BIO_free(bio_out);
    1663                 : 
    1664               0 :                                 X509_free(aCA);
    1665               0 :                         }
    1666               0 :                         if(ca) {
    1667               0 :                                 sk_X509_free(ca);
    1668               0 :                                 add_assoc_zval(zout, "extracerts", zextracerts);
    1669                 :                         } else {
    1670               0 :                                 zval_dtor(zextracerts);
    1671                 :                         }
    1672                 :                         
    1673               0 :                         RETVAL_TRUE;
    1674                 :                         
    1675               0 :                         PKCS12_free(p12);
    1676                 :                 }
    1677                 :         }
    1678                 :         
    1679               1 :   cleanup:
    1680               1 :         if (bio_in) {
    1681               1 :                 BIO_free(bio_in);
    1682                 :         }
    1683               1 :         if (pkey) {
    1684               0 :                 EVP_PKEY_free(pkey);
    1685                 :         }
    1686               1 :         if (cert) { 
    1687               0 :                 X509_free(cert);
    1688                 :         }
    1689                 : }
    1690                 : /* }}} */
    1691                 : 
    1692                 : /* {{{ x509 CSR functions */
    1693                 : 
    1694                 : /* {{{ php_openssl_make_REQ */
    1695                 : static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs TSRMLS_DC)
    1696               3 : {
    1697               3 :         STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
    1698                 :         char * str, *dn_sect, *attr_sect;
    1699                 : 
    1700               3 :         dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name");
    1701               3 :         if (dn_sect == NULL) {
    1702               0 :                 return FAILURE;
    1703                 :         }
    1704               3 :         dn_sk = CONF_get_section(req->req_config, dn_sect);
    1705               3 :         if (dn_sk == NULL) { 
    1706               0 :                 return FAILURE;
    1707                 :         }
    1708               3 :         attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
    1709               3 :         if (attr_sect == NULL) {
    1710               0 :                 attr_sk = NULL;
    1711                 :         } else {
    1712               3 :                 attr_sk = CONF_get_section(req->req_config, attr_sect);
    1713               3 :                 if (attr_sk == NULL) {
    1714               0 :                         return FAILURE;
    1715                 :                 }
    1716                 :         }
    1717                 :         /* setup the version number: version 1 */
    1718               3 :         if (X509_REQ_set_version(csr, 0L)) {
    1719                 :                 int i, nid;
    1720                 :                 char * type;
    1721                 :                 CONF_VALUE * v;
    1722                 :                 X509_NAME * subj;
    1723                 :                 HashPosition hpos;
    1724                 :                 zval ** item;
    1725                 :                 
    1726               3 :                 subj = X509_REQ_get_subject_name(csr);
    1727                 :                 /* apply values from the dn hash */
    1728               3 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(dn), &hpos);
    1729              13 :                 while(zend_hash_get_current_data_ex(HASH_OF(dn), (void**)&item, &hpos) == SUCCESS) {
    1730               7 :                         char * strindex = NULL; 
    1731               7 :                         uint strindexlen = 0;
    1732                 :                         ulong intindex;
    1733                 :                         
    1734               7 :                         zend_hash_get_current_key_ex(HASH_OF(dn), &strindex, &strindexlen, &intindex, 0, &hpos);
    1735                 : 
    1736               7 :                         convert_to_string_ex(item);
    1737                 : 
    1738               7 :                         if (strindex) {
    1739                 :                                 int nid;
    1740                 : 
    1741               5 :                                 nid = OBJ_txt2nid(strindex);
    1742               5 :                                 if (nid != NID_undef) {
    1743               5 :                                         if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, 
    1744                 :                                                                 (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0))
    1745                 :                                         {
    1746               0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item));
    1747               0 :                                                 return FAILURE;
    1748                 :                                         }
    1749                 :                                 } else {
    1750               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
    1751                 :                                 }
    1752                 :                         }
    1753               7 :                         zend_hash_move_forward_ex(HASH_OF(dn), &hpos);
    1754                 :                 }
    1755                 : 
    1756                 :                 /* Finally apply defaults from config file */
    1757              48 :                 for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
    1758                 :                         int len;
    1759                 :                         char buffer[200 + 1]; /*200 + \0 !*/
    1760                 :                         
    1761              45 :                         v = sk_CONF_VALUE_value(dn_sk, i);
    1762              45 :                         type = v->name;
    1763                 :                         
    1764              45 :                         len = strlen(type);
    1765              45 :                         if (len < sizeof("_default")) {
    1766               0 :                                 continue;
    1767                 :                         }
    1768              45 :                         len -= sizeof("_default") - 1;
    1769              45 :                         if (strcmp("_default", type + len) != 0) {
    1770              33 :                                 continue;
    1771                 :                         }
    1772              12 :                         if (len > 200) {
    1773               0 :                                 len = 200;
    1774                 :                         }
    1775              12 :                         memcpy(buffer, type, len);
    1776              12 :                         buffer[len] = '\0';
    1777              12 :                         type = buffer;
    1778                 :                 
    1779                 :                         /* Skip past any leading X. X: X, etc to allow for multiple
    1780                 :                          * instances */
    1781             141 :                         for (str = type; *str; str++) {
    1782             132 :                                 if (*str == ':' || *str == ',' || *str == '.') {
    1783               3 :                                         str++;
    1784               3 :                                         if (*str) {
    1785               3 :                                                 type = str;
    1786                 :                                         }
    1787               3 :                                         break;
    1788                 :                                 }
    1789                 :                         }
    1790                 :                         /* if it is already set, skip this */
    1791              12 :                         nid = OBJ_txt2nid(type);
    1792              12 :                         if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) {
    1793               4 :                                 continue;
    1794                 :                         }
    1795               8 :                         if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_ASC, (unsigned char*)v->value, -1, -1, 0)) {
    1796               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
    1797               0 :                                 return FAILURE;
    1798                 :                         }
    1799               8 :                         if (!X509_NAME_entry_count(subj)) {
    1800               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no objects specified in config file");
    1801               0 :                                 return FAILURE;
    1802                 :                         }
    1803                 :                 }
    1804               3 :                 if (attribs) {
    1805               1 :                         zend_hash_internal_pointer_reset_ex(HASH_OF(attribs), &hpos);
    1806               2 :                         while(zend_hash_get_current_data_ex(HASH_OF(attribs), (void**)&item, &hpos) == SUCCESS) {
    1807                 :                                 char * strindex; uint strindexlen;
    1808                 :                                 ulong intindex;
    1809                 : 
    1810               0 :                                 zend_hash_get_current_key_ex(HASH_OF(attribs), &strindex, &strindexlen, &intindex, 0, &hpos);
    1811               0 :                                 convert_to_string_ex(item);
    1812                 : 
    1813               0 :                                 if (strindex) {
    1814                 :                                         int nid;
    1815                 : 
    1816               0 :                                         nid = OBJ_txt2nid(strindex);
    1817               0 :                                         if (nid != NID_undef) {
    1818               0 :                                                 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) {
    1819               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item));
    1820               0 :                                                         return FAILURE;
    1821                 :                                                 }
    1822                 :                                         } else {
    1823               0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
    1824                 :                                         }
    1825                 :                                 }
    1826               0 :                                 zend_hash_move_forward_ex(HASH_OF(attribs), &hpos);
    1827                 :                         }
    1828               2 :                         for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
    1829               2 :                                 v = sk_CONF_VALUE_value(attr_sk, i);
    1830                 :                                 /* if it is already set, skip this */
    1831               2 :                                 nid = OBJ_txt2nid(v->name);
    1832               2 :                                 if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) {
    1833               0 :                                         continue;
    1834                 :                                 }
    1835               2 :                                 if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_ASC, (unsigned char*)v->value, -1)) {
    1836               1 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "add1_attr_by_txt %s -> %s (failed)", v->name, v->value);
    1837               1 :                                         return FAILURE;
    1838                 :                                 }
    1839                 :                         }
    1840                 :                 }
    1841                 :         }
    1842                 : 
    1843               2 :         X509_REQ_set_pubkey(csr, req->priv_key);
    1844               2 :         return SUCCESS;
    1845                 : }
    1846                 : /* }}} */
    1847                 : 
    1848                 : /* {{{ php_openssl_csr_from_zval */
    1849                 : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
    1850               3 : {
    1851               3 :         X509_REQ * csr = NULL;
    1852               3 :         char * filename = NULL;
    1853                 :         BIO * in;
    1854                 :         
    1855               3 :         if (resourceval) {
    1856               3 :                 *resourceval = -1;
    1857                 :         }
    1858               3 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
    1859                 :                 void * what;
    1860                 :                 int type;
    1861                 : 
    1862               2 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509 CSR", &type, 1, le_csr);
    1863               2 :                 if (what) {
    1864               2 :                         if (resourceval) {
    1865               2 :                                 *resourceval = Z_LVAL_PP(val);
    1866                 :                         }
    1867               2 :                         return (X509_REQ*)what;
    1868                 :                 }
    1869               0 :                 return NULL;
    1870               1 :         } else if (Z_TYPE_PP(val) != IS_STRING) {
    1871               0 :                 return NULL;
    1872                 :         }
    1873                 : 
    1874               1 :         if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
    1875               0 :                 filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
    1876                 :         }
    1877               1 :         if (filename) {
    1878               0 :                 if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    1879               0 :                         return NULL;
    1880                 :                 }
    1881               0 :                 in = BIO_new_file(filename, "r");
    1882                 :         } else {
    1883               1 :                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    1884                 :         }
    1885               1 :         csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL);
    1886               1 :         BIO_free(in);
    1887                 : 
    1888               1 :         return csr;
    1889                 : }
    1890                 : /* }}} */
    1891                 : 
    1892                 : /* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true])
    1893                 :    Exports a CSR to file */
    1894                 : PHP_FUNCTION(openssl_csr_export_to_file)
    1895               0 : {
    1896                 :         X509_REQ * csr;
    1897               0 :         zval * zcsr = NULL;
    1898               0 :         zend_bool notext = 1;
    1899               0 :         char * filename = NULL; int filename_len;
    1900                 :         BIO * bio_out;
    1901                 :         long csr_resource;
    1902                 : 
    1903               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b", &zcsr, &filename, &filename_len, &notext) == FAILURE) {
    1904               0 :                 return;
    1905                 :         }
    1906               0 :         RETVAL_FALSE;
    1907                 : 
    1908               0 :         csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
    1909               0 :         if (csr == NULL) {
    1910               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    1911               0 :                 return;
    1912                 :         }
    1913                 : 
    1914               0 :         if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    1915               0 :                 return;
    1916                 :         }
    1917                 : 
    1918               0 :         bio_out = BIO_new_file(filename, "w");
    1919               0 :         if (bio_out) {
    1920               0 :                 if (!notext) {
    1921               0 :                         X509_REQ_print(bio_out, csr);
    1922                 :                 }
    1923               0 :                 PEM_write_bio_X509_REQ(bio_out, csr);
    1924               0 :                 RETVAL_TRUE;
    1925                 :         } else {
    1926               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
    1927                 :         }
    1928                 : 
    1929               0 :         if (csr_resource == -1 && csr) {
    1930               0 :                 X509_REQ_free(csr);
    1931                 :         }
    1932               0 :         BIO_free(bio_out);
    1933                 : }
    1934                 : /* }}} */
    1935                 : 
    1936                 : /* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true])
    1937                 :    Exports a CSR to file or a var */
    1938                 : PHP_FUNCTION(openssl_csr_export)
    1939               1 : {
    1940                 :         X509_REQ * csr;
    1941               1 :         zval * zcsr = NULL, *zout=NULL;
    1942               1 :         zend_bool notext = 1;
    1943                 :         BIO * bio_out;
    1944                 : 
    1945                 :         long csr_resource;
    1946                 : 
    1947               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zcsr, &zout, &notext) == FAILURE) {
    1948               0 :                 return;
    1949                 :         }
    1950               1 :         RETVAL_FALSE;
    1951                 : 
    1952               1 :         csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
    1953               1 :         if (csr == NULL) {
    1954               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    1955               0 :                 return;
    1956                 :         }
    1957                 : 
    1958                 :         /* export to a var */
    1959                 : 
    1960               1 :         bio_out = BIO_new(BIO_s_mem());
    1961               1 :         if (!notext) {
    1962               1 :                 X509_REQ_print(bio_out, csr);
    1963                 :         }
    1964                 : 
    1965               1 :         if (PEM_write_bio_X509_REQ(bio_out, csr)) {
    1966                 :                 BUF_MEM *bio_buf;
    1967                 : 
    1968               1 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1969               1 :                 zval_dtor(zout);
    1970               1 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
    1971                 : 
    1972               1 :                 RETVAL_TRUE;
    1973                 :         }
    1974                 : 
    1975               1 :         if (csr_resource == -1 && csr) {
    1976               0 :                 X509_REQ_free(csr);
    1977                 :         }
    1978               1 :         BIO_free(bio_out);
    1979                 : }
    1980                 : /* }}} */
    1981                 : 
    1982                 : /* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]])
    1983                 :    Signs a cert with another CERT */
    1984                 : PHP_FUNCTION(openssl_csr_sign)
    1985               1 : {
    1986               1 :         zval ** zcert = NULL, **zcsr, **zpkey, *args = NULL;
    1987                 :         long num_days;
    1988               1 :         long serial = 0L;
    1989               1 :         X509 * cert = NULL, *new_cert = NULL;
    1990                 :         X509_REQ * csr;
    1991               1 :         EVP_PKEY * key = NULL, *priv_key = NULL;
    1992               1 :         long csr_resource, certresource = 0, keyresource;
    1993                 :         int i;
    1994                 :         struct php_x509_request req;
    1995                 :         
    1996               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ!Zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE)
    1997               0 :                 return;
    1998                 : 
    1999               1 :         RETVAL_FALSE;
    2000               1 :         PHP_SSL_REQ_INIT(&req);
    2001                 :         
    2002               1 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2003               1 :         if (csr == NULL) {
    2004               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    2005               0 :                 return;
    2006                 :         }
    2007               1 :         if (zcert) {
    2008               0 :                 cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    2009               0 :                 if (cert == NULL) {
    2010               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 2");
    2011               0 :                         goto cleanup;
    2012                 :                 }
    2013                 :         }
    2014               1 :         priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    2015               1 :         if (priv_key == NULL) {
    2016               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    2017               0 :                 goto cleanup;
    2018                 :         }
    2019               1 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    2020               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert");
    2021               0 :                 goto cleanup;
    2022                 :         }
    2023                 :         
    2024               1 :         if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) {
    2025               0 :                 goto cleanup;
    2026                 :         }
    2027                 :         /* Check that the request matches the signature */
    2028               1 :         key = X509_REQ_get_pubkey(csr);
    2029               1 :         if (key == NULL) {
    2030               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error unpacking public key");
    2031               0 :                 goto cleanup;
    2032                 :         }
    2033               1 :         i = X509_REQ_verify(csr, key);
    2034                 : 
    2035               1 :         if (i < 0) {
    2036               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature verification problems");
    2037               0 :                 goto cleanup;
    2038                 :         }
    2039               1 :         else if (i == 0) {
    2040               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature did not match the certificate request");
    2041               0 :                 goto cleanup;
    2042                 :         }
    2043                 :         
    2044                 :         /* Now we can get on with it */
    2045                 :         
    2046               1 :         new_cert = X509_new();
    2047               1 :         if (new_cert == NULL) {
    2048               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No memory");
    2049               0 :                 goto cleanup;
    2050                 :         }
    2051                 :         /* Version 3 cert */
    2052               1 :         if (!X509_set_version(new_cert, 2))
    2053               0 :                 goto cleanup;
    2054                 : 
    2055               1 :         ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
    2056                 :         
    2057               1 :         X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
    2058                 : 
    2059               1 :         if (cert == NULL) {
    2060               1 :                 cert = new_cert;
    2061                 :         }
    2062               1 :         if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) {
    2063               0 :                 goto cleanup;
    2064                 :         }
    2065               1 :         X509_gmtime_adj(X509_get_notBefore(new_cert), 0);
    2066               1 :         X509_gmtime_adj(X509_get_notAfter(new_cert), (long)60*60*24*num_days);
    2067               1 :         i = X509_set_pubkey(new_cert, key);
    2068               1 :         if (!i) {
    2069               0 :                 goto cleanup;
    2070                 :         }
    2071               1 :         if (req.extensions_section) {
    2072                 :                 X509V3_CTX ctx;
    2073                 :                 
    2074               1 :                 X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0);
    2075               1 :                 X509V3_set_conf_lhash(&ctx, req.req_config);
    2076               1 :                 if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) {
    2077               0 :                         goto cleanup;
    2078                 :                 }
    2079                 :         }
    2080                 : 
    2081                 :         /* Now sign it */
    2082               1 :         if (!X509_sign(new_cert, priv_key, req.digest)) {
    2083               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it");
    2084               0 :                 goto cleanup;
    2085                 :         }
    2086                 :         
    2087                 :         /* Succeeded; lets return the cert */
    2088               1 :         RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509));
    2089               1 :         new_cert = NULL;
    2090                 :         
    2091               1 : cleanup:
    2092                 : 
    2093               1 :         if (cert == new_cert) {
    2094               0 :                 cert = NULL;
    2095                 :         }
    2096               1 :         PHP_SSL_REQ_DISPOSE(&req);
    2097                 : 
    2098               1 :         if (keyresource == -1 && priv_key) {
    2099               0 :                 EVP_PKEY_free(priv_key);
    2100                 :         }
    2101               1 :         if (key) {
    2102               1 :                 EVP_PKEY_free(key);
    2103                 :         }
    2104               1 :         if (csr_resource == -1 && csr) {
    2105               0 :                 X509_REQ_free(csr);
    2106                 :         }
    2107               1 :         if (certresource == -1 && cert) { 
    2108               0 :                 X509_free(cert);
    2109                 :         }
    2110               1 :         if (new_cert) {
    2111               0 :                 X509_free(new_cert);
    2112                 :         }
    2113                 : }
    2114                 : /* }}} */
    2115                 : 
    2116                 : /* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs [, array extraattribs]])
    2117                 :    Generates a privkey and CSR */
    2118                 : PHP_FUNCTION(openssl_csr_new)
    2119               5 : {
    2120                 :         struct php_x509_request req;
    2121               5 :         zval * args = NULL, * dn, *attribs = NULL;
    2122                 :         zval * out_pkey;
    2123               5 :         X509_REQ * csr = NULL;
    2124               5 :         int we_made_the_key = 1;
    2125                 :         long key_resource;
    2126                 :         
    2127               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) {
    2128               2 :                 return;
    2129                 :         }
    2130               3 :         RETVAL_FALSE;
    2131                 :         
    2132               3 :         PHP_SSL_REQ_INIT(&req);
    2133                 : 
    2134               3 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    2135                 :                 /* Generate or use a private key */
    2136               3 :                 if (Z_TYPE_P(out_pkey) != IS_NULL) {
    2137               3 :                         req.priv_key = php_openssl_evp_from_zval(&out_pkey, 0, NULL, 0, &key_resource TSRMLS_CC);
    2138               3 :                         if (req.priv_key != NULL) {
    2139               1 :                                 we_made_the_key = 0;
    2140                 :                         }
    2141                 :                 }
    2142               3 :                 if (req.priv_key == NULL) {
    2143               2 :                         php_openssl_generate_private_key(&req TSRMLS_CC);
    2144                 :                 }
    2145               3 :                 if (req.priv_key == NULL) {
    2146               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to generate a private key");
    2147                 :                 } else {
    2148               3 :                         csr = X509_REQ_new();
    2149               3 :                         if (csr) {
    2150               3 :                                 if (php_openssl_make_REQ(&req, csr, dn, attribs TSRMLS_CC) == SUCCESS) {
    2151                 :                                         X509V3_CTX ext_ctx;
    2152                 : 
    2153               2 :                                         X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0);
    2154               2 :                                         X509V3_set_conf_lhash(&ext_ctx, req.req_config);
    2155                 : 
    2156                 :                                         /* Add extensions */
    2157               2 :                                         if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config,
    2158                 :                                                                 &ext_ctx, req.request_extensions_section, csr))
    2159                 :                                         {
    2160               0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading extension section %s", req.request_extensions_section);
    2161                 :                                         } else {
    2162               2 :                                                 RETVAL_TRUE;
    2163                 :                                                 
    2164               2 :                                                 if (X509_REQ_sign(csr, req.priv_key, req.digest)) {
    2165               2 :                                                         RETVAL_RESOURCE(zend_list_insert(csr, le_csr));
    2166               2 :                                                         csr = NULL;                     
    2167                 :                                                 } else {
    2168               0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request");
    2169                 :                                                 }
    2170                 : 
    2171               2 :                                                 if (we_made_the_key) {
    2172                 :                                                         /* and a resource for the private key */
    2173               1 :                                                         zval_dtor(out_pkey);
    2174               1 :                                                         ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key));
    2175               1 :                                                         req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
    2176               1 :                                                 } else if (key_resource != -1) {
    2177               1 :                                                         req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
    2178                 :                                                 }
    2179                 :                                         }
    2180                 :                                 }
    2181                 :                                 else {
    2182               1 :                                         if (!we_made_the_key) {
    2183                 :                                                 /* if we have not made the key we are not supposed to zap it by calling dispose! */
    2184               0 :                                                 req.priv_key = NULL;
    2185                 :                                         }
    2186                 :                                 }
    2187                 :                         }
    2188                 :                 }
    2189                 :         }
    2190               3 :         if (csr) {
    2191               1 :                 X509_REQ_free(csr);
    2192                 :         }
    2193               3 :         PHP_SSL_REQ_DISPOSE(&req);
    2194                 : }
    2195                 : /* }}} */
    2196                 : 
    2197                 : /* {{{ proto mixed openssl_csr_get_subject(mixed csr)
    2198                 :    Returns the subject of a CERT or FALSE on error */
    2199                 : PHP_FUNCTION(openssl_csr_get_subject)
    2200               1 : {
    2201                 :         zval ** zcsr;
    2202               1 :         zend_bool use_shortnames = 1;
    2203                 :         long csr_resource;
    2204                 :         X509_NAME * subject;
    2205                 :         X509_REQ * csr;
    2206                 : 
    2207               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
    2208               0 :                 return;
    2209                 :         }
    2210                 : 
    2211               1 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2212                 : 
    2213               1 :         if (csr == NULL) {
    2214               0 :                 RETURN_FALSE;
    2215                 :         }
    2216                 : 
    2217               1 :         subject = X509_REQ_get_subject_name(csr);
    2218                 : 
    2219               1 :         array_init(return_value);
    2220               1 :         add_assoc_name_entry(return_value, NULL, subject, use_shortnames TSRMLS_CC);
    2221               1 :         return;
    2222                 : }
    2223                 : /* }}} */
    2224                 : 
    2225                 : /* {{{ proto mixed openssl_csr_get_public_key(mixed csr)
    2226                 :         Returns the subject of a CERT or FALSE on error */
    2227                 : PHP_FUNCTION(openssl_csr_get_public_key)
    2228               0 : {
    2229                 :         zval ** zcsr;
    2230               0 :         zend_bool use_shortnames = 1;
    2231                 :         long csr_resource;
    2232                 : 
    2233                 :         X509_REQ * csr;
    2234                 :         EVP_PKEY *tpubkey;
    2235                 : 
    2236               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
    2237               0 :                 return;
    2238                 :         }
    2239                 : 
    2240               0 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2241                 : 
    2242               0 :         if (csr == NULL) {
    2243               0 :                 RETURN_FALSE;
    2244                 :         }
    2245                 : 
    2246               0 :         tpubkey=X509_REQ_get_pubkey(csr);
    2247               0 :         RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key));
    2248               0 :         return;
    2249                 : }
    2250                 : /* }}} */
    2251                 : 
    2252                 : /* }}} */
    2253                 : 
    2254                 : /* {{{ EVP Public/Private key functions */
    2255                 : 
    2256                 : /* {{{ php_openssl_evp_from_zval
    2257                 :    Given a zval, coerce it into a EVP_PKEY object.
    2258                 :         It can be:
    2259                 :                 1. private key resource from openssl_get_privatekey()
    2260                 :                 2. X509 resource -> public key will be extracted from it
    2261                 :                 3. if it starts with file:// interpreted as path to key file
    2262                 :                 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey()
    2263                 :                 5. an array(0 => [items 2..4], 1 => passphrase)
    2264                 :                 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key
    2265                 :         NOTE: If you are requesting a private key but have not specified a passphrase, you should use an
    2266                 :         empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in
    2267                 :         the Apache error log!
    2268                 : */
    2269                 : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC)
    2270              21 : {
    2271              21 :         EVP_PKEY * key = NULL;
    2272              21 :         X509 * cert = NULL;
    2273              21 :         int free_cert = 0;
    2274              21 :         long cert_res = -1;
    2275              21 :         char * filename = NULL;
    2276                 :         zval tmp;
    2277                 : 
    2278              21 :         Z_TYPE(tmp) = IS_NULL;
    2279                 : 
    2280                 : #define TMP_CLEAN \
    2281                 :         if (Z_TYPE(tmp) == IS_STRING) {\
    2282                 :                 zval_dtor(&tmp); \
    2283                 :         } \
    2284                 :         return NULL;
    2285                 : 
    2286              21 :         if (resourceval) {
    2287              21 :                 *resourceval = -1;
    2288                 :         }
    2289              21 :         if (Z_TYPE_PP(val) == IS_ARRAY) {
    2290                 :                 zval ** zphrase;
    2291                 :                 
    2292                 :                 /* get passphrase */
    2293                 : 
    2294               3 :                 if (zend_hash_index_find(HASH_OF(*val), 1, (void **)&zphrase) == FAILURE) {
    2295               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
    2296               1 :                         return NULL;
    2297                 :                 }
    2298                 :                 
    2299               2 :                 if (Z_TYPE_PP(zphrase) == IS_STRING) {
    2300               1 :                         passphrase = Z_STRVAL_PP(zphrase);
    2301                 :                 } else {
    2302               1 :                         tmp = **zphrase;
    2303               1 :                         zval_copy_ctor(&tmp);
    2304               1 :                         convert_to_string(&tmp);
    2305               1 :                         passphrase = Z_STRVAL(tmp);
    2306                 :                 }
    2307                 : 
    2308                 :                 /* now set val to be the key param and continue */
    2309               2 :                 if (zend_hash_index_find(HASH_OF(*val), 0, (void **)&val) == FAILURE) {
    2310               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
    2311               0 :                         TMP_CLEAN;
    2312                 :                 }
    2313                 :         }
    2314                 : 
    2315              20 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
    2316                 :                 void * what;
    2317                 :                 int type;
    2318                 : 
    2319               8 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key);
    2320               8 :                 if (!what) {
    2321               0 :                         TMP_CLEAN;
    2322                 :                 }
    2323               8 :                 if (resourceval) { 
    2324               8 :                         *resourceval = Z_LVAL_PP(val);
    2325                 :                 }
    2326               8 :                 if (type == le_x509) {
    2327                 :                         /* extract key from cert, depending on public_key param */
    2328               0 :                         cert = (X509*)what;
    2329               0 :                         free_cert = 0;
    2330               8 :                 } else if (type == le_key) {
    2331                 :                         int is_priv;
    2332                 : 
    2333               8 :                         is_priv = php_openssl_is_private_key((EVP_PKEY*)what TSRMLS_CC);
    2334                 : 
    2335                 :                         /* check whether it is actually a private key if requested */
    2336               8 :                         if (!public_key && !is_priv) {
    2337               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param is a public key");
    2338               0 :                                 TMP_CLEAN;
    2339                 :                         }
    2340                 : 
    2341               8 :                         if (public_key && is_priv) {
    2342               1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Don't know how to get public key from this private key");
    2343               1 :                                 TMP_CLEAN;
    2344                 :                         } else {
    2345               7 :                                 if (Z_TYPE(tmp) == IS_STRING) {
    2346               0 :                                         zval_dtor(&tmp);
    2347                 :                                 }
    2348                 :                                 /* got the key - return it */
    2349               7 :                                 return (EVP_PKEY*)what;
    2350                 :                         }
    2351                 :                 } else {
    2352                 :                         /* other types could be used here - eg: file pointers and read in the data from them */
    2353               0 :                         TMP_CLEAN;
    2354                 :                 }
    2355                 :         } else {
    2356                 :                 /* force it to be a string and check if it refers to a file */
    2357                 :                 /* passing non string values leaks, object uses toString, it returns NULL 
    2358                 :                  * See bug38255.phpt 
    2359                 :                  */
    2360              12 :                 if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
    2361               5 :                         TMP_CLEAN;
    2362                 :                 }
    2363               7 :                 convert_to_string_ex(val);
    2364                 : 
    2365               7 :                 if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
    2366               4 :                         filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
    2367                 :                 }
    2368                 :                 /* it's an X509 file/cert of some kind, and we need to extract the data from that */
    2369               7 :                 if (public_key) {
    2370               2 :                         cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC);
    2371               2 :                         free_cert = (cert_res == -1);
    2372                 :                         /* actual extraction done later */
    2373               2 :                         if (!cert) {
    2374                 :                                 /* not a X509 certificate, try to retrieve public key */
    2375                 :                                 BIO* in;
    2376               1 :                                 if (filename) {
    2377               1 :                                         in = BIO_new_file(filename, "r");
    2378                 :                                 } else {
    2379               0 :                                         in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    2380                 :                                 }
    2381               1 :                                 if (in == NULL) {
    2382               0 :                                         TMP_CLEAN;
    2383                 :                                 }
    2384               1 :                                 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    2385               1 :                                 BIO_free(in);
    2386                 :                         }
    2387                 :                 } else {
    2388                 :                         /* we want the private key */
    2389                 :                         BIO *in;
    2390                 : 
    2391               5 :                         if (filename) {
    2392               3 :                                 if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    2393               0 :                                         TMP_CLEAN;
    2394                 :                                 }
    2395               3 :                                 in = BIO_new_file(filename, "r");
    2396                 :                         } else {
    2397               2 :                                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    2398                 :                         }
    2399                 : 
    2400               5 :                         if (in == NULL) {
    2401               0 :                                 TMP_CLEAN;
    2402                 :                         }
    2403               5 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
    2404               5 :                         BIO_free(in);
    2405                 :                 }
    2406                 :         }
    2407                 : 
    2408               7 :         if (public_key && cert && key == NULL) {
    2409                 :                 /* extract public key from X509 cert */
    2410               1 :                 key = (EVP_PKEY *) X509_get_pubkey(cert);
    2411                 :         }
    2412                 : 
    2413               7 :         if (free_cert && cert) {
    2414               1 :                 X509_free(cert);
    2415                 :         }
    2416               7 :         if (key && makeresource && resourceval) {
    2417               7 :                 *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key);
    2418                 :         }
    2419               7 :         if (Z_TYPE(tmp) == IS_STRING) {
    2420               0 :                 zval_dtor(&tmp);
    2421                 :         }
    2422               7 :         return key;
    2423                 : }
    2424                 : /* }}} */
    2425                 : 
    2426                 : /* {{{ php_openssl_generate_private_key */
    2427                 : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC)
    2428               7 : {
    2429               7 :         char * randfile = NULL;
    2430                 :         int egdsocket, seeded;
    2431               7 :         EVP_PKEY * return_val = NULL;
    2432                 :         
    2433               7 :         if (req->priv_key_bits < MIN_KEY_LENGTH) {
    2434               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d",
    2435                 :                                 MIN_KEY_LENGTH, req->priv_key_bits);
    2436               0 :                 return NULL;
    2437                 :         }
    2438                 : 
    2439               7 :         randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
    2440               7 :         php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
    2441                 :         
    2442               7 :         if ((req->priv_key = EVP_PKEY_new()) != NULL) {
    2443               7 :                 switch(req->priv_key_type) {
    2444                 :                         case OPENSSL_KEYTYPE_RSA:
    2445               7 :                                 if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) {
    2446               7 :                                         return_val = req->priv_key;
    2447                 :                                 }
    2448               7 :                                 break;
    2449                 : #if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD)
    2450                 :                         case OPENSSL_KEYTYPE_DSA:
    2451                 :                                 {
    2452               0 :                                         DSA *dsapar = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
    2453               0 :                                         if (dsapar) {
    2454               0 :                                                 DSA_set_method(dsapar, DSA_get_default_method());
    2455               0 :                                                 if (DSA_generate_key(dsapar)) {
    2456               0 :                                                         if (EVP_PKEY_assign_DSA(req->priv_key, dsapar)) {
    2457               0 :                                                                 return_val = req->priv_key;
    2458                 :                                                         }
    2459                 :                                                 } else {
    2460               0 :                                                         DSA_free(dsapar);
    2461                 :                                                 }
    2462                 :                                         }
    2463                 :                                 }
    2464               0 :                                 break;
    2465                 : #endif
    2466                 :                         default:
    2467               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type");
    2468                 :                 }
    2469                 :         }
    2470                 : 
    2471               7 :         php_openssl_write_rand_file(randfile, egdsocket, seeded);
    2472                 :         
    2473               7 :         if (return_val == NULL) {
    2474               0 :                 EVP_PKEY_free(req->priv_key);
    2475               0 :                 req->priv_key = NULL;
    2476               0 :                 return NULL;
    2477                 :         }
    2478                 :         
    2479               7 :         return return_val;
    2480                 : }
    2481                 : /* }}} */
    2482                 : 
    2483                 : /* {{{ php_openssl_is_private_key
    2484                 :         Check whether the supplied key is a private key by checking if the secret prime factors are set */
    2485                 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
    2486               8 : {
    2487                 :         assert(pkey != NULL);
    2488                 : 
    2489               8 :         switch (pkey->type) {
    2490                 : #ifndef NO_RSA
    2491                 :                 case EVP_PKEY_RSA:
    2492                 :                 case EVP_PKEY_RSA2:
    2493                 :                         assert(pkey->pkey.rsa != NULL);
    2494               6 :                         if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q)) {
    2495               1 :                                 return 0;
    2496                 :                         }
    2497               5 :                         break;
    2498                 : #endif
    2499                 : #ifndef NO_DSA
    2500                 :                 case EVP_PKEY_DSA:
    2501                 :                 case EVP_PKEY_DSA1:
    2502                 :                 case EVP_PKEY_DSA2:
    2503                 :                 case EVP_PKEY_DSA3:
    2504                 :                 case EVP_PKEY_DSA4:
    2505                 :                         assert(pkey->pkey.dsa != NULL);
    2506                 : 
    2507               2 :                         if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){ 
    2508               1 :                                 return 0;
    2509                 :                         }
    2510               1 :                         break;
    2511                 : #endif
    2512                 : #ifndef NO_DH
    2513                 :                 case EVP_PKEY_DH:
    2514                 :                         assert(pkey->pkey.dh != NULL);
    2515                 : 
    2516               0 :                         if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key) {
    2517               0 :                                 return 0;
    2518                 :                         }
    2519               0 :                         break;
    2520                 : #endif
    2521                 :                 default:
    2522               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    2523                 :                         break;
    2524                 :         }
    2525               6 :         return 1;
    2526                 : }
    2527                 : /* }}} */
    2528                 : 
    2529                 : /* {{{ proto resource openssl_pkey_new([array configargs])
    2530                 :    Generates a new private key */
    2531                 : PHP_FUNCTION(openssl_pkey_new)
    2532               5 : {
    2533                 :         struct php_x509_request req;
    2534               5 :         zval * args = NULL;
    2535                 : 
    2536               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == FAILURE) {
    2537               0 :                 return;
    2538                 :         }
    2539               5 :         RETVAL_FALSE;
    2540                 :         
    2541               5 :         PHP_SSL_REQ_INIT(&req);
    2542                 : 
    2543               5 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
    2544                 :         {
    2545               5 :                 if (php_openssl_generate_private_key(&req TSRMLS_CC)) {
    2546                 :                         /* pass back a key resource */
    2547               5 :                         RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key));
    2548                 :                         /* make sure the cleanup code doesn't zap it! */
    2549               5 :                         req.priv_key = NULL;
    2550                 :                 }
    2551                 :         }
    2552               5 :         PHP_SSL_REQ_DISPOSE(&req);
    2553                 : }
    2554                 : /* }}} */
    2555                 : 
    2556                 : /* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
    2557                 :    Gets an exportable representation of a key into a file */
    2558                 : PHP_FUNCTION(openssl_pkey_export_to_file)
    2559               1 : {
    2560                 :         struct php_x509_request req;
    2561               1 :         zval ** zpkey, * args = NULL;
    2562               1 :         char * passphrase = NULL; int passphrase_len = 0;
    2563               1 :         char * filename = NULL; int filename_len = 0;
    2564               1 :         long key_resource = -1;
    2565                 :         EVP_PKEY * key;
    2566               1 :         BIO * bio_out = NULL;
    2567                 :         const EVP_CIPHER * cipher;
    2568                 :         
    2569               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
    2570               0 :                 return;
    2571                 :         }
    2572               1 :         RETVAL_FALSE;
    2573                 : 
    2574               1 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    2575                 : 
    2576               1 :         if (key == NULL) {
    2577               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    2578               0 :                 RETURN_FALSE;
    2579                 :         }
    2580                 :         
    2581               1 :         if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    2582               0 :                 RETURN_FALSE;
    2583                 :         }
    2584                 :         
    2585               1 :         PHP_SSL_REQ_INIT(&req);
    2586                 : 
    2587               1 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    2588               1 :                 bio_out = BIO_new_file(filename, "w");
    2589                 : 
    2590               2 :                 if (passphrase && req.priv_key_encrypt) {
    2591               1 :                         cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    2592                 :                 } else {
    2593               0 :                         cipher = NULL;
    2594                 :                 }
    2595               1 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    2596                 :                         /* Success!
    2597                 :                          * If returning the output as a string, do so now */
    2598               1 :                         RETVAL_TRUE;
    2599                 :                 }
    2600                 :         }
    2601               1 :         PHP_SSL_REQ_DISPOSE(&req);
    2602                 : 
    2603               1 :         if (key_resource == -1 && key) {
    2604               0 :                 EVP_PKEY_free(key);
    2605                 :         }
    2606               1 :         if (bio_out) {
    2607               1 :                 BIO_free(bio_out);
    2608                 :         }
    2609                 : }
    2610                 : /* }}} */
    2611                 : 
    2612                 : /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
    2613                 :    Gets an exportable representation of a key into a string or file */
    2614                 : PHP_FUNCTION(openssl_pkey_export)
    2615               0 : {
    2616                 :         struct php_x509_request req;
    2617               0 :         zval ** zpkey, * args = NULL, *out;
    2618               0 :         char * passphrase = NULL; int passphrase_len = 0;
    2619               0 :         long key_resource = -1;
    2620                 :         EVP_PKEY * key;
    2621               0 :         BIO * bio_out = NULL;
    2622                 :         const EVP_CIPHER * cipher;
    2623                 :         
    2624               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
    2625               0 :                 return;
    2626                 :         }
    2627               0 :         RETVAL_FALSE;
    2628                 : 
    2629               0 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    2630                 : 
    2631               0 :         if (key == NULL) {
    2632               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    2633               0 :                 RETURN_FALSE;
    2634                 :         }
    2635                 :         
    2636               0 :         PHP_SSL_REQ_INIT(&req);
    2637                 : 
    2638               0 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    2639               0 :                 bio_out = BIO_new(BIO_s_mem());
    2640                 : 
    2641               0 :                 if (passphrase && req.priv_key_encrypt) {
    2642               0 :                         cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    2643                 :                 } else {
    2644               0 :                         cipher = NULL;
    2645                 :                 }
    2646               0 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    2647                 :                         /* Success!
    2648                 :                          * If returning the output as a string, do so now */
    2649                 : 
    2650                 :                         char * bio_mem_ptr;
    2651                 :                         long bio_mem_len;
    2652               0 :                         RETVAL_TRUE;
    2653                 : 
    2654               0 :                         bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
    2655               0 :                         zval_dtor(out);
    2656               0 :                         ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len, 1);
    2657                 :                 }
    2658                 :         }
    2659               0 :         PHP_SSL_REQ_DISPOSE(&req);
    2660                 : 
    2661               0 :         if (key_resource == -1 && key) {
    2662               0 :                 EVP_PKEY_free(key);
    2663                 :         }
    2664               0 :         if (bio_out) {
    2665               0 :                 BIO_free(bio_out);
    2666                 :         }
    2667                 : }
    2668                 : /* }}} */
    2669                 : 
    2670                 : /* {{{ proto int openssl_pkey_get_public(mixed cert)
    2671                 :    Gets public key from X.509 certificate */
    2672                 : PHP_FUNCTION(openssl_pkey_get_public)
    2673               3 : {
    2674                 :         zval **cert;
    2675                 :         EVP_PKEY *pkey;
    2676                 : 
    2677               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
    2678               0 :                 return;
    2679                 :         }
    2680               3 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    2681               3 :         pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    2682                 : 
    2683               3 :         if (pkey == NULL) {
    2684               1 :                 RETURN_FALSE;
    2685                 :         }
    2686                 : }
    2687                 : /* }}} */
    2688                 : 
    2689                 : /* {{{ proto void openssl_pkey_free(int key)
    2690                 :    Frees a key */
    2691                 : PHP_FUNCTION(openssl_pkey_free)
    2692               3 : {
    2693                 :         zval *key;
    2694                 :         EVP_PKEY *pkey;
    2695                 : 
    2696               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    2697               0 :                 return;
    2698                 :         }
    2699               3 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
    2700               3 :         zend_list_delete(Z_LVAL_P(key));
    2701                 : }
    2702                 : /* }}} */
    2703                 : 
    2704                 : /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
    2705                 :    Gets private keys */
    2706                 : PHP_FUNCTION(openssl_pkey_get_private)
    2707               5 : {
    2708                 :         zval **cert;
    2709                 :         EVP_PKEY *pkey;
    2710               5 :         char * passphrase = "";
    2711                 :         int passphrase_len;
    2712                 : 
    2713               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
    2714               0 :                 return;
    2715                 :         }
    2716               5 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    2717               5 :         pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    2718                 : 
    2719               5 :         if (pkey == NULL) {
    2720               0 :                 RETURN_FALSE;
    2721                 :         }
    2722                 : }
    2723                 : 
    2724                 : /* }}} */
    2725                 : 
    2726                 : /* {{{ proto resource openssl_pkey_get_details(resource key)
    2727                 :         returns an array with the key details (bits, pkey, type)*/
    2728                 : PHP_FUNCTION(openssl_pkey_get_details)
    2729               0 : {
    2730                 :         zval *key;
    2731                 :         EVP_PKEY *pkey;
    2732                 :         BIO *out;
    2733                 :         unsigned int pbio_len;
    2734                 :         char *pbio;
    2735                 :         long ktype;
    2736                 : 
    2737               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    2738               0 :                 return;
    2739                 :         }
    2740               0 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
    2741               0 :         if (!pkey) {
    2742               0 :                 RETURN_FALSE;
    2743                 :         }
    2744               0 :         out = BIO_new(BIO_s_mem());
    2745               0 :         PEM_write_bio_PUBKEY(out, pkey);
    2746               0 :         pbio_len = BIO_get_mem_data(out, &pbio);
    2747                 : 
    2748               0 :         array_init(return_value);
    2749               0 :         add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
    2750               0 :         add_assoc_stringl(return_value, "key", pbio, pbio_len, 1);
    2751                 :         /*TODO: Use the real values once the openssl constants are used 
    2752                 :          * See the enum at the top of this file
    2753                 :          */
    2754               0 :         switch (EVP_PKEY_type(pkey->type)) {
    2755                 :                 case EVP_PKEY_RSA:
    2756                 :                 case EVP_PKEY_RSA2:
    2757               0 :                         ktype = OPENSSL_KEYTYPE_RSA;
    2758               0 :                         break;  
    2759                 :                 case EVP_PKEY_DSA:
    2760                 :                 case EVP_PKEY_DSA2:
    2761                 :                 case EVP_PKEY_DSA3:
    2762                 :                 case EVP_PKEY_DSA4:
    2763               0 :                         ktype = OPENSSL_KEYTYPE_DSA;
    2764               0 :                         break;
    2765                 :                 case EVP_PKEY_DH:
    2766               0 :                         ktype = OPENSSL_KEYTYPE_DH;
    2767               0 :                         break;
    2768                 : #ifdef EVP_PKEY_EC 
    2769                 :                 case EVP_PKEY_EC:
    2770               0 :                         ktype = OPENSSL_KEYTYPE_EC;
    2771               0 :                         break;
    2772                 : #endif
    2773                 :                 default:
    2774               0 :                         ktype = -1;
    2775                 :                         break;
    2776                 :         }
    2777               0 :         add_assoc_long(return_value, "type", ktype);
    2778                 : 
    2779               0 :         BIO_free(out);
    2780                 : }
    2781                 : /* }}} */
    2782                 : 
    2783                 : /* }}} */
    2784                 : 
    2785                 : /* {{{ PKCS7 S/MIME functions */
    2786                 : 
    2787                 : /* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
    2788                 :    Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
    2789                 : PHP_FUNCTION(openssl_pkcs7_verify)
    2790               0 : {
    2791               0 :         X509_STORE * store = NULL;
    2792               0 :         zval * cainfo = NULL;
    2793               0 :         STACK_OF(X509) *signers= NULL;
    2794               0 :         STACK_OF(X509) *others = NULL;
    2795               0 :         PKCS7 * p7 = NULL;
    2796               0 :         BIO * in = NULL, * datain = NULL, * dataout = NULL;
    2797               0 :         long flags = 0;
    2798                 :         char * filename; int filename_len;
    2799               0 :         char * extracerts = NULL; int extracerts_len;
    2800               0 :         char * signersfilename = NULL; int signersfilename_len;
    2801               0 :         char * datafilename = NULL; int datafilename_len;
    2802                 :         
    2803               0 :         RETVAL_LONG(-1);
    2804                 : 
    2805               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sass", &filename, &filename_len,
    2806                 :                                 &flags, &signersfilename, &signersfilename_len, &cainfo,
    2807                 :                                 &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
    2808               0 :                 return;
    2809                 :         }
    2810                 :         
    2811               0 :         if (extracerts) {
    2812               0 :                 others = load_all_certs_from_file(extracerts);
    2813               0 :                 if (others == NULL) {
    2814               0 :                         goto clean_exit;
    2815                 :                 }
    2816                 :         }
    2817                 : 
    2818               0 :         flags = flags & ~PKCS7_DETACHED;
    2819                 : 
    2820               0 :         store = setup_verify(cainfo TSRMLS_CC);
    2821                 : 
    2822               0 :         if (!store) {
    2823               0 :                 goto clean_exit;
    2824                 :         }
    2825               0 :         if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
    2826               0 :                 goto clean_exit;
    2827                 :         }
    2828                 : 
    2829               0 :         in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
    2830               0 :         if (in == NULL) {
    2831               0 :                 goto clean_exit;
    2832                 :         }
    2833               0 :         p7 = SMIME_read_PKCS7(in, &datain);
    2834               0 :         if (p7 == NULL) {
    2835                 : #if DEBUG_SMIME
    2836                 :                 zend_printf("SMIME_read_PKCS7 failed\n");
    2837                 : #endif
    2838               0 :                 goto clean_exit;
    2839                 :         }
    2840                 : 
    2841               0 :         if (datafilename) {
    2842                 : 
    2843               0 :                 if (php_openssl_safe_mode_chk(datafilename TSRMLS_CC)) {
    2844               0 :                         goto clean_exit;
    2845                 :                 }
    2846                 : 
    2847               0 :                 dataout = BIO_new_file(datafilename, "w");
    2848               0 :                 if (dataout == NULL) {
    2849               0 :                         goto clean_exit;
    2850                 :                 }
    2851                 :         }
    2852                 : #if DEBUG_SMIME
    2853                 :         zend_printf("Calling PKCS7 verify\n");
    2854                 : #endif
    2855                 : 
    2856               0 :         if (PKCS7_verify(p7, others, store, datain, dataout, flags)) {
    2857                 : 
    2858               0 :                 RETVAL_TRUE;
    2859                 : 
    2860               0 :                 if (signersfilename) {
    2861                 :                         BIO *certout;
    2862                 :                 
    2863               0 :                         if (php_openssl_safe_mode_chk(signersfilename TSRMLS_CC)) {
    2864               0 :                                 goto clean_exit;
    2865                 :                         }
    2866                 :                 
    2867               0 :                         certout = BIO_new_file(signersfilename, "w");
    2868               0 :                         if (certout) {
    2869                 :                                 int i;
    2870               0 :                                 signers = PKCS7_get0_signers(p7, NULL, flags);
    2871                 : 
    2872               0 :                                 for(i = 0; i < sk_X509_num(signers); i++) {
    2873               0 :                                         PEM_write_bio_X509(certout, sk_X509_value(signers, i));
    2874                 :                                 }
    2875               0 :                                 BIO_free(certout);
    2876               0 :                                 sk_X509_free(signers);
    2877                 :                         } else {
    2878               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
    2879               0 :                                 RETVAL_LONG(-1);
    2880                 :                         }
    2881                 :                 }
    2882               0 :                 goto clean_exit;
    2883                 :         } else {
    2884               0 :                 RETVAL_FALSE;
    2885                 :         }
    2886               0 : clean_exit:
    2887               0 :         X509_STORE_free(store);
    2888               0 :         BIO_free(datain);
    2889               0 :         BIO_free(in);
    2890               0 :         BIO_free(dataout);
    2891               0 :         PKCS7_free(p7);
    2892               0 :         sk_X509_free(others);
    2893                 : }
    2894                 : /* }}} */
    2895                 : 
    2896                 : /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
    2897                 :    Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
    2898                 : PHP_FUNCTION(openssl_pkcs7_encrypt)
    2899               0 : {
    2900               0 :         zval ** zrecipcerts, * zheaders = NULL;
    2901               0 :         STACK_OF(X509) * recipcerts = NULL;
    2902               0 :         BIO * infile = NULL, * outfile = NULL;
    2903               0 :         long flags = 0;
    2904               0 :         PKCS7 * p7 = NULL;
    2905                 :         HashPosition hpos;
    2906                 :         zval ** zcertval;
    2907                 :         X509 * cert;
    2908               0 :         const EVP_CIPHER *cipher = NULL;
    2909               0 :         long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
    2910                 :         uint strindexlen;
    2911                 :         ulong intindex;
    2912                 :         char * strindex;
    2913               0 :         char * infilename = NULL;       int infilename_len;
    2914               0 :         char * outfilename = NULL;      int outfilename_len;
    2915                 :         
    2916               0 :         RETVAL_FALSE;
    2917                 : 
    2918               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZa!|ll", &infilename, &infilename_len,
    2919                 :                                 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
    2920               0 :                 return;
    2921                 : 
    2922                 :         
    2923               0 :         if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
    2924               0 :                 return;
    2925                 :         }
    2926                 : 
    2927               0 :         infile = BIO_new_file(infilename, "r");
    2928               0 :         if (infile == NULL) {
    2929               0 :                 goto clean_exit;
    2930                 :         }
    2931                 : 
    2932               0 :         outfile = BIO_new_file(outfilename, "w");
    2933               0 :         if (outfile == NULL) { 
    2934               0 :                 goto clean_exit;
    2935                 :         }
    2936                 : 
    2937               0 :         recipcerts = sk_X509_new_null();
    2938                 : 
    2939                 :         /* get certs */
    2940               0 :         if (Z_TYPE_PP(zrecipcerts) == IS_ARRAY) {
    2941               0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(*zrecipcerts), &hpos);
    2942               0 :                 while(zend_hash_get_current_data_ex(HASH_OF(*zrecipcerts), (void**)&zcertval, &hpos) == SUCCESS) {
    2943                 :                         long certresource;
    2944                 : 
    2945               0 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
    2946               0 :                         if (cert == NULL) {
    2947               0 :                                 goto clean_exit;
    2948                 :                         }
    2949                 : 
    2950               0 :                         if (certresource != -1) {
    2951                 :                                 /* we shouldn't free this particular cert, as it is a resource.
    2952                 :                                         make a copy and push that on the stack instead */
    2953               0 :                                 cert = X509_dup(cert);
    2954               0 :                                 if (cert == NULL) {
    2955               0 :                                         goto clean_exit;
    2956                 :                                 }
    2957                 :                         }
    2958               0 :                         sk_X509_push(recipcerts, cert);
    2959                 : 
    2960               0 :                         zend_hash_move_forward_ex(HASH_OF(*zrecipcerts), &hpos);
    2961                 :                 }
    2962                 :         } else {
    2963                 :                 /* a single certificate */
    2964                 :                 long certresource;
    2965                 : 
    2966               0 :                 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource TSRMLS_CC);
    2967               0 :                 if (cert == NULL) {
    2968               0 :                         goto clean_exit;
    2969                 :                 }
    2970                 : 
    2971               0 :                 if (certresource != -1) {
    2972                 :                         /* we shouldn't free this particular cert, as it is a resource.
    2973                 :                                 make a copy and push that on the stack instead */
    2974               0 :                         cert = X509_dup(cert);
    2975               0 :                         if (cert == NULL) {
    2976               0 :                                 goto clean_exit;
    2977                 :                         }
    2978                 :                 }
    2979               0 :                 sk_X509_push(recipcerts, cert);
    2980                 :         }
    2981                 : 
    2982                 :         /* sanity check the cipher */
    2983               0 :         switch (cipherid) {
    2984                 : #ifndef OPENSSL_NO_RC2
    2985                 :                 case PHP_OPENSSL_CIPHER_RC2_40:
    2986               0 :                         cipher = EVP_rc2_40_cbc();
    2987               0 :                         break;
    2988                 :                 case PHP_OPENSSL_CIPHER_RC2_64:
    2989               0 :                         cipher = EVP_rc2_64_cbc();
    2990               0 :                         break;
    2991                 :                 case PHP_OPENSSL_CIPHER_RC2_128:
    2992               0 :                         cipher = EVP_rc2_cbc();
    2993               0 :                         break;
    2994                 : #endif
    2995                 : 
    2996                 : #ifndef OPENSSL_NO_DES
    2997                 :                 case PHP_OPENSSL_CIPHER_DES:
    2998               0 :                         cipher = EVP_des_cbc();
    2999               0 :                         break;
    3000                 :                 case PHP_OPENSSL_CIPHER_3DES:
    3001               0 :                         cipher = EVP_des_ede3_cbc();
    3002               0 :                         break;
    3003                 : #endif
    3004                 : 
    3005                 :                 default:
    3006               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid cipher type `%ld'", cipherid);
    3007               0 :                         goto clean_exit;
    3008                 :         }
    3009               0 :         if (cipher == NULL) {
    3010                 :                 /* shouldn't happen */
    3011               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher");
    3012               0 :                 goto clean_exit;
    3013                 :         }
    3014                 : 
    3015               0 :         p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, flags);
    3016                 : 
    3017               0 :         if (p7 == NULL) {
    3018               0 :                 goto clean_exit;
    3019                 :         }
    3020                 : 
    3021                 :         /* tack on extra headers */
    3022               0 :         if (zheaders) {
    3023               0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
    3024               0 :                 while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&zcertval, &hpos) == SUCCESS) {
    3025               0 :                         zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
    3026                 : 
    3027               0 :                         convert_to_string_ex(zcertval);
    3028                 : 
    3029               0 :                         if (strindex) {
    3030               0 :                                 BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(zcertval));
    3031                 :                         } else {
    3032               0 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_PP(zcertval));
    3033                 :                         }
    3034                 : 
    3035               0 :                         zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
    3036                 :                 }
    3037                 :         }
    3038                 : 
    3039               0 :         (void)BIO_reset(infile);
    3040                 : 
    3041                 :         /* write the encrypted data */
    3042               0 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    3043                 : 
    3044               0 :         RETVAL_TRUE;
    3045                 : 
    3046               0 : clean_exit:
    3047               0 :         PKCS7_free(p7);
    3048               0 :         BIO_free(infile);
    3049               0 :         BIO_free(outfile);
    3050               0 :         if (recipcerts) {
    3051               0 :                 sk_X509_pop_free(recipcerts, X509_free);
    3052                 :         }
    3053                 : }
    3054                 : /* }}} */
    3055                 : 
    3056                 : /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
    3057                 :    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 */
    3058                 : 
    3059                 : PHP_FUNCTION(openssl_pkcs7_sign)
    3060               0 : {
    3061                 :         zval ** zcert, ** zprivkey, * zheaders;
    3062                 :         zval ** hval;
    3063               0 :         X509 * cert = NULL;
    3064               0 :         EVP_PKEY * privkey = NULL;
    3065               0 :         long flags = PKCS7_DETACHED;
    3066               0 :         PKCS7 * p7 = NULL;
    3067               0 :         BIO * infile = NULL, * outfile = NULL;
    3068               0 :         STACK_OF(X509) *others = NULL;
    3069               0 :         long certresource = -1, keyresource = -1;
    3070                 :         ulong intindex;
    3071                 :         uint strindexlen;
    3072                 :         HashPosition hpos;
    3073                 :         char * strindex;
    3074                 :         char * infilename;      int infilename_len;
    3075                 :         char * outfilename;     int outfilename_len;
    3076               0 :         char * extracertsfilename = NULL; int extracertsfilename_len;
    3077                 : 
    3078               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZZa!|ls",
    3079                 :                                 &infilename, &infilename_len, &outfilename, &outfilename_len,
    3080                 :                                 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
    3081                 :                                 &extracertsfilename_len) == FAILURE) {
    3082               0 :                 return;
    3083                 :         }
    3084                 :         
    3085               0 :         RETVAL_FALSE;
    3086                 : 
    3087               0 :         if (extracertsfilename) {
    3088               0 :                 others = load_all_certs_from_file(extracertsfilename);
    3089               0 :                 if (others == NULL) { 
    3090               0 :                         goto clean_exit;
    3091                 :                 }
    3092                 :         }
    3093                 : 
    3094               0 :         privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource TSRMLS_CC);
    3095               0 :         if (privkey == NULL) {
    3096               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting private key");
    3097               0 :                 goto clean_exit;
    3098                 :         }
    3099                 : 
    3100               0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    3101               0 :         if (cert == NULL) {
    3102               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting cert");
    3103               0 :                 goto clean_exit;
    3104                 :         }
    3105                 : 
    3106               0 :         if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
    3107                 :                 goto clean_exit;
    3108                 :         }
    3109                 : 
    3110               0 :         infile = BIO_new_file(infilename, "r");
    3111               0 :         if (infile == NULL) {
    3112               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening input file %s!", infilename);
    3113               0 :                 goto clean_exit;
    3114                 :         }
    3115                 : 
    3116               0 :         outfile = BIO_new_file(outfilename, "w");
    3117               0 :         if (outfile == NULL) {
    3118               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening output file %s!", outfilename);
    3119               0 :                 goto clean_exit;
    3120                 :         }
    3121                 : 
    3122               0 :         p7 = PKCS7_sign(cert, privkey, others, infile, flags);
    3123               0 :         if (p7 == NULL) {
    3124               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error creating PKCS7 structure!");
    3125               0 :                 goto clean_exit;
    3126                 :         }
    3127                 : 
    3128               0 :         (void)BIO_reset(infile);
    3129                 : 
    3130                 :         /* tack on extra headers */
    3131               0 :         if (zheaders) {
    3132               0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
    3133               0 :                 while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&hval, &hpos) == SUCCESS) {
    3134               0 :                         zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
    3135                 : 
    3136               0 :                         convert_to_string_ex(hval);
    3137                 : 
    3138               0 :                         if (strindex) {
    3139               0 :                                 BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(hval));
    3140                 :                         } else {
    3141               0 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_PP(hval));
    3142                 :                         }
    3143               0 :                         zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
    3144                 :                 }
    3145                 :         }
    3146                 :         /* write the signed data */
    3147               0 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    3148                 : 
    3149               0 :         RETVAL_TRUE;
    3150                 : 
    3151               0 : clean_exit:
    3152               0 :         PKCS7_free(p7);
    3153               0 :         BIO_free(infile);
    3154               0 :         BIO_free(outfile);
    3155               0 :         if (others) {
    3156               0 :                 sk_X509_pop_free(others, X509_free);
    3157                 :         }
    3158               0 :         if (privkey && keyresource == -1) {
    3159               0 :                 EVP_PKEY_free(privkey);
    3160                 :         }
    3161               0 :         if (cert && certresource == -1) {
    3162               0 :                 X509_free(cert);
    3163                 :         }
    3164                 : }
    3165                 : /* }}} */
    3166                 : 
    3167                 : /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
    3168                 :    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 */
    3169                 : 
    3170                 : PHP_FUNCTION(openssl_pkcs7_decrypt)
    3171               5 : {
    3172               5 :         zval ** recipcert, ** recipkey = NULL;
    3173               5 :         X509 * cert = NULL;
    3174               5 :         EVP_PKEY * key = NULL;
    3175                 :         long certresval, keyresval;
    3176               5 :         BIO * in = NULL, * out = NULL, * datain = NULL;
    3177               5 :         PKCS7 * p7 = NULL;
    3178                 :         char * infilename;      int infilename_len;
    3179                 :         char * outfilename;     int outfilename_len;
    3180                 : 
    3181               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|Z", &infilename, &infilename_len,
    3182                 :                                 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
    3183               0 :                 return;
    3184                 :         }
    3185                 : 
    3186               5 :         RETVAL_FALSE;
    3187                 : 
    3188               5 :         cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC);
    3189               5 :         if (cert == NULL) {
    3190               5 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert");
    3191               5 :                 goto clean_exit;
    3192                 :         }
    3193                 : 
    3194               0 :         key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval TSRMLS_CC);
    3195               0 :         if (key == NULL) {
    3196               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key");
    3197               0 :                 goto clean_exit;
    3198                 :         }
    3199                 :         
    3200               0 :         if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
    3201                 :                 goto clean_exit;
    3202                 :         }
    3203                 : 
    3204               0 :         in = BIO_new_file(infilename, "r");
    3205               0 :         if (in == NULL) {
    3206               0 :                 goto clean_exit;
    3207                 :         }
    3208               0 :         out = BIO_new_file(outfilename, "w");
    3209               0 :         if (out == NULL) {
    3210               0 :                 goto clean_exit;
    3211                 :         }
    3212                 : 
    3213               0 :         p7 = SMIME_read_PKCS7(in, &datain);
    3214                 : 
    3215               0 :         if (p7 == NULL) {
    3216               0 :                 goto clean_exit;
    3217                 :         }
    3218               0 :         if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) { 
    3219               0 :                 RETVAL_TRUE;
    3220                 :         }
    3221               5 : clean_exit:
    3222               5 :         PKCS7_free(p7);
    3223               5 :         BIO_free(datain);
    3224               5 :         BIO_free(in);
    3225               5 :         BIO_free(out);
    3226               5 :         if (cert && certresval == -1) {
    3227               0 :                 X509_free(cert);
    3228                 :         }
    3229               5 :         if (key && keyresval == -1) {
    3230               0 :                 EVP_PKEY_free(key);
    3231                 :         }
    3232                 : }
    3233                 : /* }}} */
    3234                 : 
    3235                 : /* }}} */
    3236                 : 
    3237                 : /* {{{ proto bool openssl_private_encrypt(string data, string crypted, mixed key [, int padding])
    3238                 :    Encrypts data with private key */
    3239                 : PHP_FUNCTION(openssl_private_encrypt)
    3240               0 : {
    3241                 :         zval **key, *crypted;
    3242                 :         EVP_PKEY *pkey;
    3243                 :         int cryptedlen;
    3244               0 :         unsigned char *cryptedbuf = NULL;
    3245               0 :         int successful = 0;
    3246               0 :         long keyresource = -1;
    3247                 :         char * data;
    3248                 :         int data_len;
    3249               0 :         long padding = RSA_PKCS1_PADDING;
    3250                 : 
    3251               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { 
    3252               0 :                 return;
    3253                 :         }
    3254               0 :         RETVAL_FALSE;
    3255                 : 
    3256               0 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    3257                 : 
    3258               0 :         if (pkey == NULL) {
    3259               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key param is not a valid private key");
    3260               0 :                 RETURN_FALSE;
    3261                 :         }
    3262                 : 
    3263               0 :         cryptedlen = EVP_PKEY_size(pkey);
    3264               0 :         cryptedbuf = emalloc(cryptedlen + 1);
    3265                 : 
    3266               0 :         switch (pkey->type) {
    3267                 :                 case EVP_PKEY_RSA:
    3268                 :                 case EVP_PKEY_RSA2:
    3269               0 :                         successful =  (RSA_private_encrypt(data_len, 
    3270                 :                                                 (unsigned char *)data, 
    3271                 :                                                 cryptedbuf, 
    3272                 :                                                 pkey->pkey.rsa, 
    3273                 :                                                 padding) == cryptedlen);
    3274               0 :                         break;
    3275                 :                 default:
    3276               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3277                 :         }
    3278                 : 
    3279               0 :         if (successful) {
    3280               0 :                 zval_dtor(crypted);
    3281               0 :                 cryptedbuf[cryptedlen] = '\0';
    3282               0 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3283               0 :                 cryptedbuf = NULL;
    3284               0 :                 RETVAL_TRUE;
    3285                 :         }
    3286               0 :         if (cryptedbuf) {
    3287               0 :                 efree(cryptedbuf);
    3288                 :         }
    3289               0 :         if (keyresource == -1) { 
    3290               0 :                 EVP_PKEY_free(pkey);
    3291                 :         }
    3292                 : }
    3293                 : /* }}} */
    3294                 : 
    3295                 : /* {{{ proto bool openssl_private_decrypt(string data, string decrypted, mixed key [, int padding])
    3296                 :    Decrypts data with private key */
    3297                 : PHP_FUNCTION(openssl_private_decrypt)
    3298               0 : {
    3299                 :         zval **key, *crypted;
    3300                 :         EVP_PKEY *pkey;
    3301                 :         int cryptedlen;
    3302               0 :         unsigned char *cryptedbuf = NULL;
    3303                 :         unsigned char *crypttemp;
    3304               0 :         int successful = 0;
    3305               0 :         long padding = RSA_PKCS1_PADDING;
    3306               0 :         long keyresource = -1;
    3307                 :         char * data;
    3308                 :         int data_len;
    3309                 : 
    3310               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    3311               0 :                 return;
    3312                 :         }
    3313               0 :         RETVAL_FALSE;
    3314                 : 
    3315               0 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    3316               0 :         if (pkey == NULL) {
    3317               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid private key");
    3318               0 :                 RETURN_FALSE;
    3319                 :         }
    3320                 : 
    3321               0 :         cryptedlen = EVP_PKEY_size(pkey);
    3322               0 :         crypttemp = emalloc(cryptedlen + 1);
    3323                 : 
    3324               0 :         switch (pkey->type) {
    3325                 :                 case EVP_PKEY_RSA:
    3326                 :                 case EVP_PKEY_RSA2:
    3327               0 :                         cryptedlen = RSA_private_decrypt(data_len, 
    3328                 :                                         (unsigned char *)data, 
    3329                 :                                         crypttemp, 
    3330                 :                                         pkey->pkey.rsa, 
    3331                 :                                         padding);
    3332               0 :                         if (cryptedlen != -1) {
    3333               0 :                                 cryptedbuf = emalloc(cryptedlen + 1);
    3334               0 :                                 memcpy(cryptedbuf, crypttemp, cryptedlen);
    3335               0 :                                 successful = 1;
    3336                 :                         }
    3337               0 :                         break;
    3338                 :                 default:
    3339               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3340                 :         }
    3341                 : 
    3342               0 :         efree(crypttemp);
    3343                 : 
    3344               0 :         if (successful) {
    3345               0 :                 zval_dtor(crypted);
    3346               0 :                 cryptedbuf[cryptedlen] = '\0';
    3347               0 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3348               0 :                 cryptedbuf = NULL;
    3349               0 :                 RETVAL_TRUE;
    3350                 :         }
    3351                 : 
    3352               0 :         if (keyresource == -1) {
    3353               0 :                 EVP_PKEY_free(pkey);
    3354                 :         }
    3355               0 :         if (cryptedbuf) { 
    3356               0 :                 efree(cryptedbuf);
    3357                 :         }
    3358                 : }
    3359                 : /* }}} */
    3360                 : 
    3361                 : /* {{{ proto bool openssl_public_encrypt(string data, string crypted, mixed key [, int padding])
    3362                 :    Encrypts data with public key */
    3363                 : PHP_FUNCTION(openssl_public_encrypt)
    3364               0 : {
    3365                 :         zval **key, *crypted;
    3366                 :         EVP_PKEY *pkey;
    3367                 :         int cryptedlen;
    3368                 :         unsigned char *cryptedbuf;
    3369               0 :         int successful = 0;
    3370               0 :         long keyresource = -1;
    3371               0 :         long padding = RSA_PKCS1_PADDING;
    3372                 :         char * data;
    3373                 :         int data_len;
    3374                 : 
    3375               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
    3376               0 :                 return;
    3377                 : 
    3378               0 :         RETVAL_FALSE;
    3379                 :         
    3380               0 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    3381               0 :         if (pkey == NULL) {
    3382               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
    3383               0 :                 RETURN_FALSE;
    3384                 :         }
    3385                 : 
    3386               0 :         cryptedlen = EVP_PKEY_size(pkey);
    3387               0 :         cryptedbuf = emalloc(cryptedlen + 1);
    3388                 : 
    3389               0 :         switch (pkey->type) {
    3390                 :                 case EVP_PKEY_RSA:
    3391                 :                 case EVP_PKEY_RSA2:
    3392               0 :                         successful = (RSA_public_encrypt(data_len, 
    3393                 :                                                 (unsigned char *)data, 
    3394                 :                                                 cryptedbuf, 
    3395                 :                                                 pkey->pkey.rsa, 
    3396                 :                                                 padding) == cryptedlen);
    3397               0 :                         break;
    3398                 :                 default:
    3399               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3400                 : 
    3401                 :         }
    3402                 : 
    3403               0 :         if (successful) {
    3404               0 :                 zval_dtor(crypted);
    3405               0 :                 cryptedbuf[cryptedlen] = '\0';
    3406               0 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3407               0 :                 cryptedbuf = NULL;
    3408               0 :                 RETVAL_TRUE;
    3409                 :         }
    3410               0 :         if (keyresource == -1) {
    3411               0 :                 EVP_PKEY_free(pkey);
    3412                 :         }
    3413               0 :         if (cryptedbuf) {
    3414               0 :                 efree(cryptedbuf);
    3415                 :         }
    3416                 : }
    3417                 : /* }}} */
    3418                 : 
    3419                 : /* {{{ proto bool openssl_public_decrypt(string data, string crypted, resource key [, int padding])
    3420                 :    Decrypts data with public key */
    3421                 : PHP_FUNCTION(openssl_public_decrypt)
    3422               0 : {
    3423                 :         zval **key, *crypted;
    3424                 :         EVP_PKEY *pkey;
    3425                 :         int cryptedlen;
    3426               0 :         unsigned char *cryptedbuf = NULL;
    3427                 :         unsigned char *crypttemp;
    3428               0 :         int successful = 0;
    3429               0 :         long keyresource = -1;
    3430               0 :         long padding = RSA_PKCS1_PADDING;
    3431                 :         char * data;
    3432                 :         int data_len;
    3433                 : 
    3434               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    3435               0 :                 return;
    3436                 :         }
    3437               0 :         RETVAL_FALSE;
    3438                 :         
    3439               0 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    3440               0 :         if (pkey == NULL) {
    3441               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
    3442               0 :                 RETURN_FALSE;
    3443                 :         }
    3444                 : 
    3445               0 :         cryptedlen = EVP_PKEY_size(pkey);
    3446               0 :         crypttemp = emalloc(cryptedlen + 1);
    3447                 : 
    3448               0 :         switch (pkey->type) {
    3449                 :                 case EVP_PKEY_RSA:
    3450                 :                 case EVP_PKEY_RSA2:
    3451               0 :                         cryptedlen = RSA_public_decrypt(data_len, 
    3452                 :                                         (unsigned char *)data, 
    3453                 :                                         crypttemp, 
    3454                 :                                         pkey->pkey.rsa, 
    3455                 :                                         padding);
    3456               0 :                         if (cryptedlen != -1) {
    3457               0 :                                 cryptedbuf = emalloc(cryptedlen + 1);
    3458               0 :                                 memcpy(cryptedbuf, crypttemp, cryptedlen);
    3459               0 :                                 successful = 1;
    3460                 :                         }
    3461               0 :                         break;
    3462                 :                         
    3463                 :                 default:
    3464               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3465                 :                  
    3466                 :         }
    3467                 : 
    3468               0 :         efree(crypttemp);
    3469                 : 
    3470               0 :         if (successful) {
    3471               0 :                 zval_dtor(crypted);
    3472               0 :                 cryptedbuf[cryptedlen] = '\0';
    3473               0 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3474               0 :                 cryptedbuf = NULL;
    3475               0 :                 RETVAL_TRUE;
    3476                 :         }
    3477                 : 
    3478               0 :         if (cryptedbuf) {
    3479               0 :                 efree(cryptedbuf);
    3480                 :         }
    3481               0 :         if (keyresource == -1) {
    3482               0 :                 EVP_PKEY_free(pkey);
    3483                 :         }
    3484                 : }
    3485                 : /* }}} */
    3486                 : 
    3487                 : /* {{{ proto mixed openssl_error_string(void)
    3488                 :    Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
    3489                 : PHP_FUNCTION(openssl_error_string)
    3490               0 : {
    3491                 :         char buf[512];
    3492                 :         unsigned long val;
    3493                 : 
    3494               0 :         if (ZEND_NUM_ARGS() != 0) {
    3495               0 :                 WRONG_PARAM_COUNT;
    3496                 :         }
    3497                 : 
    3498               0 :         val = ERR_get_error();
    3499               0 :         if (val) {
    3500               0 :                 RETURN_STRING(ERR_error_string(val, buf), 1);
    3501                 :         } else {
    3502               0 :                 RETURN_FALSE;
    3503                 :         }
    3504                 : }
    3505                 : /* }}} */
    3506                 : 
    3507                 : /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, int signature_alg])
    3508                 :    Signs data */
    3509                 : PHP_FUNCTION(openssl_sign)
    3510               2 : {
    3511                 :         zval **key, *signature;
    3512                 :         EVP_PKEY *pkey;
    3513                 :         int siglen;
    3514                 :         unsigned char *sigbuf;
    3515               2 :         long keyresource = -1;
    3516                 :         char * data;
    3517                 :         int data_len;
    3518                 :         EVP_MD_CTX md_ctx;
    3519               2 :         long signature_algo = OPENSSL_ALGO_SHA1;
    3520                 :         EVP_MD *mdtype;
    3521                 : 
    3522               2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &signature, &key, &signature_algo) == FAILURE) {
    3523               0 :                 return;
    3524                 :         }
    3525               2 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    3526               2 :         if (pkey == NULL) {
    3527               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a private key");
    3528               0 :                 RETURN_FALSE;
    3529                 :         }
    3530                 : 
    3531               2 :         mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    3532               2 :         if (!mdtype) {
    3533               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    3534               0 :                 RETURN_FALSE;
    3535                 :         }
    3536                 : 
    3537               2 :         siglen = EVP_PKEY_size(pkey);
    3538               2 :         sigbuf = emalloc(siglen + 1);
    3539                 : 
    3540               2 :         EVP_SignInit(&md_ctx, mdtype);
    3541               2 :         EVP_SignUpdate(&md_ctx, data, data_len);
    3542               2 :         if (EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) {
    3543               2 :                 zval_dtor(signature);
    3544               2 :                 sigbuf[siglen] = '\0';
    3545               2 :                 ZVAL_STRINGL(signature, (char *)sigbuf, siglen, 0);
    3546               2 :                 RETVAL_TRUE;
    3547                 :         } else {
    3548               0 :                 efree(sigbuf);
    3549               0 :                 RETVAL_FALSE;
    3550                 :         }
    3551                 : #if OPENSSL_VERSION_NUMBER >= 0x0090700fL
    3552               2 :         EVP_MD_CTX_cleanup(&md_ctx);
    3553                 : #endif
    3554               2 :         if (keyresource == -1) {
    3555               0 :                 EVP_PKEY_free(pkey);
    3556                 :         }
    3557                 : }
    3558                 : /* }}} */
    3559                 : 
    3560                 : /* {{{ proto int openssl_verify(string data, string signature, mixed key)
    3561                 :    Verifys data */
    3562                 : PHP_FUNCTION(openssl_verify)
    3563              10 : {
    3564                 :         zval **key;
    3565                 :         EVP_PKEY *pkey;
    3566                 :         int err;
    3567                 :         EVP_MD_CTX     md_ctx;
    3568                 :         EVP_MD *mdtype;
    3569              10 :         long keyresource = -1;
    3570                 :         char * data;    int data_len;
    3571                 :         char * signature;       int signature_len;
    3572              10 :         long signature_algo = OPENSSL_ALGO_SHA1;
    3573                 :         
    3574              10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|l", &data, &data_len, &signature, &signature_len, &key, &signature_algo) == FAILURE) {
    3575               5 :                 return;
    3576                 :         }
    3577                 : 
    3578               5 :         mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    3579               5 :         if (!mdtype) {
    3580               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    3581               0 :                 RETURN_FALSE;
    3582                 :         }
    3583                 : 
    3584               5 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    3585               5 :         if (pkey == NULL) {
    3586               3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a public key");
    3587               3 :                 RETURN_FALSE;
    3588                 :         }
    3589                 : 
    3590               2 :         EVP_VerifyInit   (&md_ctx, mdtype);
    3591               2 :         EVP_VerifyUpdate (&md_ctx, data, data_len);
    3592               2 :         err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
    3593                 : #if OPENSSL_VERSION_NUMBER >= 0x0090700fL
    3594               2 :         EVP_MD_CTX_cleanup(&md_ctx);
    3595                 : #endif
    3596                 : 
    3597               2 :         if (keyresource == -1) {
    3598               0 :                 EVP_PKEY_free(pkey);
    3599                 :         }
    3600               2 :         RETURN_LONG(err);
    3601                 : }
    3602                 : /* }}} */
    3603                 : 
    3604                 : /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
    3605                 :    Seals data */
    3606                 : PHP_FUNCTION(openssl_seal)
    3607               4 : {
    3608                 :         zval *pubkeys, **pubkey, *sealdata, *ekeys;
    3609                 :         HashTable *pubkeysht;
    3610                 :         HashPosition pos;
    3611                 :         EVP_PKEY **pkeys;
    3612                 :         long * key_resources;   /* so we know what to cleanup */
    3613                 :         int i, len1, len2, *eksl, nkeys;
    3614               4 :         unsigned char *buf = NULL, **eks;
    3615                 :         char * data; int data_len;
    3616                 :         EVP_CIPHER_CTX ctx;
    3617                 : 
    3618               4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/", &data, &data_len, &sealdata, &ekeys, &pubkeys) == FAILURE) {
    3619               2 :                 return;
    3620                 :         }
    3621                 :         
    3622               2 :         pubkeysht = HASH_OF(pubkeys);
    3623               2 :         nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
    3624               2 :         if (!nkeys) {
    3625               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
    3626               1 :                 RETURN_FALSE;
    3627                 :         }
    3628                 : 
    3629               1 :         pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
    3630               1 :         eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
    3631               1 :         eks = safe_emalloc(nkeys, sizeof(*eks), 0);
    3632               1 :         memset(eks, 0, sizeof(*eks) * nkeys);
    3633               1 :         key_resources = safe_emalloc(nkeys, sizeof(long), 0);
    3634               1 :         memset(key_resources, 0, sizeof(*key_resources) * nkeys);
    3635                 : 
    3636                 :         /* get the public keys we are using to seal this data */
    3637               1 :         zend_hash_internal_pointer_reset_ex(pubkeysht, &pos);
    3638               1 :         i = 0;
    3639               2 :         while (zend_hash_get_current_data_ex(pubkeysht, (void **) &pubkey,
    3640                 :                                 &pos) == SUCCESS) {
    3641               1 :                 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i] TSRMLS_CC);
    3642               1 :                 if (pkeys[i] == NULL) {
    3643               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a public key (%dth member of pubkeys)", i);
    3644               1 :                         RETVAL_FALSE;
    3645               1 :                         goto clean_exit;
    3646                 :                 }
    3647               0 :                 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
    3648               0 :                 zend_hash_move_forward_ex(pubkeysht, &pos);
    3649               0 :                 i++;
    3650                 :         }
    3651                 : 
    3652               0 :         if (!EVP_EncryptInit(&ctx,EVP_rc4(),NULL,NULL)) {
    3653               0 :                 RETVAL_FALSE;
    3654               0 :                 goto clean_exit;
    3655                 :         }
    3656                 : 
    3657                 : #if 0
    3658                 :         /* Need this if allow ciphers that require initialization vector */
    3659                 :         ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
    3660                 :         iv = ivlen ? emalloc(ivlen + 1) : NULL;
    3661                 : #endif
    3662                 :         /* allocate one byte extra to make room for \0 */
    3663               0 :         buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
    3664                 : 
    3665               0 :         if (!EVP_SealInit(&ctx, EVP_rc4(), eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    3666               0 :                 RETVAL_FALSE;
    3667               0 :                 efree(buf);
    3668               0 :                 goto clean_exit;
    3669                 :         }
    3670                 : 
    3671               0 :         EVP_SealFinal(&ctx, buf + len1, &len2);
    3672                 : 
    3673               0 :         if (len1 + len2 > 0) {
    3674               0 :                 zval_dtor(sealdata);
    3675               0 :                 buf[len1 + len2] = '\0';
    3676               0 :                 buf = erealloc(buf, len1 + len2 + 1);
    3677               0 :                 ZVAL_STRINGL(sealdata, (char *)buf, len1 + len2, 0);
    3678                 : 
    3679               0 :                 zval_dtor(ekeys);
    3680               0 :                 array_init(ekeys);
    3681               0 :                 for (i=0; i<nkeys; i++) {
    3682               0 :                         eks[i][eksl[i]] = '\0';
    3683               0 :                         add_next_index_stringl(ekeys, erealloc(eks[i], eksl[i] + 1), eksl[i], 0);
    3684               0 :                         eks[i] = NULL;
    3685                 :                 }
    3686                 : #if 0
    3687                 :                 /* If allow ciphers that need IV, we need this */
    3688                 :                 zval_dtor(*ivec);
    3689                 :                 if (ivlen) {
    3690                 :                         iv[ivlen] = '\0';
    3691                 :                         ZVAL_STRINGL(*ivec, erealloc(iv, ivlen + 1), ivlen, 0);
    3692                 :                 } else {
    3693                 :                         ZVAL_EMPTY_STRING(*ivec);
    3694                 :                 }
    3695                 : #endif
    3696                 :         } else {
    3697               0 :                 efree(buf);
    3698                 :         }
    3699               0 :         RETVAL_LONG(len1 + len2);
    3700                 : 
    3701               1 : clean_exit:
    3702               2 :         for (i=0; i<nkeys; i++) {
    3703               1 :                 if (key_resources[i] == -1) {
    3704               1 :                         EVP_PKEY_free(pkeys[i]);
    3705                 :                 }
    3706               1 :                 if (eks[i]) { 
    3707               0 :                         efree(eks[i]);
    3708                 :                 }
    3709                 :         }
    3710               1 :         efree(eks);
    3711               1 :         efree(eksl);
    3712               1 :         efree(pkeys);
    3713               1 :         efree(key_resources);
    3714                 : }
    3715                 : /* }}} */
    3716                 : 
    3717                 : /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
    3718                 :    Opens data */
    3719                 : PHP_FUNCTION(openssl_open)
    3720               0 : {
    3721                 :         zval **privkey, *opendata;
    3722                 :         EVP_PKEY *pkey;
    3723                 :         int len1, len2;
    3724                 :         unsigned char *buf;
    3725               0 :         long keyresource = -1;
    3726                 :         EVP_CIPHER_CTX ctx;
    3727                 :         char * data;    int data_len;
    3728                 :         char * ekey;    int ekey_len;
    3729                 : 
    3730               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey) == FAILURE) {
    3731               0 :                 return;
    3732                 :         }
    3733                 : 
    3734               0 :         pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource TSRMLS_CC);
    3735               0 :         if (pkey == NULL) {
    3736               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key");
    3737               0 :                 RETURN_FALSE;
    3738                 :         }
    3739               0 :         buf = emalloc(data_len + 1);
    3740                 : 
    3741               0 :         if (EVP_OpenInit(&ctx, EVP_rc4(), (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    3742               0 :                 if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
    3743               0 :                         efree(buf);
    3744               0 :                         if (keyresource == -1) { 
    3745               0 :                                 EVP_PKEY_free(pkey);
    3746                 :                         }
    3747               0 :                         RETURN_FALSE;
    3748                 :                 }
    3749                 :         } else {
    3750               0 :                 efree(buf);
    3751               0 :                 if (keyresource == -1) {
    3752               0 :                         EVP_PKEY_free(pkey);
    3753                 :                 }
    3754               0 :                 RETURN_FALSE;
    3755                 :         }
    3756               0 :         if (keyresource == -1) {
    3757               0 :                 EVP_PKEY_free(pkey);
    3758                 :         }
    3759               0 :         zval_dtor(opendata);
    3760               0 :         buf[len1 + len2] = '\0';
    3761               0 :         ZVAL_STRINGL(opendata, erealloc(buf, len1 + len2 + 1), len1 + len2, 0);
    3762               0 :         RETURN_TRUE;
    3763                 : }
    3764                 : /* }}} */
    3765                 : 
    3766                 : /* SSL verification functions */
    3767                 : 
    3768                 : #define GET_VER_OPT(name)               (stream->context && SUCCESS == php_stream_context_get_option(stream->context, "ssl", name, &val))
    3769                 : #define GET_VER_OPT_STRING(name, str)   if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_PP(val); }
    3770                 : 
    3771                 : static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
    3772               0 : {
    3773                 :         php_stream *stream;
    3774                 :         SSL *ssl;
    3775                 :         X509 *err_cert;
    3776                 :         int err, depth, ret;
    3777                 :         zval **val;
    3778                 : 
    3779               0 :         ret = preverify_ok;
    3780                 : 
    3781                 :         /* determine the status for the current cert */
    3782               0 :         err_cert = X509_STORE_CTX_get_current_cert(ctx);
    3783               0 :         err = X509_STORE_CTX_get_error(ctx);
    3784               0 :         depth = X509_STORE_CTX_get_error_depth(ctx);
    3785                 : 
    3786                 :         /* conjure the stream & context to use */
    3787               0 :         ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    3788               0 :         stream = (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
    3789                 : 
    3790                 :         /* if allow_self_signed is set, make sure that verification succeeds */
    3791               0 :         if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
    3792               0 :                 ret = 1;
    3793                 :         }
    3794                 : 
    3795                 :         /* check the depth */
    3796               0 :         if (GET_VER_OPT("verify_depth")) {
    3797               0 :                 convert_to_long_ex(val);
    3798                 : 
    3799               0 :                 if (depth > Z_LVAL_PP(val)) {
    3800               0 :                         ret = 0;
    3801               0 :                         X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
    3802                 :                 }
    3803                 :         }
    3804                 : 
    3805               0 :         return ret;
    3806                 : 
    3807                 : }
    3808                 : /* }}} */
    3809                 : 
    3810                 : int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC) /* {{{ */
    3811               5 : {
    3812               5 :         zval **val = NULL;
    3813               5 :         char *cnmatch = NULL;
    3814                 :         X509_NAME *name;
    3815                 :         char buf[1024];
    3816                 :         int err;
    3817                 : 
    3818                 :         /* verification is turned off */
    3819               5 :         if (!(GET_VER_OPT("verify_peer") && zval_is_true(*val))) {
    3820               5 :                 return SUCCESS;
    3821                 :         }
    3822                 : 
    3823               0 :         if (peer == NULL) {
    3824               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not get peer certificate");
    3825               0 :                 return FAILURE;
    3826                 :         }
    3827                 : 
    3828               0 :         err = SSL_get_verify_result(ssl);
    3829               0 :         switch (err) {
    3830                 :                 case X509_V_OK:
    3831                 :                         /* fine */
    3832               0 :                         break;
    3833                 :                 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
    3834               0 :                         if (GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
    3835                 :                                 /* allowed */
    3836               0 :                                 break;
    3837                 :                         }
    3838                 :                         /* not allowed, so fall through */
    3839                 :                 default:
    3840               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err));
    3841               0 :                         return FAILURE;
    3842                 :         }
    3843                 : 
    3844                 :         /* if the cert passed the usual checks, apply our own local policies now */
    3845                 : 
    3846               0 :         name = X509_get_subject_name(peer);
    3847                 : 
    3848                 :         /* Does the common name match ? (used primarily for https://) */
    3849               0 :         GET_VER_OPT_STRING("CN_match", cnmatch);
    3850               0 :         if (cnmatch) {
    3851               0 :                 int match = 0;
    3852               0 :                 int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf));
    3853                 : 
    3854               0 :                 if (name_len == -1) {
    3855               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
    3856               0 :                         return FAILURE;
    3857               0 :                 } else if (name_len != strlen(buf)) {
    3858               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", name_len, buf);
    3859               0 :                         return FAILURE;
    3860                 :                 }
    3861                 : 
    3862               0 :                 match = strcmp(cnmatch, buf) == 0;
    3863               0 :                 if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') {
    3864                 :                         /* Try wildcard */
    3865                 : 
    3866               0 :                         if (strchr(buf+2, '.')) {
    3867               0 :                                 char *tmp = strstr(cnmatch, buf+1);
    3868                 : 
    3869               0 :                                 match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch, '.');
    3870                 :                         }
    3871                 :                 }
    3872                 : 
    3873               0 :                 if (!match) {
    3874                 :                         /* didn't match */
    3875               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch);
    3876               0 :                         return FAILURE;
    3877                 :                 }
    3878                 :         }
    3879                 : 
    3880               0 :         return SUCCESS;
    3881                 : }
    3882                 : /* }}} */
    3883                 : 
    3884                 : static int passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */
    3885               1 : {
    3886               1 :     php_stream *stream = (php_stream *)data;
    3887               1 :     zval **val = NULL;
    3888               1 :     char *passphrase = NULL;
    3889                 :     /* TODO: could expand this to make a callback into PHP user-space */
    3890                 : 
    3891               1 :     GET_VER_OPT_STRING("passphrase", passphrase);
    3892                 : 
    3893               1 :     if (passphrase) {
    3894               1 :         if (Z_STRLEN_PP(val) < num - 1) {
    3895               1 :             memcpy(buf, Z_STRVAL_PP(val), Z_STRLEN_PP(val)+1);
    3896               1 :             return Z_STRLEN_PP(val);
    3897                 :         }
    3898                 :     }
    3899               0 :     return 0;
    3900                 : }
    3901                 : /* }}} */
    3902                 : 
    3903                 : SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */
    3904               5 : {
    3905               5 :         zval **val = NULL;
    3906               5 :         char *cafile = NULL;
    3907               5 :         char *capath = NULL;
    3908               5 :         char *certfile = NULL;
    3909               5 :         char *cipherlist = NULL;
    3910               5 :         int ok = 1;
    3911                 : 
    3912               5 :         ERR_clear_error();
    3913                 : 
    3914                 :         /* look at context options in the stream and set appropriate verification flags */
    3915               5 :         if (GET_VER_OPT("verify_peer") && zval_is_true(*val)) {
    3916                 : 
    3917                 :                 /* turn on verification callback */
    3918               0 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
    3919                 : 
    3920                 :                 /* CA stuff */
    3921               0 :                 GET_VER_OPT_STRING("cafile", cafile);
    3922               0 :                 GET_VER_OPT_STRING("capath", capath);
    3923                 : 
    3924               0 :                 if (cafile || capath) {
    3925               0 :                         if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
    3926               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set verify locations `%s' `%s'", cafile, capath);
    3927               0 :                                 return NULL;
    3928                 :                         }
    3929                 :                 }
    3930                 : 
    3931               0 :                 if (GET_VER_OPT("verify_depth")) {
    3932               0 :                         convert_to_long_ex(val);
    3933               0 :                         SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val));
    3934                 :                 }
    3935                 :         } else {
    3936               5 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
    3937                 :         }
    3938                 : 
    3939                 :         /* callback for the passphrase (for localcert) */
    3940               5 :         if (GET_VER_OPT("passphrase")) {
    3941               1 :                 SSL_CTX_set_default_passwd_cb_userdata(ctx, stream);
    3942               1 :                 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
    3943                 :         }
    3944                 : 
    3945               5 :         GET_VER_OPT_STRING("ciphers", cipherlist);
    3946               5 :         if (!cipherlist) {
    3947               5 :                 cipherlist = "DEFAULT";
    3948                 :         }
    3949               5 :         SSL_CTX_set_cipher_list(ctx, cipherlist);
    3950                 : 
    3951               5 :         GET_VER_OPT_STRING("local_cert", certfile);
    3952               5 :         if (certfile) {
    3953               3 :                 X509 *cert = NULL;
    3954               3 :                 EVP_PKEY *key = NULL;
    3955                 :                 SSL *tmpssl;
    3956                 :                 char resolved_path_buff[MAXPATHLEN];
    3957                 : 
    3958               3 :                 if (VCWD_REALPATH(certfile, resolved_path_buff)) {
    3959                 :                         /* a certificate to use for authentication */
    3960               3 :                         if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
    3961               0 :                                 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);
    3962               0 :                                 return NULL;
    3963                 :                         }
    3964                 : 
    3965               3 :                         if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
    3966               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
    3967               0 :                                 return NULL;
    3968                 :                         }
    3969                 : 
    3970               3 :                         tmpssl = SSL_new(ctx);
    3971               3 :                         cert = SSL_get_certificate(tmpssl);
    3972                 : 
    3973               3 :                         if (cert) {
    3974               3 :                                 key = X509_get_pubkey(cert);
    3975               3 :                                 EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl));
    3976               3 :                                 EVP_PKEY_free(key);
    3977                 :                         }
    3978               3 :                         SSL_free(tmpssl);
    3979                 : 
    3980               3 :                         if (!SSL_CTX_check_private_key(ctx)) {
    3981               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Private key does not match certificate!");
    3982                 :                         }
    3983                 :                 }
    3984                 :         }
    3985               5 :         if (ok) {
    3986               5 :                 SSL *ssl = SSL_new(ctx);
    3987                 : 
    3988               5 :                 if (ssl) {
    3989                 :                         /* map SSL => stream */
    3990               5 :                         SSL_set_ex_data(ssl, ssl_stream_data_index, stream);
    3991                 :                 }
    3992               5 :                 return ssl;
    3993                 :         }
    3994                 : 
    3995               0 :         return NULL;
    3996                 : }
    3997                 : /* }}} */
    3998                 : 
    3999                 : /*
    4000                 :  * Local variables:
    4001                 :  * tab-width: 8
    4002                 :  * c-basic-offset: 8
    4003                 :  * End:
    4004                 :  * vim600: sw=4 ts=4 fdm=marker
    4005                 :  * vim<600: sw=4 ts=4
    4006                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:14 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.