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

Generated by: LCOV version 1.10

Generated at Sun, 05 Jul 2015 15:44:51 +0000 (3 hours ago)

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