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

LCOV - code coverage report
Current view: top level - ext/openssl - openssl.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1496 2267 66.0 %
Date: 2014-07-29 Functions: 66 82 80.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 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$ */
      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             : #include "ext/standard/md5.h"
      37             : #include "ext/standard/base64.h"
      38             : 
      39             : #if PHP_WIN32
      40             : # include "win32/winutil.h"
      41             : #endif
      42             : 
      43             : /* OpenSSL includes */
      44             : #include <openssl/evp.h>
      45             : #include <openssl/x509.h>
      46             : #include <openssl/x509v3.h>
      47             : #include <openssl/crypto.h>
      48             : #include <openssl/pem.h>
      49             : #include <openssl/err.h>
      50             : #include <openssl/conf.h>
      51             : #include <openssl/rand.h>
      52             : #include <openssl/ssl.h>
      53             : #include <openssl/pkcs12.h>
      54             : 
      55             : /* Common */
      56             : #include <time.h>
      57             : 
      58             : #ifdef NETWARE
      59             : #define timezone _timezone      /* timezone is called _timezone in LibC */
      60             : #endif
      61             : 
      62             : #define DEFAULT_KEY_LENGTH      512
      63             : #define MIN_KEY_LENGTH          384
      64             : 
      65             : #define OPENSSL_ALGO_SHA1       1
      66             : #define OPENSSL_ALGO_MD5        2
      67             : #define OPENSSL_ALGO_MD4        3
      68             : #ifdef HAVE_OPENSSL_MD2_H
      69             : #define OPENSSL_ALGO_MD2        4
      70             : #endif
      71             : #define OPENSSL_ALGO_DSS1       5
      72             : #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
      73             : #define OPENSSL_ALGO_SHA224 6
      74             : #define OPENSSL_ALGO_SHA256 7
      75             : #define OPENSSL_ALGO_SHA384 8
      76             : #define OPENSSL_ALGO_SHA512 9
      77             : #define OPENSSL_ALGO_RMD160 10
      78             : #endif
      79             : #define DEBUG_SMIME     0
      80             : 
      81             : #if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
      82             : #define HAVE_EVP_PKEY_EC 1
      83             : #endif
      84             : 
      85             : /* FIXME: Use the openssl constants instead of
      86             :  * enum. It is now impossible to match real values
      87             :  * against php constants. Also sorry to break the
      88             :  * enum principles here, BC...
      89             :  */
      90             : enum php_openssl_key_type {
      91             :         OPENSSL_KEYTYPE_RSA,
      92             :         OPENSSL_KEYTYPE_DSA,
      93             :         OPENSSL_KEYTYPE_DH,
      94             :         OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
      95             : #ifdef HAVE_EVP_PKEY_EC
      96             :         OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
      97             : #endif
      98             : };
      99             : 
     100             : enum php_openssl_cipher_type {
     101             :         PHP_OPENSSL_CIPHER_RC2_40,
     102             :         PHP_OPENSSL_CIPHER_RC2_128,
     103             :         PHP_OPENSSL_CIPHER_RC2_64,
     104             :         PHP_OPENSSL_CIPHER_DES,
     105             :         PHP_OPENSSL_CIPHER_3DES,
     106             :         PHP_OPENSSL_CIPHER_AES_128_CBC,
     107             :         PHP_OPENSSL_CIPHER_AES_192_CBC,
     108             :         PHP_OPENSSL_CIPHER_AES_256_CBC,
     109             : 
     110             :         PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
     111             : };
     112             : 
     113             : PHP_FUNCTION(openssl_get_md_methods);
     114             : PHP_FUNCTION(openssl_get_cipher_methods);
     115             : 
     116             : PHP_FUNCTION(openssl_digest);
     117             : PHP_FUNCTION(openssl_encrypt);
     118             : PHP_FUNCTION(openssl_decrypt);
     119             : PHP_FUNCTION(openssl_cipher_iv_length);
     120             : 
     121             : PHP_FUNCTION(openssl_dh_compute_key);
     122             : PHP_FUNCTION(openssl_random_pseudo_bytes);
     123             : 
     124             : /* {{{ arginfo */
     125             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2)
     126             :     ZEND_ARG_INFO(0, x509)
     127             :     ZEND_ARG_INFO(0, outfilename)
     128             :     ZEND_ARG_INFO(0, notext)
     129             : ZEND_END_ARG_INFO()
     130             : 
     131             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
     132             :     ZEND_ARG_INFO(0, x509)
     133             :     ZEND_ARG_INFO(1, out)
     134             :     ZEND_ARG_INFO(0, notext)
     135             : ZEND_END_ARG_INFO()
     136             : 
     137             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
     138             :     ZEND_ARG_INFO(0, cert)
     139             :     ZEND_ARG_INFO(0, key)
     140             : ZEND_END_ARG_INFO()
     141             : 
     142             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_parse, 0)
     143             :     ZEND_ARG_INFO(0, x509)
     144             :     ZEND_ARG_INFO(0, shortname)
     145             : ZEND_END_ARG_INFO()
     146             : 
     147             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 3)
     148             :     ZEND_ARG_INFO(0, x509cert)
     149             :     ZEND_ARG_INFO(0, purpose)
     150             :     ZEND_ARG_INFO(0, cainfo) /* array */
     151             :     ZEND_ARG_INFO(0, untrustedfile)
     152             : ZEND_END_ARG_INFO()
     153             : 
     154             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0)
     155             :     ZEND_ARG_INFO(0, cert)
     156             : ZEND_END_ARG_INFO()
     157             : 
     158             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0)
     159             :     ZEND_ARG_INFO(0, x509)
     160             : ZEND_END_ARG_INFO()
     161             : 
     162             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4)
     163             :     ZEND_ARG_INFO(0, x509)
     164             :     ZEND_ARG_INFO(0, filename)
     165             :     ZEND_ARG_INFO(0, priv_key)
     166             :     ZEND_ARG_INFO(0, pass)
     167             :     ZEND_ARG_INFO(0, args) /* array */
     168             : ZEND_END_ARG_INFO()
     169             : 
     170             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_export, 0)
     171             :     ZEND_ARG_INFO(0, x509)
     172             :     ZEND_ARG_INFO(1, out)
     173             :     ZEND_ARG_INFO(0, priv_key)
     174             :     ZEND_ARG_INFO(0, pass)
     175             :     ZEND_ARG_INFO(0, args) /* array */
     176             : ZEND_END_ARG_INFO()
     177             : 
     178             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0)
     179             :     ZEND_ARG_INFO(0, PKCS12)
     180             :     ZEND_ARG_INFO(1, certs) /* array */
     181             :     ZEND_ARG_INFO(0, pass)
     182             : ZEND_END_ARG_INFO()
     183             : 
     184             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2)
     185             :     ZEND_ARG_INFO(0, csr)
     186             :     ZEND_ARG_INFO(0, outfilename)
     187             :     ZEND_ARG_INFO(0, notext)
     188             : ZEND_END_ARG_INFO()
     189             : 
     190             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2)
     191             :     ZEND_ARG_INFO(0, csr)
     192             :     ZEND_ARG_INFO(1, out)
     193             :     ZEND_ARG_INFO(0, notext)
     194             : ZEND_END_ARG_INFO()
     195             : 
     196             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4)
     197             :     ZEND_ARG_INFO(0, csr)
     198             :     ZEND_ARG_INFO(0, x509)
     199             :     ZEND_ARG_INFO(0, priv_key)
     200             :     ZEND_ARG_INFO(0, days)
     201             :     ZEND_ARG_INFO(0, config_args) /* array */
     202             :     ZEND_ARG_INFO(0, serial)
     203             : ZEND_END_ARG_INFO()
     204             : 
     205             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2)
     206             :     ZEND_ARG_INFO(0, dn) /* array */
     207             :     ZEND_ARG_INFO(1, privkey)
     208             :     ZEND_ARG_INFO(0, configargs)
     209             :     ZEND_ARG_INFO(0, extraattribs)
     210             : ZEND_END_ARG_INFO()
     211             : 
     212             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_subject, 0)
     213             :     ZEND_ARG_INFO(0, csr)
     214             : ZEND_END_ARG_INFO()
     215             : 
     216             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_public_key, 0)
     217             :     ZEND_ARG_INFO(0, csr)
     218             : ZEND_END_ARG_INFO()
     219             : 
     220             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0)
     221             :     ZEND_ARG_INFO(0, configargs) /* array */
     222             : ZEND_END_ARG_INFO()
     223             : 
     224             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2)
     225             :     ZEND_ARG_INFO(0, key)
     226             :     ZEND_ARG_INFO(0, outfilename)
     227             :     ZEND_ARG_INFO(0, passphrase)
     228             :     ZEND_ARG_INFO(0, config_args) /* array */
     229             : ZEND_END_ARG_INFO()
     230             : 
     231             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2)
     232             :     ZEND_ARG_INFO(0, key)
     233             :     ZEND_ARG_INFO(1, out)
     234             :     ZEND_ARG_INFO(0, passphrase)
     235             :     ZEND_ARG_INFO(0, config_args) /* array */
     236             : ZEND_END_ARG_INFO()
     237             : 
     238             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0)
     239             :     ZEND_ARG_INFO(0, cert)
     240             : ZEND_END_ARG_INFO()
     241             : 
     242             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0)
     243             :     ZEND_ARG_INFO(0, key)
     244             : ZEND_END_ARG_INFO()
     245             : 
     246             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1)
     247             :     ZEND_ARG_INFO(0, key)
     248             :     ZEND_ARG_INFO(0, passphrase)
     249             : ZEND_END_ARG_INFO()
     250             : 
     251             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
     252             :     ZEND_ARG_INFO(0, key)
     253             : ZEND_END_ARG_INFO()
     254             : 
     255             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
     256             :     ZEND_ARG_INFO(0, filename)
     257             :     ZEND_ARG_INFO(0, flags)
     258             :     ZEND_ARG_INFO(0, signerscerts)
     259             :     ZEND_ARG_INFO(0, cainfo) /* array */
     260             :     ZEND_ARG_INFO(0, extracerts)
     261             :     ZEND_ARG_INFO(0, content)
     262             : ZEND_END_ARG_INFO()
     263             : 
     264             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
     265             :     ZEND_ARG_INFO(0, infile)
     266             :     ZEND_ARG_INFO(0, outfile)
     267             :     ZEND_ARG_INFO(0, recipcerts)
     268             :     ZEND_ARG_INFO(0, headers) /* array */
     269             :     ZEND_ARG_INFO(0, flags)
     270             :     ZEND_ARG_INFO(0, cipher)
     271             : ZEND_END_ARG_INFO()
     272             : 
     273             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5)
     274             :     ZEND_ARG_INFO(0, infile)
     275             :     ZEND_ARG_INFO(0, outfile)
     276             :     ZEND_ARG_INFO(0, signcert)
     277             :     ZEND_ARG_INFO(0, signkey)
     278             :     ZEND_ARG_INFO(0, headers) /* array */
     279             :     ZEND_ARG_INFO(0, flags)
     280             :     ZEND_ARG_INFO(0, extracertsfilename)
     281             : ZEND_END_ARG_INFO()
     282             : 
     283             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
     284             :     ZEND_ARG_INFO(0, infilename)
     285             :     ZEND_ARG_INFO(0, outfilename)
     286             :     ZEND_ARG_INFO(0, recipcert)
     287             :     ZEND_ARG_INFO(0, recipkey)
     288             : ZEND_END_ARG_INFO()
     289             : 
     290             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
     291             :     ZEND_ARG_INFO(0, data)
     292             :     ZEND_ARG_INFO(1, crypted)
     293             :     ZEND_ARG_INFO(0, key)
     294             :     ZEND_ARG_INFO(0, padding)
     295             : ZEND_END_ARG_INFO()
     296             : 
     297             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3)
     298             :     ZEND_ARG_INFO(0, data)
     299             :     ZEND_ARG_INFO(1, crypted)
     300             :     ZEND_ARG_INFO(0, key)
     301             :     ZEND_ARG_INFO(0, padding)
     302             : ZEND_END_ARG_INFO()
     303             : 
     304             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3)
     305             :     ZEND_ARG_INFO(0, data)
     306             :     ZEND_ARG_INFO(1, crypted)
     307             :     ZEND_ARG_INFO(0, key)
     308             :     ZEND_ARG_INFO(0, padding)
     309             : ZEND_END_ARG_INFO()
     310             : 
     311             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3)
     312             :     ZEND_ARG_INFO(0, data)
     313             :     ZEND_ARG_INFO(1, crypted)
     314             :     ZEND_ARG_INFO(0, key)
     315             :     ZEND_ARG_INFO(0, padding)
     316             : ZEND_END_ARG_INFO()
     317             : 
     318             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0)
     319             : ZEND_END_ARG_INFO()
     320             : 
     321             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3)
     322             :     ZEND_ARG_INFO(0, data)
     323             :     ZEND_ARG_INFO(1, signature)
     324             :     ZEND_ARG_INFO(0, key)
     325             :     ZEND_ARG_INFO(0, method)
     326             : ZEND_END_ARG_INFO()
     327             : 
     328             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3)
     329             :     ZEND_ARG_INFO(0, data)
     330             :     ZEND_ARG_INFO(0, signature)
     331             :     ZEND_ARG_INFO(0, key)
     332             :     ZEND_ARG_INFO(0, method)
     333             : ZEND_END_ARG_INFO()
     334             : 
     335             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_seal, 0)
     336             :     ZEND_ARG_INFO(0, data)
     337             :     ZEND_ARG_INFO(1, sealdata)
     338             :     ZEND_ARG_INFO(1, ekeys) /* arary */
     339             :     ZEND_ARG_INFO(0, pubkeys) /* array */
     340             : ZEND_END_ARG_INFO()
     341             : 
     342             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
     343             :     ZEND_ARG_INFO(0, data)
     344             :     ZEND_ARG_INFO(1, opendata)
     345             :     ZEND_ARG_INFO(0, ekey)
     346             :     ZEND_ARG_INFO(0, privkey)
     347             : ZEND_END_ARG_INFO()
     348             : 
     349             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
     350             :     ZEND_ARG_INFO(0, aliases)
     351             : ZEND_END_ARG_INFO()
     352             : 
     353             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
     354             :     ZEND_ARG_INFO(0, aliases)
     355             : ZEND_END_ARG_INFO()
     356             : 
     357             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
     358             :     ZEND_ARG_INFO(0, data)
     359             :     ZEND_ARG_INFO(0, method)
     360             :     ZEND_ARG_INFO(0, raw_output)
     361             : ZEND_END_ARG_INFO()
     362             : 
     363             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
     364             :     ZEND_ARG_INFO(0, data)
     365             :     ZEND_ARG_INFO(0, method)
     366             :     ZEND_ARG_INFO(0, password)
     367             :     ZEND_ARG_INFO(0, options)
     368             :     ZEND_ARG_INFO(0, iv)
     369             : ZEND_END_ARG_INFO()
     370             : 
     371             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
     372             :     ZEND_ARG_INFO(0, data)
     373             :     ZEND_ARG_INFO(0, method)
     374             :     ZEND_ARG_INFO(0, password)
     375             :     ZEND_ARG_INFO(0, options)
     376             :     ZEND_ARG_INFO(0, iv)
     377             : ZEND_END_ARG_INFO()
     378             : 
     379             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
     380             :     ZEND_ARG_INFO(0, method)
     381             : ZEND_END_ARG_INFO()
     382             : 
     383             : ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
     384             :     ZEND_ARG_INFO(0, pub_key)
     385             :     ZEND_ARG_INFO(0, dh_key)
     386             : ZEND_END_ARG_INFO()
     387             : 
     388             : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
     389             :     ZEND_ARG_INFO(0, length)
     390             :     ZEND_ARG_INFO(1, result_is_strong)
     391             : ZEND_END_ARG_INFO()
     392             : /* }}} */
     393             : 
     394             : /* {{{ openssl_functions[]
     395             :  */
     396             : const zend_function_entry openssl_functions[] = {
     397             : /* public/private key functions */
     398             :         PHP_FE(openssl_pkey_free,                       arginfo_openssl_pkey_free)
     399             :         PHP_FE(openssl_pkey_new,                        arginfo_openssl_pkey_new)
     400             :         PHP_FE(openssl_pkey_export,                     arginfo_openssl_pkey_export)
     401             :         PHP_FE(openssl_pkey_export_to_file,     arginfo_openssl_pkey_export_to_file)
     402             :         PHP_FE(openssl_pkey_get_private,        arginfo_openssl_pkey_get_private)
     403             :         PHP_FE(openssl_pkey_get_public,         arginfo_openssl_pkey_get_public)
     404             :         PHP_FE(openssl_pkey_get_details,        arginfo_openssl_pkey_get_details)
     405             : 
     406             :         PHP_FALIAS(openssl_free_key,            openssl_pkey_free,                      arginfo_openssl_pkey_free)
     407             :         PHP_FALIAS(openssl_get_privatekey,      openssl_pkey_get_private,       arginfo_openssl_pkey_get_private)
     408             :         PHP_FALIAS(openssl_get_publickey,       openssl_pkey_get_public,        arginfo_openssl_pkey_get_public)
     409             : 
     410             : /* x.509 cert funcs */
     411             :         PHP_FE(openssl_x509_read,                               arginfo_openssl_x509_read)
     412             :         PHP_FE(openssl_x509_free,                       arginfo_openssl_x509_free)
     413             :         PHP_FE(openssl_x509_parse,                              arginfo_openssl_x509_parse)
     414             :         PHP_FE(openssl_x509_checkpurpose,               arginfo_openssl_x509_checkpurpose)
     415             :         PHP_FE(openssl_x509_check_private_key,  arginfo_openssl_x509_check_private_key)
     416             :         PHP_FE(openssl_x509_export,                             arginfo_openssl_x509_export)
     417             :         PHP_FE(openssl_x509_export_to_file,             arginfo_openssl_x509_export_to_file)
     418             : 
     419             : /* PKCS12 funcs */
     420             :         PHP_FE(openssl_pkcs12_export,                   arginfo_openssl_pkcs12_export)
     421             :         PHP_FE(openssl_pkcs12_export_to_file,   arginfo_openssl_pkcs12_export_to_file)
     422             :         PHP_FE(openssl_pkcs12_read,                             arginfo_openssl_pkcs12_read)
     423             : 
     424             : /* CSR funcs */
     425             :         PHP_FE(openssl_csr_new,                         arginfo_openssl_csr_new)
     426             :         PHP_FE(openssl_csr_export,                      arginfo_openssl_csr_export)
     427             :         PHP_FE(openssl_csr_export_to_file,      arginfo_openssl_csr_export_to_file)
     428             :         PHP_FE(openssl_csr_sign,                        arginfo_openssl_csr_sign)
     429             :         PHP_FE(openssl_csr_get_subject,         arginfo_openssl_csr_get_subject)
     430             :         PHP_FE(openssl_csr_get_public_key,      arginfo_openssl_csr_get_public_key)
     431             : 
     432             :         PHP_FE(openssl_digest,                          arginfo_openssl_digest)
     433             :         PHP_FE(openssl_encrypt,                         arginfo_openssl_encrypt)
     434             :         PHP_FE(openssl_decrypt,                         arginfo_openssl_decrypt)
     435             :         PHP_FE(openssl_cipher_iv_length,        arginfo_openssl_cipher_iv_length)
     436             :         PHP_FE(openssl_sign,                            arginfo_openssl_sign)
     437             :         PHP_FE(openssl_verify,                          arginfo_openssl_verify)
     438             :         PHP_FE(openssl_seal,                            arginfo_openssl_seal)
     439             :         PHP_FE(openssl_open,                            arginfo_openssl_open)
     440             : 
     441             : /* for S/MIME handling */
     442             :         PHP_FE(openssl_pkcs7_verify,            arginfo_openssl_pkcs7_verify)
     443             :         PHP_FE(openssl_pkcs7_decrypt,           arginfo_openssl_pkcs7_decrypt)
     444             :         PHP_FE(openssl_pkcs7_sign,                      arginfo_openssl_pkcs7_sign)
     445             :         PHP_FE(openssl_pkcs7_encrypt,           arginfo_openssl_pkcs7_encrypt)
     446             : 
     447             :         PHP_FE(openssl_private_encrypt,         arginfo_openssl_private_encrypt)
     448             :         PHP_FE(openssl_private_decrypt,         arginfo_openssl_private_decrypt)
     449             :         PHP_FE(openssl_public_encrypt,          arginfo_openssl_public_encrypt)
     450             :         PHP_FE(openssl_public_decrypt,          arginfo_openssl_public_decrypt)
     451             : 
     452             :         PHP_FE(openssl_get_md_methods,          arginfo_openssl_get_md_methods)
     453             :         PHP_FE(openssl_get_cipher_methods,      arginfo_openssl_get_cipher_methods)
     454             : 
     455             :         PHP_FE(openssl_dh_compute_key,      arginfo_openssl_dh_compute_key)
     456             : 
     457             :         PHP_FE(openssl_random_pseudo_bytes,    arginfo_openssl_random_pseudo_bytes)
     458             :         PHP_FE(openssl_error_string, arginfo_openssl_error_string)
     459             :         PHP_FE_END
     460             : };
     461             : /* }}} */
     462             : 
     463             : /* {{{ openssl_module_entry
     464             :  */
     465             : zend_module_entry openssl_module_entry = {
     466             :         STANDARD_MODULE_HEADER,
     467             :         "openssl",
     468             :         openssl_functions,
     469             :         PHP_MINIT(openssl),
     470             :         PHP_MSHUTDOWN(openssl),
     471             :         NULL,
     472             :         NULL,
     473             :         PHP_MINFO(openssl),
     474             :         NO_VERSION_YET,
     475             :         STANDARD_MODULE_PROPERTIES
     476             : };
     477             : /* }}} */
     478             : 
     479             : #ifdef COMPILE_DL_OPENSSL
     480             : ZEND_GET_MODULE(openssl)
     481             : #endif
     482             : 
     483             : static int le_key;
     484             : static int le_x509;
     485             : static int le_csr;
     486             : static int ssl_stream_data_index;
     487             : 
     488           9 : int php_openssl_get_x509_list_id(void) /* {{{ */
     489             : {
     490           9 :         return le_x509;
     491             : }
     492             : /* }}} */
     493             : 
     494             : /* {{{ resource destructors */
     495          24 : static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     496             : {
     497          24 :         EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
     498             : 
     499             :         assert(pkey != NULL);
     500             : 
     501          24 :         EVP_PKEY_free(pkey);
     502          24 : }
     503             : 
     504          18 : static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     505             : {
     506          18 :         X509 *x509 = (X509 *)rsrc->ptr;
     507          18 :         X509_free(x509);
     508          18 : }
     509             : 
     510           5 : static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     511             : {
     512           5 :         X509_REQ * csr = (X509_REQ*)rsrc->ptr;
     513           5 :         X509_REQ_free(csr);
     514           5 : }
     515             : /* }}} */
     516             : 
     517             : /* {{{ openssl open_basedir check */
     518         126 : inline static int php_openssl_open_base_dir_chk(char *filename TSRMLS_DC)
     519             : {
     520         126 :         if (php_check_open_basedir(filename TSRMLS_CC)) {
     521           0 :                 return -1;
     522             :         }
     523             : 
     524         126 :         return 0;
     525             : }
     526             : /* }}} */
     527             : 
     528             : /* openssl -> PHP "bridging" */
     529             : /* true global; readonly after module startup */
     530             : static char default_ssl_conf_filename[MAXPATHLEN];
     531             : 
     532             : struct php_x509_request { /* {{{ */
     533             : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
     534             :         LHASH_OF(CONF_VALUE) * global_config;   /* Global SSL config */
     535             :         LHASH_OF(CONF_VALUE) * req_config;              /* SSL config for this request */
     536             : #else
     537             :         LHASH * global_config;  /* Global SSL config */
     538             :         LHASH * req_config;             /* SSL config for this request */
     539             : #endif
     540             :         const EVP_MD * md_alg;
     541             :         const EVP_MD * digest;
     542             :         char    * section_name,
     543             :                         * config_filename,
     544             :                         * digest_name,
     545             :                         * extensions_section,
     546             :                         * request_extensions_section;
     547             :         int priv_key_bits;
     548             :         int priv_key_type;
     549             : 
     550             :         int priv_key_encrypt;
     551             : 
     552             :         EVP_PKEY * priv_key;
     553             : 
     554             :     const EVP_CIPHER * priv_key_encrypt_cipher;
     555             : };
     556             : /* }}} */
     557             : 
     558             : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
     559             : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC);
     560             : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);
     561             : static X509_STORE     * setup_verify(zval * calist TSRMLS_DC);
     562             : static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
     563             : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
     564             : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC);
     565             : 
     566          40 : static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */
     567             : {
     568             :         zval **data;
     569             :         zval *subitem, *subentries;
     570          40 :         int i, j = -1, last = -1, obj_cnt = 0;
     571             :         char *sname;
     572             :         int nid;
     573             :         X509_NAME_ENTRY * ne;
     574          40 :         ASN1_STRING * str = NULL;
     575             :         ASN1_OBJECT * obj;
     576             : 
     577          40 :         if (key != NULL) {
     578          38 :                 MAKE_STD_ZVAL(subitem);
     579          38 :                 array_init(subitem);
     580             :         } else {
     581           2 :                 subitem = val;
     582             :         }
     583             : 
     584         251 :         for (i = 0; i < X509_NAME_entry_count(name); i++) {
     585             :                 unsigned char *to_add;
     586         211 :                 int to_add_len = 0;
     587             : 
     588             : 
     589         211 :                 ne  = X509_NAME_get_entry(name, i);
     590         211 :                 obj = X509_NAME_ENTRY_get_object(ne);
     591         211 :                 nid = OBJ_obj2nid(obj);
     592         211 :                 obj_cnt = 0;
     593             : 
     594         211 :                 if (shortname) {
     595         201 :                         sname = (char *) OBJ_nid2sn(nid);
     596             :                 } else {
     597          10 :                         sname = (char *) OBJ_nid2ln(nid);
     598             :                 }
     599             : 
     600         211 :                 str = X509_NAME_ENTRY_get_data(ne);
     601         211 :                 if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
     602         191 :                         to_add_len = ASN1_STRING_to_UTF8(&to_add, str);
     603             :                 } else {
     604          20 :                         to_add = ASN1_STRING_data(str);
     605          20 :                         to_add_len = ASN1_STRING_length(str);
     606             :                 }
     607             : 
     608         211 :                 if (to_add_len != -1) {
     609         209 :                         if (zend_hash_find(Z_ARRVAL_P(subitem), sname, strlen(sname)+1, (void**)&data) == SUCCESS) {
     610           8 :                                 if (Z_TYPE_PP(data) == IS_ARRAY) {
     611           4 :                                         subentries = *data;
     612           4 :                                         add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
     613           4 :                                 } else if (Z_TYPE_PP(data) == IS_STRING) {
     614           4 :                                         MAKE_STD_ZVAL(subentries);
     615           4 :                                         array_init(subentries);
     616           4 :                                         add_next_index_stringl(subentries, Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
     617           4 :                                         add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
     618           4 :                                         zend_hash_update(Z_ARRVAL_P(subitem), sname, strlen(sname)+1, &subentries, sizeof(zval*), NULL);
     619             :                                 }
     620             :                         } else {
     621         201 :                                 add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1);
     622             :                         }
     623             :                 }
     624             :         }
     625          40 :         if (key != NULL) {
     626          38 :                 zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL);
     627             :         }
     628          40 : }
     629             : /* }}} */
     630             : 
     631          40 : static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
     632             : {
     633          40 :         add_assoc_stringl(val, key, (char *)str->data, str->length, 1);
     634          40 : }
     635             : /* }}} */
     636             : 
     637          38 : static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
     638             : {
     639             : /*
     640             :         This is how the time string is formatted:
     641             : 
     642             :    snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
     643             :       ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
     644             : */
     645             : 
     646             :         time_t ret;
     647             :         struct tm thetime;
     648             :         char * strbuf;
     649             :         char * thestr;
     650          38 :         long gmadjust = 0;
     651             : 
     652          38 :         if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
     653           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal ASN1 data type for timestamp");
     654           0 :                 return (time_t)-1;
     655             :         }
     656             : 
     657          38 :         if (ASN1_STRING_length(timestr) != strlen(ASN1_STRING_data(timestr))) {
     658           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal length in timestamp");
     659           1 :                 return (time_t)-1;
     660             :         }
     661             : 
     662          37 :         if (ASN1_STRING_length(timestr) < 13) {
     663           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data);
     664           0 :                 return (time_t)-1;
     665             :         }
     666             : 
     667          37 :         if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && ASN1_STRING_length(timestr) < 15) {
     668           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data);
     669           0 :                 return (time_t)-1;
     670             :         }
     671             : 
     672          37 :         strbuf = estrdup((char *)ASN1_STRING_data(timestr));
     673             : 
     674          37 :         memset(&thetime, 0, sizeof(thetime));
     675             : 
     676             :         /* we work backwards so that we can use atoi more easily */
     677             : 
     678          37 :         thestr = strbuf + ASN1_STRING_length(timestr) - 3;
     679             : 
     680          37 :         thetime.tm_sec = atoi(thestr);
     681          37 :         *thestr = '\0';
     682          37 :         thestr -= 2;
     683          37 :         thetime.tm_min = atoi(thestr);
     684          37 :         *thestr = '\0';
     685          37 :         thestr -= 2;
     686          37 :         thetime.tm_hour = atoi(thestr);
     687          37 :         *thestr = '\0';
     688          37 :         thestr -= 2;
     689          37 :         thetime.tm_mday = atoi(thestr);
     690          37 :         *thestr = '\0';
     691          37 :         thestr -= 2;
     692          37 :         thetime.tm_mon = atoi(thestr)-1;
     693             : 
     694          37 :         *thestr = '\0';
     695          37 :         if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
     696          35 :                 thestr -= 2;
     697          35 :                 thetime.tm_year = atoi(thestr);
     698             : 
     699          35 :                 if (thetime.tm_year < 68) {
     700          35 :                         thetime.tm_year += 100;
     701             :                 }
     702           2 :         } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
     703           2 :                 thestr -= 4;
     704           2 :                 thetime.tm_year = atoi(thestr) - 1900;
     705             :         }
     706             : 
     707             : 
     708          37 :         thetime.tm_isdst = -1;
     709          37 :         ret = mktime(&thetime);
     710             : 
     711             : #if HAVE_TM_GMTOFF
     712          37 :         gmadjust = thetime.tm_gmtoff;
     713             : #else
     714             :         /*
     715             :         ** If correcting for daylight savings time, we set the adjustment to
     716             :         ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
     717             :         ** set the adjustment to the main timezone + 3600 seconds.
     718             :         */
     719             :         gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
     720             : #endif
     721          37 :         ret += gmadjust;
     722             : 
     723          37 :         efree(strbuf);
     724             : 
     725          37 :         return ret;
     726             : }
     727             : /* }}} */
     728             : 
     729             : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
     730          27 : 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) /* {{{ */
     731             : #else
     732             : static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config TSRMLS_DC)
     733             : #endif
     734             : {
     735             :         X509V3_CTX ctx;
     736             : 
     737          27 :         X509V3_set_ctx_test(&ctx);
     738          27 :         X509V3_set_conf_lhash(&ctx, config);
     739          27 :         if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
     740           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s",
     741             :                                 section_label,
     742             :                                 section,
     743             :                                 config_filename);
     744           0 :                 return FAILURE;
     745             :         }
     746          27 :         return SUCCESS;
     747             : }
     748             : /* }}} */
     749             : 
     750          24 : static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
     751             : {
     752             :         char * str;
     753             :         STACK_OF(CONF_VALUE) * sktmp;
     754             :         CONF_VALUE * cnf;
     755             :         int i;
     756             : 
     757          24 :         str = CONF_get_string(req->req_config, NULL, "oid_section");
     758          24 :         if (str == NULL) {
     759          17 :                 return SUCCESS;
     760             :         }
     761           7 :         sktmp = CONF_get_section(req->req_config, str);
     762           7 :         if (sktmp == NULL) {
     763           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str);
     764           0 :                 return FAILURE;
     765             :         }
     766          28 :         for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
     767          21 :                 cnf = sk_CONF_VALUE_value(sktmp, i);
     768          21 :                 if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
     769           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
     770           0 :                         return FAILURE;
     771             :                 }
     772             :         }
     773           7 :         return SUCCESS;
     774             : }
     775             : /* }}} */
     776             : 
     777             : #define PHP_SSL_REQ_INIT(req)           memset(req, 0, sizeof(*req))
     778             : #define PHP_SSL_REQ_DISPOSE(req)        php_openssl_dispose_config(req TSRMLS_CC)
     779             : #define PHP_SSL_REQ_PARSE(req, zval)    php_openssl_parse_config(req, zval TSRMLS_CC)
     780             : 
     781             : #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
     782             :                         req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE
     783             : 
     784             : #define SET_OPTIONAL_STRING_ARG(key, varname, defval)   \
     785             :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
     786             :                 varname = Z_STRVAL_PP(item); \
     787             :         else \
     788             :                 varname = defval
     789             : 
     790             : #define SET_OPTIONAL_LONG_ARG(key, varname, defval)     \
     791             :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
     792             :                 varname = Z_LVAL_PP(item); \
     793             :         else \
     794             :                 varname = defval
     795             : 
     796             : static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo);
     797             : 
     798             : 
     799          24 : static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */
     800             : {
     801             :         char * str;
     802             :         zval ** item;
     803             : 
     804          24 :         SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
     805          24 :         SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
     806          24 :         req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
     807          24 :         req->req_config = CONF_load(NULL, req->config_filename, NULL);
     808             : 
     809          24 :         if (req->req_config == NULL) {
     810           0 :                 return FAILURE;
     811             :         }
     812             : 
     813             :         /* read in the oids */
     814          24 :         str = CONF_get_string(req->req_config, NULL, "oid_file");
     815          24 :         if (str && !php_openssl_open_base_dir_chk(str TSRMLS_CC)) {
     816           0 :                 BIO *oid_bio = BIO_new_file(str, "r");
     817           0 :                 if (oid_bio) {
     818           0 :                         OBJ_create_objects(oid_bio);
     819           0 :                         BIO_free(oid_bio);
     820             :                 }
     821             :         }
     822          24 :         if (add_oid_section(req TSRMLS_CC) == FAILURE) {
     823           0 :                 return FAILURE;
     824             :         }
     825          24 :         SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
     826             :                 CONF_get_string(req->req_config, req->section_name, "default_md"));
     827          24 :         SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
     828             :                 CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
     829          24 :         SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
     830             :                 CONF_get_string(req->req_config, req->section_name, "req_extensions"));
     831          24 :         SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
     832             :                 CONF_get_number(req->req_config, req->section_name, "default_bits"));
     833             : 
     834          24 :         SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
     835             : 
     836          28 :         if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) {
     837           4 :                 req->priv_key_encrypt = Z_BVAL_PP(item);
     838             :         } else {
     839          20 :                 str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
     840          20 :                 if (str == NULL) {
     841          20 :                         str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
     842             :                 }
     843          20 :                 if (str && strcmp(str, "no") == 0) {
     844           0 :                         req->priv_key_encrypt = 0;
     845             :                 } else {
     846          20 :                         req->priv_key_encrypt = 1;
     847             :                 }
     848             :         }
     849             : 
     850          24 :         if (req->priv_key_encrypt && optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher"), (void**)&item) == SUCCESS) {
     851           0 :                 long cipher_algo = Z_LVAL_PP(item);
     852           0 :                 const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo);
     853           0 :                 if (cipher == NULL) {
     854           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm for private key.");
     855           0 :                         return FAILURE;
     856             :                 } else  {
     857           0 :                         req->priv_key_encrypt_cipher = cipher;
     858             :                 }
     859             :         } else {
     860          24 :                 req->priv_key_encrypt_cipher = NULL;
     861             :         }
     862             : 
     863             : 
     864             : 
     865             :         /* digest alg */
     866          24 :         if (req->digest_name == NULL) {
     867          14 :                 req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
     868             :         }
     869          24 :         if (req->digest_name) {
     870          10 :                 req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
     871             :         }
     872          24 :         if (req->md_alg == NULL) {
     873          14 :                 req->md_alg = req->digest = EVP_sha1();
     874             :         }
     875             : 
     876          24 :         PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
     877             : 
     878             :         /* set the string mask */
     879          24 :         str = CONF_get_string(req->req_config, req->section_name, "string_mask");
     880          24 :         if (str && !ASN1_STRING_set_default_mask_asc(str)) {
     881           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid global string mask setting %s", str);
     882           0 :                 return FAILURE;
     883             :         }
     884             : 
     885          24 :         PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
     886             : 
     887          24 :         return SUCCESS;
     888             : }
     889             : /* }}} */
     890             : 
     891          28 : static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */
     892             : {
     893          28 :         if (req->priv_key) {
     894           1 :                 EVP_PKEY_free(req->priv_key);
     895           1 :                 req->priv_key = NULL;
     896             :         }
     897          28 :         if (req->global_config) {
     898          24 :                 CONF_free(req->global_config);
     899          24 :                 req->global_config = NULL;
     900             :         }
     901          28 :         if (req->req_config) {
     902          24 :                 CONF_free(req->req_config);
     903          24 :                 req->req_config = NULL;
     904             :         }
     905          28 : }
     906             : /* }}} */
     907             : 
     908          11 : static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded TSRMLS_DC) /* {{{ */
     909             : {
     910             :         char buffer[MAXPATHLEN];
     911             : 
     912          11 :         *egdsocket = 0;
     913          11 :         *seeded = 0;
     914             : 
     915          11 :         if (file == NULL) {
     916           5 :                 file = RAND_file_name(buffer, sizeof(buffer));
     917           6 :         } else if (RAND_egd(file) > 0) {
     918             :                 /* if the given filename is an EGD socket, don't
     919             :                  * write anything back to it */
     920           0 :                 *egdsocket = 1;
     921           0 :                 return SUCCESS;
     922             :         }
     923          11 :         if (file == NULL || !RAND_load_file(file, -1)) {
     924          11 :                 if (RAND_status() == 0) {
     925           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to load random state; not enough random data!");
     926           0 :                         return FAILURE;
     927             :                 }
     928          11 :                 return FAILURE;
     929             :         }
     930           0 :         *seeded = 1;
     931           0 :         return SUCCESS;
     932             : }
     933             : /* }}} */
     934             : 
     935          11 : static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
     936             : {
     937             :         char buffer[MAXPATHLEN];
     938             : 
     939             :         TSRMLS_FETCH();
     940             : 
     941          11 :         if (egdsocket || !seeded) {
     942             :                 /* if we did not manage to read the seed file, we should not write
     943             :                  * a low-entropy seed file back */
     944          11 :                 return FAILURE;
     945             :         }
     946           0 :         if (file == NULL) {
     947           0 :                 file = RAND_file_name(buffer, sizeof(buffer));
     948             :         }
     949           0 :         if (file == NULL || !RAND_write_file(file)) {
     950           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to write random state");
     951           0 :                 return FAILURE;
     952             :         }
     953           0 :         return SUCCESS;
     954             : }
     955             : /* }}} */
     956             : 
     957          15 : static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
     958             :         EVP_MD *mdtype;
     959             : 
     960          15 :         switch (algo) {
     961             :                 case OPENSSL_ALGO_SHA1:
     962           8 :                         mdtype = (EVP_MD *) EVP_sha1();
     963           8 :                         break;
     964             :                 case OPENSSL_ALGO_MD5:
     965           5 :                         mdtype = (EVP_MD *) EVP_md5();
     966           5 :                         break;
     967             :                 case OPENSSL_ALGO_MD4:
     968           0 :                         mdtype = (EVP_MD *) EVP_md4();
     969           0 :                         break;
     970             : #ifdef HAVE_OPENSSL_MD2_H
     971             :                 case OPENSSL_ALGO_MD2:
     972             :                         mdtype = (EVP_MD *) EVP_md2();
     973             :                         break;
     974             : #endif
     975             :                 case OPENSSL_ALGO_DSS1:
     976           2 :                         mdtype = (EVP_MD *) EVP_dss1();
     977           2 :                         break;
     978             : #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
     979             :                 case OPENSSL_ALGO_SHA224:
     980           0 :                         mdtype = (EVP_MD *) EVP_sha224();
     981           0 :                         break;
     982             :                 case OPENSSL_ALGO_SHA256:
     983           0 :                         mdtype = (EVP_MD *) EVP_sha256();
     984           0 :                         break;
     985             :                 case OPENSSL_ALGO_SHA384:
     986           0 :                         mdtype = (EVP_MD *) EVP_sha384();
     987           0 :                         break;
     988             :                 case OPENSSL_ALGO_SHA512:
     989           0 :                         mdtype = (EVP_MD *) EVP_sha512();
     990           0 :                         break;
     991             :                 case OPENSSL_ALGO_RMD160:
     992           0 :                         mdtype = (EVP_MD *) EVP_ripemd160();
     993           0 :                         break;
     994             : #endif
     995             :                 default:
     996           0 :                         return NULL;
     997             :                         break;
     998             :         }
     999          15 :         return mdtype;
    1000             : }
    1001             : /* }}} */
    1002             : 
    1003           5 : static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* {{{ */
    1004           5 :         switch (algo) {
    1005             : #ifndef OPENSSL_NO_RC2
    1006             :                 case PHP_OPENSSL_CIPHER_RC2_40:
    1007           5 :                         return EVP_rc2_40_cbc();
    1008             :                         break;
    1009             :                 case PHP_OPENSSL_CIPHER_RC2_64:
    1010           0 :                         return EVP_rc2_64_cbc();
    1011             :                         break;
    1012             :                 case PHP_OPENSSL_CIPHER_RC2_128:
    1013           0 :                         return EVP_rc2_cbc();
    1014             :                         break;
    1015             : #endif
    1016             : 
    1017             : #ifndef OPENSSL_NO_DES
    1018             :                 case PHP_OPENSSL_CIPHER_DES:
    1019           0 :                         return EVP_des_cbc();
    1020             :                         break;
    1021             :                 case PHP_OPENSSL_CIPHER_3DES:
    1022           0 :                         return EVP_des_ede3_cbc();
    1023             :                         break;
    1024             : #endif
    1025             : 
    1026             : #ifndef OPENSSL_NO_AES
    1027             :                 case PHP_OPENSSL_CIPHER_AES_128_CBC:
    1028           0 :                         return EVP_aes_128_cbc();
    1029             :                         break;
    1030             :                 case PHP_OPENSSL_CIPHER_AES_192_CBC:
    1031           0 :                         return EVP_aes_192_cbc();
    1032             :                         break;
    1033             :                 case PHP_OPENSSL_CIPHER_AES_256_CBC:
    1034           0 :                         return EVP_aes_256_cbc();
    1035             :                         break;
    1036             : #endif
    1037             : 
    1038             : 
    1039             :                 default:
    1040           0 :                         return NULL;
    1041             :                         break;
    1042             :         }
    1043             : }
    1044             : /* }}} */
    1045             : 
    1046             : /* {{{ PHP_MINIT_FUNCTION
    1047             :  */
    1048       20151 : PHP_MINIT_FUNCTION(openssl)
    1049             : {
    1050             :         char * config_filename;
    1051             : 
    1052       20151 :         le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
    1053       20151 :         le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
    1054       20151 :         le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
    1055             : 
    1056       20151 :         SSL_library_init();
    1057       20151 :         OpenSSL_add_all_ciphers();
    1058       20151 :         OpenSSL_add_all_digests();
    1059       20151 :         OpenSSL_add_all_algorithms();
    1060             : 
    1061       20151 :         SSL_load_error_strings();
    1062             : 
    1063             :         /* register a resource id number with OpenSSL so that we can map SSL -> stream structures in
    1064             :          * OpenSSL callbacks */
    1065       20151 :         ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
    1066             : 
    1067       20151 :         REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
    1068       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
    1069             : 
    1070             :         /* purposes for cert purpose checking */
    1071       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
    1072       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1073       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1074       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
    1075       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
    1076       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
    1077             : #ifdef X509_PURPOSE_ANY
    1078       20151 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
    1079             : #endif
    1080             : 
    1081             :         /* signature algorithm constants */
    1082       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
    1083       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
    1084       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
    1085             : #ifdef HAVE_OPENSSL_MD2_H
    1086             :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
    1087             : #endif
    1088       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
    1089             : #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
    1090       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
    1091       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
    1092       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
    1093       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
    1094       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
    1095             : #endif
    1096             : 
    1097             :         /* flags for S/MIME */
    1098       20151 :         REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
    1099       20151 :         REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
    1100       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
    1101       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
    1102       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
    1103       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
    1104       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
    1105       20151 :         REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
    1106       20151 :         REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
    1107             : 
    1108       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
    1109       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
    1110       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
    1111       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
    1112             : 
    1113             :         /* Ciphers */
    1114             : #ifndef OPENSSL_NO_RC2
    1115       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
    1116       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
    1117       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
    1118             : #endif
    1119             : #ifndef OPENSSL_NO_DES
    1120       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
    1121       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
    1122             : #endif
    1123             : #ifndef OPENSSL_NO_AES
    1124       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
    1125       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
    1126       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT);
    1127             : #endif
    1128             : 
    1129             :         /* Values for key types */
    1130       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
    1131             : #ifndef NO_DSA
    1132       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
    1133             : #endif
    1134       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
    1135             : #ifdef HAVE_EVP_PKEY_EC
    1136       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
    1137             : #endif
    1138             : 
    1139       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
    1140       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
    1141             : 
    1142             : #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
    1143             :         /* SNI support included in OpenSSL >= 0.9.8j */
    1144       20151 :         REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
    1145             : #endif
    1146             : 
    1147             :         /* Determine default SSL configuration file */
    1148       20151 :         config_filename = getenv("OPENSSL_CONF");
    1149       20151 :         if (config_filename == NULL) {
    1150       20151 :                 config_filename = getenv("SSLEAY_CONF");
    1151             :         }
    1152             : 
    1153             :         /* default to 'openssl.cnf' if no environment variable is set */
    1154       20151 :         if (config_filename == NULL) {
    1155       20151 :                 snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
    1156             :                                 X509_get_default_cert_area(),
    1157             :                                 "openssl.cnf");
    1158             :         } else {
    1159           0 :                 strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
    1160             :         }
    1161             : 
    1162       20151 :         php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC);
    1163       20151 :         php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC);
    1164             : #ifndef OPENSSL_NO_SSL2
    1165       20151 :         php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
    1166             : #endif
    1167       20151 :         php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC);
    1168             : 
    1169             :         /* override the default tcp socket provider */
    1170       20151 :         php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
    1171             : 
    1172       20151 :         php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC);
    1173       20151 :         php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC);
    1174             : 
    1175       20151 :         return SUCCESS;
    1176             : }
    1177             : /* }}} */
    1178             : 
    1179             : /* {{{ PHP_MINFO_FUNCTION
    1180             :  */
    1181         148 : PHP_MINFO_FUNCTION(openssl)
    1182             : {
    1183         148 :         php_info_print_table_start();
    1184         148 :         php_info_print_table_row(2, "OpenSSL support", "enabled");
    1185         148 :         php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
    1186         148 :         php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
    1187         148 :         php_info_print_table_end();
    1188         148 : }
    1189             : /* }}} */
    1190             : 
    1191             : /* {{{ PHP_MSHUTDOWN_FUNCTION
    1192             :  */
    1193       20187 : PHP_MSHUTDOWN_FUNCTION(openssl)
    1194             : {
    1195       20187 :         EVP_cleanup();
    1196             : 
    1197       20187 :         php_unregister_url_stream_wrapper("https" TSRMLS_CC);
    1198       20187 :         php_unregister_url_stream_wrapper("ftps" TSRMLS_CC);
    1199             : 
    1200       20187 :         php_stream_xport_unregister("ssl" TSRMLS_CC);
    1201             : #ifndef OPENSSL_NO_SSL2
    1202       20187 :         php_stream_xport_unregister("sslv2" TSRMLS_CC);
    1203             : #endif
    1204       20187 :         php_stream_xport_unregister("sslv3" TSRMLS_CC);
    1205       20187 :         php_stream_xport_unregister("tls" TSRMLS_CC);
    1206             : 
    1207             :         /* reinstate the default tcp handler */
    1208       20187 :         php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
    1209             : 
    1210       20187 :         return SUCCESS;
    1211             : }
    1212             : /* }}} */
    1213             : 
    1214             : /* {{{ x509 cert functions */
    1215             : 
    1216             : /* {{{ php_openssl_x509_from_zval
    1217             :         Given a zval, coerce it into an X509 object.
    1218             :         The zval can be:
    1219             :                 . X509 resource created using openssl_read_x509()
    1220             :                 . if it starts with file:// then it will be interpreted as the path to that cert
    1221             :                 . it will be interpreted as the cert data
    1222             :         If you supply makeresource, the result will be registered as an x509 resource and
    1223             :         it's value returned in makeresource.
    1224             : */
    1225         115 : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
    1226             : {
    1227         115 :         X509 *cert = NULL;
    1228             : 
    1229         115 :         if (resourceval) {
    1230         115 :                 *resourceval = -1;
    1231             :         }
    1232         115 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
    1233             :                 /* is it an x509 resource ? */
    1234             :                 void * what;
    1235             :                 int type;
    1236             : 
    1237          13 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509", &type, 1, le_x509);
    1238          13 :                 if (!what) {
    1239           0 :                         return NULL;
    1240             :                 }
    1241             :                 /* this is so callers can decide if they should free the X509 */
    1242          13 :                 if (resourceval) {
    1243          13 :                         *resourceval = Z_LVAL_PP(val);
    1244             :                 }
    1245          13 :                 if (type == le_x509) {
    1246          13 :                         return (X509*)what;
    1247             :                 }
    1248             :                 /* other types could be used here - eg: file pointers and read in the data from them */
    1249             : 
    1250           0 :                 return NULL;
    1251             :         }
    1252             : 
    1253         102 :         if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
    1254          16 :                 return NULL;
    1255             :         }
    1256             : 
    1257             :         /* force it to be a string and check if it refers to a file */
    1258          99 :         convert_to_string_ex(val);
    1259             : 
    1260         134 :         if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
    1261             :                 /* read cert from the named file */
    1262             :                 BIO *in;
    1263             : 
    1264          49 :                 if (php_openssl_open_base_dir_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) {
    1265           0 :                         return NULL;
    1266             :                 }
    1267             : 
    1268          49 :                 in = BIO_new_file(Z_STRVAL_PP(val) + (sizeof("file://") - 1), "r");
    1269          49 :                 if (in == NULL) {
    1270           0 :                         return NULL;
    1271             :                 }
    1272          49 :                 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
    1273          49 :                 BIO_free(in);
    1274             :         } else {
    1275             :                 BIO *in;
    1276             : 
    1277          36 :                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    1278          36 :                 if (in == NULL) {
    1279           0 :                         return NULL;
    1280             :                 }
    1281             : #ifdef TYPEDEF_D2I_OF
    1282          36 :                 cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
    1283             : #else
    1284             :                 cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
    1285             : #endif
    1286          36 :                 BIO_free(in);
    1287             :         }
    1288             : 
    1289          85 :         if (cert && makeresource && resourceval) {
    1290           4 :                 *resourceval = zend_list_insert(cert, le_x509 TSRMLS_CC);
    1291             :         }
    1292          85 :         return cert;
    1293             : }
    1294             : 
    1295             : /* }}} */
    1296             : 
    1297             : /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
    1298             :    Exports a CERT to file or a var */
    1299           5 : PHP_FUNCTION(openssl_x509_export_to_file)
    1300             : {
    1301             :         X509 * cert;
    1302             :         zval ** zcert;
    1303           5 :         zend_bool notext = 1;
    1304             :         BIO * bio_out;
    1305             :         long certresource;
    1306             :         char * filename;
    1307             :         int filename_len;
    1308             : 
    1309           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|b", &zcert, &filename, &filename_len, &notext) == FAILURE) {
    1310           0 :                 return;
    1311             :         }
    1312           5 :         RETVAL_FALSE;
    1313             : 
    1314           5 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1315           5 :         if (cert == NULL) {
    1316           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    1317           2 :                 return;
    1318             :         }
    1319             : 
    1320           3 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    1321           0 :                 return;
    1322             :         }
    1323             : 
    1324           3 :         bio_out = BIO_new_file(filename, "w");
    1325           3 :         if (bio_out) {
    1326           3 :                 if (!notext) {
    1327           0 :                         X509_print(bio_out, cert);
    1328             :                 }
    1329           3 :                 PEM_write_bio_X509(bio_out, cert);
    1330             : 
    1331           3 :                 RETVAL_TRUE;
    1332             :         } else {
    1333           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
    1334             :         }
    1335           3 :         if (certresource == -1 && cert) {
    1336           2 :                 X509_free(cert);
    1337             :         }
    1338           3 :         BIO_free(bio_out);
    1339             : }
    1340             : /* }}} */
    1341             : 
    1342             : /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
    1343             :    Exports a CERT to file or a var */
    1344           6 : PHP_FUNCTION(openssl_x509_export)
    1345             : {
    1346             :         X509 * cert;
    1347             :         zval ** zcert, *zout;
    1348           6 :         zend_bool notext = 1;
    1349             :         BIO * bio_out;
    1350             :         long certresource;
    1351             : 
    1352           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|b", &zcert, &zout, &notext) == FAILURE) {
    1353           0 :                 return;
    1354             :         }
    1355           6 :         RETVAL_FALSE;
    1356             : 
    1357           6 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1358           6 :         if (cert == NULL) {
    1359           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    1360           2 :                 return;
    1361             :         }
    1362             : 
    1363           4 :         bio_out = BIO_new(BIO_s_mem());
    1364           4 :         if (!notext) {
    1365           1 :                 X509_print(bio_out, cert);
    1366             :         }
    1367           4 :         if (PEM_write_bio_X509(bio_out, cert))  {
    1368             :                 BUF_MEM *bio_buf;
    1369             : 
    1370           4 :                 zval_dtor(zout);
    1371           4 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1372           4 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
    1373             : 
    1374           4 :                 RETVAL_TRUE;
    1375             :         }
    1376             : 
    1377           4 :         if (certresource == -1 && cert) {
    1378           2 :                 X509_free(cert);
    1379             :         }
    1380           4 :         BIO_free(bio_out);
    1381             : }
    1382             : /* }}} */
    1383             : 
    1384             : /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
    1385             :    Checks if a private key corresponds to a CERT */
    1386           5 : PHP_FUNCTION(openssl_x509_check_private_key)
    1387             : {
    1388             :         zval ** zcert, **zkey;
    1389           5 :         X509 * cert = NULL;
    1390           5 :         EVP_PKEY * key = NULL;
    1391           5 :         long certresource = -1, keyresource = -1;
    1392             : 
    1393           5 :         RETVAL_FALSE;
    1394             : 
    1395           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) {
    1396           0 :                 return;
    1397             :         }
    1398           5 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1399           5 :         if (cert == NULL) {
    1400           2 :                 RETURN_FALSE;
    1401             :         }
    1402           3 :         key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC);
    1403           3 :         if (key) {
    1404           2 :                 RETVAL_BOOL(X509_check_private_key(cert, key));
    1405             :         }
    1406             : 
    1407           3 :         if (keyresource == -1 && key) {
    1408           0 :                 EVP_PKEY_free(key);
    1409             :         }
    1410           3 :         if (certresource == -1 && cert) {
    1411           3 :                 X509_free(cert);
    1412             :         }
    1413             : }
    1414             : /* }}} */
    1415             : 
    1416             : /* Special handling of subjectAltName, see CVE-2013-4073
    1417             :  * Christian Heimes
    1418             :  */
    1419             : 
    1420          12 : static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
    1421             : {
    1422             :         GENERAL_NAMES *names;
    1423          12 :         const X509V3_EXT_METHOD *method = NULL;
    1424             :         long i, length, num;
    1425             :         const unsigned char *p;
    1426             : 
    1427          12 :         method = X509V3_EXT_get(extension);
    1428          12 :         if (method == NULL) {
    1429           0 :                 return -1;
    1430             :         }
    1431             : 
    1432          12 :         p = extension->value->data;
    1433          12 :         length = extension->value->length;
    1434          12 :         if (method->it) {
    1435          12 :                 names = (GENERAL_NAMES*)(ASN1_item_d2i(NULL, &p, length,
    1436          12 :                                                        ASN1_ITEM_ptr(method->it)));
    1437             :         } else {
    1438           0 :                 names = (GENERAL_NAMES*)(method->d2i(NULL, &p, length));
    1439             :         }
    1440          12 :         if (names == NULL) {
    1441           0 :                 return -1;
    1442             :         }
    1443             : 
    1444          12 :         num = sk_GENERAL_NAME_num(names);
    1445          42 :         for (i = 0; i < num; i++) {
    1446             :                         GENERAL_NAME *name;
    1447             :                         ASN1_STRING *as;
    1448          30 :                         name = sk_GENERAL_NAME_value(names, i);
    1449          30 :                         switch (name->type) {
    1450             :                                 case GEN_EMAIL:
    1451           2 :                                         BIO_puts(bio, "email:");
    1452           2 :                                         as = name->d.rfc822Name;
    1453           2 :                                         BIO_write(bio, ASN1_STRING_data(as),
    1454             :                                                   ASN1_STRING_length(as));
    1455           2 :                                         break;
    1456             :                                 case GEN_DNS:
    1457          25 :                                         BIO_puts(bio, "DNS:");
    1458          25 :                                         as = name->d.dNSName;
    1459          25 :                                         BIO_write(bio, ASN1_STRING_data(as),
    1460             :                                                   ASN1_STRING_length(as));
    1461          25 :                                         break;
    1462             :                                 case GEN_URI:
    1463           1 :                                         BIO_puts(bio, "URI:");
    1464           1 :                                         as = name->d.uniformResourceIdentifier;
    1465           1 :                                         BIO_write(bio, ASN1_STRING_data(as),
    1466             :                                                   ASN1_STRING_length(as));
    1467           1 :                                         break;
    1468             :                                 default:
    1469             :                                         /* use builtin print for GEN_OTHERNAME, GEN_X400,
    1470             :                                          * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID
    1471             :                                          */
    1472           2 :                                         GENERAL_NAME_print(bio, name);
    1473             :                         }
    1474             :                         /* trailing ', ' except for last element */
    1475          30 :                         if (i < (num - 1)) {
    1476          18 :                                 BIO_puts(bio, ", ");
    1477             :                         }
    1478             :         }
    1479          12 :         sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
    1480             : 
    1481          12 :         return 0;
    1482             : }
    1483             : 
    1484             : /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
    1485             :    Returns an array of the fields/values of the CERT */
    1486          30 : PHP_FUNCTION(openssl_x509_parse)
    1487             : {
    1488             :         zval ** zcert;
    1489          30 :         X509 * cert = NULL;
    1490          30 :         long certresource = -1;
    1491             :         int i;
    1492          30 :         zend_bool useshortnames = 1;
    1493             :         char * tmpstr;
    1494             :         zval * subitem;
    1495             :         X509_EXTENSION *extension;
    1496             :         char *extname;
    1497             :         BIO  *bio_out;
    1498             :         BUF_MEM *bio_buf;
    1499             :         char buf[256];
    1500             : 
    1501          30 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) {
    1502           1 :                 return;
    1503             :         }
    1504          29 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1505          28 :         if (cert == NULL) {
    1506           9 :                 RETURN_FALSE;
    1507             :         }
    1508          19 :         array_init(return_value);
    1509             : 
    1510          19 :         if (cert->name) {
    1511          19 :                 add_assoc_string(return_value, "name", cert->name, 1);
    1512             :         }
    1513             : /*      add_assoc_bool(return_value, "valid", cert->valid); */
    1514             : 
    1515          19 :         add_assoc_name_entry(return_value, "subject",                 X509_get_subject_name(cert), useshortnames TSRMLS_CC);
    1516             :         /* hash as used in CA directories to lookup cert by subject name */
    1517             :         {
    1518             :                 char buf[32];
    1519          19 :                 snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
    1520          19 :                 add_assoc_string(return_value, "hash", buf, 1);
    1521             :         }
    1522             : 
    1523          19 :         add_assoc_name_entry(return_value, "issuer",          X509_get_issuer_name(cert), useshortnames TSRMLS_CC);
    1524          19 :         add_assoc_long(return_value, "version",                       X509_get_version(cert));
    1525             : 
    1526          19 :         add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1);
    1527             : 
    1528          19 :         add_assoc_asn1_string(return_value, "validFrom",      X509_get_notBefore(cert));
    1529          19 :         add_assoc_asn1_string(return_value, "validTo",                X509_get_notAfter(cert));
    1530             : 
    1531          19 :         add_assoc_long(return_value, "validFrom_time_t",      asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC));
    1532          19 :         add_assoc_long(return_value, "validTo_time_t",                asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC));
    1533             : 
    1534          19 :         tmpstr = (char *)X509_alias_get0(cert, NULL);
    1535          19 :         if (tmpstr) {
    1536           0 :                 add_assoc_string(return_value, "alias", tmpstr, 1);
    1537             :         }
    1538             : /*
    1539             :         add_assoc_long(return_value, "signaturetypeLONG", X509_get_signature_type(cert));
    1540             :         add_assoc_string(return_value, "signaturetype", OBJ_nid2sn(X509_get_signature_type(cert)), 1);
    1541             :         add_assoc_string(return_value, "signaturetypeLN", OBJ_nid2ln(X509_get_signature_type(cert)), 1);
    1542             : */
    1543          19 :         MAKE_STD_ZVAL(subitem);
    1544          19 :         array_init(subitem);
    1545             : 
    1546             :         /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
    1547             :            in x509v3.h */
    1548         190 :         for (i = 0; i < X509_PURPOSE_get_count(); i++) {
    1549             :                 int id, purpset;
    1550             :                 char * pname;
    1551             :                 X509_PURPOSE * purp;
    1552             :                 zval * subsub;
    1553             : 
    1554         171 :                 MAKE_STD_ZVAL(subsub);
    1555         171 :                 array_init(subsub);
    1556             : 
    1557         171 :                 purp = X509_PURPOSE_get0(i);
    1558         171 :                 id = X509_PURPOSE_get_id(purp);
    1559             : 
    1560         171 :                 purpset = X509_check_purpose(cert, id, 0);
    1561         171 :                 add_index_bool(subsub, 0, purpset);
    1562             : 
    1563         171 :                 purpset = X509_check_purpose(cert, id, 1);
    1564         171 :                 add_index_bool(subsub, 1, purpset);
    1565             : 
    1566         171 :                 pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
    1567         171 :                 add_index_string(subsub, 2, pname, 1);
    1568             : 
    1569             :                 /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
    1570             : 
    1571         171 :                 add_index_zval(subitem, id, subsub);
    1572             :         }
    1573          19 :         add_assoc_zval(return_value, "purposes", subitem);
    1574             : 
    1575          19 :         MAKE_STD_ZVAL(subitem);
    1576          19 :         array_init(subitem);
    1577             : 
    1578             : 
    1579         144 :         for (i = 0; i < X509_get_ext_count(cert); i++) {
    1580             :                 int nid;
    1581         125 :                 extension = X509_get_ext(cert, i);
    1582         125 :                 nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
    1583         125 :                 if (nid != NID_undef) {
    1584         123 :                         extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
    1585             :                 } else {
    1586           2 :                         OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
    1587           2 :                         extname = buf;
    1588             :                 }
    1589         125 :                 bio_out = BIO_new(BIO_s_mem());
    1590         125 :                 if (nid == NID_subject_alt_name) {
    1591          12 :                         if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) {
    1592          12 :                                 BIO_get_mem_ptr(bio_out, &bio_buf);
    1593          12 :                                 add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1);
    1594             :                         } else {
    1595             :                                 zval_dtor(return_value);
    1596           0 :                                 if (certresource == -1 && cert) {
    1597           0 :                                         X509_free(cert);
    1598             :                                 }
    1599           0 :                                 BIO_free(bio_out);
    1600           0 :                                 RETURN_FALSE;
    1601             :                         }
    1602             :                 }
    1603         113 :                 else if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
    1604         111 :                         BIO_get_mem_ptr(bio_out, &bio_buf);
    1605         111 :                         add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1);
    1606             :                 } else {
    1607           2 :                         add_assoc_asn1_string(subitem, extname, X509_EXTENSION_get_data(extension));
    1608             :                 }
    1609         125 :                 BIO_free(bio_out);
    1610             :         }
    1611          19 :         add_assoc_zval(return_value, "extensions", subitem);
    1612             : 
    1613          19 :         if (certresource == -1 && cert) {
    1614          10 :                 X509_free(cert);
    1615             :         }
    1616             : }
    1617             : /* }}} */
    1618             : 
    1619             : /* {{{ load_all_certs_from_file */
    1620           0 : static STACK_OF(X509) * load_all_certs_from_file(char *certfile)
    1621             : {
    1622           0 :         STACK_OF(X509_INFO) *sk=NULL;
    1623           0 :         STACK_OF(X509) *stack=NULL, *ret=NULL;
    1624           0 :         BIO *in=NULL;
    1625             :         X509_INFO *xi;
    1626             :         TSRMLS_FETCH();
    1627             : 
    1628           0 :         if(!(stack = sk_X509_new_null())) {
    1629           0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
    1630           0 :                 goto end;
    1631             :         }
    1632             : 
    1633           0 :         if (php_openssl_open_base_dir_chk(certfile TSRMLS_CC)) {
    1634           0 :                 sk_X509_free(stack);
    1635           0 :                 goto end;
    1636             :         }
    1637             : 
    1638           0 :         if(!(in=BIO_new_file(certfile, "r"))) {
    1639           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile);
    1640           0 :                 sk_X509_free(stack);
    1641           0 :                 goto end;
    1642             :         }
    1643             : 
    1644             :         /* This loads from a file, a stack of x509/crl/pkey sets */
    1645           0 :         if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
    1646           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile);
    1647           0 :                 sk_X509_free(stack);
    1648           0 :                 goto end;
    1649             :         }
    1650             : 
    1651             :         /* scan over it and pull out the certs */
    1652           0 :         while (sk_X509_INFO_num(sk)) {
    1653           0 :                 xi=sk_X509_INFO_shift(sk);
    1654           0 :                 if (xi->x509 != NULL) {
    1655           0 :                         sk_X509_push(stack,xi->x509);
    1656           0 :                         xi->x509=NULL;
    1657             :                 }
    1658           0 :                 X509_INFO_free(xi);
    1659             :         }
    1660           0 :         if(!sk_X509_num(stack)) {
    1661           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile);
    1662           0 :                 sk_X509_free(stack);
    1663           0 :                 goto end;
    1664             :         }
    1665           0 :         ret=stack;
    1666             : end:
    1667           0 :         BIO_free(in);
    1668           0 :         sk_X509_INFO_free(sk);
    1669             : 
    1670           0 :         return ret;
    1671             : }
    1672             : /* }}} */
    1673             : 
    1674             : /* {{{ check_cert */
    1675           0 : static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
    1676             : {
    1677           0 :         int ret=0;
    1678             :         X509_STORE_CTX *csc;
    1679             :         TSRMLS_FETCH();
    1680             : 
    1681           0 :         csc = X509_STORE_CTX_new();
    1682           0 :         if (csc == NULL) {
    1683           0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
    1684           0 :                 return 0;
    1685             :         }
    1686           0 :         X509_STORE_CTX_init(csc, ctx, x, untrustedchain);
    1687           0 :         if(purpose >= 0) {
    1688           0 :                 X509_STORE_CTX_set_purpose(csc, purpose);
    1689             :         }
    1690           0 :         ret = X509_verify_cert(csc);
    1691           0 :         X509_STORE_CTX_free(csc);
    1692             : 
    1693           0 :         return ret;
    1694             : }
    1695             : /* }}} */
    1696             : 
    1697             : /* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
    1698             :    Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */
    1699           0 : PHP_FUNCTION(openssl_x509_checkpurpose)
    1700             : {
    1701           0 :         zval ** zcert, * zcainfo = NULL;
    1702           0 :         X509_STORE * cainfo = NULL;
    1703           0 :         X509 * cert = NULL;
    1704           0 :         long certresource = -1;
    1705           0 :         STACK_OF(X509) * untrustedchain = NULL;
    1706             :         long purpose;
    1707           0 :         char * untrusted = NULL;
    1708           0 :         int untrusted_len = 0, ret;
    1709             : 
    1710           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) {
    1711           0 :                 return;
    1712             :         }
    1713             : 
    1714           0 :         RETVAL_LONG(-1);
    1715             : 
    1716           0 :         if (untrusted) {
    1717           0 :                 untrustedchain = load_all_certs_from_file(untrusted);
    1718           0 :                 if (untrustedchain == NULL) {
    1719           0 :                         goto clean_exit;
    1720             :                 }
    1721             :         }
    1722             : 
    1723           0 :         cainfo = setup_verify(zcainfo TSRMLS_CC);
    1724           0 :         if (cainfo == NULL) {
    1725           0 :                 goto clean_exit;
    1726             :         }
    1727           0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1728           0 :         if (cert == NULL) {
    1729           0 :                 goto clean_exit;
    1730             :         }
    1731             : 
    1732           0 :         ret = check_cert(cainfo, cert, untrustedchain, purpose);
    1733           0 :         if (ret != 0 && ret != 1) {
    1734           0 :                 RETVAL_LONG(ret);
    1735             :         } else {
    1736           0 :                 RETVAL_BOOL(ret);
    1737             :         }
    1738             : 
    1739             : clean_exit:
    1740           0 :         if (certresource == 1 && cert) {
    1741           0 :                 X509_free(cert);
    1742             :         }
    1743           0 :         if (cainfo) {
    1744           0 :                 X509_STORE_free(cainfo);
    1745             :         }
    1746           0 :         if (untrustedchain) {
    1747           0 :                 sk_X509_pop_free(untrustedchain, X509_free);
    1748             :         }
    1749             : }
    1750             : /* }}} */
    1751             : 
    1752             : /* {{{ setup_verify
    1753             :  * calist is an array containing file and directory names.  create a
    1754             :  * certificate store and add those certs to it for use in verification.
    1755             : */
    1756           0 : static X509_STORE * setup_verify(zval * calist TSRMLS_DC)
    1757             : {
    1758             :         X509_STORE *store;
    1759             :         X509_LOOKUP * dir_lookup, * file_lookup;
    1760             :         HashPosition pos;
    1761           0 :         int ndirs = 0, nfiles = 0;
    1762             : 
    1763           0 :         store = X509_STORE_new();
    1764             : 
    1765           0 :         if (store == NULL) {
    1766           0 :                 return NULL;
    1767             :         }
    1768             : 
    1769           0 :         if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
    1770           0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos);
    1771           0 :                 for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) {
    1772             :                         zval ** item;
    1773             :                         struct stat sb;
    1774             : 
    1775           0 :                         if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) {
    1776           0 :                                 break;
    1777             :                         }
    1778           0 :                         convert_to_string_ex(item);
    1779             : 
    1780           0 :                         if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) {
    1781           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item));
    1782           0 :                                 continue;
    1783             :                         }
    1784             : 
    1785           0 :                         if ((sb.st_mode & S_IFREG) == S_IFREG) {
    1786           0 :                                 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    1787           0 :                                 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
    1788           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item));
    1789             :                                 } else {
    1790           0 :                                         nfiles++;
    1791             :                                 }
    1792           0 :                                 file_lookup = NULL;
    1793             :                         } else {
    1794           0 :                                 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    1795           0 :                                 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
    1796           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item));
    1797             :                                 } else {
    1798           0 :                                         ndirs++;
    1799             :                                 }
    1800           0 :                                 dir_lookup = NULL;
    1801             :                         }
    1802           0 :                 }
    1803             :         }
    1804           0 :         if (nfiles == 0) {
    1805           0 :                 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    1806           0 :                 if (file_lookup) {
    1807           0 :                         X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT);
    1808             :                 }
    1809             :         }
    1810           0 :         if (ndirs == 0) {
    1811           0 :                 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    1812           0 :                 if (dir_lookup) {
    1813           0 :                         X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT);
    1814             :                 }
    1815             :         }
    1816           0 :         return store;
    1817             : }
    1818             : /* }}} */
    1819             : 
    1820             : /* {{{ proto resource openssl_x509_read(mixed cert)
    1821             :    Reads X.509 certificates */
    1822           8 : PHP_FUNCTION(openssl_x509_read)
    1823             : {
    1824             :         zval **cert;
    1825             :         X509 *x509;
    1826             : 
    1827           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
    1828           0 :                 return;
    1829             :         }
    1830           8 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    1831           8 :         x509 = php_openssl_x509_from_zval(cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    1832             : 
    1833           8 :         if (x509 == NULL) {
    1834           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
    1835           3 :                 RETURN_FALSE;
    1836             :         }
    1837             : }
    1838             : /* }}} */
    1839             : 
    1840             : /* {{{ proto void openssl_x509_free(resource x509)
    1841             :    Frees X.509 certificates */
    1842           6 : PHP_FUNCTION(openssl_x509_free)
    1843             : {
    1844             :         zval *x509;
    1845             :         X509 *cert;
    1846             : 
    1847           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) {
    1848           3 :                 return;
    1849             :         }
    1850           3 :         ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509);
    1851           3 :         zend_list_delete(Z_LVAL_P(x509));
    1852             : }
    1853             : /* }}} */
    1854             : 
    1855             : /* }}} */
    1856             : 
    1857             : /* Pop all X509 from Stack and free them, free the stack afterwards */
    1858           0 : static void php_sk_X509_free(STACK_OF(X509) * sk) /* {{{ */
    1859             : {
    1860             :         for (;;) {
    1861           0 :                 X509* x = sk_X509_pop(sk);
    1862           0 :                 if (!x) break;
    1863           0 :                 X509_free(x);
    1864           0 :         }
    1865           0 :         sk_X509_free(sk);
    1866           0 : }
    1867             : /* }}} */
    1868             : 
    1869           0 : static STACK_OF(X509) * php_array_to_X509_sk(zval ** zcerts TSRMLS_DC) /* {{{ */
    1870             : {
    1871             :         HashPosition hpos;
    1872             :         zval ** zcertval;
    1873           0 :         STACK_OF(X509) * sk = NULL;
    1874             :     X509 * cert;
    1875             :     long certresource;
    1876             : 
    1877           0 :         sk = sk_X509_new_null();
    1878             : 
    1879             :         /* get certs */
    1880           0 :         if (Z_TYPE_PP(zcerts) == IS_ARRAY) {
    1881           0 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(*zcerts), &hpos);
    1882           0 :                 while(zend_hash_get_current_data_ex(HASH_OF(*zcerts), (void**)&zcertval, &hpos) == SUCCESS) {
    1883             : 
    1884           0 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
    1885           0 :                         if (cert == NULL) {
    1886           0 :                                 goto clean_exit;
    1887             :                         }
    1888             : 
    1889           0 :                         if (certresource != -1) {
    1890           0 :                                 cert = X509_dup(cert);
    1891             : 
    1892           0 :                                 if (cert == NULL) {
    1893           0 :                                         goto clean_exit;
    1894             :                                 }
    1895             : 
    1896             :                         }
    1897           0 :                         sk_X509_push(sk, cert);
    1898             : 
    1899           0 :                         zend_hash_move_forward_ex(HASH_OF(*zcerts), &hpos);
    1900             :                 }
    1901             :         } else {
    1902             :                 /* a single certificate */
    1903           0 :                 cert = php_openssl_x509_from_zval(zcerts, 0, &certresource TSRMLS_CC);
    1904             : 
    1905           0 :                 if (cert == NULL) {
    1906           0 :                         goto clean_exit;
    1907             :                 }
    1908             : 
    1909           0 :                 if (certresource != -1) {
    1910           0 :                         cert = X509_dup(cert);
    1911           0 :                         if (cert == NULL) {
    1912           0 :                                 goto clean_exit;
    1913             :                         }
    1914             :                 }
    1915           0 :                 sk_X509_push(sk, cert);
    1916             :         }
    1917             : 
    1918             :   clean_exit:
    1919           0 :     return sk;
    1920             : }
    1921             : /* }}} */
    1922             : 
    1923             : /* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args])
    1924             :    Creates and exports a PKCS to file */
    1925           0 : PHP_FUNCTION(openssl_pkcs12_export_to_file)
    1926             : {
    1927           0 :         X509 * cert = NULL;
    1928           0 :         BIO * bio_out = NULL;
    1929           0 :         PKCS12 * p12 = NULL;
    1930             :         char * filename;
    1931           0 :         char * friendly_name = NULL;
    1932             :         int filename_len;
    1933             :         char * pass;
    1934             :         int pass_len;
    1935           0 :         zval **zcert = NULL, *zpkey = NULL, *args = NULL;
    1936           0 :         EVP_PKEY *priv_key = NULL;
    1937             :         long certresource, keyresource;
    1938             :         zval ** item;
    1939           0 :         STACK_OF(X509) *ca = NULL;
    1940             : 
    1941           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE)
    1942           0 :                 return;
    1943             : 
    1944           0 :         RETVAL_FALSE;
    1945             : 
    1946           0 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    1947           0 :         if (cert == NULL) {
    1948           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    1949           0 :                 return;
    1950             :         }
    1951           0 :         priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    1952           0 :         if (priv_key == NULL) {
    1953           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    1954           0 :                 goto cleanup;
    1955             :         }
    1956           0 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    1957           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
    1958           0 :                 goto cleanup;
    1959             :         }
    1960           0 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    1961           0 :                 goto cleanup;
    1962             :         }
    1963             : 
    1964             :         /* parse extra config from args array, promote this to an extra function */
    1965           0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
    1966           0 :                 friendly_name = Z_STRVAL_PP(item);
    1967             :         /* certpbe (default RC2-40)
    1968             :            keypbe (default 3DES)
    1969             :            friendly_caname
    1970             :         */
    1971             : 
    1972           0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
    1973           0 :                 ca = php_array_to_X509_sk(item TSRMLS_CC);
    1974             :         /* end parse extra config */
    1975             : 
    1976             :         /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
    1977             :                                        int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/
    1978             : 
    1979           0 :         p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
    1980             : 
    1981           0 :         bio_out = BIO_new_file(filename, "w");
    1982           0 :         if (bio_out) {
    1983             : 
    1984           0 :                 i2d_PKCS12_bio(bio_out, p12);
    1985             : 
    1986           0 :                 RETVAL_TRUE;
    1987             :         } else {
    1988           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
    1989             :         }
    1990             : 
    1991           0 :         BIO_free(bio_out);
    1992           0 :         PKCS12_free(p12);
    1993           0 :         php_sk_X509_free(ca);
    1994             : 
    1995             : cleanup:
    1996             : 
    1997           0 :         if (keyresource == -1 && priv_key) {
    1998           0 :                 EVP_PKEY_free(priv_key);
    1999             :         }
    2000           0 :         if (certresource == -1 && cert) {
    2001           0 :                 X509_free(cert);
    2002             :         }
    2003             : }
    2004             : /* }}} */
    2005             : 
    2006             : /* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
    2007             :    Creates and exports a PKCS12 to a var */
    2008           0 : PHP_FUNCTION(openssl_pkcs12_export)
    2009             : {
    2010           0 :         X509 * cert = NULL;
    2011             :         BIO * bio_out;
    2012           0 :         PKCS12 * p12 = NULL;
    2013           0 :         zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
    2014           0 :         EVP_PKEY *priv_key = NULL;
    2015             :         long certresource, keyresource;
    2016             :         char * pass;
    2017             :         int pass_len;
    2018           0 :         char * friendly_name = NULL;
    2019             :         zval ** item;
    2020           0 :         STACK_OF(X509) *ca = NULL;
    2021             : 
    2022           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
    2023           0 :                 return;
    2024             : 
    2025           0 :         RETVAL_FALSE;
    2026             : 
    2027           0 :         cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC);
    2028           0 :         if (cert == NULL) {
    2029           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
    2030           0 :                 return;
    2031             :         }
    2032           0 :         priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    2033           0 :         if (priv_key == NULL) {
    2034           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    2035           0 :                 goto cleanup;
    2036             :         }
    2037           0 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    2038           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
    2039           0 :                 goto cleanup;
    2040             :         }
    2041             : 
    2042             :         /* parse extra config from args array, promote this to an extra function */
    2043           0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
    2044           0 :                 friendly_name = Z_STRVAL_PP(item);
    2045             : 
    2046           0 :         if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
    2047           0 :                 ca = php_array_to_X509_sk(item TSRMLS_CC);
    2048             :         /* end parse extra config */
    2049             : 
    2050           0 :         p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
    2051             : 
    2052           0 :         bio_out = BIO_new(BIO_s_mem());
    2053           0 :         if (i2d_PKCS12_bio(bio_out, p12))  {
    2054             :                 BUF_MEM *bio_buf;
    2055             : 
    2056           0 :                 zval_dtor(zout);
    2057           0 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
    2058           0 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
    2059             : 
    2060           0 :                 RETVAL_TRUE;
    2061             :         }
    2062             : 
    2063           0 :         BIO_free(bio_out);
    2064           0 :         PKCS12_free(p12);
    2065           0 :         php_sk_X509_free(ca);
    2066             : 
    2067             : cleanup:
    2068             : 
    2069           0 :         if (keyresource == -1 && priv_key) {
    2070           0 :                 EVP_PKEY_free(priv_key);
    2071             :         }
    2072           0 :         if (certresource == -1 && cert) {
    2073           0 :                 X509_free(cert);
    2074             :         }
    2075             : }
    2076             : /* }}} */
    2077             : 
    2078             : /* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass)
    2079             :    Parses a PKCS12 to an array */
    2080           1 : PHP_FUNCTION(openssl_pkcs12_read)
    2081             : {
    2082           1 :         zval *zout = NULL, *zextracerts, *zcert, *zpkey;
    2083             :         char *pass, *zp12;
    2084             :         int pass_len, zp12_len;
    2085           1 :         PKCS12 * p12 = NULL;
    2086           1 :         EVP_PKEY * pkey = NULL;
    2087           1 :         X509 * cert = NULL;
    2088           1 :         STACK_OF(X509) * ca = NULL;
    2089           1 :         BIO * bio_in = NULL;
    2090             :         int i;
    2091             : 
    2092           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szs", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE)
    2093           0 :                 return;
    2094             : 
    2095           1 :         RETVAL_FALSE;
    2096             : 
    2097           1 :         bio_in = BIO_new(BIO_s_mem());
    2098             : 
    2099           1 :         if(!BIO_write(bio_in, zp12, zp12_len))
    2100           0 :                 goto cleanup;
    2101             : 
    2102           1 :         if(d2i_PKCS12_bio(bio_in, &p12)) {
    2103           0 :                 if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
    2104             :                         BIO * bio_out;
    2105             : 
    2106           0 :                         zval_dtor(zout);
    2107           0 :                         array_init(zout);
    2108             : 
    2109           0 :                         bio_out = BIO_new(BIO_s_mem());
    2110           0 :                         if (PEM_write_bio_X509(bio_out, cert)) {
    2111             :                                 BUF_MEM *bio_buf;
    2112           0 :                                 BIO_get_mem_ptr(bio_out, &bio_buf);
    2113           0 :                                 MAKE_STD_ZVAL(zcert);
    2114           0 :                                 ZVAL_STRINGL(zcert, bio_buf->data, bio_buf->length, 1);
    2115           0 :                                 add_assoc_zval(zout, "cert", zcert);
    2116             :                         }
    2117           0 :                         BIO_free(bio_out);
    2118             : 
    2119           0 :                         bio_out = BIO_new(BIO_s_mem());
    2120           0 :                         if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) {
    2121             :                                 BUF_MEM *bio_buf;
    2122           0 :                                 BIO_get_mem_ptr(bio_out, &bio_buf);
    2123           0 :                                 MAKE_STD_ZVAL(zpkey);
    2124           0 :                                 ZVAL_STRINGL(zpkey, bio_buf->data, bio_buf->length, 1);
    2125           0 :                                 add_assoc_zval(zout, "pkey", zpkey);
    2126             :                         }
    2127           0 :                         BIO_free(bio_out);
    2128             : 
    2129           0 :                         MAKE_STD_ZVAL(zextracerts);
    2130           0 :                         array_init(zextracerts);
    2131             : 
    2132           0 :                         for (i=0;;i++) {
    2133             :                                 zval * zextracert;
    2134           0 :                                 X509* aCA = sk_X509_pop(ca);
    2135           0 :                                 if (!aCA) break;
    2136             : 
    2137           0 :                                 bio_out = BIO_new(BIO_s_mem());
    2138           0 :                                 if (PEM_write_bio_X509(bio_out, aCA)) {
    2139             :                                         BUF_MEM *bio_buf;
    2140           0 :                                         BIO_get_mem_ptr(bio_out, &bio_buf);
    2141           0 :                                         MAKE_STD_ZVAL(zextracert);
    2142           0 :                                         ZVAL_STRINGL(zextracert, bio_buf->data, bio_buf->length, 1);
    2143           0 :                                         add_index_zval(zextracerts, i, zextracert);
    2144             : 
    2145             :                                 }
    2146           0 :                                 BIO_free(bio_out);
    2147             : 
    2148           0 :                                 X509_free(aCA);
    2149           0 :                         }
    2150           0 :                         if(ca) {
    2151           0 :                                 sk_X509_free(ca);
    2152           0 :                                 add_assoc_zval(zout, "extracerts", zextracerts);
    2153             :                         } else {
    2154             :                                 zval_dtor(zextracerts);
    2155             :                         }
    2156             : 
    2157           0 :                         RETVAL_TRUE;
    2158             : 
    2159           0 :                         PKCS12_free(p12);
    2160             :                 }
    2161             :         }
    2162             : 
    2163             :   cleanup:
    2164           1 :         if (bio_in) {
    2165           1 :                 BIO_free(bio_in);
    2166             :         }
    2167           1 :         if (pkey) {
    2168           0 :                 EVP_PKEY_free(pkey);
    2169             :         }
    2170           1 :         if (cert) {
    2171           0 :                 X509_free(cert);
    2172             :         }
    2173             : }
    2174             : /* }}} */
    2175             : 
    2176             : /* {{{ x509 CSR functions */
    2177             : 
    2178             : /* {{{ php_openssl_make_REQ */
    2179           6 : static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs TSRMLS_DC)
    2180             : {
    2181           6 :         STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
    2182             :         char * str, *dn_sect, *attr_sect;
    2183             : 
    2184           6 :         dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name");
    2185           6 :         if (dn_sect == NULL) {
    2186           0 :                 return FAILURE;
    2187             :         }
    2188           6 :         dn_sk = CONF_get_section(req->req_config, dn_sect);
    2189           6 :         if (dn_sk == NULL) {
    2190           0 :                 return FAILURE;
    2191             :         }
    2192           6 :         attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
    2193           6 :         if (attr_sect == NULL) {
    2194           0 :                 attr_sk = NULL;
    2195             :         } else {
    2196           6 :                 attr_sk = CONF_get_section(req->req_config, attr_sect);
    2197           6 :                 if (attr_sk == NULL) {
    2198           0 :                         return FAILURE;
    2199             :                 }
    2200             :         }
    2201             :         /* setup the version number: version 1 */
    2202           6 :         if (X509_REQ_set_version(csr, 0L)) {
    2203             :                 int i, nid;
    2204             :                 char * type;
    2205             :                 CONF_VALUE * v;
    2206             :                 X509_NAME * subj;
    2207             :                 HashPosition hpos;
    2208             :                 zval ** item;
    2209             : 
    2210           6 :                 subj = X509_REQ_get_subject_name(csr);
    2211             :                 /* apply values from the dn hash */
    2212           6 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(dn), &hpos);
    2213          35 :                 while(zend_hash_get_current_data_ex(HASH_OF(dn), (void**)&item, &hpos) == SUCCESS) {
    2214          23 :                         char * strindex = NULL;
    2215          23 :                         uint strindexlen = 0;
    2216             :                         ulong intindex;
    2217             : 
    2218          23 :                         zend_hash_get_current_key_ex(HASH_OF(dn), &strindex, &strindexlen, &intindex, 0, &hpos);
    2219             : 
    2220          29 :                         convert_to_string_ex(item);
    2221             : 
    2222          23 :                         if (strindex) {
    2223             :                                 int nid;
    2224             : 
    2225          21 :                                 nid = OBJ_txt2nid(strindex);
    2226          21 :                                 if (nid != NID_undef) {
    2227          21 :                                         if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8,
    2228          21 :                                                                 (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0))
    2229             :                                         {
    2230           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
    2231             :                                                         "dn: add_entry_by_NID %d -> %s (failed; check error"
    2232             :                                                         " queue and value of string_mask OpenSSL option "
    2233             :                                                         "if illegal characters are reported)",
    2234           0 :                                                         nid, Z_STRVAL_PP(item));
    2235           0 :                                                 return FAILURE;
    2236             :                                         }
    2237             :                                 } else {
    2238           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
    2239             :                                 }
    2240             :                         }
    2241          23 :                         zend_hash_move_forward_ex(HASH_OF(dn), &hpos);
    2242             :                 }
    2243             : 
    2244             :                 /* Finally apply defaults from config file */
    2245          90 :                 for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
    2246             :                         int len;
    2247             :                         char buffer[200 + 1]; /*200 + \0 !*/
    2248             : 
    2249          84 :                         v = sk_CONF_VALUE_value(dn_sk, i);
    2250          84 :                         type = v->name;
    2251             : 
    2252          84 :                         len = strlen(type);
    2253          84 :                         if (len < sizeof("_default")) {
    2254           0 :                                 continue;
    2255             :                         }
    2256          84 :                         len -= sizeof("_default") - 1;
    2257          84 :                         if (strcmp("_default", type + len) != 0) {
    2258          66 :                                 continue;
    2259             :                         }
    2260          18 :                         if (len > 200) {
    2261           0 :                                 len = 200;
    2262             :                         }
    2263          18 :                         memcpy(buffer, type, len);
    2264          18 :                         buffer[len] = '\0';
    2265          18 :                         type = buffer;
    2266             : 
    2267             :                         /* Skip past any leading X. X: X, etc to allow for multiple
    2268             :                          * instances */
    2269         204 :                         for (str = type; *str; str++) {
    2270         192 :                                 if (*str == ':' || *str == ',' || *str == '.') {
    2271           6 :                                         str++;
    2272           6 :                                         if (*str) {
    2273           6 :                                                 type = str;
    2274             :                                         }
    2275           6 :                                         break;
    2276             :                                 }
    2277             :                         }
    2278             :                         /* if it is already set, skip this */
    2279          18 :                         nid = OBJ_txt2nid(type);
    2280          18 :                         if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) {
    2281          10 :                                 continue;
    2282             :                         }
    2283           8 :                         if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) {
    2284           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
    2285           0 :                                 return FAILURE;
    2286             :                         }
    2287           8 :                         if (!X509_NAME_entry_count(subj)) {
    2288           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no objects specified in config file");
    2289           0 :                                 return FAILURE;
    2290             :                         }
    2291             :                 }
    2292           6 :                 if (attribs) {
    2293           1 :                         zend_hash_internal_pointer_reset_ex(HASH_OF(attribs), &hpos);
    2294           2 :                         while(zend_hash_get_current_data_ex(HASH_OF(attribs), (void**)&item, &hpos) == SUCCESS) {
    2295           0 :                                 char *strindex = NULL;
    2296             :                                 uint strindexlen;
    2297             :                                 ulong intindex;
    2298             : 
    2299           0 :                                 zend_hash_get_current_key_ex(HASH_OF(attribs), &strindex, &strindexlen, &intindex, 0, &hpos);
    2300           0 :                                 convert_to_string_ex(item);
    2301             : 
    2302           0 :                                 if (strindex) {
    2303             :                                         int nid;
    2304             : 
    2305           0 :                                         nid = OBJ_txt2nid(strindex);
    2306           0 :                                         if (nid != NID_undef) {
    2307           0 :                                                 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) {
    2308           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item));
    2309           0 :                                                         return FAILURE;
    2310             :                                                 }
    2311             :                                         } else {
    2312           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
    2313             :                                         }
    2314             :                                 }
    2315           0 :                                 zend_hash_move_forward_ex(HASH_OF(attribs), &hpos);
    2316             :                         }
    2317           2 :                         for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
    2318           2 :                                 v = sk_CONF_VALUE_value(attr_sk, i);
    2319             :                                 /* if it is already set, skip this */
    2320           2 :                                 nid = OBJ_txt2nid(v->name);
    2321           2 :                                 if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) {
    2322           0 :                                         continue;
    2323             :                                 }
    2324           2 :                                 if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_UTF8, (unsigned char*)v->value, -1)) {
    2325           1 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
    2326             :                                                 "add1_attr_by_txt %s -> %s (failed; check error queue "
    2327             :                                                 "and value of string_mask OpenSSL option if illegal "
    2328             :                                                 "characters are reported)",
    2329             :                                                 v->name, v->value);
    2330           1 :                                         return FAILURE;
    2331             :                                 }
    2332             :                         }
    2333             :                 }
    2334             :         }
    2335             : 
    2336           5 :         X509_REQ_set_pubkey(csr, req->priv_key);
    2337           5 :         return SUCCESS;
    2338             : }
    2339             : /* }}} */
    2340             : 
    2341             : /* {{{ php_openssl_csr_from_zval */
    2342          18 : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
    2343             : {
    2344          18 :         X509_REQ * csr = NULL;
    2345          18 :         char * filename = NULL;
    2346             :         BIO * in;
    2347             : 
    2348          18 :         if (resourceval) {
    2349          18 :                 *resourceval = -1;
    2350             :         }
    2351          18 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
    2352             :                 void * what;
    2353             :                 int type;
    2354             : 
    2355          14 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509 CSR", &type, 1, le_csr);
    2356          14 :                 if (what) {
    2357          13 :                         if (resourceval) {
    2358          13 :                                 *resourceval = Z_LVAL_PP(val);
    2359             :                         }
    2360          13 :                         return (X509_REQ*)what;
    2361             :                 }
    2362           1 :                 return NULL;
    2363           4 :         } else if (Z_TYPE_PP(val) != IS_STRING) {
    2364           1 :                 return NULL;
    2365             :         }
    2366             : 
    2367           3 :         if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
    2368           0 :                 filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
    2369             :         }
    2370           3 :         if (filename) {
    2371           0 :                 if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    2372           0 :                         return NULL;
    2373             :                 }
    2374           0 :                 in = BIO_new_file(filename, "r");
    2375             :         } else {
    2376           3 :                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    2377             :         }
    2378           3 :         csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL);
    2379           3 :         BIO_free(in);
    2380             : 
    2381           3 :         return csr;
    2382             : }
    2383             : /* }}} */
    2384             : 
    2385             : /* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true])
    2386             :    Exports a CSR to file */
    2387           0 : PHP_FUNCTION(openssl_csr_export_to_file)
    2388             : {
    2389             :         X509_REQ * csr;
    2390           0 :         zval * zcsr = NULL;
    2391           0 :         zend_bool notext = 1;
    2392           0 :         char * filename = NULL; int filename_len;
    2393             :         BIO * bio_out;
    2394             :         long csr_resource;
    2395             : 
    2396           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rp|b", &zcsr, &filename, &filename_len, &notext) == FAILURE) {
    2397           0 :                 return;
    2398             :         }
    2399           0 :         RETVAL_FALSE;
    2400             : 
    2401           0 :         csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
    2402           0 :         if (csr == NULL) {
    2403           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    2404           0 :                 return;
    2405             :         }
    2406             : 
    2407           0 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    2408           0 :                 return;
    2409             :         }
    2410             : 
    2411           0 :         bio_out = BIO_new_file(filename, "w");
    2412           0 :         if (bio_out) {
    2413           0 :                 if (!notext) {
    2414           0 :                         X509_REQ_print(bio_out, csr);
    2415             :                 }
    2416           0 :                 PEM_write_bio_X509_REQ(bio_out, csr);
    2417           0 :                 RETVAL_TRUE;
    2418             :         } else {
    2419           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
    2420             :         }
    2421             : 
    2422           0 :         if (csr_resource == -1 && csr) {
    2423           0 :                 X509_REQ_free(csr);
    2424             :         }
    2425           0 :         BIO_free(bio_out);
    2426             : }
    2427             : /* }}} */
    2428             : 
    2429             : /* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true])
    2430             :    Exports a CSR to file or a var */
    2431           7 : PHP_FUNCTION(openssl_csr_export)
    2432             : {
    2433             :         X509_REQ * csr;
    2434           7 :         zval * zcsr = NULL, *zout=NULL;
    2435           7 :         zend_bool notext = 1;
    2436             :         BIO * bio_out;
    2437             : 
    2438             :         long csr_resource;
    2439             : 
    2440           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zcsr, &zout, &notext) == FAILURE) {
    2441           2 :                 return;
    2442             :         }
    2443           5 :         RETVAL_FALSE;
    2444             : 
    2445           5 :         csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
    2446           5 :         if (csr == NULL) {
    2447           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    2448           1 :                 return;
    2449             :         }
    2450             : 
    2451             :         /* export to a var */
    2452             : 
    2453           4 :         bio_out = BIO_new(BIO_s_mem());
    2454           4 :         if (!notext) {
    2455           2 :                 X509_REQ_print(bio_out, csr);
    2456             :         }
    2457             : 
    2458           4 :         if (PEM_write_bio_X509_REQ(bio_out, csr)) {
    2459             :                 BUF_MEM *bio_buf;
    2460             : 
    2461           4 :                 BIO_get_mem_ptr(bio_out, &bio_buf);
    2462           4 :                 zval_dtor(zout);
    2463           4 :                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
    2464             : 
    2465           4 :                 RETVAL_TRUE;
    2466             :         }
    2467             : 
    2468           4 :         if (csr_resource == -1 && csr) {
    2469           0 :                 X509_REQ_free(csr);
    2470             :         }
    2471           4 :         BIO_free(bio_out);
    2472             : }
    2473             : /* }}} */
    2474             : 
    2475             : /* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]])
    2476             :    Signs a cert with another CERT */
    2477          14 : PHP_FUNCTION(openssl_csr_sign)
    2478             : {
    2479          14 :         zval ** zcert = NULL, **zcsr, **zpkey, *args = NULL;
    2480             :         long num_days;
    2481          14 :         long serial = 0L;
    2482          14 :         X509 * cert = NULL, *new_cert = NULL;
    2483             :         X509_REQ * csr;
    2484          14 :         EVP_PKEY * key = NULL, *priv_key = NULL;
    2485          14 :         long csr_resource, certresource = 0, keyresource = -1;
    2486             :         int i;
    2487             :         struct php_x509_request req;
    2488             : 
    2489          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ!Zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE)
    2490           3 :                 return;
    2491             : 
    2492          11 :         RETVAL_FALSE;
    2493          11 :         PHP_SSL_REQ_INIT(&req);
    2494             : 
    2495          11 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2496          11 :         if (csr == NULL) {
    2497           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
    2498           2 :                 return;
    2499             :         }
    2500           9 :         if (zcert) {
    2501           3 :                 cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    2502           3 :                 if (cert == NULL) {
    2503           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 2");
    2504           2 :                         goto cleanup;
    2505             :                 }
    2506             :         }
    2507           7 :         priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource TSRMLS_CC);
    2508           7 :         if (priv_key == NULL) {
    2509           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
    2510           2 :                 goto cleanup;
    2511             :         }
    2512           5 :         if (cert && !X509_check_private_key(cert, priv_key)) {
    2513           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert");
    2514           0 :                 goto cleanup;
    2515             :         }
    2516             : 
    2517           5 :         if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) {
    2518           0 :                 goto cleanup;
    2519             :         }
    2520             :         /* Check that the request matches the signature */
    2521           5 :         key = X509_REQ_get_pubkey(csr);
    2522           5 :         if (key == NULL) {
    2523           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error unpacking public key");
    2524           0 :                 goto cleanup;
    2525             :         }
    2526           5 :         i = X509_REQ_verify(csr, key);
    2527             : 
    2528           5 :         if (i < 0) {
    2529           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature verification problems");
    2530           0 :                 goto cleanup;
    2531             :         }
    2532           5 :         else if (i == 0) {
    2533           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature did not match the certificate request");
    2534           0 :                 goto cleanup;
    2535             :         }
    2536             : 
    2537             :         /* Now we can get on with it */
    2538             : 
    2539           5 :         new_cert = X509_new();
    2540           5 :         if (new_cert == NULL) {
    2541           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No memory");
    2542           0 :                 goto cleanup;
    2543             :         }
    2544             :         /* Version 3 cert */
    2545           5 :         if (!X509_set_version(new_cert, 2))
    2546           0 :                 goto cleanup;
    2547             : 
    2548           5 :         ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
    2549             : 
    2550           5 :         X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
    2551             : 
    2552           5 :         if (cert == NULL) {
    2553           4 :                 cert = new_cert;
    2554             :         }
    2555           5 :         if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) {
    2556           0 :                 goto cleanup;
    2557             :         }
    2558           5 :         X509_gmtime_adj(X509_get_notBefore(new_cert), 0);
    2559           5 :         X509_gmtime_adj(X509_get_notAfter(new_cert), (long)60*60*24*num_days);
    2560           5 :         i = X509_set_pubkey(new_cert, key);
    2561           5 :         if (!i) {
    2562           0 :                 goto cleanup;
    2563             :         }
    2564           5 :         if (req.extensions_section) {
    2565             :                 X509V3_CTX ctx;
    2566             : 
    2567           5 :                 X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0);
    2568           5 :                 X509V3_set_conf_lhash(&ctx, req.req_config);
    2569           5 :                 if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) {
    2570           0 :                         goto cleanup;
    2571             :                 }
    2572             :         }
    2573             : 
    2574             :         /* Now sign it */
    2575           5 :         if (!X509_sign(new_cert, priv_key, req.digest)) {
    2576           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it");
    2577           0 :                 goto cleanup;
    2578             :         }
    2579             : 
    2580             :         /* Succeeded; lets return the cert */
    2581           5 :         RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509 TSRMLS_CC));
    2582           5 :         new_cert = NULL;
    2583             : 
    2584             : cleanup:
    2585             : 
    2586           9 :         if (cert == new_cert) {
    2587           4 :                 cert = NULL;
    2588             :         }
    2589           9 :         PHP_SSL_REQ_DISPOSE(&req);
    2590             : 
    2591           9 :         if (keyresource == -1 && priv_key) {
    2592           0 :                 EVP_PKEY_free(priv_key);
    2593             :         }
    2594           9 :         if (key) {
    2595           5 :                 EVP_PKEY_free(key);
    2596             :         }
    2597           9 :         if (csr_resource == -1 && csr) {
    2598           0 :                 X509_REQ_free(csr);
    2599             :         }
    2600           9 :         if (certresource == -1 && cert) {
    2601           1 :                 X509_free(cert);
    2602             :         }
    2603           9 :         if (new_cert) {
    2604           0 :                 X509_free(new_cert);
    2605             :         }
    2606             : }
    2607             : /* }}} */
    2608             : 
    2609             : /* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs [, array extraattribs]])
    2610             :    Generates a privkey and CSR */
    2611           8 : PHP_FUNCTION(openssl_csr_new)
    2612             : {
    2613             :         struct php_x509_request req;
    2614           8 :         zval * args = NULL, * dn, *attribs = NULL;
    2615             :         zval * out_pkey;
    2616           8 :         X509_REQ * csr = NULL;
    2617           8 :         int we_made_the_key = 1;
    2618             :         long key_resource;
    2619             : 
    2620           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) {
    2621           2 :                 return;
    2622             :         }
    2623           6 :         RETVAL_FALSE;
    2624             : 
    2625           6 :         PHP_SSL_REQ_INIT(&req);
    2626             : 
    2627           6 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    2628             :                 /* Generate or use a private key */
    2629           6 :                 if (Z_TYPE_P(out_pkey) != IS_NULL) {
    2630           6 :                         req.priv_key = php_openssl_evp_from_zval(&out_pkey, 0, NULL, 0, &key_resource TSRMLS_CC);
    2631           6 :                         if (req.priv_key != NULL) {
    2632           4 :                                 we_made_the_key = 0;
    2633             :                         }
    2634             :                 }
    2635           6 :                 if (req.priv_key == NULL) {
    2636           2 :                         php_openssl_generate_private_key(&req TSRMLS_CC);
    2637             :                 }
    2638           6 :                 if (req.priv_key == NULL) {
    2639           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to generate a private key");
    2640             :                 } else {
    2641           6 :                         csr = X509_REQ_new();
    2642           6 :                         if (csr) {
    2643           6 :                                 if (php_openssl_make_REQ(&req, csr, dn, attribs TSRMLS_CC) == SUCCESS) {
    2644             :                                         X509V3_CTX ext_ctx;
    2645             : 
    2646           5 :                                         X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0);
    2647           5 :                                         X509V3_set_conf_lhash(&ext_ctx, req.req_config);
    2648             : 
    2649             :                                         /* Add extensions */
    2650           5 :                                         if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config,
    2651             :                                                                 &ext_ctx, req.request_extensions_section, csr))
    2652             :                                         {
    2653           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading extension section %s", req.request_extensions_section);
    2654             :                                         } else {
    2655           5 :                                                 RETVAL_TRUE;
    2656             : 
    2657           5 :                                                 if (X509_REQ_sign(csr, req.priv_key, req.digest)) {
    2658           5 :                                                         RETVAL_RESOURCE(zend_list_insert(csr, le_csr TSRMLS_CC));
    2659           5 :                                                         csr = NULL;
    2660             :                                                 } else {
    2661           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request");
    2662             :                                                 }
    2663             : 
    2664           5 :                                                 if (we_made_the_key) {
    2665             :                                                         /* and a resource for the private key */
    2666           1 :                                                         zval_dtor(out_pkey);
    2667           1 :                                                         ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key TSRMLS_CC));
    2668           1 :                                                         req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
    2669           4 :                                                 } else if (key_resource != -1) {
    2670           4 :                                                         req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
    2671             :                                                 }
    2672             :                                         }
    2673             :                                 }
    2674             :                                 else {
    2675           1 :                                         if (!we_made_the_key) {
    2676             :                                                 /* if we have not made the key we are not supposed to zap it by calling dispose! */
    2677           0 :                                                 req.priv_key = NULL;
    2678             :                                         }
    2679             :                                 }
    2680             :                         }
    2681             :                 }
    2682             :         }
    2683           6 :         if (csr) {
    2684           1 :                 X509_REQ_free(csr);
    2685             :         }
    2686           6 :         PHP_SSL_REQ_DISPOSE(&req);
    2687             : }
    2688             : /* }}} */
    2689             : 
    2690             : /* {{{ proto mixed openssl_csr_get_subject(mixed csr)
    2691             :    Returns the subject of a CERT or FALSE on error */
    2692           2 : PHP_FUNCTION(openssl_csr_get_subject)
    2693             : {
    2694             :         zval ** zcsr;
    2695           2 :         zend_bool use_shortnames = 1;
    2696             :         long csr_resource;
    2697             :         X509_NAME * subject;
    2698             :         X509_REQ * csr;
    2699             : 
    2700           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
    2701           0 :                 return;
    2702             :         }
    2703             : 
    2704           2 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2705             : 
    2706           2 :         if (csr == NULL) {
    2707           0 :                 RETURN_FALSE;
    2708             :         }
    2709             : 
    2710           2 :         subject = X509_REQ_get_subject_name(csr);
    2711             : 
    2712           2 :         array_init(return_value);
    2713           2 :         add_assoc_name_entry(return_value, NULL, subject, use_shortnames TSRMLS_CC);
    2714           2 :         return;
    2715             : }
    2716             : /* }}} */
    2717             : 
    2718             : /* {{{ proto mixed openssl_csr_get_public_key(mixed csr)
    2719             :         Returns the subject of a CERT or FALSE on error */
    2720           0 : PHP_FUNCTION(openssl_csr_get_public_key)
    2721             : {
    2722             :         zval ** zcsr;
    2723           0 :         zend_bool use_shortnames = 1;
    2724             :         long csr_resource;
    2725             : 
    2726             :         X509_REQ * csr;
    2727             :         EVP_PKEY *tpubkey;
    2728             : 
    2729           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
    2730           0 :                 return;
    2731             :         }
    2732             : 
    2733           0 :         csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
    2734             : 
    2735           0 :         if (csr == NULL) {
    2736           0 :                 RETURN_FALSE;
    2737             :         }
    2738             : 
    2739           0 :         tpubkey=X509_REQ_get_pubkey(csr);
    2740           0 :         RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key TSRMLS_CC));
    2741           0 :         return;
    2742             : }
    2743             : /* }}} */
    2744             : 
    2745             : /* }}} */
    2746             : 
    2747             : /* {{{ EVP Public/Private key functions */
    2748             : 
    2749             : /* {{{ php_openssl_evp_from_zval
    2750             :    Given a zval, coerce it into a EVP_PKEY object.
    2751             :         It can be:
    2752             :                 1. private key resource from openssl_get_privatekey()
    2753             :                 2. X509 resource -> public key will be extracted from it
    2754             :                 3. if it starts with file:// interpreted as path to key file
    2755             :                 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey()
    2756             :                 5. an array(0 => [items 2..4], 1 => passphrase)
    2757             :                 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key
    2758             :         NOTE: If you are requesting a private key but have not specified a passphrase, you should use an
    2759             :         empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in
    2760             :         the Apache error log!
    2761             : */
    2762         105 : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC)
    2763             : {
    2764         105 :         EVP_PKEY * key = NULL;
    2765         105 :         X509 * cert = NULL;
    2766         105 :         int free_cert = 0;
    2767         105 :         long cert_res = -1;
    2768         105 :         char * filename = NULL;
    2769             :         zval tmp;
    2770             : 
    2771         105 :         Z_TYPE(tmp) = IS_NULL;
    2772             : 
    2773             : #define TMP_CLEAN \
    2774             :         if (Z_TYPE(tmp) == IS_STRING) {\
    2775             :                 zval_dtor(&tmp); \
    2776             :         } \
    2777             :         return NULL;
    2778             : 
    2779         105 :         if (resourceval) {
    2780         105 :                 *resourceval = -1;
    2781             :         }
    2782         105 :         if (Z_TYPE_PP(val) == IS_ARRAY) {
    2783             :                 zval ** zphrase;
    2784             : 
    2785             :                 /* get passphrase */
    2786             : 
    2787           9 :                 if (zend_hash_index_find(HASH_OF(*val), 1, (void **)&zphrase) == FAILURE) {
    2788           5 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
    2789           5 :                         return NULL;
    2790             :                 }
    2791             : 
    2792           4 :                 if (Z_TYPE_PP(zphrase) == IS_STRING) {
    2793           3 :                         passphrase = Z_STRVAL_PP(zphrase);
    2794             :                 } else {
    2795           1 :                         tmp = **zphrase;
    2796             :                         zval_copy_ctor(&tmp);
    2797           1 :                         convert_to_string(&tmp);
    2798           1 :                         passphrase = Z_STRVAL(tmp);
    2799             :                 }
    2800             : 
    2801             :                 /* now set val to be the key param and continue */
    2802           4 :                 if (zend_hash_index_find(HASH_OF(*val), 0, (void **)&val) == FAILURE) {
    2803           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
    2804           0 :                         TMP_CLEAN;
    2805             :                 }
    2806             :         }
    2807             : 
    2808         100 :         if (Z_TYPE_PP(val) == IS_RESOURCE) {
    2809             :                 void * what;
    2810             :                 int type;
    2811             : 
    2812          20 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key);
    2813          20 :                 if (!what) {
    2814           0 :                         TMP_CLEAN;
    2815             :                 }
    2816          20 :                 if (resourceval) {
    2817          20 :                         *resourceval = Z_LVAL_PP(val);
    2818             :                 }
    2819          20 :                 if (type == le_x509) {
    2820             :                         /* extract key from cert, depending on public_key param */
    2821           0 :                         cert = (X509*)what;
    2822           0 :                         free_cert = 0;
    2823          20 :                 } else if (type == le_key) {
    2824             :                         int is_priv;
    2825             : 
    2826          20 :                         is_priv = php_openssl_is_private_key((EVP_PKEY*)what TSRMLS_CC);
    2827             : 
    2828             :                         /* check whether it is actually a private key if requested */
    2829          20 :                         if (!public_key && !is_priv) {
    2830           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param is a public key");
    2831           0 :                                 TMP_CLEAN;
    2832             :                         }
    2833             : 
    2834          20 :                         if (public_key && is_priv) {
    2835           1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Don't know how to get public key from this private key");
    2836           2 :                                 TMP_CLEAN;
    2837             :                         } else {
    2838          19 :                                 if (Z_TYPE(tmp) == IS_STRING) {
    2839             :                                         zval_dtor(&tmp);
    2840             :                                 }
    2841             :                                 /* got the key - return it */
    2842          19 :                                 return (EVP_PKEY*)what;
    2843             :                         }
    2844             :                 } else {
    2845             :                         /* other types could be used here - eg: file pointers and read in the data from them */
    2846           0 :                         TMP_CLEAN;
    2847             :                 }
    2848             :         } else {
    2849             :                 /* force it to be a string and check if it refers to a file */
    2850             :                 /* passing non string values leaks, object uses toString, it returns NULL
    2851             :                  * See bug38255.phpt
    2852             :                  */
    2853          80 :                 if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
    2854          10 :                         TMP_CLEAN;
    2855             :                 }
    2856          85 :                 convert_to_string_ex(val);
    2857             : 
    2858          75 :                 if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
    2859          51 :                         filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
    2860             :                 }
    2861             :                 /* it's an X509 file/cert of some kind, and we need to extract the data from that */
    2862          75 :                 if (public_key) {
    2863          28 :                         cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC);
    2864          28 :                         free_cert = (cert_res == -1);
    2865             :                         /* actual extraction done later */
    2866          28 :                         if (!cert) {
    2867             :                                 /* not a X509 certificate, try to retrieve public key */
    2868             :                                 BIO* in;
    2869          26 :                                 if (filename) {
    2870          20 :                                         in = BIO_new_file(filename, "r");
    2871             :                                 } else {
    2872           6 :                                         in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    2873             :                                 }
    2874          26 :                                 if (in == NULL) {
    2875           0 :                                         TMP_CLEAN;
    2876             :                                 }
    2877          26 :                                 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    2878          26 :                                 BIO_free(in);
    2879             :                         }
    2880             :                 } else {
    2881             :                         /* we want the private key */
    2882             :                         BIO *in;
    2883             : 
    2884          47 :                         if (filename) {
    2885          31 :                                 if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    2886           0 :                                         TMP_CLEAN;
    2887             :                                 }
    2888          31 :                                 in = BIO_new_file(filename, "r");
    2889             :                         } else {
    2890          16 :                                 in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
    2891             :                         }
    2892             : 
    2893          47 :                         if (in == NULL) {
    2894           0 :                                 TMP_CLEAN;
    2895             :                         }
    2896          47 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
    2897          47 :                         BIO_free(in);
    2898             :                 }
    2899             :         }
    2900             : 
    2901          75 :         if (public_key && cert && key == NULL) {
    2902             :                 /* extract public key from X509 cert */
    2903           2 :                 key = (EVP_PKEY *) X509_get_pubkey(cert);
    2904             :         }
    2905             : 
    2906          75 :         if (free_cert && cert) {
    2907           2 :                 X509_free(cert);
    2908             :         }
    2909          75 :         if (key && makeresource && resourceval) {
    2910          14 :                 *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key);
    2911             :         }
    2912          75 :         if (Z_TYPE(tmp) == IS_STRING) {
    2913             :                 zval_dtor(&tmp);
    2914             :         }
    2915          75 :         return key;
    2916             : }
    2917             : /* }}} */
    2918             : 
    2919             : /* {{{ php_openssl_generate_private_key */
    2920          11 : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC)
    2921             : {
    2922          11 :         char * randfile = NULL;
    2923             :         int egdsocket, seeded;
    2924          11 :         EVP_PKEY * return_val = NULL;
    2925             : 
    2926          11 :         if (req->priv_key_bits < MIN_KEY_LENGTH) {
    2927           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",
    2928             :                                 MIN_KEY_LENGTH, req->priv_key_bits);
    2929           0 :                 return NULL;
    2930             :         }
    2931             : 
    2932          11 :         randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
    2933          11 :         php_openssl_load_rand_file(randfile, &egdsocket, &seeded TSRMLS_CC);
    2934             : 
    2935          11 :         if ((req->priv_key = EVP_PKEY_new()) != NULL) {
    2936          11 :                 switch(req->priv_key_type) {
    2937             :                         case OPENSSL_KEYTYPE_RSA:
    2938          11 :                                 if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) {
    2939          11 :                                         return_val = req->priv_key;
    2940             :                                 }
    2941          11 :                                 break;
    2942             : #if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD)
    2943             :                         case OPENSSL_KEYTYPE_DSA:
    2944             :                                 {
    2945           0 :                                         DSA *dsapar = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
    2946           0 :                                         if (dsapar) {
    2947           0 :                                                 DSA_set_method(dsapar, DSA_get_default_method());
    2948           0 :                                                 if (DSA_generate_key(dsapar)) {
    2949           0 :                                                         if (EVP_PKEY_assign_DSA(req->priv_key, dsapar)) {
    2950           0 :                                                                 return_val = req->priv_key;
    2951             :                                                         }
    2952             :                                                 } else {
    2953           0 :                                                         DSA_free(dsapar);
    2954             :                                                 }
    2955             :                                         }
    2956             :                                 }
    2957           0 :                                 break;
    2958             : #endif
    2959             : #if !defined(NO_DH)
    2960             :                         case OPENSSL_KEYTYPE_DH:
    2961             :                                 {
    2962           0 :                                         DH *dhpar = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
    2963           0 :                                         int codes = 0;
    2964             : 
    2965           0 :                                         if (dhpar) {
    2966           0 :                                                 DH_set_method(dhpar, DH_get_default_method());
    2967           0 :                                                 if (DH_check(dhpar, &codes) && codes == 0 && DH_generate_key(dhpar)) {
    2968           0 :                                                         if (EVP_PKEY_assign_DH(req->priv_key, dhpar)) {
    2969           0 :                                                                 return_val = req->priv_key;
    2970             :                                                         }
    2971             :                                                 } else {
    2972           0 :                                                         DH_free(dhpar);
    2973             :                                                 }
    2974             :                                         }
    2975             :                                 }
    2976           0 :                                 break;
    2977             : #endif
    2978             :                         default:
    2979           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type");
    2980             :                 }
    2981             :         }
    2982             : 
    2983          11 :         php_openssl_write_rand_file(randfile, egdsocket, seeded);
    2984             : 
    2985          11 :         if (return_val == NULL) {
    2986           0 :                 EVP_PKEY_free(req->priv_key);
    2987           0 :                 req->priv_key = NULL;
    2988           0 :                 return NULL;
    2989             :         }
    2990             : 
    2991          11 :         return return_val;
    2992             : }
    2993             : /* }}} */
    2994             : 
    2995             : /* {{{ php_openssl_is_private_key
    2996             :         Check whether the supplied key is a private key by checking if the secret prime factors are set */
    2997          20 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
    2998             : {
    2999             :         assert(pkey != NULL);
    3000             : 
    3001          20 :         switch (pkey->type) {
    3002             : #ifndef NO_RSA
    3003             :                 case EVP_PKEY_RSA:
    3004             :                 case EVP_PKEY_RSA2:
    3005             :                         assert(pkey->pkey.rsa != NULL);
    3006          17 :                         if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q)) {
    3007           3 :                                 return 0;
    3008             :                         }
    3009          14 :                         break;
    3010             : #endif
    3011             : #ifndef NO_DSA
    3012             :                 case EVP_PKEY_DSA:
    3013             :                 case EVP_PKEY_DSA1:
    3014             :                 case EVP_PKEY_DSA2:
    3015             :                 case EVP_PKEY_DSA3:
    3016             :                 case EVP_PKEY_DSA4:
    3017             :                         assert(pkey->pkey.dsa != NULL);
    3018             : 
    3019           2 :                         if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){
    3020           1 :                                 return 0;
    3021             :                         }
    3022           1 :                         break;
    3023             : #endif
    3024             : #ifndef NO_DH
    3025             :                 case EVP_PKEY_DH:
    3026             :                         assert(pkey->pkey.dh != NULL);
    3027             : 
    3028           0 :                         if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key) {
    3029           0 :                                 return 0;
    3030             :                         }
    3031           0 :                         break;
    3032             : #endif
    3033             : #ifdef HAVE_EVP_PKEY_EC
    3034             :                 case EVP_PKEY_EC:
    3035             :                         assert(pkey->pkey.ec != NULL);
    3036             : 
    3037           1 :                         if ( NULL == EC_KEY_get0_private_key(pkey->pkey.ec)) {
    3038           0 :                                 return 0;
    3039             :                         }
    3040           1 :                         break;
    3041             : #endif
    3042             :                 default:
    3043           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3044             :                         break;
    3045             :         }
    3046          16 :         return 1;
    3047             : }
    3048             : /* }}} */
    3049             : 
    3050             : #define OPENSSL_PKEY_GET_BN(_type, _name) do {                                                  \
    3051             :                 if (pkey->pkey._type->_name != NULL) {                                                    \
    3052             :                         int len = BN_num_bytes(pkey->pkey._type->_name);                  \
    3053             :                         char *str = emalloc(len + 1);                                                           \
    3054             :                         BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)str);  \
    3055             :                         str[len] = 0;                                                   \
    3056             :                         add_assoc_stringl(_type, #_name, str, len, 0);                          \
    3057             :                 }                                                                                                                               \
    3058             :         } while (0)
    3059             : 
    3060             : #define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do {                                             \
    3061             :                 zval **bn;                                                                                                              \
    3062             :                 if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \
    3063             :                                 Z_TYPE_PP(bn) == IS_STRING) {                                                   \
    3064             :                         _type->_name = BN_bin2bn(                                                                    \
    3065             :                                 (unsigned char*)Z_STRVAL_PP(bn),                                                \
    3066             :                                 Z_STRLEN_PP(bn), NULL);                                                                 \
    3067             :             }                                                               \
    3068             :         } while (0);
    3069             : 
    3070             : 
    3071             : /* {{{ proto resource openssl_pkey_new([array configargs])
    3072             :    Generates a new private key */
    3073          12 : PHP_FUNCTION(openssl_pkey_new)
    3074             : {
    3075             :         struct php_x509_request req;
    3076          12 :         zval * args = NULL;
    3077             :         zval **data;
    3078             : 
    3079          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == FAILURE) {
    3080           0 :                 return;
    3081             :         }
    3082          12 :         RETVAL_FALSE;
    3083             : 
    3084          12 :         if (args && Z_TYPE_P(args) == IS_ARRAY) {
    3085             :                 EVP_PKEY *pkey;
    3086             : 
    3087           8 :                 if (zend_hash_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa"), (void**)&data) == SUCCESS &&
    3088           1 :                     Z_TYPE_PP(data) == IS_ARRAY) {
    3089           1 :                     pkey = EVP_PKEY_new();
    3090           1 :                     if (pkey) {
    3091           1 :                                 RSA *rsa = RSA_new();
    3092           1 :                                 if (rsa) {
    3093           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, n);
    3094           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, e);
    3095           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, d);
    3096           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, p);
    3097           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, q);
    3098           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmp1);
    3099           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmq1);
    3100           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp);
    3101           1 :                                         if (rsa->n && rsa->d) {
    3102           0 :                                                 if (EVP_PKEY_assign_RSA(pkey, rsa)) {
    3103           0 :                                                         RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
    3104             :                                                 }
    3105             :                                         }
    3106           1 :                                         RSA_free(rsa);
    3107             :                                 }
    3108           1 :                                 EVP_PKEY_free(pkey);
    3109             :                         }
    3110           1 :                         RETURN_FALSE;
    3111           7 :                 } else if (zend_hash_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa"), (void**)&data) == SUCCESS &&
    3112           1 :                            Z_TYPE_PP(data) == IS_ARRAY) {
    3113           1 :                     pkey = EVP_PKEY_new();
    3114           1 :                     if (pkey) {
    3115           1 :                                 DSA *dsa = DSA_new();
    3116           1 :                                 if (dsa) {
    3117           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, p);
    3118           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, q);
    3119           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, g);
    3120           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, priv_key);
    3121           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, pub_key);
    3122           1 :                                         if (dsa->p && dsa->q && dsa->g) {
    3123           0 :                                                 if (!dsa->priv_key && !dsa->pub_key) {
    3124           0 :                                                         DSA_generate_key(dsa);
    3125             :                                                 }
    3126           0 :                                                 if (EVP_PKEY_assign_DSA(pkey, dsa)) {
    3127           0 :                                                         RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
    3128             :                                                 }
    3129             :                                         }
    3130           1 :                                         DSA_free(dsa);
    3131             :                                 }
    3132           1 :                                 EVP_PKEY_free(pkey);
    3133             :                         }
    3134           1 :                         RETURN_FALSE;
    3135           6 :                 } else if (zend_hash_find(Z_ARRVAL_P(args), "dh", sizeof("dh"), (void**)&data) == SUCCESS &&
    3136           1 :                            Z_TYPE_PP(data) == IS_ARRAY) {
    3137           1 :                     pkey = EVP_PKEY_new();
    3138           1 :                     if (pkey) {
    3139           1 :                                 DH *dh = DH_new();
    3140           1 :                                 if (dh) {
    3141           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, p);
    3142           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, g);
    3143           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, priv_key);
    3144           1 :                                         OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, pub_key);
    3145           1 :                                         if (dh->p && dh->g) {
    3146           0 :                                                 if (!dh->pub_key) {
    3147           0 :                                                         DH_generate_key(dh);
    3148             :                                                 }
    3149           0 :                                                 if (EVP_PKEY_assign_DH(pkey, dh)) {
    3150           0 :                                                         RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
    3151             :                                                 }
    3152             :                                         }
    3153           1 :                                         DH_free(dh);
    3154             :                                 }
    3155           1 :                                 EVP_PKEY_free(pkey);
    3156             :                         }
    3157           1 :                         RETURN_FALSE;
    3158             :                 }
    3159             :         }
    3160             : 
    3161           9 :         PHP_SSL_REQ_INIT(&req);
    3162             : 
    3163           9 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
    3164             :         {
    3165           9 :                 if (php_openssl_generate_private_key(&req TSRMLS_CC)) {
    3166             :                         /* pass back a key resource */
    3167           9 :                         RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key TSRMLS_CC));
    3168             :                         /* make sure the cleanup code doesn't zap it! */
    3169           9 :                         req.priv_key = NULL;
    3170             :                 }
    3171             :         }
    3172           9 :         PHP_SSL_REQ_DISPOSE(&req);
    3173             : }
    3174             : /* }}} */
    3175             : 
    3176             : /* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
    3177             :    Gets an exportable representation of a key into a file */
    3178           1 : PHP_FUNCTION(openssl_pkey_export_to_file)
    3179             : {
    3180             :         struct php_x509_request req;
    3181           1 :         zval ** zpkey, * args = NULL;
    3182           1 :         char * passphrase = NULL; int passphrase_len = 0;
    3183           1 :         char * filename = NULL; int filename_len = 0;
    3184           1 :         long key_resource = -1;
    3185             :         EVP_PKEY * key;
    3186           1 :         BIO * bio_out = NULL;
    3187             :         const EVP_CIPHER * cipher;
    3188             : 
    3189           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
    3190           0 :                 return;
    3191             :         }
    3192           1 :         RETVAL_FALSE;
    3193             : 
    3194           1 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    3195             : 
    3196           1 :         if (key == NULL) {
    3197           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    3198           0 :                 RETURN_FALSE;
    3199             :         }
    3200             : 
    3201           1 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    3202           0 :                 RETURN_FALSE;
    3203             :         }
    3204             : 
    3205           1 :         PHP_SSL_REQ_INIT(&req);
    3206             : 
    3207           1 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    3208           1 :                 bio_out = BIO_new_file(filename, "w");
    3209             : 
    3210           2 :                 if (passphrase && req.priv_key_encrypt) {
    3211           1 :                         if (req.priv_key_encrypt_cipher) {
    3212           0 :                                 cipher = req.priv_key_encrypt_cipher;
    3213             :                         } else {
    3214           1 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    3215             :                         }
    3216             :                 } else {
    3217           0 :                         cipher = NULL;
    3218             :                 }
    3219           1 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    3220             :                         /* Success!
    3221             :                          * If returning the output as a string, do so now */
    3222           1 :                         RETVAL_TRUE;
    3223             :                 }
    3224             :         }
    3225           1 :         PHP_SSL_REQ_DISPOSE(&req);
    3226             : 
    3227           1 :         if (key_resource == -1 && key) {
    3228           0 :                 EVP_PKEY_free(key);
    3229             :         }
    3230           1 :         if (bio_out) {
    3231           1 :                 BIO_free(bio_out);
    3232             :         }
    3233             : }
    3234             : /* }}} */
    3235             : 
    3236             : /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
    3237             :    Gets an exportable representation of a key into a string or file */
    3238           3 : PHP_FUNCTION(openssl_pkey_export)
    3239             : {
    3240             :         struct php_x509_request req;
    3241           3 :         zval ** zpkey, * args = NULL, *out;
    3242           3 :         char * passphrase = NULL; int passphrase_len = 0;
    3243           3 :         long key_resource = -1;
    3244             :         EVP_PKEY * key;
    3245           3 :         BIO * bio_out = NULL;
    3246             :         const EVP_CIPHER * cipher;
    3247             : 
    3248           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
    3249           0 :                 return;
    3250             :         }
    3251           3 :         RETVAL_FALSE;
    3252             : 
    3253           3 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    3254             : 
    3255           3 :         if (key == NULL) {
    3256           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    3257           0 :                 RETURN_FALSE;
    3258             :         }
    3259             : 
    3260           3 :         PHP_SSL_REQ_INIT(&req);
    3261             : 
    3262           3 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    3263           3 :                 bio_out = BIO_new(BIO_s_mem());
    3264             : 
    3265           3 :                 if (passphrase && req.priv_key_encrypt) {
    3266           0 :                         if (req.priv_key_encrypt_cipher) {
    3267           0 :                                 cipher = req.priv_key_encrypt_cipher;
    3268             :                         } else {
    3269           0 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    3270             :                         }
    3271             :                 } else {
    3272           3 :                         cipher = NULL;
    3273             :                 }
    3274           3 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    3275             :                         /* Success!
    3276             :                          * If returning the output as a string, do so now */
    3277             : 
    3278             :                         char * bio_mem_ptr;
    3279             :                         long bio_mem_len;
    3280           3 :                         RETVAL_TRUE;
    3281             : 
    3282           3 :                         bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
    3283           3 :                         zval_dtor(out);
    3284           3 :                         ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len, 1);
    3285             :                 }
    3286             :         }
    3287           3 :         PHP_SSL_REQ_DISPOSE(&req);
    3288             : 
    3289           3 :         if (key_resource == -1 && key) {
    3290           0 :                 EVP_PKEY_free(key);
    3291             :         }
    3292           3 :         if (bio_out) {
    3293           3 :                 BIO_free(bio_out);
    3294             :         }
    3295             : }
    3296             : /* }}} */
    3297             : 
    3298             : /* {{{ proto int openssl_pkey_get_public(mixed cert)
    3299             :    Gets public key from X.509 certificate */
    3300           5 : PHP_FUNCTION(openssl_pkey_get_public)
    3301             : {
    3302             :         zval **cert;
    3303             :         EVP_PKEY *pkey;
    3304             : 
    3305           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
    3306           0 :                 return;
    3307             :         }
    3308           5 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    3309           5 :         pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    3310             : 
    3311           5 :         if (pkey == NULL) {
    3312           1 :                 RETURN_FALSE;
    3313             :         }
    3314           4 :         zend_list_addref(Z_LVAL_P(return_value));
    3315             : }
    3316             : /* }}} */
    3317             : 
    3318             : /* {{{ proto void openssl_pkey_free(int key)
    3319             :    Frees a key */
    3320           3 : PHP_FUNCTION(openssl_pkey_free)
    3321             : {
    3322             :         zval *key;
    3323             :         EVP_PKEY *pkey;
    3324             : 
    3325           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    3326           0 :                 return;
    3327             :         }
    3328           3 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
    3329           3 :         zend_list_delete(Z_LVAL_P(key));
    3330             : }
    3331             : /* }}} */
    3332             : 
    3333             : /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
    3334             :    Gets private keys */
    3335           8 : PHP_FUNCTION(openssl_pkey_get_private)
    3336             : {
    3337             :         zval **cert;
    3338             :         EVP_PKEY *pkey;
    3339           8 :         char * passphrase = "";
    3340           8 :         int passphrase_len = sizeof("")-1;
    3341             : 
    3342           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
    3343           0 :                 return;
    3344             :         }
    3345           8 :         Z_TYPE_P(return_value) = IS_RESOURCE;
    3346           8 :         pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
    3347             : 
    3348           8 :         if (pkey == NULL) {
    3349           0 :                 RETURN_FALSE;
    3350             :         }
    3351           8 :         zend_list_addref(Z_LVAL_P(return_value));
    3352             : }
    3353             : 
    3354             : /* }}} */
    3355             : 
    3356             : /* {{{ proto resource openssl_pkey_get_details(resource key)
    3357             :         returns an array with the key details (bits, pkey, type)*/
    3358           4 : PHP_FUNCTION(openssl_pkey_get_details)
    3359             : {
    3360             :         zval *key;
    3361             :         EVP_PKEY *pkey;
    3362             :         BIO *out;
    3363             :         unsigned int pbio_len;
    3364             :         char *pbio;
    3365             :         long ktype;
    3366             : 
    3367           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    3368           3 :                 return;
    3369             :         }
    3370           1 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
    3371           1 :         if (!pkey) {
    3372           0 :                 RETURN_FALSE;
    3373             :         }
    3374           1 :         out = BIO_new(BIO_s_mem());
    3375           1 :         PEM_write_bio_PUBKEY(out, pkey);
    3376           1 :         pbio_len = BIO_get_mem_data(out, &pbio);
    3377             : 
    3378           1 :         array_init(return_value);
    3379           1 :         add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
    3380           1 :         add_assoc_stringl(return_value, "key", pbio, pbio_len, 1);
    3381             :         /*TODO: Use the real values once the openssl constants are used
    3382             :          * See the enum at the top of this file
    3383             :          */
    3384           1 :         switch (EVP_PKEY_type(pkey->type)) {
    3385             :                 case EVP_PKEY_RSA:
    3386             :                 case EVP_PKEY_RSA2:
    3387           1 :                         ktype = OPENSSL_KEYTYPE_RSA;
    3388             : 
    3389           1 :                         if (pkey->pkey.rsa != NULL) {
    3390             :                                 zval *rsa;
    3391             : 
    3392           1 :                                 ALLOC_INIT_ZVAL(rsa);
    3393           1 :                                 array_init(rsa);
    3394           1 :                                 OPENSSL_PKEY_GET_BN(rsa, n);
    3395           1 :                                 OPENSSL_PKEY_GET_BN(rsa, e);
    3396           1 :                                 OPENSSL_PKEY_GET_BN(rsa, d);
    3397           1 :                                 OPENSSL_PKEY_GET_BN(rsa, p);
    3398           1 :                                 OPENSSL_PKEY_GET_BN(rsa, q);
    3399           1 :                                 OPENSSL_PKEY_GET_BN(rsa, dmp1);
    3400           1 :                                 OPENSSL_PKEY_GET_BN(rsa, dmq1);
    3401           1 :                                 OPENSSL_PKEY_GET_BN(rsa, iqmp);
    3402           1 :                                 add_assoc_zval(return_value, "rsa", rsa);
    3403             :                         }
    3404             : 
    3405           1 :                         break;
    3406             :                 case EVP_PKEY_DSA:
    3407             :                 case EVP_PKEY_DSA2:
    3408             :                 case EVP_PKEY_DSA3:
    3409             :                 case EVP_PKEY_DSA4:
    3410           0 :                         ktype = OPENSSL_KEYTYPE_DSA;
    3411             : 
    3412           0 :                         if (pkey->pkey.dsa != NULL) {
    3413             :                                 zval *dsa;
    3414             : 
    3415           0 :                                 ALLOC_INIT_ZVAL(dsa);
    3416           0 :                                 array_init(dsa);
    3417           0 :                                 OPENSSL_PKEY_GET_BN(dsa, p);
    3418           0 :                                 OPENSSL_PKEY_GET_BN(dsa, q);
    3419           0 :                                 OPENSSL_PKEY_GET_BN(dsa, g);
    3420           0 :                                 OPENSSL_PKEY_GET_BN(dsa, priv_key);
    3421           0 :                                 OPENSSL_PKEY_GET_BN(dsa, pub_key);
    3422           0 :                                 add_assoc_zval(return_value, "dsa", dsa);
    3423             :                         }
    3424           0 :                         break;
    3425             :                 case EVP_PKEY_DH:
    3426             : 
    3427           0 :                         ktype = OPENSSL_KEYTYPE_DH;
    3428             : 
    3429           0 :                         if (pkey->pkey.dh != NULL) {
    3430             :                                 zval *dh;
    3431             : 
    3432           0 :                                 ALLOC_INIT_ZVAL(dh);
    3433           0 :                                 array_init(dh);
    3434           0 :                                 OPENSSL_PKEY_GET_BN(dh, p);
    3435           0 :                                 OPENSSL_PKEY_GET_BN(dh, g);
    3436           0 :                                 OPENSSL_PKEY_GET_BN(dh, priv_key);
    3437           0 :                                 OPENSSL_PKEY_GET_BN(dh, pub_key);
    3438           0 :                                 add_assoc_zval(return_value, "dh", dh);
    3439             :                         }
    3440             : 
    3441           0 :                         break;
    3442             : #ifdef HAVE_EVP_PKEY_EC
    3443             :                 case EVP_PKEY_EC:
    3444           0 :                         ktype = OPENSSL_KEYTYPE_EC;
    3445           0 :                         break;
    3446             : #endif
    3447             :                 default:
    3448           0 :                         ktype = -1;
    3449             :                         break;
    3450             :         }
    3451           1 :         add_assoc_long(return_value, "type", ktype);
    3452             : 
    3453           1 :         BIO_free(out);
    3454             : }
    3455             : /* }}} */
    3456             : 
    3457             : /* }}} */
    3458             : 
    3459             : /* {{{ PKCS7 S/MIME functions */
    3460             : 
    3461             : /* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
    3462             :    Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
    3463           0 : PHP_FUNCTION(openssl_pkcs7_verify)
    3464             : {
    3465           0 :         X509_STORE * store = NULL;
    3466           0 :         zval * cainfo = NULL;
    3467           0 :         STACK_OF(X509) *signers= NULL;
    3468           0 :         STACK_OF(X509) *others = NULL;
    3469           0 :         PKCS7 * p7 = NULL;
    3470           0 :         BIO * in = NULL, * datain = NULL, * dataout = NULL;
    3471           0 :         long flags = 0;
    3472             :         char * filename; int filename_len;
    3473           0 :         char * extracerts = NULL; int extracerts_len = 0;
    3474           0 :         char * signersfilename = NULL; int signersfilename_len = 0;
    3475           0 :         char * datafilename = NULL; int datafilename_len = 0;
    3476             : 
    3477           0 :         RETVAL_LONG(-1);
    3478             : 
    3479           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pl|papp", &filename, &filename_len,
    3480             :                                 &flags, &signersfilename, &signersfilename_len, &cainfo,
    3481             :                                 &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
    3482           0 :                 return;
    3483             :         }
    3484             : 
    3485           0 :         if (extracerts) {
    3486           0 :                 others = load_all_certs_from_file(extracerts);
    3487           0 :                 if (others == NULL) {
    3488           0 :                         goto clean_exit;
    3489             :                 }
    3490             :         }
    3491             : 
    3492           0 :         flags = flags & ~PKCS7_DETACHED;
    3493             : 
    3494           0 :         store = setup_verify(cainfo TSRMLS_CC);
    3495             : 
    3496           0 :         if (!store) {
    3497           0 :                 goto clean_exit;
    3498             :         }
    3499           0 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    3500           0 :                 goto clean_exit;
    3501             :         }
    3502             : 
    3503           0 :         in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
    3504           0 :         if (in == NULL) {
    3505           0 :                 goto clean_exit;
    3506             :         }
    3507           0 :         p7 = SMIME_read_PKCS7(in, &datain);
    3508           0 :         if (p7 == NULL) {
    3509             : #if DEBUG_SMIME
    3510             :                 zend_printf("SMIME_read_PKCS7 failed\n");
    3511             : #endif
    3512           0 :                 goto clean_exit;
    3513             :         }
    3514             : 
    3515           0 :         if (datafilename) {
    3516             : 
    3517           0 :                 if (php_openssl_open_base_dir_chk(datafilename TSRMLS_CC)) {
    3518           0 :                         goto clean_exit;
    3519             :                 }
    3520             : 
    3521           0 :                 dataout = BIO_new_file(datafilename, "w");
    3522           0 :                 if (dataout == NULL) {
    3523           0 :                         goto clean_exit;
    3524             :                 }
    3525             :         }
    3526             : #if DEBUG_SMIME
    3527             :         zend_printf("Calling PKCS7 verify\n");
    3528             : #endif
    3529             : 
    3530           0 :         if (PKCS7_verify(p7, others, store, datain, dataout, flags)) {
    3531             : 
    3532           0 :                 RETVAL_TRUE;
    3533             : 
    3534           0 :                 if (signersfilename) {
    3535             :                         BIO *certout;
    3536             : 
    3537           0 :                         if (php_openssl_open_base_dir_chk(signersfilename TSRMLS_CC)) {
    3538           0 :                                 goto clean_exit;
    3539             :                         }
    3540             : 
    3541           0 :                         certout = BIO_new_file(signersfilename, "w");
    3542           0 :                         if (certout) {
    3543             :                                 int i;
    3544           0 :                                 signers = PKCS7_get0_signers(p7, NULL, flags);
    3545             : 
    3546           0 :                                 for(i = 0; i < sk_X509_num(signers); i++) {
    3547           0 :                                         PEM_write_bio_X509(certout, sk_X509_value(signers, i));
    3548             :                                 }
    3549           0 :                                 BIO_free(certout);
    3550           0 :                                 sk_X509_free(signers);
    3551             :                         } else {
    3552           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
    3553           0 :                                 RETVAL_LONG(-1);
    3554             :                         }
    3555             :                 }
    3556           0 :                 goto clean_exit;
    3557             :         } else {
    3558           0 :                 RETVAL_FALSE;
    3559             :         }
    3560             : clean_exit:
    3561           0 :         X509_STORE_free(store);
    3562           0 :         BIO_free(datain);
    3563           0 :         BIO_free(in);
    3564           0 :         BIO_free(dataout);
    3565           0 :         PKCS7_free(p7);
    3566           0 :         sk_X509_free(others);
    3567             : }
    3568             : /* }}} */
    3569             : 
    3570             : /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
    3571             :    Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
    3572          12 : PHP_FUNCTION(openssl_pkcs7_encrypt)
    3573             : {
    3574          12 :         zval ** zrecipcerts, * zheaders = NULL;
    3575          12 :         STACK_OF(X509) * recipcerts = NULL;
    3576          12 :         BIO * infile = NULL, * outfile = NULL;
    3577          12 :         long flags = 0;
    3578          12 :         PKCS7 * p7 = NULL;
    3579             :         HashPosition hpos;
    3580             :         zval ** zcertval;
    3581             :         X509 * cert;
    3582          12 :         const EVP_CIPHER *cipher = NULL;
    3583          12 :         long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
    3584             :         uint strindexlen;
    3585             :         ulong intindex;
    3586             :         char * strindex;
    3587          12 :         char * infilename = NULL;       int infilename_len;
    3588          12 :         char * outfilename = NULL;      int outfilename_len;
    3589             : 
    3590          12 :         RETVAL_FALSE;
    3591             : 
    3592          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZa!|ll", &infilename, &infilename_len,
    3593             :                                 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
    3594           2 :                 return;
    3595             : 
    3596             : 
    3597          10 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    3598           0 :                 return;
    3599             :         }
    3600             : 
    3601          10 :         infile = BIO_new_file(infilename, "r");
    3602          10 :         if (infile == NULL) {
    3603           2 :                 goto clean_exit;
    3604             :         }
    3605             : 
    3606           8 :         outfile = BIO_new_file(outfilename, "w");
    3607           8 :         if (outfile == NULL) {
    3608           1 :                 goto clean_exit;
    3609             :         }
    3610             : 
    3611           7 :         recipcerts = sk_X509_new_null();
    3612             : 
    3613             :         /* get certs */
    3614           7 :         if (Z_TYPE_PP(zrecipcerts) == IS_ARRAY) {
    3615           1 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(*zrecipcerts), &hpos);
    3616           4 :                 while(zend_hash_get_current_data_ex(HASH_OF(*zrecipcerts), (void**)&zcertval, &hpos) == SUCCESS) {
    3617             :                         long certresource;
    3618             : 
    3619           2 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
    3620           2 :                         if (cert == NULL) {
    3621           0 :                                 goto clean_exit;
    3622             :                         }
    3623             : 
    3624           2 :                         if (certresource != -1) {
    3625             :                                 /* we shouldn't free this particular cert, as it is a resource.
    3626             :                                         make a copy and push that on the stack instead */
    3627           0 :                                 cert = X509_dup(cert);
    3628           0 :                                 if (cert == NULL) {
    3629           0 :                                         goto clean_exit;
    3630             :                                 }
    3631             :                         }
    3632           2 :                         sk_X509_push(recipcerts, cert);
    3633             : 
    3634           2 :                         zend_hash_move_forward_ex(HASH_OF(*zrecipcerts), &hpos);
    3635             :                 }
    3636             :         } else {
    3637             :                 /* a single certificate */
    3638             :                 long certresource;
    3639             : 
    3640           6 :                 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource TSRMLS_CC);
    3641           6 :                 if (cert == NULL) {
    3642           2 :                         goto clean_exit;
    3643             :                 }
    3644             : 
    3645           4 :                 if (certresource != -1) {
    3646             :                         /* we shouldn't free this particular cert, as it is a resource.
    3647             :                                 make a copy and push that on the stack instead */
    3648           0 :                         cert = X509_dup(cert);
    3649           0 :                         if (cert == NULL) {
    3650           0 :                                 goto clean_exit;
    3651             :                         }
    3652             :                 }
    3653           4 :                 sk_X509_push(recipcerts, cert);
    3654             :         }
    3655             : 
    3656             :         /* sanity check the cipher */
    3657           5 :         cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
    3658           5 :         if (cipher == NULL) {
    3659             :                 /* shouldn't happen */
    3660           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher");
    3661           0 :                 goto clean_exit;
    3662             :         }
    3663             : 
    3664           5 :         p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, flags);
    3665             : 
    3666           5 :         if (p7 == NULL) {
    3667           0 :                 goto clean_exit;
    3668             :         }
    3669             : 
    3670             :         /* tack on extra headers */
    3671           5 :         if (zheaders) {
    3672           5 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
    3673          18 :                 while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&zcertval, &hpos) == SUCCESS) {
    3674           8 :                         strindex = NULL;
    3675           8 :                         zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
    3676             : 
    3677           8 :                         convert_to_string_ex(zcertval);
    3678             : 
    3679           8 :                         if (strindex) {
    3680           2 :                                 BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(zcertval));
    3681             :                         } else {
    3682           6 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_PP(zcertval));
    3683             :                         }
    3684             : 
    3685           8 :                         zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
    3686             :                 }
    3687             :         }
    3688             : 
    3689           5 :         (void)BIO_reset(infile);
    3690             : 
    3691             :         /* write the encrypted data */
    3692           5 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    3693             : 
    3694           5 :         RETVAL_TRUE;
    3695             : 
    3696             : clean_exit:
    3697          10 :         PKCS7_free(p7);
    3698          10 :         BIO_free(infile);
    3699          10 :         BIO_free(outfile);
    3700          10 :         if (recipcerts) {
    3701           7 :                 sk_X509_pop_free(recipcerts, X509_free);
    3702             :         }
    3703             : }
    3704             : /* }}} */
    3705             : 
    3706             : /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
    3707             :    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 */
    3708             : 
    3709          11 : PHP_FUNCTION(openssl_pkcs7_sign)
    3710             : {
    3711             :         zval ** zcert, ** zprivkey, * zheaders;
    3712             :         zval ** hval;
    3713          11 :         X509 * cert = NULL;
    3714          11 :         EVP_PKEY * privkey = NULL;
    3715          11 :         long flags = PKCS7_DETACHED;
    3716          11 :         PKCS7 * p7 = NULL;
    3717          11 :         BIO * infile = NULL, * outfile = NULL;
    3718          11 :         STACK_OF(X509) *others = NULL;
    3719          11 :         long certresource = -1, keyresource = -1;
    3720             :         ulong intindex;
    3721             :         uint strindexlen;
    3722             :         HashPosition hpos;
    3723             :         char * strindex;
    3724             :         char * infilename;      int infilename_len;
    3725             :         char * outfilename;     int outfilename_len;
    3726          11 :         char * extracertsfilename = NULL; int extracertsfilename_len;
    3727             : 
    3728          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZZa!|lp",
    3729             :                                 &infilename, &infilename_len, &outfilename, &outfilename_len,
    3730             :                                 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
    3731             :                                 &extracertsfilename_len) == FAILURE) {
    3732           2 :                 return;
    3733             :         }
    3734             : 
    3735           9 :         RETVAL_FALSE;
    3736             : 
    3737           9 :         if (extracertsfilename) {
    3738           0 :                 others = load_all_certs_from_file(extracertsfilename);
    3739           0 :                 if (others == NULL) {
    3740           0 :                         goto clean_exit;
    3741             :                 }
    3742             :         }
    3743             : 
    3744           9 :         privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource TSRMLS_CC);
    3745           9 :         if (privkey == NULL) {
    3746           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting private key");
    3747           1 :                 goto clean_exit;
    3748             :         }
    3749             : 
    3750           8 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    3751           8 :         if (cert == NULL) {
    3752           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting cert");
    3753           2 :                 goto clean_exit;
    3754             :         }
    3755             : 
    3756           6 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    3757             :                 goto clean_exit;
    3758             :         }
    3759             : 
    3760           6 :         infile = BIO_new_file(infilename, "r");
    3761           6 :         if (infile == NULL) {
    3762           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening input file %s!", infilename);
    3763           2 :                 goto clean_exit;
    3764             :         }
    3765             : 
    3766           4 :         outfile = BIO_new_file(outfilename, "w");
    3767           4 :         if (outfile == NULL) {
    3768           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening output file %s!", outfilename);
    3769           1 :                 goto clean_exit;
    3770             :         }
    3771             : 
    3772           3 :         p7 = PKCS7_sign(cert, privkey, others, infile, flags);
    3773           3 :         if (p7 == NULL) {
    3774           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error creating PKCS7 structure!");
    3775           0 :                 goto clean_exit;
    3776             :         }
    3777             : 
    3778           3 :         (void)BIO_reset(infile);
    3779             : 
    3780             :         /* tack on extra headers */
    3781           3 :         if (zheaders) {
    3782           3 :                 zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
    3783          10 :                 while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&hval, &hpos) == SUCCESS) {
    3784           4 :                         strindex = NULL;
    3785           4 :                         zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
    3786             : 
    3787           4 :                         convert_to_string_ex(hval);
    3788             : 
    3789           4 :                         if (strindex) {
    3790           2 :                                 BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(hval));
    3791             :                         } else {
    3792           2 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_PP(hval));
    3793             :                         }
    3794           4 :                         zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
    3795             :                 }
    3796             :         }
    3797             :         /* write the signed data */
    3798           3 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    3799             : 
    3800           3 :         RETVAL_TRUE;
    3801             : 
    3802             : clean_exit:
    3803           9 :         PKCS7_free(p7);
    3804           9 :         BIO_free(infile);
    3805           9 :         BIO_free(outfile);
    3806           9 :         if (others) {
    3807           0 :                 sk_X509_pop_free(others, X509_free);
    3808             :         }
    3809           9 :         if (privkey && keyresource == -1) {
    3810           8 :                 EVP_PKEY_free(privkey);
    3811             :         }
    3812           9 :         if (cert && certresource == -1) {
    3813           6 :                 X509_free(cert);
    3814             :         }
    3815             : }
    3816             : /* }}} */
    3817             : 
    3818             : /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
    3819             :    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 */
    3820             : 
    3821          15 : PHP_FUNCTION(openssl_pkcs7_decrypt)
    3822             : {
    3823          15 :         zval ** recipcert, ** recipkey = NULL;
    3824          15 :         X509 * cert = NULL;
    3825          15 :         EVP_PKEY * key = NULL;
    3826             :         long certresval, keyresval;
    3827          15 :         BIO * in = NULL, * out = NULL, * datain = NULL;
    3828          15 :         PKCS7 * p7 = NULL;
    3829             :         char * infilename;      int infilename_len;
    3830             :         char * outfilename;     int outfilename_len;
    3831             : 
    3832          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppZ|Z", &infilename, &infilename_len,
    3833             :                                 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
    3834           0 :                 return;
    3835             :         }
    3836             : 
    3837          15 :         RETVAL_FALSE;
    3838             : 
    3839          15 :         cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC);
    3840          15 :         if (cert == NULL) {
    3841           8 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert");
    3842           8 :                 goto clean_exit;
    3843             :         }
    3844             : 
    3845           7 :         key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval TSRMLS_CC);
    3846           7 :         if (key == NULL) {
    3847           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key");
    3848           2 :                 goto clean_exit;
    3849             :         }
    3850             : 
    3851           5 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    3852             :                 goto clean_exit;
    3853             :         }
    3854             : 
    3855           5 :         in = BIO_new_file(infilename, "r");
    3856           5 :         if (in == NULL) {
    3857           2 :                 goto clean_exit;
    3858             :         }
    3859           3 :         out = BIO_new_file(outfilename, "w");
    3860           3 :         if (out == NULL) {
    3861           1 :                 goto clean_exit;
    3862             :         }
    3863             : 
    3864           2 :         p7 = SMIME_read_PKCS7(in, &datain);
    3865             : 
    3866           2 :         if (p7 == NULL) {
    3867           0 :                 goto clean_exit;
    3868             :         }
    3869           2 :         if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) {
    3870           2 :                 RETVAL_TRUE;
    3871             :         }
    3872             : clean_exit:
    3873          15 :         PKCS7_free(p7);
    3874          15 :         BIO_free(datain);
    3875          15 :         BIO_free(in);
    3876          15 :         BIO_free(out);
    3877          15 :         if (cert && certresval == -1) {
    3878           7 :                 X509_free(cert);
    3879             :         }
    3880          15 :         if (key && keyresval == -1) {
    3881           5 :                 EVP_PKEY_free(key);
    3882             :         }
    3883             : }
    3884             : /* }}} */
    3885             : 
    3886             : /* }}} */
    3887             : 
    3888             : /* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
    3889             :    Encrypts data with private key */
    3890           6 : PHP_FUNCTION(openssl_private_encrypt)
    3891             : {
    3892             :         zval **key, *crypted;
    3893             :         EVP_PKEY *pkey;
    3894             :         int cryptedlen;
    3895           6 :         unsigned char *cryptedbuf = NULL;
    3896           6 :         int successful = 0;
    3897           6 :         long keyresource = -1;
    3898             :         char * data;
    3899             :         int data_len;
    3900           6 :         long padding = RSA_PKCS1_PADDING;
    3901             : 
    3902           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    3903           0 :                 return;
    3904             :         }
    3905           6 :         RETVAL_FALSE;
    3906             : 
    3907           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    3908             : 
    3909           6 :         if (pkey == NULL) {
    3910           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key param is not a valid private key");
    3911           3 :                 RETURN_FALSE;
    3912             :         }
    3913             : 
    3914           3 :         cryptedlen = EVP_PKEY_size(pkey);
    3915           3 :         cryptedbuf = emalloc(cryptedlen + 1);
    3916             : 
    3917           3 :         switch (pkey->type) {
    3918             :                 case EVP_PKEY_RSA:
    3919             :                 case EVP_PKEY_RSA2:
    3920           6 :                         successful =  (RSA_private_encrypt(data_len,
    3921             :                                                 (unsigned char *)data,
    3922             :                                                 cryptedbuf,
    3923           3 :                                                 pkey->pkey.rsa,
    3924             :                                                 padding) == cryptedlen);
    3925           3 :                         break;
    3926             :                 default:
    3927           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3928             :         }
    3929             : 
    3930           3 :         if (successful) {
    3931           3 :                 zval_dtor(crypted);
    3932           3 :                 cryptedbuf[cryptedlen] = '\0';
    3933           3 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3934           3 :                 cryptedbuf = NULL;
    3935           3 :                 RETVAL_TRUE;
    3936             :         }
    3937           3 :         if (cryptedbuf) {
    3938           0 :                 efree(cryptedbuf);
    3939             :         }
    3940           3 :         if (keyresource == -1) {
    3941           3 :                 EVP_PKEY_free(pkey);
    3942             :         }
    3943             : }
    3944             : /* }}} */
    3945             : 
    3946             : /* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding])
    3947             :    Decrypts data with private key */
    3948           6 : PHP_FUNCTION(openssl_private_decrypt)
    3949             : {
    3950             :         zval **key, *crypted;
    3951             :         EVP_PKEY *pkey;
    3952             :         int cryptedlen;
    3953           6 :         unsigned char *cryptedbuf = NULL;
    3954             :         unsigned char *crypttemp;
    3955           6 :         int successful = 0;
    3956           6 :         long padding = RSA_PKCS1_PADDING;
    3957           6 :         long keyresource = -1;
    3958             :         char * data;
    3959             :         int data_len;
    3960             : 
    3961           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    3962           0 :                 return;
    3963             :         }
    3964           6 :         RETVAL_FALSE;
    3965             : 
    3966           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    3967           6 :         if (pkey == NULL) {
    3968           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid private key");
    3969           2 :                 RETURN_FALSE;
    3970             :         }
    3971             : 
    3972           4 :         cryptedlen = EVP_PKEY_size(pkey);
    3973           4 :         crypttemp = emalloc(cryptedlen + 1);
    3974             : 
    3975           4 :         switch (pkey->type) {
    3976             :                 case EVP_PKEY_RSA:
    3977             :                 case EVP_PKEY_RSA2:
    3978           8 :                         cryptedlen = RSA_private_decrypt(data_len,
    3979             :                                         (unsigned char *)data,
    3980             :                                         crypttemp,
    3981           4 :                                         pkey->pkey.rsa,
    3982             :                                         padding);
    3983           4 :                         if (cryptedlen != -1) {
    3984           3 :                                 cryptedbuf = emalloc(cryptedlen + 1);
    3985           3 :                                 memcpy(cryptedbuf, crypttemp, cryptedlen);
    3986           3 :                                 successful = 1;
    3987             :                         }
    3988           4 :                         break;
    3989             :                 default:
    3990           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    3991             :         }
    3992             : 
    3993           4 :         efree(crypttemp);
    3994             : 
    3995           4 :         if (successful) {
    3996           3 :                 zval_dtor(crypted);
    3997           3 :                 cryptedbuf[cryptedlen] = '\0';
    3998           3 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    3999           3 :                 cryptedbuf = NULL;
    4000           3 :                 RETVAL_TRUE;
    4001             :         }
    4002             : 
    4003           4 :         if (keyresource == -1) {
    4004           4 :                 EVP_PKEY_free(pkey);
    4005             :         }
    4006           4 :         if (cryptedbuf) {
    4007           0 :                 efree(cryptedbuf);
    4008             :         }
    4009             : }
    4010             : /* }}} */
    4011             : 
    4012             : /* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding])
    4013             :    Encrypts data with public key */
    4014           6 : PHP_FUNCTION(openssl_public_encrypt)
    4015             : {
    4016             :         zval **key, *crypted;
    4017             :         EVP_PKEY *pkey;
    4018             :         int cryptedlen;
    4019             :         unsigned char *cryptedbuf;
    4020           6 :         int successful = 0;
    4021           6 :         long keyresource = -1;
    4022           6 :         long padding = RSA_PKCS1_PADDING;
    4023             :         char * data;
    4024             :         int data_len;
    4025             : 
    4026           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
    4027           0 :                 return;
    4028             : 
    4029           6 :         RETVAL_FALSE;
    4030             : 
    4031           6 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4032           6 :         if (pkey == NULL) {
    4033           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
    4034           3 :                 RETURN_FALSE;
    4035             :         }
    4036             : 
    4037           3 :         cryptedlen = EVP_PKEY_size(pkey);
    4038           3 :         cryptedbuf = emalloc(cryptedlen + 1);
    4039             : 
    4040           3 :         switch (pkey->type) {
    4041             :                 case EVP_PKEY_RSA:
    4042             :                 case EVP_PKEY_RSA2:
    4043           6 :                         successful = (RSA_public_encrypt(data_len,
    4044             :                                                 (unsigned char *)data,
    4045             :                                                 cryptedbuf,
    4046           3 :                                                 pkey->pkey.rsa,
    4047             :                                                 padding) == cryptedlen);
    4048           3 :                         break;
    4049             :                 default:
    4050           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4051             : 
    4052             :         }
    4053             : 
    4054           3 :         if (successful) {
    4055           3 :                 zval_dtor(crypted);
    4056           3 :                 cryptedbuf[cryptedlen] = '\0';
    4057           3 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    4058           3 :                 cryptedbuf = NULL;
    4059           3 :                 RETVAL_TRUE;
    4060             :         }
    4061           3 :         if (keyresource == -1) {
    4062           3 :                 EVP_PKEY_free(pkey);
    4063             :         }
    4064           3 :         if (cryptedbuf) {
    4065           0 :                 efree(cryptedbuf);
    4066             :         }
    4067             : }
    4068             : /* }}} */
    4069             : 
    4070             : /* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding])
    4071             :    Decrypts data with public key */
    4072           7 : PHP_FUNCTION(openssl_public_decrypt)
    4073             : {
    4074             :         zval **key, *crypted;
    4075             :         EVP_PKEY *pkey;
    4076             :         int cryptedlen;
    4077           7 :         unsigned char *cryptedbuf = NULL;
    4078             :         unsigned char *crypttemp;
    4079           7 :         int successful = 0;
    4080           7 :         long keyresource = -1;
    4081           7 :         long padding = RSA_PKCS1_PADDING;
    4082             :         char * data;
    4083             :         int data_len;
    4084             : 
    4085           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    4086           0 :                 return;
    4087             :         }
    4088           7 :         RETVAL_FALSE;
    4089             : 
    4090           7 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4091           7 :         if (pkey == NULL) {
    4092           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
    4093           3 :                 RETURN_FALSE;
    4094             :         }
    4095             : 
    4096           4 :         cryptedlen = EVP_PKEY_size(pkey);
    4097           4 :         crypttemp = emalloc(cryptedlen + 1);
    4098             : 
    4099           4 :         switch (pkey->type) {
    4100             :                 case EVP_PKEY_RSA:
    4101             :                 case EVP_PKEY_RSA2:
    4102           8 :                         cryptedlen = RSA_public_decrypt(data_len,
    4103             :                                         (unsigned char *)data,
    4104             :                                         crypttemp,
    4105           4 :                                         pkey->pkey.rsa,
    4106             :                                         padding);
    4107           4 :                         if (cryptedlen != -1) {
    4108           3 :                                 cryptedbuf = emalloc(cryptedlen + 1);
    4109           3 :                                 memcpy(cryptedbuf, crypttemp, cryptedlen);
    4110           3 :                                 successful = 1;
    4111             :                         }
    4112           4 :                         break;
    4113             : 
    4114             :                 default:
    4115           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4116             : 
    4117             :         }
    4118             : 
    4119           4 :         efree(crypttemp);
    4120             : 
    4121           4 :         if (successful) {
    4122           3 :                 zval_dtor(crypted);
    4123           3 :                 cryptedbuf[cryptedlen] = '\0';
    4124           3 :                 ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
    4125           3 :                 cryptedbuf = NULL;
    4126           3 :                 RETVAL_TRUE;
    4127             :         }
    4128             : 
    4129           4 :         if (cryptedbuf) {
    4130           0 :                 efree(cryptedbuf);
    4131             :         }
    4132           4 :         if (keyresource == -1) {
    4133           4 :                 EVP_PKEY_free(pkey);
    4134             :         }
    4135             : }
    4136             : /* }}} */
    4137             : 
    4138             : /* {{{ proto mixed openssl_error_string(void)
    4139             :    Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
    4140           2 : PHP_FUNCTION(openssl_error_string)
    4141             : {
    4142             :         char buf[512];
    4143             :         unsigned long val;
    4144             : 
    4145           2 :         if (zend_parse_parameters_none() == FAILURE) {
    4146           0 :                 return;
    4147             :         }
    4148             : 
    4149           2 :         val = ERR_get_error();
    4150           2 :         if (val) {
    4151           1 :                 RETURN_STRING(ERR_error_string(val, buf), 1);
    4152             :         } else {
    4153           1 :                 RETURN_FALSE;
    4154             :         }
    4155             : }
    4156             : /* }}} */
    4157             : 
    4158             : /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
    4159             :    Signs data */
    4160           7 : PHP_FUNCTION(openssl_sign)
    4161             : {
    4162             :         zval **key, *signature;
    4163             :         EVP_PKEY *pkey;
    4164             :         int siglen;
    4165             :         unsigned char *sigbuf;
    4166           7 :         long keyresource = -1;
    4167             :         char * data;
    4168             :         int data_len;
    4169             :         EVP_MD_CTX md_ctx;
    4170           7 :         zval *method = NULL;
    4171           7 :         long signature_algo = OPENSSL_ALGO_SHA1;
    4172             :         const EVP_MD *mdtype;
    4173             : 
    4174           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
    4175           1 :                 return;
    4176             :         }
    4177           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    4178           6 :         if (pkey == NULL) {
    4179           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a private key");
    4180           1 :                 RETURN_FALSE;
    4181             :         }
    4182             : 
    4183           9 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    4184           4 :                 if (method != NULL) {
    4185           2 :                         signature_algo = Z_LVAL_P(method);
    4186             :                 }
    4187           4 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    4188           1 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    4189           1 :                 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
    4190             :         } else {
    4191           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4192           0 :                 RETURN_FALSE;
    4193             :         }
    4194           5 :         if (!mdtype) {
    4195           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4196           0 :                 RETURN_FALSE;
    4197             :         }
    4198             : 
    4199           5 :         siglen = EVP_PKEY_size(pkey);
    4200           5 :         sigbuf = emalloc(siglen + 1);
    4201             : 
    4202           5 :         EVP_SignInit(&md_ctx, mdtype);
    4203           5 :         EVP_SignUpdate(&md_ctx, data, data_len);
    4204           5 :         if (EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) {
    4205           5 :                 zval_dtor(signature);
    4206           5 :                 sigbuf[siglen] = '\0';
    4207           5 :                 ZVAL_STRINGL(signature, (char *)sigbuf, siglen, 0);
    4208           5 :                 RETVAL_TRUE;
    4209             :         } else {
    4210           0 :                 efree(sigbuf);
    4211           0 :                 RETVAL_FALSE;
    4212             :         }
    4213           5 :         EVP_MD_CTX_cleanup(&md_ctx);
    4214           5 :         if (keyresource == -1) {
    4215           2 :                 EVP_PKEY_free(pkey);
    4216             :         }
    4217             : }
    4218             : /* }}} */
    4219             : 
    4220             : /* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
    4221             :    Verifys data */
    4222          16 : PHP_FUNCTION(openssl_verify)
    4223             : {
    4224             :         zval **key;
    4225             :         EVP_PKEY *pkey;
    4226             :         int err;
    4227             :         EVP_MD_CTX     md_ctx;
    4228             :         const EVP_MD *mdtype;
    4229          16 :         long keyresource = -1;
    4230             :         char * data;    int data_len;
    4231             :         char * signature;       int signature_len;
    4232          16 :         zval *method = NULL;
    4233          16 :         long signature_algo = OPENSSL_ALGO_SHA1;
    4234             : 
    4235          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
    4236           5 :                 return;
    4237             :         }
    4238             : 
    4239          22 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    4240          11 :                 if (method != NULL) {
    4241           5 :                         signature_algo = Z_LVAL_P(method);
    4242             :                 }
    4243          11 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    4244           0 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    4245           0 :                 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
    4246             :         } else {
    4247           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4248           0 :                 RETURN_FALSE;
    4249             :         }
    4250          11 :         if (!mdtype) {
    4251           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4252           0 :                 RETURN_FALSE;
    4253             :         }
    4254             : 
    4255          11 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4256          11 :         if (pkey == NULL) {
    4257           5 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a public key");
    4258           5 :                 RETURN_FALSE;
    4259             :         }
    4260             : 
    4261           6 :         EVP_VerifyInit   (&md_ctx, mdtype);
    4262           6 :         EVP_VerifyUpdate (&md_ctx, data, data_len);
    4263           6 :         err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
    4264           6 :         EVP_MD_CTX_cleanup(&md_ctx);
    4265             : 
    4266           6 :         if (keyresource == -1) {
    4267           3 :                 EVP_PKEY_free(pkey);
    4268             :         }
    4269           6 :         RETURN_LONG(err);
    4270             : }
    4271             : /* }}} */
    4272             : 
    4273             : /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
    4274             :    Seals data */
    4275          11 : PHP_FUNCTION(openssl_seal)
    4276             : {
    4277             :         zval *pubkeys, **pubkey, *sealdata, *ekeys;
    4278             :         HashTable *pubkeysht;
    4279             :         HashPosition pos;
    4280             :         EVP_PKEY **pkeys;
    4281             :         long * key_resources;   /* so we know what to cleanup */
    4282             :         int i, len1, len2, *eksl, nkeys;
    4283          11 :         unsigned char *buf = NULL, **eks;
    4284             :         char * data; int data_len;
    4285          11 :         char *method =NULL;
    4286          11 :         int method_len = 0;
    4287             :         const EVP_CIPHER *cipher;
    4288             :         EVP_CIPHER_CTX ctx;
    4289             : 
    4290          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
    4291           3 :                 return;
    4292             :         }
    4293             : 
    4294           8 :         pubkeysht = HASH_OF(pubkeys);
    4295           8 :         nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
    4296           8 :         if (!nkeys) {
    4297           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
    4298           2 :                 RETURN_FALSE;
    4299             :         }
    4300             : 
    4301           6 :         if (method) {
    4302           0 :                 cipher = EVP_get_cipherbyname(method);
    4303           0 :                 if (!cipher) {
    4304           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4305           0 :                         RETURN_FALSE;
    4306             :                 }
    4307             :         } else {
    4308           6 :                 cipher = EVP_rc4();
    4309             :         }
    4310             : 
    4311           6 :         pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
    4312           6 :         eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
    4313           6 :         eks = safe_emalloc(nkeys, sizeof(*eks), 0);
    4314           6 :         memset(eks, 0, sizeof(*eks) * nkeys);
    4315           6 :         key_resources = safe_emalloc(nkeys, sizeof(long), 0);
    4316           6 :         memset(key_resources, 0, sizeof(*key_resources) * nkeys);
    4317             : 
    4318             :         /* get the public keys we are using to seal this data */
    4319           6 :         zend_hash_internal_pointer_reset_ex(pubkeysht, &pos);
    4320           6 :         i = 0;
    4321          19 :         while (zend_hash_get_current_data_ex(pubkeysht, (void **) &pubkey,
    4322             :                                 &pos) == SUCCESS) {
    4323          10 :                 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i] TSRMLS_CC);
    4324          10 :                 if (pkeys[i] == NULL) {
    4325           3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
    4326           3 :                         RETVAL_FALSE;
    4327           3 :                         goto clean_exit;
    4328             :                 }
    4329           7 :                 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
    4330           7 :                 zend_hash_move_forward_ex(pubkeysht, &pos);
    4331           7 :                 i++;
    4332             :         }
    4333             : 
    4334           3 :         if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
    4335           0 :                 RETVAL_FALSE;
    4336           0 :                 EVP_CIPHER_CTX_cleanup(&ctx);
    4337           0 :                 goto clean_exit;
    4338             :         }
    4339             : 
    4340             : #if 0
    4341             :         /* Need this if allow ciphers that require initialization vector */
    4342             :         ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
    4343             :         iv = ivlen ? emalloc(ivlen + 1) : NULL;
    4344             : #endif
    4345             :         /* allocate one byte extra to make room for \0 */
    4346           3 :         buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
    4347           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4348             : 
    4349           3 :         if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    4350           0 :                 RETVAL_FALSE;
    4351           0 :                 efree(buf);
    4352           0 :                 EVP_CIPHER_CTX_cleanup(&ctx);
    4353           0 :                 goto clean_exit;
    4354             :         }
    4355             : 
    4356           3 :         EVP_SealFinal(&ctx, buf + len1, &len2);
    4357             : 
    4358           3 :         if (len1 + len2 > 0) {
    4359           3 :                 zval_dtor(sealdata);
    4360           3 :                 buf[len1 + len2] = '\0';
    4361           3 :                 buf = erealloc(buf, len1 + len2 + 1);
    4362           3 :                 ZVAL_STRINGL(sealdata, (char *)buf, len1 + len2, 0);
    4363             : 
    4364           3 :                 zval_dtor(ekeys);
    4365           3 :                 array_init(ekeys);
    4366           9 :                 for (i=0; i<nkeys; i++) {
    4367           6 :                         eks[i][eksl[i]] = '\0';
    4368           6 :                         add_next_index_stringl(ekeys, erealloc(eks[i], eksl[i] + 1), eksl[i], 0);
    4369           6 :                         eks[i] = NULL;
    4370             :                 }
    4371             : #if 0
    4372             :                 /* If allow ciphers that need IV, we need this */
    4373             :                 zval_dtor(*ivec);
    4374             :                 if (ivlen) {
    4375             :                         iv[ivlen] = '\0';
    4376             :                         ZVAL_STRINGL(*ivec, erealloc(iv, ivlen + 1), ivlen, 0);
    4377             :                 } else {
    4378             :                         ZVAL_EMPTY_STRING(*ivec);
    4379             :                 }
    4380             : #endif
    4381             :         } else {
    4382           0 :                 efree(buf);
    4383             :         }
    4384           3 :         RETVAL_LONG(len1 + len2);
    4385           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4386             : 
    4387             : clean_exit:
    4388          16 :         for (i=0; i<nkeys; i++) {
    4389          10 :                 if (key_resources[i] == -1) {
    4390          10 :                         EVP_PKEY_free(pkeys[i]);
    4391             :                 }
    4392          10 :                 if (eks[i]) {
    4393           1 :                         efree(eks[i]);
    4394             :                 }
    4395             :         }
    4396           6 :         efree(eks);
    4397           6 :         efree(eksl);
    4398           6 :         efree(pkeys);
    4399           6 :         efree(key_resources);
    4400             : }
    4401             : /* }}} */
    4402             : 
    4403             : /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
    4404             :    Opens data */
    4405           4 : PHP_FUNCTION(openssl_open)
    4406             : {
    4407             :         zval **privkey, *opendata;
    4408             :         EVP_PKEY *pkey;
    4409             :         int len1, len2;
    4410             :         unsigned char *buf;
    4411           4 :         long keyresource = -1;
    4412             :         EVP_CIPHER_CTX ctx;
    4413             :         char * data;    int data_len;
    4414             :         char * ekey;    int ekey_len;
    4415           4 :         char *method =NULL;
    4416           4 :         int method_len = 0;
    4417             :         const EVP_CIPHER *cipher;
    4418             : 
    4419           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) {
    4420           0 :                 return;
    4421             :         }
    4422             : 
    4423           4 :         pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource TSRMLS_CC);
    4424           4 :         if (pkey == NULL) {
    4425           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key");
    4426           1 :                 RETURN_FALSE;
    4427             :         }
    4428             : 
    4429           3 :         if (method) {
    4430           0 :                 cipher = EVP_get_cipherbyname(method);
    4431           0 :                 if (!cipher) {
    4432           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4433           0 :                         RETURN_FALSE;
    4434             :                 }
    4435             :         } else {
    4436           3 :                 cipher = EVP_rc4();
    4437             :         }
    4438             : 
    4439           3 :         buf = emalloc(data_len + 1);
    4440             : 
    4441           5 :         if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    4442           2 :                 if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
    4443           0 :                         efree(buf);
    4444           0 :                         RETVAL_FALSE;
    4445             :                 } else {
    4446           2 :                         zval_dtor(opendata);
    4447           2 :                         buf[len1 + len2] = '\0';
    4448           2 :                         ZVAL_STRINGL(opendata, erealloc(buf, len1 + len2 + 1), len1 + len2, 0);
    4449           2 :                         RETVAL_TRUE;
    4450             :                 }
    4451             :         } else {
    4452           1 :                 efree(buf);
    4453           1 :                 RETVAL_FALSE;
    4454             :         }
    4455           3 :         if (keyresource == -1) {
    4456           3 :                 EVP_PKEY_free(pkey);
    4457             :         }
    4458           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4459             : }
    4460             : /* }}} */
    4461             : 
    4462             : /* SSL verification functions */
    4463             : 
    4464             : #define GET_VER_OPT(name)               (stream->context && SUCCESS == php_stream_context_get_option(stream->context, "ssl", name, &val))
    4465             : #define GET_VER_OPT_STRING(name, str)   if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_PP(val); }
    4466             : 
    4467           2 : static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
    4468             : {
    4469             :         php_stream *stream;
    4470             :         SSL *ssl;
    4471             :         X509 *err_cert;
    4472             :         int err, depth, ret;
    4473             :         zval **val;
    4474             : 
    4475           2 :         ret = preverify_ok;
    4476             : 
    4477             :         /* determine the status for the current cert */
    4478           2 :         err_cert = X509_STORE_CTX_get_current_cert(ctx);
    4479           2 :         err = X509_STORE_CTX_get_error(ctx);
    4480           2 :         depth = X509_STORE_CTX_get_error_depth(ctx);
    4481             : 
    4482             :         /* conjure the stream & context to use */
    4483           2 :         ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    4484           2 :         stream = (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
    4485             : 
    4486             :         /* if allow_self_signed is set, make sure that verification succeeds */
    4487           2 :         if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
    4488           0 :                 ret = 1;
    4489             :         }
    4490             : 
    4491             :         /* check the depth */
    4492           2 :         if (GET_VER_OPT("verify_depth")) {
    4493           0 :                 convert_to_long_ex(val);
    4494             : 
    4495           0 :                 if (depth > Z_LVAL_PP(val)) {
    4496           0 :                         ret = 0;
    4497           0 :                         X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
    4498             :                 }
    4499             :         }
    4500             : 
    4501           2 :         return ret;
    4502             : 
    4503             : }
    4504             : /* }}} */
    4505             : 
    4506          15 : int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC) /* {{{ */
    4507             : {
    4508          15 :         zval **val = NULL;
    4509          15 :         char *cnmatch = NULL;
    4510             :         X509_NAME *name;
    4511             :         char buf[1024];
    4512             :         int err;
    4513             : 
    4514             :         /* verification is turned off */
    4515          15 :         if (!(GET_VER_OPT("verify_peer") && zval_is_true(*val))) {
    4516          15 :                 return SUCCESS;
    4517             :         }
    4518             : 
    4519           0 :         if (peer == NULL) {
    4520           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not get peer certificate");
    4521           0 :                 return FAILURE;
    4522             :         }
    4523             : 
    4524           0 :         err = SSL_get_verify_result(ssl);
    4525           0 :         switch (err) {
    4526             :                 case X509_V_OK:
    4527             :                         /* fine */
    4528           0 :                         break;
    4529             :                 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
    4530           0 :                         if (GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
    4531             :                                 /* allowed */
    4532           0 :                                 break;
    4533             :                         }
    4534             :                         /* not allowed, so fall through */
    4535             :                 default:
    4536           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err));
    4537           0 :                         return FAILURE;
    4538             :         }
    4539             : 
    4540             :         /* if the cert passed the usual checks, apply our own local policies now */
    4541             : 
    4542           0 :         name = X509_get_subject_name(peer);
    4543             : 
    4544             :         /* Does the common name match ? (used primarily for https://) */
    4545           0 :         GET_VER_OPT_STRING("CN_match", cnmatch);
    4546           0 :         if (cnmatch) {
    4547           0 :                 int match = 0;
    4548           0 :                 int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf));
    4549             : 
    4550           0 :                 if (name_len == -1) {
    4551           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
    4552           0 :                         return FAILURE;
    4553           0 :                 } else if (name_len != strlen(buf)) {
    4554           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", name_len, buf);
    4555           0 :                         return FAILURE;
    4556             :                 }
    4557             : 
    4558           0 :                 match = strcmp(cnmatch, buf) == 0;
    4559           0 :                 if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') {
    4560             :                         /* Try wildcard */
    4561             : 
    4562           0 :                         if (strchr(buf+2, '.')) {
    4563           0 :                                 char *tmp = strstr(cnmatch, buf+1);
    4564             : 
    4565           0 :                                 match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch, '.');
    4566             :                         }
    4567             :                 }
    4568             : 
    4569           0 :                 if (!match) {
    4570             :                         /* didn't match */
    4571           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch);
    4572           0 :                         return FAILURE;
    4573             :                 }
    4574             :         }
    4575             : 
    4576           0 :         return SUCCESS;
    4577             : }
    4578             : /* }}} */
    4579             : 
    4580           1 : static int passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */
    4581             : {
    4582           1 :     php_stream *stream = (php_stream *)data;
    4583           1 :     zval **val = NULL;
    4584           1 :     char *passphrase = NULL;
    4585             :     /* TODO: could expand this to make a callback into PHP user-space */
    4586             : 
    4587           1 :     GET_VER_OPT_STRING("passphrase", passphrase);
    4588             : 
    4589           1 :     if (passphrase) {
    4590           1 :         if (Z_STRLEN_PP(val) < num - 1) {
    4591           1 :             memcpy(buf, Z_STRVAL_PP(val), Z_STRLEN_PP(val)+1);
    4592           1 :             return Z_STRLEN_PP(val);
    4593             :         }
    4594             :     }
    4595           0 :     return 0;
    4596             : }
    4597             : /* }}} */
    4598             : 
    4599          16 : SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */
    4600             : {
    4601          16 :         zval **val = NULL;
    4602          16 :         char *cafile = NULL;
    4603          16 :         char *capath = NULL;
    4604          16 :         char *certfile = NULL;
    4605          16 :         char *cipherlist = NULL;
    4606          16 :         int ok = 1;
    4607             : 
    4608          16 :         ERR_clear_error();
    4609             : 
    4610             :         /* look at context options in the stream and set appropriate verification flags */
    4611          17 :         if (GET_VER_OPT("verify_peer") && zval_is_true(*val)) {
    4612             : 
    4613             :                 /* turn on verification callback */
    4614           1 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
    4615             : 
    4616             :                 /* CA stuff */
    4617           1 :                 GET_VER_OPT_STRING("cafile", cafile);
    4618           1 :                 GET_VER_OPT_STRING("capath", capath);
    4619             : 
    4620           1 :                 if (cafile || capath) {
    4621           1 :                         if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
    4622           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set verify locations `%s' `%s'", cafile, capath);
    4623           0 :                                 return NULL;
    4624             :                         }
    4625             :                 }
    4626             : 
    4627           1 :                 if (GET_VER_OPT("verify_depth")) {
    4628           0 :                         convert_to_long_ex(val);
    4629           0 :                         SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val));
    4630             :                 }
    4631             :         } else {
    4632          15 :                 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
    4633             :         }
    4634             : 
    4635             :         /* callback for the passphrase (for localcert) */
    4636          16 :         if (GET_VER_OPT("passphrase")) {
    4637           1 :                 SSL_CTX_set_default_passwd_cb_userdata(ctx, stream);
    4638           1 :                 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
    4639             :         }
    4640             : 
    4641          16 :         GET_VER_OPT_STRING("ciphers", cipherlist);
    4642          16 :         if (!cipherlist) {
    4643          16 :                 cipherlist = "DEFAULT";
    4644             :         }
    4645          16 :         if (SSL_CTX_set_cipher_list(ctx, cipherlist) != 1) {
    4646           0 :                 return NULL;
    4647             :         }
    4648             : 
    4649          16 :         GET_VER_OPT_STRING("local_cert", certfile);
    4650          16 :         if (certfile) {
    4651             :                 char resolved_path_buff[MAXPATHLEN];
    4652           4 :                 const char * private_key = NULL;
    4653             : 
    4654           4 :                 if (VCWD_REALPATH(certfile, resolved_path_buff)) {
    4655             :                         /* a certificate to use for authentication */
    4656           4 :                         if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
    4657           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);
    4658           0 :                                 return NULL;
    4659             :                         }
    4660           4 :                         GET_VER_OPT_STRING("local_pk", private_key);
    4661             : 
    4662           4 :                         if (private_key) {
    4663             :                                 char resolved_path_buff_pk[MAXPATHLEN];
    4664           0 :                                 if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) {
    4665           0 :                                         if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) {
    4666           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk);
    4667           0 :                                                 return NULL;
    4668             :                                         }
    4669             :                                 }
    4670             :                         } else {
    4671           4 :                                 if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
    4672           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
    4673           0 :                                         return NULL;
    4674             :                                 }
    4675             :                         }
    4676             : 
    4677             : #if OPENSSL_VERSION_NUMBER < 0x10001001L
    4678             :                         do {
    4679             :                                 /* Unnecessary as of OpenSSLv1.0.1 (will segfault if used with >= 10001001 ) */
    4680             :                                 X509 *cert = NULL;
    4681             :                                 EVP_PKEY *key = NULL;
    4682             :                                 SSL *tmpssl = SSL_new(ctx);
    4683             :                                 cert = SSL_get_certificate(tmpssl);
    4684             : 
    4685             :                                 if (cert) {
    4686             :                                         key = X509_get_pubkey(cert);
    4687             :                                         EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl));
    4688             :                                         EVP_PKEY_free(key);
    4689             :                                 }
    4690             :                                 SSL_free(tmpssl);
    4691             :                         } while (0);
    4692             : #endif
    4693           4 :                         if (!SSL_CTX_check_private_key(ctx)) {
    4694           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Private key does not match certificate!");
    4695             :                         }
    4696             :                 }
    4697             :         }
    4698          16 :         if (ok) {
    4699          16 :                 SSL *ssl = SSL_new(ctx);
    4700             : 
    4701          16 :                 if (ssl) {
    4702             :                         /* map SSL => stream */
    4703          16 :                         SSL_set_ex_data(ssl, ssl_stream_data_index, stream);
    4704             :                 }
    4705          16 :                 return ssl;
    4706             :         }
    4707             : 
    4708           0 :         return NULL;
    4709             : }
    4710             : /* }}} */
    4711             : 
    4712           0 : static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
    4713             : {
    4714           0 :         add_next_index_string((zval*)arg, (char*)name->name, 1);
    4715           0 : }
    4716             : /* }}} */
    4717             : 
    4718           0 : static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
    4719             : {
    4720           0 :         if (name->alias == 0) {
    4721           0 :                 add_next_index_string((zval*)arg, (char*)name->name, 1);
    4722             :         }
    4723           0 : }
    4724             : /* }}} */
    4725             : 
    4726             : /* {{{ proto array openssl_get_md_methods([bool aliases = false])
    4727             :    Return array of available digest methods */
    4728           0 : PHP_FUNCTION(openssl_get_md_methods)
    4729             : {
    4730           0 :         zend_bool aliases = 0;
    4731             : 
    4732           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
    4733           0 :                 return;
    4734             :         }
    4735           0 :         array_init(return_value);
    4736           0 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
    4737           0 :                 aliases ? openssl_add_method_or_alias: openssl_add_method,
    4738             :                 return_value);
    4739             : }
    4740             : /* }}} */
    4741             : 
    4742             : /* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
    4743             :    Return array of available cipher methods */
    4744           0 : PHP_FUNCTION(openssl_get_cipher_methods)
    4745             : {
    4746           0 :         zend_bool aliases = 0;
    4747             : 
    4748           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
    4749           0 :                 return;
    4750             :         }
    4751           0 :         array_init(return_value);
    4752           0 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
    4753           0 :                 aliases ? openssl_add_method_or_alias: openssl_add_method,
    4754             :                 return_value);
    4755             : }
    4756             : /* }}} */
    4757             : 
    4758             : /* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
    4759             :    Computes digest hash value for given data using given method, returns raw or binhex encoded string */
    4760           2 : PHP_FUNCTION(openssl_digest)
    4761             : {
    4762           2 :         zend_bool raw_output = 0;
    4763             :         char *data, *method;
    4764             :         int data_len, method_len;
    4765             :         const EVP_MD *mdtype;
    4766             :         EVP_MD_CTX md_ctx;
    4767             :         int siglen;
    4768             :         unsigned char *sigbuf;
    4769             : 
    4770           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
    4771           0 :                 return;
    4772             :         }
    4773           2 :         mdtype = EVP_get_digestbyname(method);
    4774           2 :         if (!mdtype) {
    4775           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
    4776           0 :                 RETURN_FALSE;
    4777             :         }
    4778             : 
    4779           2 :         siglen = EVP_MD_size(mdtype);
    4780           2 :         sigbuf = emalloc(siglen + 1);
    4781             : 
    4782           2 :         EVP_DigestInit(&md_ctx, mdtype);
    4783           2 :         EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
    4784           2 :         if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int *)&siglen)) {
    4785           2 :                 if (raw_output) {
    4786           0 :                         sigbuf[siglen] = '\0';
    4787           0 :                         RETVAL_STRINGL((char *)sigbuf, siglen, 0);
    4788             :                 } else {
    4789           2 :                         int digest_str_len = siglen * 2;
    4790           2 :                         char *digest_str = emalloc(digest_str_len + 1);
    4791             : 
    4792           2 :                         make_digest_ex(digest_str, sigbuf, siglen);
    4793           2 :                         efree(sigbuf);
    4794           2 :                         RETVAL_STRINGL(digest_str, digest_str_len, 0);
    4795             :                 }
    4796             :         } else {
    4797           0 :                 efree(sigbuf);
    4798           0 :                 RETVAL_FALSE;
    4799             :         }
    4800             : }
    4801             : /* }}} */
    4802             : 
    4803          14 : static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_required_len TSRMLS_DC)
    4804             : {
    4805             :         char *iv_new;
    4806             : 
    4807             :         /* Best case scenario, user behaved */
    4808          14 :         if (*piv_len == iv_required_len) {
    4809          10 :                 return 0;
    4810             :         }
    4811             : 
    4812           4 :         iv_new = ecalloc(1, iv_required_len + 1);
    4813             : 
    4814           4 :         if (*piv_len <= 0) {
    4815             :                 /* BC behavior */
    4816           4 :                 *piv_len = iv_required_len;
    4817           4 :                 *piv     = iv_new;
    4818           4 :                 return 1;
    4819             :         }
    4820             : 
    4821           0 :         if (*piv_len < iv_required_len) {
    4822           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is only %d bytes long, cipher expects an IV of precisely %d bytes, padding with \\0", *piv_len, iv_required_len);
    4823           0 :                 memcpy(iv_new, *piv, *piv_len);
    4824           0 :                 *piv_len = iv_required_len;
    4825           0 :                 *piv     = iv_new;
    4826           0 :                 return 1;
    4827             :         }
    4828             : 
    4829           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "IV passed is %d bytes long which is longer than the %d expected by selected cipher, truncating", *piv_len, iv_required_len);
    4830           0 :         memcpy(iv_new, *piv, iv_required_len);
    4831           0 :         *piv_len = iv_required_len;
    4832           0 :         *piv     = iv_new;
    4833           0 :         return 1;
    4834             : 
    4835             : }
    4836             : 
    4837             : /* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv='']])
    4838             :    Encrypts given data with given method and key, returns raw or base64 encoded string */
    4839          15 : PHP_FUNCTION(openssl_encrypt)
    4840             : {
    4841          15 :         long options = 0;
    4842          15 :         char *data, *method, *password, *iv = "";
    4843          15 :         int data_len, method_len, password_len, iv_len = 0, max_iv_len;
    4844             :         const EVP_CIPHER *cipher_type;
    4845             :         EVP_CIPHER_CTX cipher_ctx;
    4846          15 :         int i=0, outlen, keylen;
    4847             :         unsigned char *outbuf, *key;
    4848             :         zend_bool free_iv;
    4849             : 
    4850          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) {
    4851           6 :                 return;
    4852             :         }
    4853           9 :         cipher_type = EVP_get_cipherbyname(method);
    4854           9 :         if (!cipher_type) {
    4855           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    4856           1 :                 RETURN_FALSE;
    4857             :         }
    4858             : 
    4859           8 :         keylen = EVP_CIPHER_key_length(cipher_type);
    4860           8 :         if (keylen > password_len) {
    4861           8 :                 key = emalloc(keylen);
    4862           8 :                 memset(key, 0, keylen);
    4863           8 :                 memcpy(key, password, password_len);
    4864             :         } else {
    4865           0 :                 key = (unsigned char*)password;
    4866             :         }
    4867             : 
    4868           8 :         max_iv_len = EVP_CIPHER_iv_length(cipher_type);
    4869           8 :         if (iv_len <= 0 && max_iv_len > 0) {
    4870           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
    4871             :         }
    4872           8 :         free_iv = php_openssl_validate_iv(&iv, &iv_len, max_iv_len TSRMLS_CC);
    4873             : 
    4874           8 :         outlen = data_len + EVP_CIPHER_block_size(cipher_type);
    4875           8 :         outbuf = emalloc(outlen + 1);
    4876             : 
    4877           8 :         EVP_EncryptInit(&cipher_ctx, cipher_type, NULL, NULL);
    4878           8 :         if (password_len > keylen) {
    4879           0 :                 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
    4880             :         }
    4881           8 :         EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
    4882           8 :         if (options & OPENSSL_ZERO_PADDING) {
    4883           1 :                 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
    4884             :         }
    4885           8 :         if (data_len > 0) {
    4886           7 :                 EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
    4887             :         }
    4888           8 :         outlen = i;
    4889           8 :         if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
    4890           8 :                 outlen += i;
    4891           8 :                 if (options & OPENSSL_RAW_DATA) {
    4892           2 :                         outbuf[outlen] = '\0';
    4893           2 :                         RETVAL_STRINGL((char *)outbuf, outlen, 0);
    4894             :                 } else {
    4895             :                         int base64_str_len;
    4896             :                         char *base64_str;
    4897             : 
    4898           6 :                         base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len);
    4899           6 :                         efree(outbuf);
    4900           6 :                         RETVAL_STRINGL(base64_str, base64_str_len, 0);
    4901             :                 }
    4902             :         } else {
    4903           0 :                 efree(outbuf);
    4904           0 :                 RETVAL_FALSE;
    4905             :         }
    4906           8 :         if (key != (unsigned char*)password) {
    4907           8 :                 efree(key);
    4908             :         }
    4909           8 :         if (free_iv) {
    4910           2 :                 efree(iv);
    4911             :         }
    4912           8 :         EVP_CIPHER_CTX_cleanup(&cipher_ctx);
    4913             : }
    4914             : /* }}} */
    4915             : 
    4916             : /* {{{ proto string openssl_decrypt(string data, string method, string password [, long options=0 [, string $iv = '']])
    4917             :    Takes raw or base64 encoded string and dectupt it using given method and key */
    4918          14 : PHP_FUNCTION(openssl_decrypt)
    4919             : {
    4920          14 :         long options = 0;
    4921          14 :         char *data, *method, *password, *iv = "";
    4922          14 :         int data_len, method_len, password_len, iv_len = 0;
    4923             :         const EVP_CIPHER *cipher_type;
    4924             :         EVP_CIPHER_CTX cipher_ctx;
    4925             :         int i, outlen, keylen;
    4926             :         unsigned char *outbuf, *key;
    4927             :         int base64_str_len;
    4928          14 :         char *base64_str = NULL;
    4929             :         zend_bool free_iv;
    4930             : 
    4931          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) {
    4932           3 :                 return;
    4933             :         }
    4934             : 
    4935          11 :         if (!method_len) {
    4936           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    4937           0 :                 RETURN_FALSE;
    4938             :         }
    4939             : 
    4940          11 :         cipher_type = EVP_get_cipherbyname(method);
    4941          11 :         if (!cipher_type) {
    4942           4 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    4943           4 :                 RETURN_FALSE;
    4944             :         }
    4945             : 
    4946           7 :         if (!(options & OPENSSL_RAW_DATA)) {
    4947           5 :                 base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len);
    4948           5 :                 if (!base64_str) {
    4949           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to base64 decode the input");
    4950           1 :                         RETURN_FALSE;
    4951             :                 }
    4952           4 :                 data_len = base64_str_len;
    4953           4 :                 data = base64_str;
    4954             :         }
    4955             : 
    4956           6 :         keylen = EVP_CIPHER_key_length(cipher_type);
    4957           6 :         if (keylen > password_len) {
    4958           6 :                 key = emalloc(keylen);
    4959           6 :                 memset(key, 0, keylen);
    4960           6 :                 memcpy(key, password, password_len);
    4961             :         } else {
    4962           0 :                 key = (unsigned char*)password;
    4963             :         }
    4964             : 
    4965           6 :         free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type) TSRMLS_CC);
    4966             : 
    4967           6 :         outlen = data_len + EVP_CIPHER_block_size(cipher_type);
    4968           6 :         outbuf = emalloc(outlen + 1);
    4969             : 
    4970           6 :         EVP_DecryptInit(&cipher_ctx, cipher_type, NULL, NULL);
    4971           6 :         if (password_len > keylen) {
    4972           0 :                 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
    4973             :         }
    4974           6 :         EVP_DecryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
    4975           6 :         if (options & OPENSSL_ZERO_PADDING) {
    4976           1 :                 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
    4977             :         }
    4978           6 :         EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
    4979           6 :         outlen = i;
    4980           6 :         if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
    4981           4 :                 outlen += i;
    4982           4 :                 outbuf[outlen] = '\0';
    4983           4 :                 RETVAL_STRINGL((char *)outbuf, outlen, 0);
    4984             :         } else {
    4985           2 :                 efree(outbuf);
    4986           2 :                 RETVAL_FALSE;
    4987             :         }
    4988           6 :         if (key != (unsigned char*)password) {
    4989           6 :                 efree(key);
    4990             :         }
    4991           6 :         if (free_iv) {
    4992           2 :                 efree(iv);
    4993             :         }
    4994           6 :         if (base64_str) {
    4995           4 :                 efree(base64_str);
    4996             :         }
    4997           6 :         EVP_CIPHER_CTX_cleanup(&cipher_ctx);
    4998             : }
    4999             : /* }}} */
    5000             : 
    5001             : /* {{{ proto int openssl_cipher_iv_length(string $method) */
    5002           2 : PHP_FUNCTION(openssl_cipher_iv_length)
    5003             : {
    5004             :         char *method;
    5005             :         int method_len;
    5006             :         const EVP_CIPHER *cipher_type;
    5007             : 
    5008           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len) == FAILURE) {
    5009           0 :                 return;
    5010             :         }
    5011             : 
    5012           2 :         if (!method_len) {
    5013           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5014           0 :                 RETURN_FALSE;
    5015             :         }
    5016             : 
    5017           2 :         cipher_type = EVP_get_cipherbyname(method);
    5018           2 :         if (!cipher_type) {
    5019           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5020           0 :                 RETURN_FALSE;
    5021             :         }
    5022             : 
    5023           2 :         RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
    5024             : }
    5025             : /* }}} */
    5026             : 
    5027             : 
    5028             : /* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
    5029             :    Computes shared secret for public value of remote DH key and local DH key */
    5030           0 : PHP_FUNCTION(openssl_dh_compute_key)
    5031             : {
    5032             :         zval *key;
    5033             :         char *pub_str;
    5034             :         int pub_len;
    5035             :         EVP_PKEY *pkey;
    5036             :         BIGNUM *pub;
    5037             :         char *data;
    5038             :         int len;
    5039             : 
    5040           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, &pub_len, &key) == FAILURE) {
    5041           0 :                 return;
    5042             :         }
    5043           0 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
    5044           0 :         if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
    5045           0 :                 RETURN_FALSE;
    5046             :         }
    5047             : 
    5048           0 :         pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
    5049             : 
    5050           0 :         data = emalloc(DH_size(pkey->pkey.dh) + 1);
    5051           0 :         len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
    5052             : 
    5053           0 :         if (len >= 0) {
    5054           0 :                 data[len] = 0;
    5055           0 :                 RETVAL_STRINGL(data, len, 0);
    5056             :         } else {
    5057           0 :                 efree(data);
    5058           0 :                 RETVAL_FALSE;
    5059             :         }
    5060             : 
    5061           0 :         BN_free(pub);
    5062             : }
    5063             : /* }}} */
    5064             : 
    5065             : /* {{{ proto string openssl_random_pseudo_bytes(integer length [, &bool returned_strong_result])
    5066             :    Returns a string of the length specified filled with random pseudo bytes */
    5067          10 : PHP_FUNCTION(openssl_random_pseudo_bytes)
    5068             : {
    5069             :         long buffer_length;
    5070          10 :         unsigned char *buffer = NULL;
    5071          10 :         zval *zstrong_result_returned = NULL;
    5072          10 :         int strong_result = 0;
    5073             : 
    5074          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|z", &buffer_length, &zstrong_result_returned) == FAILURE) {
    5075           0 :                 return;
    5076             :         }
    5077             : 
    5078          10 :         if (buffer_length <= 0) {
    5079           1 :                 RETURN_FALSE;
    5080             :         }
    5081             : 
    5082           9 :         if (zstrong_result_returned) {
    5083           9 :                 zval_dtor(zstrong_result_returned);
    5084           9 :                 ZVAL_BOOL(zstrong_result_returned, 0);
    5085             :         }
    5086             : 
    5087           9 :         buffer = emalloc(buffer_length + 1);
    5088             : 
    5089             : #ifdef PHP_WIN32
    5090             :         strong_result = 1;
    5091             :         /* random/urandom equivalent on Windows */
    5092             :         if (php_win32_get_random_bytes(buffer, (size_t) buffer_length) == FAILURE) {
    5093             :                 efree(buffer);
    5094             :                 if (zstrong_result_returned) {
    5095             :                         ZVAL_BOOL(zstrong_result_returned, 0);
    5096             :                 }
    5097             :                 RETURN_FALSE;
    5098             :         }
    5099             : #else
    5100           9 :         if ((strong_result = RAND_pseudo_bytes(buffer, buffer_length)) < 0) {
    5101           0 :                 efree(buffer);
    5102           0 :                 if (zstrong_result_returned) {
    5103           0 :                         ZVAL_BOOL(zstrong_result_returned, 0);
    5104             :                 }
    5105           0 :                 RETURN_FALSE;
    5106             :         }
    5107             : #endif
    5108             : 
    5109           9 :         buffer[buffer_length] = 0;
    5110           9 :         RETVAL_STRINGL((char *)buffer, buffer_length, 0);
    5111             : 
    5112           9 :         if (zstrong_result_returned) {
    5113           9 :                 ZVAL_BOOL(zstrong_result_returned, strong_result);
    5114             :         }
    5115             : }
    5116             : /* }}} */
    5117             : 
    5118             : /*
    5119             :  * Local variables:
    5120             :  * tab-width: 8
    5121             :  * c-basic-offset: 8
    5122             :  * End:
    5123             :  * vim600: sw=4 ts=4 fdm=marker
    5124             :  * vim<600: sw=4 ts=4
    5125             :  */

Generated by: LCOV version 1.10

Generated at Tue, 29 Jul 2014 09:53:07 +0000 (3 days ago)

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