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

Generated by: LCOV version 1.10

Generated at Sun, 21 Sep 2014 15:27:39 +0000 (2 days ago)

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