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: 2141 2958 72.4 %
Date: 2016-08-24 Functions: 106 115 92.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:26 +0000 (25 hours ago)

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