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: 1676 2392 70.1 %
Date: 2015-08-29 Functions: 72 89 80.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 29 Aug 2015 10:22:19 +0000 (2 days ago)

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