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: 2138 2961 72.2 %
Date: 2016-09-18 Functions: 104 115 90.4 %
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           0 : static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
     634             : {
     635           0 :         dh->pub_key = pub_key;
     636           0 :         dh->priv_key = priv_key;
     637             : 
     638           0 :         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           0 : int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
     664             : {
     665           0 :         d->pub_key = pub_key;
     666           0 :         d->priv_key = priv_key;
     667             : 
     668           0 :         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          63 : php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
     774             : {
     775          63 :         return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
     776             : }
     777             : 
     778         195 : int php_openssl_get_ssl_stream_data_index()
     779             : {
     780         195 :         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       23922 : PHP_MINIT_FUNCTION(openssl)
    1379             : {
    1380             :         char * config_filename;
    1381             : 
    1382       23922 :         le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
    1383       23922 :         le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
    1384       23922 :         le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
    1385             : 
    1386       23922 :         SSL_library_init();
    1387       23922 :         OpenSSL_add_all_ciphers();
    1388       23922 :         OpenSSL_add_all_digests();
    1389       23922 :         OpenSSL_add_all_algorithms();
    1390             : 
    1391             : #if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && OPENSSL_VERSION_NUMBER < 0x100020000
    1392       23922 :         EVP_add_cipher(EVP_aes_128_ccm());
    1393       23922 :         EVP_add_cipher(EVP_aes_192_ccm());
    1394       23922 :         EVP_add_cipher(EVP_aes_256_ccm());
    1395             : #endif
    1396             : 
    1397       23922 :         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       23922 :         ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
    1402             : 
    1403       23922 :         REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
    1404       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
    1405             : 
    1406             :         /* purposes for cert purpose checking */
    1407       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
    1408       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1409       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1410       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
    1411       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
    1412       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
    1413             : #ifdef X509_PURPOSE_ANY
    1414       23922 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
    1415             : #endif
    1416             : 
    1417             :         /* signature algorithm constants */
    1418       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
    1419       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
    1420       23922 :         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       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
    1426             : #endif
    1427       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
    1428       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
    1429       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
    1430       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
    1431       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
    1432             : 
    1433             :         /* flags for S/MIME */
    1434       23922 :         REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
    1435       23922 :         REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
    1436       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
    1437       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
    1438       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
    1439       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
    1440       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
    1441       23922 :         REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
    1442       23922 :         REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
    1443             : 
    1444       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
    1445       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
    1446       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
    1447       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
    1448             : 
    1449             :         /* Informational stream wrapper constants */
    1450       23922 :         REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
    1451             : 
    1452             :         /* Ciphers */
    1453             : #ifndef OPENSSL_NO_RC2
    1454       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
    1455       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
    1456       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
    1457             : #endif
    1458             : #ifndef OPENSSL_NO_DES
    1459       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
    1460       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
    1461             : #endif
    1462             : #ifndef OPENSSL_NO_AES
    1463       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
    1464       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
    1465       23922 :         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       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
    1470             : #ifndef NO_DSA
    1471       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
    1472             : #endif
    1473       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
    1474             : #ifdef HAVE_EVP_PKEY_EC
    1475       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
    1476             : #endif
    1477             : 
    1478       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
    1479       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
    1480             : 
    1481             : #ifndef OPENSSL_NO_TLSEXT
    1482             :         /* SNI support included */
    1483       23922 :         REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
    1484             : #endif
    1485             : 
    1486             :         /* Determine default SSL configuration file */
    1487       23922 :         config_filename = getenv("OPENSSL_CONF");
    1488       23922 :         if (config_filename == NULL) {
    1489       23922 :                 config_filename = getenv("SSLEAY_CONF");
    1490             :         }
    1491             : 
    1492             :         /* default to 'openssl.cnf' if no environment variable is set */
    1493       23922 :         if (config_filename == NULL) {
    1494       23922 :                 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       23922 :         php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
    1502             : #ifndef OPENSSL_NO_SSL3
    1503       23922 :         php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
    1504             : #endif
    1505       23922 :         php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
    1506       23922 :         php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory);
    1507       23922 :         php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory);
    1508       23922 :         php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory);
    1509             : 
    1510             :         /* override the default tcp socket provider */
    1511       23922 :         php_stream_xport_register("tcp", php_openssl_ssl_socket_factory);
    1512             : 
    1513       23922 :         php_register_url_stream_wrapper("https", &php_stream_http_wrapper);
    1514       23922 :         php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper);
    1515             : 
    1516       23922 :         REGISTER_INI_ENTRIES();
    1517             : 
    1518       23922 :         return SUCCESS;
    1519             : }
    1520             : /* }}} */
    1521             : 
    1522             : /* {{{ PHP_GINIT_FUNCTION
    1523             : */
    1524       23922 : PHP_GINIT_FUNCTION(openssl)
    1525             : {
    1526             : #if defined(COMPILE_DL_OPENSSL) && defined(ZTS)
    1527             :         ZEND_TSRMLS_CACHE_UPDATE();
    1528             : #endif
    1529       23922 :         openssl_globals->errors = NULL;
    1530       23922 : }
    1531             : /* }}} */
    1532             : 
    1533             : /* {{{ PHP_GSHUTDOWN_FUNCTION
    1534             : */
    1535       23963 : PHP_GSHUTDOWN_FUNCTION(openssl)
    1536             : {
    1537       23963 :         if (openssl_globals->errors) {
    1538          46 :                 pefree(openssl_globals->errors, 1);
    1539             :         }
    1540       23963 : }
    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       23963 : PHP_MSHUTDOWN_FUNCTION(openssl)
    1560             : {
    1561       23963 :         EVP_cleanup();
    1562             : 
    1563             :         /* prevent accessing locking callback from unloaded extension */
    1564       23963 :         CRYPTO_set_locking_callback(NULL);
    1565             :         /* free allocated error strings */
    1566       23963 :         ERR_free_strings();
    1567             : 
    1568       23963 :         php_unregister_url_stream_wrapper("https");
    1569       23963 :         php_unregister_url_stream_wrapper("ftps");
    1570             : 
    1571       23963 :         php_stream_xport_unregister("ssl");
    1572             : #ifndef OPENSSL_NO_SSL3
    1573       23963 :         php_stream_xport_unregister("sslv3");
    1574             : #endif
    1575       23963 :         php_stream_xport_unregister("tls");
    1576       23963 :         php_stream_xport_unregister("tlsv1.0");
    1577       23963 :         php_stream_xport_unregister("tlsv1.1");
    1578       23963 :         php_stream_xport_unregister("tlsv1.2");
    1579             : 
    1580             :         /* reinstate the default tcp handler */
    1581       23963 :         php_stream_xport_register("tcp", php_stream_generic_socket_factory);
    1582             : 
    1583       23963 :         UNREGISTER_INI_ENTRIES();
    1584             : 
    1585       23963 :         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 (pub_key) {
    4063           0 :                 return DSA_set0_key(dsa, pub_key, priv_key);
    4064             :         }
    4065             : 
    4066             :         /* generate key */
    4067           2 :         PHP_OPENSSL_RAND_ADD_TIME();
    4068           2 :         if (!DSA_generate_key(dsa)) {
    4069           0 :                 php_openssl_store_errors();
    4070           0 :                 return 0;
    4071             :         }
    4072             : 
    4073             :         /* if BN_mod_exp return -1, then DSA_generate_key succeed for failed key
    4074             :          * so we need to double check that public key is created */
    4075           2 :         DSA_get0_key(dsa, &pub_key_const, &priv_key_const);
    4076           2 :         if (!pub_key_const || BN_is_zero(pub_key_const)) {
    4077           1 :                 return 0;
    4078             :         }
    4079             :         /* all good */
    4080           1 :         return 1;
    4081             : }
    4082             : /* }}} */
    4083             : 
    4084             : /* {{{ php_openssl_pkey_init_dh */
    4085           4 : zend_bool php_openssl_pkey_init_dh(DH *dh, zval *data)
    4086             : {
    4087             :         BIGNUM *p, *q, *g, *priv_key, *pub_key;
    4088             : 
    4089           7 :         OPENSSL_PKEY_SET_BN(data, p);
    4090           4 :         OPENSSL_PKEY_SET_BN(data, q);
    4091           7 :         OPENSSL_PKEY_SET_BN(data, g);
    4092           4 :         if (!p || !g || !DH_set0_pqg(dh, p, q, g)) {
    4093           1 :                 return 0;
    4094             :         }
    4095             : 
    4096           3 :         OPENSSL_PKEY_SET_BN(data, priv_key);
    4097           3 :         OPENSSL_PKEY_SET_BN(data, pub_key);
    4098           3 :         if (pub_key) {
    4099           0 :                 return DH_set0_key(dh, pub_key, priv_key);
    4100             :         }
    4101             : 
    4102             :         /* generate key */
    4103           3 :         PHP_OPENSSL_RAND_ADD_TIME();
    4104           3 :         if (!DH_generate_key(dh)) {
    4105           1 :                 php_openssl_store_errors();
    4106           1 :                 return 0;
    4107             :         }
    4108             :         /* all good */
    4109           2 :         return 1;
    4110             : }
    4111             : /* }}} */
    4112             : 
    4113             : /* {{{ proto resource openssl_pkey_new([array configargs])
    4114             :    Generates a new private key */
    4115          27 : PHP_FUNCTION(openssl_pkey_new)
    4116             : {
    4117             :         struct php_x509_request req;
    4118          27 :         zval * args = NULL;
    4119             :         zval *data;
    4120             : 
    4121          27 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &args) == FAILURE) {
    4122           0 :                 return;
    4123             :         }
    4124          27 :         RETVAL_FALSE;
    4125             : 
    4126          46 :         if (args && Z_TYPE_P(args) == IS_ARRAY) {
    4127             :                 EVP_PKEY *pkey;
    4128             : 
    4129          21 :                 if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa")-1)) != NULL &&
    4130             :                         Z_TYPE_P(data) == IS_ARRAY) {
    4131           2 :                         pkey = EVP_PKEY_new();
    4132           2 :                         if (pkey) {
    4133           2 :                                 RSA *rsa = RSA_new();
    4134           2 :                                 if (rsa) {
    4135           2 :                                         if (php_openssl_pkey_init_and_assign_rsa(pkey, rsa, data)) {
    4136           1 :                                                 RETURN_RES(zend_register_resource(pkey, le_key));
    4137             :                                         }
    4138           1 :                                         RSA_free(rsa);
    4139             :                                 } else {
    4140           0 :                                         php_openssl_store_errors();
    4141             :                                 }
    4142           1 :                                 EVP_PKEY_free(pkey);
    4143             :                         } else {
    4144           0 :                                 php_openssl_store_errors();
    4145             :                         }
    4146           1 :                         RETURN_FALSE;
    4147          20 :                 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL &&
    4148             :                         Z_TYPE_P(data) == IS_ARRAY) {
    4149           3 :                         pkey = EVP_PKEY_new();
    4150           3 :                         if (pkey) {
    4151           3 :                                 DSA *dsa = DSA_new();
    4152           3 :                                 if (dsa) {
    4153           3 :                                         if (php_openssl_pkey_init_dsa(dsa, data)) {
    4154           1 :                                                 if (EVP_PKEY_assign_DSA(pkey, dsa)) {
    4155           1 :                                                         RETURN_RES(zend_register_resource(pkey, le_key));
    4156             :                                                 } else {
    4157           0 :                                                         php_openssl_store_errors();
    4158             :                                                 }
    4159             :                                         }
    4160           2 :                                         DSA_free(dsa);
    4161             :                                 } else {
    4162           0 :                                         php_openssl_store_errors();
    4163             :                                 }
    4164           2 :                                 EVP_PKEY_free(pkey);
    4165             :                         } else {
    4166           0 :                                 php_openssl_store_errors();
    4167             :                         }
    4168           2 :                         RETURN_FALSE;
    4169          18 :                 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL &&
    4170             :                         Z_TYPE_P(data) == IS_ARRAY) {
    4171           4 :                         pkey = EVP_PKEY_new();
    4172           4 :                         if (pkey) {
    4173           4 :                                 DH *dh = DH_new();
    4174           4 :                                 if (dh) {
    4175           4 :                                         if (php_openssl_pkey_init_dh(dh, data)) {
    4176           2 :                                                 if (EVP_PKEY_assign_DH(pkey, dh)) {
    4177           2 :                                                         ZVAL_COPY_VALUE(return_value, zend_list_insert(pkey, le_key));
    4178           2 :                                                         return;
    4179             :                                                 } else {
    4180           0 :                                                         php_openssl_store_errors();
    4181             :                                                 }
    4182             :                                         }
    4183           2 :                                         DH_free(dh);
    4184             :                                 } else {
    4185           0 :                                         php_openssl_store_errors();
    4186             :                                 }
    4187           2 :                                 EVP_PKEY_free(pkey);
    4188             :                         } else {
    4189           0 :                                 php_openssl_store_errors();
    4190             :                         }
    4191           2 :                         RETURN_FALSE;
    4192             : #ifdef HAVE_EVP_PKEY_EC
    4193          11 :                 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ec", sizeof("ec") - 1)) != NULL &&
    4194             :                         Z_TYPE_P(data) == IS_ARRAY) {
    4195           1 :                         EC_KEY *eckey = NULL;
    4196           1 :                         EC_GROUP *group = NULL;
    4197           1 :                         EC_POINT *pnt = NULL;
    4198             :                         const BIGNUM *d;
    4199           1 :                         pkey = EVP_PKEY_new();
    4200           1 :                         if (pkey) {
    4201           1 :                                 eckey = EC_KEY_new();
    4202           1 :                                 if (eckey) {
    4203           1 :                                         EC_GROUP *group = NULL;
    4204             :                                         zval *bn;
    4205             :                                         zval *x;
    4206             :                                         zval *y;
    4207             : 
    4208           2 :                                         if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1)) != NULL &&
    4209             :                                                         Z_TYPE_P(bn) == IS_STRING) {
    4210           1 :                                                 int nid = OBJ_sn2nid(Z_STRVAL_P(bn));
    4211           1 :                                                 if (nid != NID_undef) {
    4212           1 :                                                         group = EC_GROUP_new_by_curve_name(nid);
    4213           1 :                                                         if (!group) {
    4214           0 :                                                                 php_openssl_store_errors();
    4215           0 :                                                                 goto clean_exit;
    4216             :                                                         }
    4217           1 :                                                         EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
    4218           1 :                                                         EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
    4219           1 :                                                         if (!EC_KEY_set_group(eckey, group)) {
    4220           0 :                                                                 php_openssl_store_errors();
    4221           0 :                                                                 goto clean_exit;
    4222             :                                                         }
    4223             :                                                 }
    4224             :                                         }
    4225             : 
    4226           1 :                                         if (group == NULL) {
    4227           0 :                                                 php_error_docref(NULL, E_WARNING, "Unknown curve_name");
    4228           0 :                                                 goto clean_exit;
    4229             :                                         }
    4230             : 
    4231             :                                         // The public key 'pnt' can be calculated from 'd' or is defined by 'x' and 'y'
    4232           3 :                                         if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "d", sizeof("d") - 1)) != NULL &&
    4233             :                                                         Z_TYPE_P(bn) == IS_STRING) {
    4234           1 :                                                 d = BN_bin2bn((unsigned char*) Z_STRVAL_P(bn), Z_STRLEN_P(bn), NULL);
    4235           1 :                                                 if (!EC_KEY_set_private_key(eckey, d)) {
    4236           0 :                                                         php_openssl_store_errors();
    4237           0 :                                                         goto clean_exit;
    4238             :                                                 }
    4239             :                                                 // Calculate the public key by multiplying the Point Q with the public key
    4240             :                                                 // P = d * Q
    4241           1 :                                                 pnt = EC_POINT_new(group);
    4242           1 :                                                 if (!pnt || !EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) {
    4243           0 :                                                         php_openssl_store_errors();
    4244           0 :                                                         goto clean_exit;
    4245             :                                                 }
    4246           0 :                                         } else if ((x = zend_hash_str_find(Z_ARRVAL_P(data), "x", sizeof("x") - 1)) != NULL &&
    4247             :                                                         Z_TYPE_P(x) == IS_STRING &&
    4248           0 :                                                         (y = zend_hash_str_find(Z_ARRVAL_P(data), "y", sizeof("y") - 1)) != NULL &&
    4249             :                                                         Z_TYPE_P(y) == IS_STRING) {
    4250           0 :                                                 pnt = EC_POINT_new(group);
    4251           0 :                                                 if (pnt == NULL) {
    4252           0 :                                                         php_openssl_store_errors();
    4253           0 :                                                         goto clean_exit;
    4254             :                                                 }
    4255           0 :                                                 if (!EC_POINT_set_affine_coordinates_GFp(
    4256           0 :                                                                 group, pnt, BN_bin2bn((unsigned char*) Z_STRVAL_P(x), Z_STRLEN_P(x), NULL),
    4257           0 :                                                                 BN_bin2bn((unsigned char*) Z_STRVAL_P(y), Z_STRLEN_P(y), NULL), NULL)) {
    4258           0 :                                                         php_openssl_store_errors();
    4259           0 :                                                         goto clean_exit;
    4260             :                                                 }
    4261             :                                         }
    4262             : 
    4263           1 :                                         if (pnt != NULL) {
    4264           1 :                                                 if (!EC_KEY_set_public_key(eckey, pnt)) {
    4265           0 :                                                         php_openssl_store_errors();
    4266           0 :                                                         goto clean_exit;
    4267             :                                                 }
    4268           1 :                                                 EC_POINT_free(pnt);
    4269           1 :                                                 pnt = NULL;
    4270             :                                         }
    4271             : 
    4272           1 :                                         if (!EC_KEY_check_key(eckey)) {
    4273           0 :                                                 PHP_OPENSSL_RAND_ADD_TIME();
    4274           0 :                                                 EC_KEY_generate_key(eckey);
    4275           0 :                                                 php_openssl_store_errors();
    4276             :                                         }
    4277           1 :                                         if (EC_KEY_check_key(eckey) && EVP_PKEY_assign_EC_KEY(pkey, eckey)) {
    4278           1 :                                                 EC_GROUP_free(group);
    4279           1 :                                                 RETURN_RES(zend_register_resource(pkey, le_key));
    4280             :                                         } else {
    4281           0 :                                                 php_openssl_store_errors();
    4282             :                                         }
    4283             :                                 } else {
    4284           0 :                                         php_openssl_store_errors();
    4285             :                                 }
    4286             :                         } else {
    4287           0 :                                 php_openssl_store_errors();
    4288             :                         }
    4289             : clean_exit:
    4290           0 :                         if (pnt != NULL) {
    4291           0 :                                 EC_POINT_free(pnt);
    4292             :                         }
    4293           0 :                         if (group != NULL) {
    4294           0 :                                 EC_GROUP_free(group);
    4295             :                         }
    4296           0 :                         if (eckey != NULL) {
    4297           0 :                                 EC_KEY_free(eckey);
    4298             :                         }
    4299           0 :                         if (pkey != NULL) {
    4300           0 :                                 EVP_PKEY_free(pkey);
    4301             :                         }
    4302           0 :                         RETURN_FALSE;
    4303             : #endif
    4304             :                 }
    4305             :         }
    4306             : 
    4307          17 :         PHP_SSL_REQ_INIT(&req);
    4308             : 
    4309          17 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
    4310             :         {
    4311          16 :                 if (php_openssl_generate_private_key(&req)) {
    4312             :                         /* pass back a key resource */
    4313          16 :                         RETVAL_RES(zend_register_resource(req.priv_key, le_key));
    4314             :                         /* make sure the cleanup code doesn't zap it! */
    4315          16 :                         req.priv_key = NULL;
    4316             :                 }
    4317             :         }
    4318          17 :         PHP_SSL_REQ_DISPOSE(&req);
    4319             : }
    4320             : /* }}} */
    4321             : 
    4322             : /* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
    4323             :    Gets an exportable representation of a key into a file */
    4324           5 : PHP_FUNCTION(openssl_pkey_export_to_file)
    4325             : {
    4326             :         struct php_x509_request req;
    4327           5 :         zval * zpkey, * args = NULL;
    4328           5 :         char * passphrase = NULL;
    4329           5 :         size_t passphrase_len = 0;
    4330           5 :         char * filename = NULL;
    4331           5 :         size_t filename_len = 0;
    4332           5 :         zend_resource *key_resource = NULL;
    4333           5 :         int pem_write = 0;
    4334             :         EVP_PKEY * key;
    4335           5 :         BIO * bio_out = NULL;
    4336             :         const EVP_CIPHER * cipher;
    4337             : 
    4338           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
    4339           0 :                 return;
    4340             :         }
    4341           5 :         RETVAL_FALSE;
    4342             : 
    4343           5 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
    4344             : 
    4345           5 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource);
    4346             : 
    4347           5 :         if (key == NULL) {
    4348           2 :                 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
    4349           2 :                 RETURN_FALSE;
    4350             :         }
    4351             : 
    4352           3 :         if (php_openssl_open_base_dir_chk(filename)) {
    4353           0 :                 RETURN_FALSE;
    4354             :         }
    4355             : 
    4356           3 :         PHP_SSL_REQ_INIT(&req);
    4357             : 
    4358           3 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    4359           3 :                 bio_out = BIO_new_file(filename, "w");
    4360           3 :                 if (bio_out == NULL) {
    4361           1 :                         php_openssl_store_errors();
    4362           1 :                         goto clean_exit;
    4363             :                 }
    4364             : 
    4365           3 :                 if (passphrase && req.priv_key_encrypt) {
    4366           1 :                         if (req.priv_key_encrypt_cipher) {
    4367           0 :                                 cipher = req.priv_key_encrypt_cipher;
    4368             :                         } else {
    4369           1 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    4370             :                         }
    4371             :                 } else {
    4372           1 :                         cipher = NULL;
    4373             :                 }
    4374             : 
    4375           2 :                 switch (EVP_PKEY_base_id(key)) {
    4376             : #ifdef HAVE_EVP_PKEY_EC
    4377             :                         case EVP_PKEY_EC:
    4378           1 :                                 pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
    4379           1 :                                 break;
    4380             : #endif
    4381             :                         default:
    4382           1 :                                 pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
    4383             :                                 break;
    4384             :                 }
    4385             : 
    4386           2 :                 if (pem_write) {
    4387             :                         /* Success!
    4388             :                          * If returning the output as a string, do so now */
    4389           2 :                         RETVAL_TRUE;
    4390             :                 } else {
    4391           0 :                         php_openssl_store_errors();
    4392             :                 }
    4393             :         }
    4394             : 
    4395             : clean_exit:
    4396           3 :         PHP_SSL_REQ_DISPOSE(&req);
    4397             : 
    4398           3 :         if (key_resource == NULL && key) {
    4399           1 :                 EVP_PKEY_free(key);
    4400             :         }
    4401           3 :         if (bio_out) {
    4402           2 :                 BIO_free(bio_out);
    4403             :         }
    4404             : }
    4405             : /* }}} */
    4406             : 
    4407             : /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
    4408             :    Gets an exportable representation of a key into a string or file */
    4409           6 : PHP_FUNCTION(openssl_pkey_export)
    4410             : {
    4411             :         struct php_x509_request req;
    4412           6 :         zval * zpkey, * args = NULL, *out;
    4413           6 :         char * passphrase = NULL; size_t passphrase_len = 0;
    4414           6 :         int pem_write = 0;
    4415           6 :         zend_resource *key_resource = NULL;
    4416             :         EVP_PKEY * key;
    4417           6 :         BIO * bio_out = NULL;
    4418             :         const EVP_CIPHER * cipher;
    4419             : 
    4420           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
    4421           0 :                 return;
    4422             :         }
    4423           6 :         RETVAL_FALSE;
    4424             : 
    4425           6 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
    4426             : 
    4427           6 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource);
    4428             : 
    4429           6 :         if (key == NULL) {
    4430           1 :                 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
    4431           1 :                 RETURN_FALSE;
    4432             :         }
    4433             : 
    4434           5 :         PHP_SSL_REQ_INIT(&req);
    4435             : 
    4436           5 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    4437           5 :                 bio_out = BIO_new(BIO_s_mem());
    4438             : 
    4439           6 :                 if (passphrase && req.priv_key_encrypt) {
    4440           1 :                         if (req.priv_key_encrypt_cipher) {
    4441           0 :                                 cipher = req.priv_key_encrypt_cipher;
    4442             :                         } else {
    4443           1 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    4444             :                         }
    4445             :                 } else {
    4446           4 :                         cipher = NULL;
    4447             :                 }
    4448             : 
    4449           5 :                 switch (EVP_PKEY_base_id(key)) {
    4450             : #ifdef HAVE_EVP_PKEY_EC
    4451             :                         case EVP_PKEY_EC:
    4452           2 :                                 pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
    4453           2 :                                 break;
    4454             : #endif
    4455             :                         default:
    4456           3 :                                 pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
    4457             :                                 break;
    4458             :                 }
    4459             : 
    4460           5 :                 if (pem_write) {
    4461             :                         /* Success!
    4462             :                          * If returning the output as a string, do so now */
    4463             : 
    4464             :                         char * bio_mem_ptr;
    4465             :                         long bio_mem_len;
    4466           5 :                         RETVAL_TRUE;
    4467             : 
    4468           5 :                         bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
    4469           5 :                         zval_dtor(out);
    4470          10 :                         ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len);
    4471             :                 } else {
    4472           0 :                         php_openssl_store_errors();
    4473             :                 }
    4474             :         }
    4475           5 :         PHP_SSL_REQ_DISPOSE(&req);
    4476             : 
    4477           5 :         if (key_resource == NULL && key) {
    4478           0 :                 EVP_PKEY_free(key);
    4479             :         }
    4480           5 :         if (bio_out) {
    4481           5 :                 BIO_free(bio_out);
    4482             :         }
    4483             : }
    4484             : /* }}} */
    4485             : 
    4486             : /* {{{ proto int openssl_pkey_get_public(mixed cert)
    4487             :    Gets public key from X.509 certificate */
    4488           8 : PHP_FUNCTION(openssl_pkey_get_public)
    4489             : {
    4490             :         zval *cert;
    4491             :         EVP_PKEY *pkey;
    4492             :         zend_resource *res;
    4493             : 
    4494           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) {
    4495           0 :                 return;
    4496             :         }
    4497           8 :         pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &res);
    4498           8 :         if (pkey == NULL) {
    4499           2 :                 RETURN_FALSE;
    4500             :         }
    4501           6 :         ZVAL_RES(return_value, res);
    4502             :         Z_ADDREF_P(return_value);
    4503             : }
    4504             : /* }}} */
    4505             : 
    4506             : /* {{{ proto void openssl_pkey_free(int key)
    4507             :    Frees a key */
    4508           3 : PHP_FUNCTION(openssl_pkey_free)
    4509             : {
    4510             :         zval *key;
    4511             :         EVP_PKEY *pkey;
    4512             : 
    4513           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
    4514           0 :                 return;
    4515             :         }
    4516           3 :         if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
    4517           0 :                 RETURN_FALSE;
    4518             :         }
    4519           3 :         zend_list_close(Z_RES_P(key));
    4520             : }
    4521             : /* }}} */
    4522             : 
    4523             : /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
    4524             :    Gets private keys */
    4525          25 : PHP_FUNCTION(openssl_pkey_get_private)
    4526             : {
    4527             :         zval *cert;
    4528             :         EVP_PKEY *pkey;
    4529          25 :         char * passphrase = "";
    4530          25 :         size_t passphrase_len = sizeof("")-1;
    4531             :         zend_resource *res;
    4532             : 
    4533          25 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
    4534           0 :                 return;
    4535             :         }
    4536          25 :         pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &res);
    4537             : 
    4538          25 :         if (pkey == NULL) {
    4539           0 :                 RETURN_FALSE;
    4540             :         }
    4541          25 :         ZVAL_RES(return_value, res);
    4542             :         Z_ADDREF_P(return_value);
    4543             : }
    4544             : 
    4545             : /* }}} */
    4546             : 
    4547             : /* {{{ proto resource openssl_pkey_get_details(resource key)
    4548             :         returns an array with the key details (bits, pkey, type)*/
    4549          17 : PHP_FUNCTION(openssl_pkey_get_details)
    4550             : {
    4551             :         zval *key;
    4552             :         EVP_PKEY *pkey;
    4553             :         BIO *out;
    4554             :         unsigned int pbio_len;
    4555             :         char *pbio;
    4556             :         zend_long ktype;
    4557             : 
    4558          17 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
    4559           3 :                 return;
    4560             :         }
    4561          14 :         if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
    4562           0 :                 RETURN_FALSE;
    4563             :         }
    4564          14 :         out = BIO_new(BIO_s_mem());
    4565          14 :         if (!PEM_write_bio_PUBKEY(out, pkey)) {
    4566           0 :                 BIO_free(out);
    4567           0 :                 php_openssl_store_errors();
    4568           0 :                 RETURN_FALSE;
    4569             :         }
    4570          14 :         pbio_len = BIO_get_mem_data(out, &pbio);
    4571             : 
    4572          14 :         array_init(return_value);
    4573          14 :         add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
    4574          14 :         add_assoc_stringl(return_value, "key", pbio, pbio_len);
    4575             :         /*TODO: Use the real values once the openssl constants are used
    4576             :          * See the enum at the top of this file
    4577             :          */
    4578          14 :         switch (EVP_PKEY_base_id(pkey)) {
    4579             :                 case EVP_PKEY_RSA:
    4580             :                 case EVP_PKEY_RSA2:
    4581             :                         {
    4582           3 :                                 RSA *rsa = EVP_PKEY_get0_RSA(pkey);
    4583           3 :                                 ktype = OPENSSL_KEYTYPE_RSA;
    4584             : 
    4585           3 :                                 if (rsa != NULL) {
    4586             :                                         zval z_rsa;
    4587             :                                         const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
    4588             : 
    4589           3 :                                         RSA_get0_key(rsa, &n, &e, &d);
    4590           3 :                                         RSA_get0_factors(rsa, &p, &q);
    4591           3 :                                         RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
    4592             : 
    4593           3 :                                         array_init(&z_rsa);
    4594           6 :                                         OPENSSL_PKEY_GET_BN(z_rsa, n);
    4595           6 :                                         OPENSSL_PKEY_GET_BN(z_rsa, e);
    4596           6 :                                         OPENSSL_PKEY_GET_BN(z_rsa, d);
    4597           6 :                                         OPENSSL_PKEY_GET_BN(z_rsa, p);
    4598           6 :                                         OPENSSL_PKEY_GET_BN(z_rsa, q);
    4599           5 :                                         OPENSSL_PKEY_GET_BN(z_rsa, dmp1);
    4600           5 :                                         OPENSSL_PKEY_GET_BN(z_rsa, dmq1);
    4601           5 :                                         OPENSSL_PKEY_GET_BN(z_rsa, iqmp);
    4602           3 :                                         add_assoc_zval(return_value, "rsa", &z_rsa);
    4603             :                                 }
    4604             :                         }
    4605           3 :                         break;
    4606             :                 case EVP_PKEY_DSA:
    4607             :                 case EVP_PKEY_DSA2:
    4608             :                 case EVP_PKEY_DSA3:
    4609             :                 case EVP_PKEY_DSA4:
    4610             :                         {
    4611           1 :                                 DSA *dsa = EVP_PKEY_get0_DSA(pkey);
    4612           1 :                                 ktype = OPENSSL_KEYTYPE_DSA;
    4613             : 
    4614           1 :                                 if (dsa != NULL) {
    4615             :                                         zval z_dsa;
    4616             :                                         const BIGNUM *p, *q, *g, *priv_key, *pub_key;
    4617             : 
    4618           1 :                                         DSA_get0_pqg(dsa, &p, &q, &g);
    4619           1 :                                         DSA_get0_key(dsa, &pub_key, &priv_key);
    4620             : 
    4621           1 :                                         array_init(&z_dsa);
    4622           2 :                                         OPENSSL_PKEY_GET_BN(z_dsa, p);
    4623           2 :                                         OPENSSL_PKEY_GET_BN(z_dsa, q);
    4624           2 :                                         OPENSSL_PKEY_GET_BN(z_dsa, g);
    4625           2 :                                         OPENSSL_PKEY_GET_BN(z_dsa, priv_key);
    4626           2 :                                         OPENSSL_PKEY_GET_BN(z_dsa, pub_key);
    4627           1 :                                         add_assoc_zval(return_value, "dsa", &z_dsa);
    4628             :                                 }
    4629             :                         }
    4630           1 :                         break;
    4631             :                 case EVP_PKEY_DH:
    4632             :                         {
    4633           2 :                                 DH *dh = EVP_PKEY_get0_DH(pkey);
    4634           2 :                                 ktype = OPENSSL_KEYTYPE_DH;
    4635             : 
    4636           2 :                                 if (dh != NULL) {
    4637             :                                         zval z_dh;
    4638             :                                         const BIGNUM *p, *q, *g, *priv_key, *pub_key;
    4639             : 
    4640           2 :                                         DH_get0_pqg(dh, &p, &q, &g);
    4641           2 :                                         DH_get0_key(dh, &pub_key, &priv_key);
    4642             : 
    4643           2 :                                         array_init(&z_dh);
    4644           4 :                                         OPENSSL_PKEY_GET_BN(z_dh, p);
    4645           4 :                                         OPENSSL_PKEY_GET_BN(z_dh, g);
    4646           4 :                                         OPENSSL_PKEY_GET_BN(z_dh, priv_key);
    4647           4 :                                         OPENSSL_PKEY_GET_BN(z_dh, pub_key);
    4648           2 :                                         add_assoc_zval(return_value, "dh", &z_dh);
    4649             :                                 }
    4650             :                         }
    4651           2 :                         break;
    4652             : #ifdef HAVE_EVP_PKEY_EC
    4653             :                 case EVP_PKEY_EC:
    4654           8 :                         ktype = OPENSSL_KEYTYPE_EC;
    4655           8 :                         if (EVP_PKEY_get0_EC_KEY(pkey) != NULL) {
    4656             :                                 zval ec;
    4657             :                                 const EC_GROUP *ec_group;
    4658             :                                 const EC_POINT *pub;
    4659             :                                 int nid;
    4660             :                                 char *crv_sn;
    4661             :                                 ASN1_OBJECT *obj;
    4662             :                                 // openssl recommends a buffer length of 80
    4663             :                                 char oir_buf[80];
    4664           8 :                                 const EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey);
    4665           8 :                                 BIGNUM *x = BN_new();
    4666           8 :                                 BIGNUM *y = BN_new();
    4667             :                                 const BIGNUM *d;
    4668             : 
    4669           8 :                                 ec_group = EC_KEY_get0_group(ec_key);
    4670             : 
    4671             :                                 // Curve nid (numerical identifier) used for ASN1 mapping
    4672           8 :                                 nid = EC_GROUP_get_curve_name(ec_group);
    4673           8 :                                 if (nid == NID_undef) {
    4674           0 :                                         break;
    4675             :                                 }
    4676           8 :                                 array_init(&ec);
    4677             : 
    4678             :                                 // Short object name
    4679           8 :                                 crv_sn = (char*) OBJ_nid2sn(nid);
    4680           8 :                                 if (crv_sn != NULL) {
    4681           8 :                                         add_assoc_string(&ec, "curve_name", crv_sn);
    4682             :                                 }
    4683             : 
    4684           8 :                                 obj = OBJ_nid2obj(nid);
    4685           8 :                                 if (obj != NULL) {
    4686           8 :                                         int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
    4687           8 :                                         add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len);
    4688           8 :                                         ASN1_OBJECT_free(obj);
    4689             :                                 }
    4690             : 
    4691           8 :                                 pub = EC_KEY_get0_public_key(ec_key);
    4692             : 
    4693           8 :                                 if (EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x, y, NULL)) {
    4694          16 :                                         OPENSSL_GET_BN(ec, x, x);
    4695          16 :                                         OPENSSL_GET_BN(ec, y, y);
    4696             :                                 } else {
    4697           0 :                                         php_openssl_store_errors();
    4698             :                                 }
    4699             : 
    4700           8 :                                 if ((d = EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(pkey))) != NULL) {
    4701          12 :                                         OPENSSL_GET_BN(ec, d, d);
    4702             :                                 }
    4703             : 
    4704           8 :                                 add_assoc_zval(return_value, "ec", &ec);
    4705             : 
    4706           8 :                                 BN_free(x);
    4707           8 :                                 BN_free(y);
    4708             :                         }
    4709           8 :                         break;
    4710             : #endif
    4711             :                 default:
    4712           0 :                         ktype = -1;
    4713             :                         break;
    4714             :         }
    4715          14 :         add_assoc_long(return_value, "type", ktype);
    4716             : 
    4717          14 :         BIO_free(out);
    4718             : }
    4719             : /* }}} */
    4720             : 
    4721             : /* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
    4722             :    Computes shared secret for public value of remote DH key and local DH key */
    4723           0 : PHP_FUNCTION(openssl_dh_compute_key)
    4724             : {
    4725             :         zval *key;
    4726             :         char *pub_str;
    4727             :         size_t pub_len;
    4728             :         DH *dh;
    4729             :         EVP_PKEY *pkey;
    4730             :         BIGNUM *pub;
    4731             :         zend_string *data;
    4732             :         int len;
    4733             : 
    4734           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sr", &pub_str, &pub_len, &key) == FAILURE) {
    4735           0 :                 return;
    4736             :         }
    4737           0 :         if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
    4738           0 :                 RETURN_FALSE;
    4739             :         }
    4740           0 :         if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
    4741           0 :                 RETURN_FALSE;
    4742             :         }
    4743           0 :         dh = EVP_PKEY_get0_DH(pkey);
    4744           0 :         if (dh == NULL) {
    4745           0 :                 RETURN_FALSE;
    4746             :         }
    4747             : 
    4748           0 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key);
    4749           0 :         pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
    4750             : 
    4751           0 :         data = zend_string_alloc(DH_size(dh), 0);
    4752           0 :         len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
    4753             : 
    4754           0 :         if (len >= 0) {
    4755           0 :                 ZSTR_LEN(data) = len;
    4756           0 :                 ZSTR_VAL(data)[len] = 0;
    4757           0 :                 RETVAL_STR(data);
    4758             :         } else {
    4759           0 :                 php_openssl_store_errors();
    4760             :                 zend_string_release(data);
    4761           0 :                 RETVAL_FALSE;
    4762             :         }
    4763             : 
    4764           0 :         BN_free(pub);
    4765             : }
    4766             : /* }}} */
    4767             : 
    4768             : /* }}} */
    4769             : 
    4770             : /* {{{ proto string openssl_pbkdf2(string password, string salt, long key_length, long iterations [, string digest_method = "sha1"])
    4771             :    Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */
    4772           5 : PHP_FUNCTION(openssl_pbkdf2)
    4773             : {
    4774           5 :         zend_long key_length = 0, iterations = 0;
    4775             :         char *password;
    4776             :         size_t password_len;
    4777             :         char *salt;
    4778             :         size_t salt_len;
    4779             :         char *method;
    4780           5 :         size_t method_len = 0;
    4781             :         zend_string *out_buffer;
    4782             : 
    4783             :         const EVP_MD *digest;
    4784             : 
    4785           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssll|s",
    4786             :                                 &password, &password_len,
    4787             :                                 &salt, &salt_len,
    4788             :                                 &key_length, &iterations,
    4789             :                                 &method, &method_len) == FAILURE) {
    4790           0 :                 return;
    4791             :         }
    4792             : 
    4793           5 :         if (key_length <= 0) {
    4794           0 :                 RETURN_FALSE;
    4795             :         }
    4796             : 
    4797           5 :         if (method_len) {
    4798           0 :                 digest = EVP_get_digestbyname(method);
    4799             :         } else {
    4800           5 :                 digest = EVP_sha1();
    4801             :         }
    4802             : 
    4803           5 :         if (!digest) {
    4804           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
    4805           0 :                 RETURN_FALSE;
    4806             :         }
    4807             : 
    4808           5 :         PHP_OPENSSL_CHECK_LONG_TO_INT(key_length, key);
    4809           5 :         PHP_OPENSSL_CHECK_LONG_TO_INT(iterations, iterations);
    4810           5 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
    4811           5 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(salt_len, salt);
    4812             : 
    4813          10 :         out_buffer = zend_string_alloc(key_length, 0);
    4814             : 
    4815           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) {
    4816           5 :                 ZSTR_VAL(out_buffer)[key_length] = 0;
    4817           5 :                 RETURN_NEW_STR(out_buffer);
    4818             :         } else {
    4819           0 :                 php_openssl_store_errors();
    4820             :                 zend_string_release(out_buffer);
    4821           0 :                 RETURN_FALSE;
    4822             :         }
    4823             : }
    4824             : /* }}} */
    4825             : 
    4826             : /* {{{ PKCS7 S/MIME functions */
    4827             : 
    4828             : /* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
    4829             :    Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
    4830           0 : PHP_FUNCTION(openssl_pkcs7_verify)
    4831             : {
    4832           0 :         X509_STORE * store = NULL;
    4833           0 :         zval * cainfo = NULL;
    4834           0 :         STACK_OF(X509) *signers= NULL;
    4835           0 :         STACK_OF(X509) *others = NULL;
    4836           0 :         PKCS7 * p7 = NULL;
    4837           0 :         BIO * in = NULL, * datain = NULL, * dataout = NULL;
    4838           0 :         zend_long flags = 0;
    4839             :         char * filename;
    4840             :         size_t filename_len;
    4841           0 :         char * extracerts = NULL;
    4842           0 :         size_t extracerts_len = 0;
    4843           0 :         char * signersfilename = NULL;
    4844           0 :         size_t signersfilename_len = 0;
    4845           0 :         char * datafilename = NULL;
    4846           0 :         size_t datafilename_len = 0;
    4847             : 
    4848           0 :         RETVAL_LONG(-1);
    4849             : 
    4850           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|papp", &filename, &filename_len,
    4851             :                                 &flags, &signersfilename, &signersfilename_len, &cainfo,
    4852             :                                 &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
    4853           0 :                 return;
    4854             :         }
    4855             : 
    4856           0 :         if (extracerts) {
    4857           0 :                 others = load_all_certs_from_file(extracerts);
    4858           0 :                 if (others == NULL) {
    4859           0 :                         goto clean_exit;
    4860             :                 }
    4861             :         }
    4862             : 
    4863           0 :         flags = flags & ~PKCS7_DETACHED;
    4864             : 
    4865           0 :         store = setup_verify(cainfo);
    4866             : 
    4867           0 :         if (!store) {
    4868           0 :                 goto clean_exit;
    4869             :         }
    4870           0 :         if (php_openssl_open_base_dir_chk(filename)) {
    4871           0 :                 goto clean_exit;
    4872             :         }
    4873             : 
    4874           0 :         in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
    4875           0 :         if (in == NULL) {
    4876           0 :                 php_openssl_store_errors();
    4877           0 :                 goto clean_exit;
    4878             :         }
    4879           0 :         p7 = SMIME_read_PKCS7(in, &datain);
    4880           0 :         if (p7 == NULL) {
    4881             : #if DEBUG_SMIME
    4882             :                 zend_printf("SMIME_read_PKCS7 failed\n");
    4883             : #endif
    4884           0 :                 php_openssl_store_errors();
    4885           0 :                 goto clean_exit;
    4886             :         }
    4887             : 
    4888           0 :         if (datafilename) {
    4889             : 
    4890           0 :                 if (php_openssl_open_base_dir_chk(datafilename)) {
    4891           0 :                         goto clean_exit;
    4892             :                 }
    4893             : 
    4894           0 :                 dataout = BIO_new_file(datafilename, "w");
    4895           0 :                 if (dataout == NULL) {
    4896           0 :                         php_openssl_store_errors();
    4897           0 :                         goto clean_exit;
    4898             :                 }
    4899             :         }
    4900             : #if DEBUG_SMIME
    4901             :         zend_printf("Calling PKCS7 verify\n");
    4902             : #endif
    4903             : 
    4904           0 :         if (PKCS7_verify(p7, others, store, datain, dataout, (int)flags)) {
    4905             : 
    4906           0 :                 RETVAL_TRUE;
    4907             : 
    4908           0 :                 if (signersfilename) {
    4909             :                         BIO *certout;
    4910             : 
    4911           0 :                         if (php_openssl_open_base_dir_chk(signersfilename)) {
    4912           0 :                                 goto clean_exit;
    4913             :                         }
    4914             : 
    4915           0 :                         certout = BIO_new_file(signersfilename, "w");
    4916           0 :                         if (certout) {
    4917             :                                 int i;
    4918           0 :                                 signers = PKCS7_get0_signers(p7, NULL, (int)flags);
    4919           0 :                                 if (signers != NULL) {
    4920             : 
    4921           0 :                                         for (i = 0; i < sk_X509_num(signers); i++) {
    4922           0 :                                                 if (!PEM_write_bio_X509(certout, sk_X509_value(signers, i))) {
    4923           0 :                                                         php_openssl_store_errors();
    4924           0 :                                                         RETVAL_LONG(-1);
    4925           0 :                                                         php_error_docref(NULL, E_WARNING, "failed to write signer %d", i);
    4926             :                                                 }
    4927             :                                         }
    4928             : 
    4929           0 :                                         sk_X509_free(signers);
    4930             :                                 } else {
    4931           0 :                                         RETVAL_LONG(-1);
    4932           0 :                                         php_openssl_store_errors();
    4933             :                                 }
    4934             : 
    4935           0 :                                 BIO_free(certout);
    4936             :                         } else {
    4937           0 :                                 php_openssl_store_errors();
    4938           0 :                                 php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
    4939           0 :                                 RETVAL_LONG(-1);
    4940             :                         }
    4941             :                 }
    4942             :         } else {
    4943           0 :                 php_openssl_store_errors();
    4944           0 :                 RETVAL_FALSE;
    4945             :         }
    4946             : clean_exit:
    4947           0 :         X509_STORE_free(store);
    4948           0 :         BIO_free(datain);
    4949           0 :         BIO_free(in);
    4950           0 :         BIO_free(dataout);
    4951           0 :         PKCS7_free(p7);
    4952           0 :         sk_X509_free(others);
    4953             : }
    4954             : /* }}} */
    4955             : 
    4956             : /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
    4957             :    Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
    4958          12 : PHP_FUNCTION(openssl_pkcs7_encrypt)
    4959             : {
    4960          12 :         zval * zrecipcerts, * zheaders = NULL;
    4961          12 :         STACK_OF(X509) * recipcerts = NULL;
    4962          12 :         BIO * infile = NULL, * outfile = NULL;
    4963          12 :         zend_long flags = 0;
    4964          12 :         PKCS7 * p7 = NULL;
    4965             :         zval * zcertval;
    4966             :         X509 * cert;
    4967          12 :         const EVP_CIPHER *cipher = NULL;
    4968          12 :         zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
    4969             :         zend_string * strindex;
    4970          12 :         char * infilename = NULL;
    4971             :         size_t infilename_len;
    4972          12 :         char * outfilename = NULL;
    4973             :         size_t outfilename_len;
    4974             : 
    4975          12 :         RETVAL_FALSE;
    4976             : 
    4977          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len,
    4978             :                                 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
    4979           2 :                 return;
    4980             : 
    4981             : 
    4982          10 :         if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
    4983           0 :                 return;
    4984             :         }
    4985             : 
    4986          10 :         infile = BIO_new_file(infilename, "r");
    4987          10 :         if (infile == NULL) {
    4988           2 :                 php_openssl_store_errors();
    4989           2 :                 goto clean_exit;
    4990             :         }
    4991             : 
    4992           8 :         outfile = BIO_new_file(outfilename, "w");
    4993           8 :         if (outfile == NULL) {
    4994           1 :                 php_openssl_store_errors();
    4995           1 :                 goto clean_exit;
    4996             :         }
    4997             : 
    4998           7 :         recipcerts = sk_X509_new_null();
    4999             : 
    5000             :         /* get certs */
    5001          14 :         if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) {
    5002           5 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) {
    5003             :                         zend_resource *certresource;
    5004             : 
    5005           2 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
    5006           2 :                         if (cert == NULL) {
    5007           0 :                                 goto clean_exit;
    5008             :                         }
    5009             : 
    5010           2 :                         if (certresource != NULL) {
    5011             :                                 /* we shouldn't free this particular cert, as it is a resource.
    5012             :                                         make a copy and push that on the stack instead */
    5013           0 :                                 cert = X509_dup(cert);
    5014           0 :                                 if (cert == NULL) {
    5015           0 :                                         php_openssl_store_errors();
    5016           0 :                                         goto clean_exit;
    5017             :                                 }
    5018             :                         }
    5019           2 :                         sk_X509_push(recipcerts, cert);
    5020             :                 } ZEND_HASH_FOREACH_END();
    5021             :         } else {
    5022             :                 /* a single certificate */
    5023             :                 zend_resource *certresource;
    5024             : 
    5025           6 :                 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource);
    5026           6 :                 if (cert == NULL) {
    5027           2 :                         goto clean_exit;
    5028             :                 }
    5029             : 
    5030           4 :                 if (certresource != NULL) {
    5031             :                         /* we shouldn't free this particular cert, as it is a resource.
    5032             :                                 make a copy and push that on the stack instead */
    5033           0 :                         cert = X509_dup(cert);
    5034           0 :                         if (cert == NULL) {
    5035           0 :                                 php_openssl_store_errors();
    5036           0 :                                 goto clean_exit;
    5037             :                         }
    5038             :                 }
    5039           4 :                 sk_X509_push(recipcerts, cert);
    5040             :         }
    5041             : 
    5042             :         /* sanity check the cipher */
    5043           5 :         cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
    5044           5 :         if (cipher == NULL) {
    5045             :                 /* shouldn't happen */
    5046           0 :                 php_error_docref(NULL, E_WARNING, "Failed to get cipher");
    5047           0 :                 goto clean_exit;
    5048             :         }
    5049             : 
    5050           5 :         p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (int)flags);
    5051             : 
    5052           5 :         if (p7 == NULL) {
    5053           0 :                 php_openssl_store_errors();
    5054           0 :                 goto clean_exit;
    5055             :         }
    5056             : 
    5057             :         /* tack on extra headers */
    5058           5 :         if (zheaders) {
    5059          21 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) {
    5060           8 :                         convert_to_string_ex(zcertval);
    5061             : 
    5062           8 :                         if (strindex) {
    5063           2 :                                 BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval));
    5064             :                         } else {
    5065           6 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval));
    5066             :                         }
    5067             :                 } ZEND_HASH_FOREACH_END();
    5068             :         }
    5069             : 
    5070           5 :         (void)BIO_reset(infile);
    5071             : 
    5072             :         /* write the encrypted data */
    5073           5 :         if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) {
    5074           0 :                 php_openssl_store_errors();
    5075           0 :                 goto clean_exit;
    5076             :         }
    5077             : 
    5078           5 :         RETVAL_TRUE;
    5079             : 
    5080             : clean_exit:
    5081          10 :         PKCS7_free(p7);
    5082          10 :         BIO_free(infile);
    5083          10 :         BIO_free(outfile);
    5084          10 :         if (recipcerts) {
    5085           7 :                 sk_X509_pop_free(recipcerts, X509_free);
    5086             :         }
    5087             : }
    5088             : /* }}} */
    5089             : 
    5090             : /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
    5091             :    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 */
    5092             : 
    5093          11 : PHP_FUNCTION(openssl_pkcs7_sign)
    5094             : {
    5095             :         zval * zcert, * zprivkey, * zheaders;
    5096             :         zval * hval;
    5097          11 :         X509 * cert = NULL;
    5098          11 :         EVP_PKEY * privkey = NULL;
    5099          11 :         zend_long flags = PKCS7_DETACHED;
    5100          11 :         PKCS7 * p7 = NULL;
    5101          11 :         BIO * infile = NULL, * outfile = NULL;
    5102          11 :         STACK_OF(X509) *others = NULL;
    5103          11 :         zend_resource *certresource = NULL, *keyresource = NULL;
    5104             :         zend_string * strindex;
    5105             :         char * infilename;
    5106             :         size_t infilename_len;
    5107             :         char * outfilename;
    5108             :         size_t outfilename_len;
    5109          11 :         char * extracertsfilename = NULL;
    5110             :         size_t extracertsfilename_len;
    5111             : 
    5112          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|lp!",
    5113             :                                 &infilename, &infilename_len, &outfilename, &outfilename_len,
    5114             :                                 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
    5115             :                                 &extracertsfilename_len) == FAILURE) {
    5116           2 :                 return;
    5117             :         }
    5118             : 
    5119           9 :         RETVAL_FALSE;
    5120             : 
    5121           9 :         if (extracertsfilename) {
    5122           0 :                 others = load_all_certs_from_file(extracertsfilename);
    5123           0 :                 if (others == NULL) {
    5124           0 :                         goto clean_exit;
    5125             :                 }
    5126             :         }
    5127             : 
    5128           9 :         privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource);
    5129           9 :         if (privkey == NULL) {
    5130           1 :                 php_error_docref(NULL, E_WARNING, "error getting private key");
    5131           1 :                 goto clean_exit;
    5132             :         }
    5133             : 
    5134           8 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
    5135           8 :         if (cert == NULL) {
    5136           2 :                 php_error_docref(NULL, E_WARNING, "error getting cert");
    5137           2 :                 goto clean_exit;
    5138             :         }
    5139             : 
    5140           6 :         if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
    5141             :                 goto clean_exit;
    5142             :         }
    5143             : 
    5144           6 :         infile = BIO_new_file(infilename, "r");
    5145           6 :         if (infile == NULL) {
    5146           2 :                 php_openssl_store_errors();
    5147           2 :                 php_error_docref(NULL, E_WARNING, "error opening input file %s!", infilename);
    5148           2 :                 goto clean_exit;
    5149             :         }
    5150             : 
    5151           4 :         outfile = BIO_new_file(outfilename, "w");
    5152           4 :         if (outfile == NULL) {
    5153           1 :                 php_openssl_store_errors();
    5154           1 :                 php_error_docref(NULL, E_WARNING, "error opening output file %s!", outfilename);
    5155           1 :                 goto clean_exit;
    5156             :         }
    5157             : 
    5158           3 :         p7 = PKCS7_sign(cert, privkey, others, infile, (int)flags);
    5159           3 :         if (p7 == NULL) {
    5160           0 :                 php_openssl_store_errors();
    5161           0 :                 php_error_docref(NULL, E_WARNING, "error creating PKCS7 structure!");
    5162           0 :                 goto clean_exit;
    5163             :         }
    5164             : 
    5165           3 :         (void)BIO_reset(infile);
    5166             : 
    5167             :         /* tack on extra headers */
    5168           3 :         if (zheaders) {
    5169             :                 int ret;
    5170             : 
    5171          11 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) {
    5172           4 :                         convert_to_string_ex(hval);
    5173             : 
    5174           4 :                         if (strindex) {
    5175           2 :                                 ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval));
    5176             :                         } else {
    5177           2 :                                 ret = BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval));
    5178             :                         }
    5179           4 :                         if (ret < 0) {
    5180           0 :                                 php_openssl_store_errors();
    5181             :                         }
    5182             :                 } ZEND_HASH_FOREACH_END();
    5183             :         }
    5184             :         /* write the signed data */
    5185           3 :         if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) {
    5186           0 :                 php_openssl_store_errors();
    5187           0 :                 goto clean_exit;
    5188             :         }
    5189             : 
    5190           3 :         RETVAL_TRUE;
    5191             : 
    5192             : clean_exit:
    5193           9 :         PKCS7_free(p7);
    5194           9 :         BIO_free(infile);
    5195           9 :         BIO_free(outfile);
    5196           9 :         if (others) {
    5197           0 :                 sk_X509_pop_free(others, X509_free);
    5198             :         }
    5199           9 :         if (privkey && keyresource == NULL) {
    5200           8 :                 EVP_PKEY_free(privkey);
    5201             :         }
    5202           9 :         if (cert && certresource == NULL) {
    5203           6 :                 X509_free(cert);
    5204             :         }
    5205             : }
    5206             : /* }}} */
    5207             : 
    5208             : /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
    5209             :    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 */
    5210             : 
    5211          15 : PHP_FUNCTION(openssl_pkcs7_decrypt)
    5212             : {
    5213          15 :         zval * recipcert, * recipkey = NULL;
    5214          15 :         X509 * cert = NULL;
    5215          15 :         EVP_PKEY * key = NULL;
    5216             :         zend_resource *certresval, *keyresval;
    5217          15 :         BIO * in = NULL, * out = NULL, * datain = NULL;
    5218          15 :         PKCS7 * p7 = NULL;
    5219             :         char * infilename;
    5220             :         size_t infilename_len;
    5221             :         char * outfilename;
    5222             :         size_t outfilename_len;
    5223             : 
    5224          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|z", &infilename, &infilename_len,
    5225             :                                 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
    5226           0 :                 return;
    5227             :         }
    5228             : 
    5229          15 :         RETVAL_FALSE;
    5230             : 
    5231          15 :         cert = php_openssl_x509_from_zval(recipcert, 0, &certresval);
    5232          15 :         if (cert == NULL) {
    5233           8 :                 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 3 to x509 cert");
    5234           8 :                 goto clean_exit;
    5235             :         }
    5236             : 
    5237           7 :         key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval);
    5238           7 :         if (key == NULL) {
    5239           2 :                 php_error_docref(NULL, E_WARNING, "unable to get private key");
    5240           2 :                 goto clean_exit;
    5241             :         }
    5242             : 
    5243           5 :         if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
    5244             :                 goto clean_exit;
    5245             :         }
    5246             : 
    5247           5 :         in = BIO_new_file(infilename, "r");
    5248           5 :         if (in == NULL) {
    5249           2 :                 php_openssl_store_errors();
    5250           2 :                 goto clean_exit;
    5251             :         }
    5252           3 :         out = BIO_new_file(outfilename, "w");
    5253           3 :         if (out == NULL) {
    5254           1 :                 php_openssl_store_errors();
    5255           1 :                 goto clean_exit;
    5256             :         }
    5257             : 
    5258           2 :         p7 = SMIME_read_PKCS7(in, &datain);
    5259             : 
    5260           2 :         if (p7 == NULL) {
    5261           0 :                 php_openssl_store_errors();
    5262           0 :                 goto clean_exit;
    5263             :         }
    5264           2 :         if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) {
    5265           2 :                 RETVAL_TRUE;
    5266             :         } else {
    5267           0 :                 php_openssl_store_errors();
    5268             :         }
    5269             : clean_exit:
    5270          15 :         PKCS7_free(p7);
    5271          15 :         BIO_free(datain);
    5272          15 :         BIO_free(in);
    5273          15 :         BIO_free(out);
    5274          15 :         if (cert && certresval == NULL) {
    5275           7 :                 X509_free(cert);
    5276             :         }
    5277          15 :         if (key && keyresval == NULL) {
    5278           5 :                 EVP_PKEY_free(key);
    5279             :         }
    5280             : }
    5281             : /* }}} */
    5282             : 
    5283             : /* }}} */
    5284             : 
    5285             : /* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
    5286             :    Encrypts data with private key */
    5287           7 : PHP_FUNCTION(openssl_private_encrypt)
    5288             : {
    5289             :         zval *key, *crypted;
    5290             :         EVP_PKEY *pkey;
    5291             :         int cryptedlen;
    5292           7 :         zend_string *cryptedbuf = NULL;
    5293           7 :         int successful = 0;
    5294           7 :         zend_resource *keyresource = NULL;
    5295             :         char * data;
    5296             :         size_t data_len;
    5297           7 :         zend_long padding = RSA_PKCS1_PADDING;
    5298             : 
    5299           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    5300           0 :                 return;
    5301             :         }
    5302           7 :         RETVAL_FALSE;
    5303             : 
    5304           7 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
    5305             : 
    5306           7 :         if (pkey == NULL) {
    5307           3 :                 php_error_docref(NULL, E_WARNING, "key param is not a valid private key");
    5308           3 :                 RETURN_FALSE;
    5309             :         }
    5310             : 
    5311           4 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5312             : 
    5313           4 :         cryptedlen = EVP_PKEY_size(pkey);
    5314           8 :         cryptedbuf = zend_string_alloc(cryptedlen, 0);
    5315             : 
    5316           4 :         switch (EVP_PKEY_id(pkey)) {
    5317             :                 case EVP_PKEY_RSA:
    5318             :                 case EVP_PKEY_RSA2:
    5319           8 :                         successful = (RSA_private_encrypt((int)data_len,
    5320             :                                                 (unsigned char *)data,
    5321             :                                                 (unsigned char *)ZSTR_VAL(cryptedbuf),
    5322           4 :                                                 EVP_PKEY_get0_RSA(pkey),
    5323             :                                                 (int)padding) == cryptedlen);
    5324           4 :                         break;
    5325             :                 default:
    5326           0 :                         php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
    5327             :         }
    5328             : 
    5329           4 :         if (successful) {
    5330           3 :                 zval_dtor(crypted);
    5331           3 :                 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
    5332           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    5333           3 :                 cryptedbuf = NULL;
    5334           3 :                 RETVAL_TRUE;
    5335             :         } else {
    5336           1 :                 php_openssl_store_errors();
    5337             :         }
    5338           4 :         if (cryptedbuf) {
    5339             :                 zend_string_release(cryptedbuf);
    5340             :         }
    5341           4 :         if (keyresource == NULL) {
    5342           4 :                 EVP_PKEY_free(pkey);
    5343             :         }
    5344             : }
    5345             : /* }}} */
    5346             : 
    5347             : /* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding])
    5348             :    Decrypts data with private key */
    5349           7 : PHP_FUNCTION(openssl_private_decrypt)
    5350             : {
    5351             :         zval *key, *crypted;
    5352             :         EVP_PKEY *pkey;
    5353             :         int cryptedlen;
    5354           7 :         zend_string *cryptedbuf = NULL;
    5355             :         unsigned char *crypttemp;
    5356           7 :         int successful = 0;
    5357           7 :         zend_long padding = RSA_PKCS1_PADDING;
    5358           7 :         zend_resource *keyresource = NULL;
    5359             :         char * data;
    5360             :         size_t data_len;
    5361             : 
    5362           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    5363           0 :                 return;
    5364             :         }
    5365           7 :         RETVAL_FALSE;
    5366             : 
    5367           7 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
    5368           7 :         if (pkey == NULL) {
    5369           2 :                 php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key");
    5370           2 :                 RETURN_FALSE;
    5371             :         }
    5372             : 
    5373           5 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5374             : 
    5375           5 :         cryptedlen = EVP_PKEY_size(pkey);
    5376           5 :         crypttemp = emalloc(cryptedlen + 1);
    5377             : 
    5378           5 :         switch (EVP_PKEY_id(pkey)) {
    5379             :                 case EVP_PKEY_RSA:
    5380             :                 case EVP_PKEY_RSA2:
    5381          10 :                         cryptedlen = RSA_private_decrypt((int)data_len,
    5382             :                                         (unsigned char *)data,
    5383             :                                         crypttemp,
    5384           5 :                                         EVP_PKEY_get0_RSA(pkey),
    5385             :                                         (int)padding);
    5386           5 :                         if (cryptedlen != -1) {
    5387           6 :                                 cryptedbuf = zend_string_alloc(cryptedlen, 0);
    5388           3 :                                 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
    5389           3 :                                 successful = 1;
    5390             :                         }
    5391           5 :                         break;
    5392             :                 default:
    5393           0 :                         php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
    5394             :         }
    5395             : 
    5396           5 :         efree(crypttemp);
    5397             : 
    5398           5 :         if (successful) {
    5399           3 :                 zval_dtor(crypted);
    5400           3 :                 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
    5401           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    5402           3 :                 cryptedbuf = NULL;
    5403           3 :                 RETVAL_TRUE;
    5404             :         } else {
    5405           2 :                 php_openssl_store_errors();
    5406             :         }
    5407             : 
    5408           5 :         if (keyresource == NULL) {
    5409           5 :                 EVP_PKEY_free(pkey);
    5410             :         }
    5411           5 :         if (cryptedbuf) {
    5412             :                 zend_string_release(cryptedbuf);
    5413             :         }
    5414             : }
    5415             : /* }}} */
    5416             : 
    5417             : /* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding])
    5418             :    Encrypts data with public key */
    5419           7 : PHP_FUNCTION(openssl_public_encrypt)
    5420             : {
    5421             :         zval *key, *crypted;
    5422             :         EVP_PKEY *pkey;
    5423             :         int cryptedlen;
    5424             :         zend_string *cryptedbuf;
    5425           7 :         int successful = 0;
    5426           7 :         zend_resource *keyresource = NULL;
    5427           7 :         zend_long padding = RSA_PKCS1_PADDING;
    5428             :         char * data;
    5429             :         size_t data_len;
    5430             : 
    5431           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
    5432           0 :                 return;
    5433           7 :         RETVAL_FALSE;
    5434             : 
    5435           7 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
    5436           7 :         if (pkey == NULL) {
    5437           3 :                 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
    5438           3 :                 RETURN_FALSE;
    5439             :         }
    5440             : 
    5441           4 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5442             : 
    5443           4 :         cryptedlen = EVP_PKEY_size(pkey);
    5444           8 :         cryptedbuf = zend_string_alloc(cryptedlen, 0);
    5445             : 
    5446           4 :         switch (EVP_PKEY_id(pkey)) {
    5447             :                 case EVP_PKEY_RSA:
    5448             :                 case EVP_PKEY_RSA2:
    5449           8 :                         successful = (RSA_public_encrypt((int)data_len,
    5450             :                                                 (unsigned char *)data,
    5451             :                                                 (unsigned char *)ZSTR_VAL(cryptedbuf),
    5452           4 :                                                 EVP_PKEY_get0_RSA(pkey),
    5453             :                                                 (int)padding) == cryptedlen);
    5454           4 :                         break;
    5455             :                 default:
    5456           0 :                         php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
    5457             : 
    5458             :         }
    5459             : 
    5460           4 :         if (successful) {
    5461           3 :                 zval_dtor(crypted);
    5462           3 :                 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
    5463           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    5464           3 :                 cryptedbuf = NULL;
    5465           3 :                 RETVAL_TRUE;
    5466             :         } else {
    5467           1 :                 php_openssl_store_errors();
    5468             :         }
    5469           4 :         if (keyresource == NULL) {
    5470           4 :                 EVP_PKEY_free(pkey);
    5471             :         }
    5472           4 :         if (cryptedbuf) {
    5473             :                 zend_string_release(cryptedbuf);
    5474             :         }
    5475             : }
    5476             : /* }}} */
    5477             : 
    5478             : /* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding])
    5479             :    Decrypts data with public key */
    5480           8 : PHP_FUNCTION(openssl_public_decrypt)
    5481             : {
    5482             :         zval *key, *crypted;
    5483             :         EVP_PKEY *pkey;
    5484             :         int cryptedlen;
    5485           8 :         zend_string *cryptedbuf = NULL;
    5486             :         unsigned char *crypttemp;
    5487           8 :         int successful = 0;
    5488           8 :         zend_resource *keyresource = NULL;
    5489           8 :         zend_long padding = RSA_PKCS1_PADDING;
    5490             :         char * data;
    5491             :         size_t data_len;
    5492             : 
    5493           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    5494           0 :                 return;
    5495             :         }
    5496           8 :         RETVAL_FALSE;
    5497             : 
    5498           8 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
    5499           8 :         if (pkey == NULL) {
    5500           3 :                 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
    5501           3 :                 RETURN_FALSE;
    5502             :         }
    5503             : 
    5504           5 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5505             : 
    5506           5 :         cryptedlen = EVP_PKEY_size(pkey);
    5507           5 :         crypttemp = emalloc(cryptedlen + 1);
    5508             : 
    5509           5 :         switch (EVP_PKEY_id(pkey)) {
    5510             :                 case EVP_PKEY_RSA:
    5511             :                 case EVP_PKEY_RSA2:
    5512          10 :                         cryptedlen = RSA_public_decrypt((int)data_len,
    5513             :                                         (unsigned char *)data,
    5514             :                                         crypttemp,
    5515           5 :                                         EVP_PKEY_get0_RSA(pkey),
    5516             :                                         (int)padding);
    5517           5 :                         if (cryptedlen != -1) {
    5518           6 :                                 cryptedbuf = zend_string_alloc(cryptedlen, 0);
    5519           3 :                                 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
    5520           3 :                                 successful = 1;
    5521             :                         }
    5522           5 :                         break;
    5523             : 
    5524             :                 default:
    5525           0 :                         php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
    5526             : 
    5527             :         }
    5528             : 
    5529           5 :         efree(crypttemp);
    5530             : 
    5531           5 :         if (successful) {
    5532           3 :                 zval_dtor(crypted);
    5533           3 :                 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
    5534           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    5535           3 :                 cryptedbuf = NULL;
    5536           3 :                 RETVAL_TRUE;
    5537             :         } else {
    5538           2 :                 php_openssl_store_errors();
    5539             :         }
    5540             : 
    5541           5 :         if (cryptedbuf) {
    5542             :                 zend_string_release(cryptedbuf);
    5543             :         }
    5544           5 :         if (keyresource == NULL) {
    5545           5 :                 EVP_PKEY_free(pkey);
    5546             :         }
    5547             : }
    5548             : /* }}} */
    5549             : 
    5550             : /* {{{ proto mixed openssl_error_string(void)
    5551             :    Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
    5552          64 : PHP_FUNCTION(openssl_error_string)
    5553             : {
    5554             :         char buf[256];
    5555             :         unsigned long val;
    5556             : 
    5557          64 :         if (zend_parse_parameters_none() == FAILURE) {
    5558           0 :                 return;
    5559             :         }
    5560             : 
    5561          64 :         php_openssl_store_errors();
    5562             : 
    5563          64 :         if (OPENSSL_G(errors) == NULL || OPENSSL_G(errors)->top == OPENSSL_G(errors)->bottom) {
    5564          17 :                 RETURN_FALSE;
    5565             :         }
    5566             : 
    5567          47 :         OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % ERR_NUM_ERRORS;
    5568          47 :         val = OPENSSL_G(errors)->buffer[OPENSSL_G(errors)->bottom];
    5569             : 
    5570          47 :         if (val) {
    5571          47 :                 ERR_error_string_n(val, buf, 256);
    5572          94 :                 RETURN_STRING(buf);
    5573             :         } else {
    5574           0 :                 RETURN_FALSE;
    5575             :         }
    5576             : }
    5577             : /* }}} */
    5578             : 
    5579             : /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
    5580             :    Signs data */
    5581           7 : PHP_FUNCTION(openssl_sign)
    5582             : {
    5583             :         zval *key, *signature;
    5584             :         EVP_PKEY *pkey;
    5585             :         unsigned int siglen;
    5586             :         zend_string *sigbuf;
    5587           7 :         zend_resource *keyresource = NULL;
    5588             :         char * data;
    5589             :         size_t data_len;
    5590             :         EVP_MD_CTX *md_ctx;
    5591           7 :         zval *method = NULL;
    5592           7 :         zend_long signature_algo = OPENSSL_ALGO_SHA1;
    5593             :         const EVP_MD *mdtype;
    5594             : 
    5595           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
    5596           1 :                 return;
    5597             :         }
    5598           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
    5599           6 :         if (pkey == NULL) {
    5600           1 :                 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key");
    5601           1 :                 RETURN_FALSE;
    5602             :         }
    5603             : 
    5604          12 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    5605           4 :                 if (method != NULL) {
    5606           2 :                         signature_algo = Z_LVAL_P(method);
    5607             :                 }
    5608           4 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    5609           2 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    5610           1 :                 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
    5611             :         } else {
    5612           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5613           0 :                 RETURN_FALSE;
    5614             :         }
    5615           5 :         if (!mdtype) {
    5616           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5617           0 :                 RETURN_FALSE;
    5618             :         }
    5619             : 
    5620           5 :         siglen = EVP_PKEY_size(pkey);
    5621          10 :         sigbuf = zend_string_alloc(siglen, 0);
    5622             : 
    5623           5 :         md_ctx = EVP_MD_CTX_create();
    5624          25 :         if (md_ctx != NULL &&
    5625           5 :                         EVP_SignInit(md_ctx, mdtype) &&
    5626           5 :                         EVP_SignUpdate(md_ctx, data, data_len) &&
    5627           5 :                         EVP_SignFinal(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, pkey)) {
    5628           5 :                 zval_dtor(signature);
    5629           5 :                 ZSTR_VAL(sigbuf)[siglen] = '\0';
    5630           5 :                 ZSTR_LEN(sigbuf) = siglen;
    5631           5 :                 ZVAL_NEW_STR(signature, sigbuf);
    5632           5 :                 RETVAL_TRUE;
    5633             :         } else {
    5634           0 :                 php_openssl_store_errors();
    5635           0 :                 efree(sigbuf);
    5636           0 :                 RETVAL_FALSE;
    5637             :         }
    5638           5 :         EVP_MD_CTX_destroy(md_ctx);
    5639           5 :         if (keyresource == NULL) {
    5640           2 :                 EVP_PKEY_free(pkey);
    5641             :         }
    5642             : }
    5643             : /* }}} */
    5644             : 
    5645             : /* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
    5646             :    Verifys data */
    5647          16 : PHP_FUNCTION(openssl_verify)
    5648             : {
    5649             :         zval *key;
    5650             :         EVP_PKEY *pkey;
    5651          16 :         int err = 0;
    5652             :         EVP_MD_CTX *md_ctx;
    5653             :         const EVP_MD *mdtype;
    5654          16 :         zend_resource *keyresource = NULL;
    5655             :         char * data;
    5656             :         size_t data_len;
    5657             :         char * signature;
    5658             :         size_t signature_len;
    5659          16 :         zval *method = NULL;
    5660          16 :         zend_long signature_algo = OPENSSL_ALGO_SHA1;
    5661             : 
    5662          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
    5663           5 :                 return;
    5664             :         }
    5665             : 
    5666          11 :         PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature);
    5667             : 
    5668          27 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    5669          11 :                 if (method != NULL) {
    5670           5 :                         signature_algo = Z_LVAL_P(method);
    5671             :                 }
    5672          11 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    5673           0 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    5674           0 :                 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
    5675             :         } else {
    5676           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5677           0 :                 RETURN_FALSE;
    5678             :         }
    5679          11 :         if (!mdtype) {
    5680           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5681           0 :                 RETURN_FALSE;
    5682             :         }
    5683             : 
    5684          11 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
    5685          11 :         if (pkey == NULL) {
    5686           5 :                 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key");
    5687           5 :                 RETURN_FALSE;
    5688             :         }
    5689             : 
    5690           6 :         md_ctx = EVP_MD_CTX_create();
    5691          24 :         if (md_ctx == NULL ||
    5692           6 :                         !EVP_VerifyInit (md_ctx, mdtype) ||
    5693           6 :                         !EVP_VerifyUpdate (md_ctx, data, data_len) ||
    5694           6 :                         (err = EVP_VerifyFinal(md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey)) < 0) {
    5695           0 :                 php_openssl_store_errors();
    5696             :         }
    5697           6 :         EVP_MD_CTX_destroy(md_ctx);
    5698             : 
    5699           6 :         if (keyresource == NULL) {
    5700           3 :                 EVP_PKEY_free(pkey);
    5701             :         }
    5702           6 :         RETURN_LONG(err);
    5703             : }
    5704             : /* }}} */
    5705             : 
    5706             : /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
    5707             :    Seals data */
    5708          16 : PHP_FUNCTION(openssl_seal)
    5709             : {
    5710          16 :         zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL;
    5711             :         HashTable *pubkeysht;
    5712             :         EVP_PKEY **pkeys;
    5713             :         zend_resource ** key_resources; /* so we know what to cleanup */
    5714             :         int i, len1, len2, *eksl, nkeys, iv_len;
    5715          16 :         unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks;
    5716             :         char * data;
    5717             :         size_t data_len;
    5718          16 :         char *method =NULL;
    5719          16 :         size_t method_len = 0;
    5720             :         const EVP_CIPHER *cipher;
    5721             :         EVP_CIPHER_CTX *ctx;
    5722             : 
    5723          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|sz/", &data, &data_len,
    5724             :                                 &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) {
    5725           3 :                 return;
    5726             :         }
    5727          13 :         pubkeysht = Z_ARRVAL_P(pubkeys);
    5728          13 :         nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
    5729          13 :         if (!nkeys) {
    5730           2 :                 php_error_docref(NULL, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
    5731           2 :                 RETURN_FALSE;
    5732             :         }
    5733             : 
    5734          11 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5735             : 
    5736          11 :         if (method) {
    5737           4 :                 cipher = EVP_get_cipherbyname(method);
    5738           4 :                 if (!cipher) {
    5739           1 :                         php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5740           1 :                         RETURN_FALSE;
    5741             :                 }
    5742             :         } else {
    5743           7 :                 cipher = EVP_rc4();
    5744             :         }
    5745             : 
    5746          10 :         iv_len = EVP_CIPHER_iv_length(cipher);
    5747          10 :         if (!iv && iv_len > 0) {
    5748           2 :                 php_error_docref(NULL, E_WARNING,
    5749             :                                 "Cipher algorithm requires an IV to be supplied as a sixth parameter");
    5750           2 :                 RETURN_FALSE;
    5751             :         }
    5752             : 
    5753           8 :         pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
    5754           8 :         eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
    5755           8 :         eks = safe_emalloc(nkeys, sizeof(*eks), 0);
    5756           8 :         memset(eks, 0, sizeof(*eks) * nkeys);
    5757           8 :         key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0);
    5758           8 :         memset(key_resources, 0, sizeof(zend_resource*) * nkeys);
    5759           8 :         memset(pkeys, 0, sizeof(*pkeys) * nkeys);
    5760             : 
    5761             :         /* get the public keys we are using to seal this data */
    5762           8 :         i = 0;
    5763          30 :         ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) {
    5764          13 :                 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i]);
    5765          13 :                 if (pkeys[i] == NULL) {
    5766           4 :                         php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
    5767           4 :                         RETVAL_FALSE;
    5768           4 :                         goto clean_exit;
    5769             :                 }
    5770           9 :                 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
    5771           9 :                 i++;
    5772             :         } ZEND_HASH_FOREACH_END();
    5773             : 
    5774           4 :         ctx = EVP_CIPHER_CTX_new();
    5775           4 :         if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) {
    5776           0 :                 EVP_CIPHER_CTX_free(ctx);
    5777           0 :                 php_openssl_store_errors();
    5778           0 :                 RETVAL_FALSE;
    5779           0 :                 goto clean_exit;
    5780             :         }
    5781             : 
    5782             :         /* allocate one byte extra to make room for \0 */
    5783           4 :         buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(ctx));
    5784           4 :         EVP_CIPHER_CTX_cleanup(ctx);
    5785             : 
    5786          12 :         if (!EVP_SealInit(ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) ||
    5787           4 :                         !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) ||
    5788           4 :                         !EVP_SealFinal(ctx, buf + len1, &len2)) {
    5789           0 :                 efree(buf);
    5790           0 :                 EVP_CIPHER_CTX_free(ctx);
    5791           0 :                 php_openssl_store_errors();
    5792           0 :                 RETVAL_FALSE;
    5793           0 :                 goto clean_exit;
    5794             :         }
    5795             : 
    5796           4 :         if (len1 + len2 > 0) {
    5797           4 :                 zval_dtor(sealdata);
    5798           4 :                 buf[len1 + len2] = '\0';
    5799           8 :                 ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0));
    5800           4 :                 efree(buf);
    5801             : 
    5802           4 :                 zval_dtor(ekeys);
    5803           4 :                 array_init(ekeys);
    5804          12 :                 for (i=0; i<nkeys; i++) {
    5805           8 :                         eks[i][eksl[i]] = '\0';
    5806           8 :                         add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]);
    5807           8 :                         efree(eks[i]);
    5808           8 :                         eks[i] = NULL;
    5809             :                 }
    5810             : 
    5811           4 :                 if (iv) {
    5812           1 :                         zval_dtor(iv);
    5813           1 :                         iv_buf[iv_len] = '\0';
    5814           2 :                         ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0));
    5815             :                 }
    5816             :         } else {
    5817           0 :                 efree(buf);
    5818             :         }
    5819           4 :         RETVAL_LONG(len1 + len2);
    5820           4 :         EVP_CIPHER_CTX_free(ctx);
    5821             : 
    5822             : clean_exit:
    5823          84 :         for (i=0; i<nkeys; i++) {
    5824          76 :                 if (key_resources[i] == NULL && pkeys[i] != NULL) {
    5825           9 :                         EVP_PKEY_free(pkeys[i]);
    5826             :                 }
    5827          76 :                 if (eks[i]) {
    5828           1 :                         efree(eks[i]);
    5829             :                 }
    5830             :         }
    5831           8 :         efree(eks);
    5832           8 :         efree(eksl);
    5833           8 :         efree(pkeys);
    5834           8 :         efree(key_resources);
    5835             : }
    5836             : /* }}} */
    5837             : 
    5838             : /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
    5839             :    Opens data */
    5840           5 : PHP_FUNCTION(openssl_open)
    5841             : {
    5842             :         zval *privkey, *opendata;
    5843             :         EVP_PKEY *pkey;
    5844             :         int len1, len2, cipher_iv_len;
    5845             :         unsigned char *buf, *iv_buf;
    5846           5 :         zend_resource *keyresource = NULL;
    5847             :         EVP_CIPHER_CTX *ctx;
    5848             :         char * data;
    5849             :         size_t data_len;
    5850             :         char * ekey;
    5851             :         size_t ekey_len;
    5852           5 :         char *method = NULL, *iv = NULL;
    5853           5 :         size_t method_len = 0, iv_len = 0;
    5854             :         const EVP_CIPHER *cipher;
    5855             : 
    5856           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata,
    5857             :                                 &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) {
    5858           0 :                 return;
    5859             :         }
    5860             : 
    5861           5 :         pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource);
    5862           5 :         if (pkey == NULL) {
    5863           1 :                 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 4 into a private key");
    5864           1 :                 RETURN_FALSE;
    5865             :         }
    5866             : 
    5867           4 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(ekey_len, ekey);
    5868           4 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    5869             : 
    5870           4 :         if (method) {
    5871           1 :                 cipher = EVP_get_cipherbyname(method);
    5872           1 :                 if (!cipher) {
    5873           0 :                         php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
    5874           0 :                         RETURN_FALSE;
    5875             :                 }
    5876             :         } else {
    5877           3 :                 cipher = EVP_rc4();
    5878             :         }
    5879             : 
    5880           4 :         cipher_iv_len = EVP_CIPHER_iv_length(cipher);
    5881           4 :         if (cipher_iv_len > 0) {
    5882           1 :                 if (!iv) {
    5883           0 :                         php_error_docref(NULL, E_WARNING,
    5884             :                                         "Cipher algorithm requires an IV to be supplied as a sixth parameter");
    5885           0 :                         RETURN_FALSE;
    5886             :                 }
    5887           1 :                 if ((size_t)cipher_iv_len != iv_len) {
    5888           0 :                         php_error_docref(NULL, E_WARNING, "IV length is invalid");
    5889           0 :                         RETURN_FALSE;
    5890             :                 }
    5891           1 :                 iv_buf = (unsigned char *)iv;
    5892             :         } else {
    5893           3 :                 iv_buf = NULL;
    5894             :         }
    5895             : 
    5896           4 :         buf = emalloc(data_len + 1);
    5897             : 
    5898           4 :         ctx = EVP_CIPHER_CTX_new();
    5899          16 :         if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) &&
    5900           3 :                         EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) &&
    5901           6 :                         EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) {
    5902           3 :                 zval_dtor(opendata);
    5903           3 :                 buf[len1 + len2] = '\0';
    5904           6 :                 ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0));
    5905           3 :                 RETVAL_TRUE;
    5906             :         } else {
    5907           1 :                 php_openssl_store_errors();
    5908           1 :                 RETVAL_FALSE;
    5909             :         }
    5910             : 
    5911           4 :         efree(buf);
    5912           4 :         if (keyresource == NULL) {
    5913           4 :                 EVP_PKEY_free(pkey);
    5914             :         }
    5915           4 :         EVP_CIPHER_CTX_free(ctx);
    5916             : }
    5917             : /* }}} */
    5918             : 
    5919         475 : static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
    5920             : {
    5921         475 :         add_next_index_string((zval*)arg, (char*)name->name);
    5922         475 : }
    5923             : /* }}} */
    5924             : 
    5925        1102 : static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
    5926             : {
    5927        1102 :         if (name->alias == 0) {
    5928         918 :                 add_next_index_string((zval*)arg, (char*)name->name);
    5929             :         }
    5930        1102 : }
    5931             : /* }}} */
    5932             : 
    5933             : /* {{{ proto array openssl_get_md_methods([bool aliases = false])
    5934             :    Return array of available digest methods */
    5935           2 : PHP_FUNCTION(openssl_get_md_methods)
    5936             : {
    5937           2 :         zend_bool aliases = 0;
    5938             : 
    5939           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
    5940           0 :                 return;
    5941             :         }
    5942           2 :         array_init(return_value);
    5943           2 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
    5944           2 :                 aliases ? openssl_add_method_or_alias: openssl_add_method,
    5945             :                 return_value);
    5946             : }
    5947             : /* }}} */
    5948             : 
    5949             : /* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
    5950             :    Return array of available cipher methods */
    5951           7 : PHP_FUNCTION(openssl_get_cipher_methods)
    5952             : {
    5953           7 :         zend_bool aliases = 0;
    5954             : 
    5955           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
    5956           0 :                 return;
    5957             :         }
    5958           7 :         array_init(return_value);
    5959           7 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
    5960           7 :                 aliases ? openssl_add_method_or_alias: openssl_add_method,
    5961             :                 return_value);
    5962             : }
    5963             : /* }}} */
    5964             : 
    5965             : /* {{{ proto array openssl_get_curve_names()
    5966             :    Return array of available elliptic curves */
    5967             : #ifdef HAVE_EVP_PKEY_EC
    5968           1 : PHP_FUNCTION(openssl_get_curve_names)
    5969             : {
    5970           1 :         EC_builtin_curve *curves = NULL;
    5971             :         const char *sname;
    5972             :         size_t i;
    5973           1 :         size_t len = EC_get_builtin_curves(NULL, 0);
    5974             : 
    5975           1 :         curves = emalloc(sizeof(EC_builtin_curve) * len);
    5976           1 :         if (!EC_get_builtin_curves(curves, len)) {
    5977           0 :                 RETURN_FALSE;
    5978             :         }
    5979             : 
    5980           1 :         array_init(return_value);
    5981           4 :         for (i = 0; i < len; i++) {
    5982           3 :                 sname = OBJ_nid2sn(curves[i].nid);
    5983           3 :                 if (sname != NULL) {
    5984           3 :                         add_next_index_string(return_value, sname);
    5985             :                 }
    5986             :         }
    5987           1 :         efree(curves);
    5988             : }
    5989             : #endif
    5990             : /* }}} */
    5991             : 
    5992             : /* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
    5993             :    Computes digest hash value for given data using given method, returns raw or binhex encoded string */
    5994           2 : PHP_FUNCTION(openssl_digest)
    5995             : {
    5996           2 :         zend_bool raw_output = 0;
    5997             :         char *data, *method;
    5998             :         size_t data_len, method_len;
    5999             :         const EVP_MD *mdtype;
    6000             :         EVP_MD_CTX *md_ctx;
    6001             :         unsigned int siglen;
    6002             :         zend_string *sigbuf;
    6003             : 
    6004           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
    6005           0 :                 return;
    6006             :         }
    6007           2 :         mdtype = EVP_get_digestbyname(method);
    6008           2 :         if (!mdtype) {
    6009           0 :                 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
    6010           0 :                 RETURN_FALSE;
    6011             :         }
    6012             : 
    6013           2 :         siglen = EVP_MD_size(mdtype);
    6014           4 :         sigbuf = zend_string_alloc(siglen, 0);
    6015             : 
    6016           2 :         md_ctx = EVP_MD_CTX_create();
    6017           8 :         if (EVP_DigestInit(md_ctx, mdtype) &&
    6018           2 :                         EVP_DigestUpdate(md_ctx, (unsigned char *)data, data_len) &&
    6019           2 :                         EVP_DigestFinal (md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) {
    6020           2 :                 if (raw_output) {
    6021           0 :                         ZSTR_VAL(sigbuf)[siglen] = '\0';
    6022           0 :                         ZSTR_LEN(sigbuf) = siglen;
    6023           0 :                         RETVAL_STR(sigbuf);
    6024             :                 } else {
    6025           2 :                         int digest_str_len = siglen * 2;
    6026           4 :                         zend_string *digest_str = zend_string_alloc(digest_str_len, 0);
    6027             : 
    6028           2 :                         make_digest_ex(ZSTR_VAL(digest_str), (unsigned char*)ZSTR_VAL(sigbuf), siglen);
    6029           2 :                         ZSTR_VAL(digest_str)[digest_str_len] = '\0';
    6030             :                         zend_string_release(sigbuf);
    6031           2 :                         RETVAL_STR(digest_str);
    6032             :                 }
    6033             :         } else {
    6034           0 :                 php_openssl_store_errors();
    6035             :                 zend_string_release(sigbuf);
    6036           0 :                 RETVAL_FALSE;
    6037             :         }
    6038             : 
    6039           2 :         EVP_MD_CTX_destroy(md_ctx);
    6040             : }
    6041             : /* }}} */
    6042             : 
    6043             : /* Cipher mode info */
    6044             : struct php_openssl_cipher_mode {
    6045             :         zend_bool is_aead;
    6046             :         zend_bool is_single_run_aead;
    6047             :         int aead_get_tag_flag;
    6048             :         int aead_set_tag_flag;
    6049             :         int aead_ivlen_flag;
    6050             : };
    6051             : 
    6052          63 : static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
    6053             : {
    6054          63 :         switch (EVP_CIPHER_mode(cipher_type)) {
    6055             : #ifdef EVP_CIPH_GCM_MODE
    6056             :                 case EVP_CIPH_GCM_MODE:
    6057          18 :                         mode->is_aead = 1;
    6058          18 :                         mode->is_single_run_aead = 0;
    6059          18 :                         mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG;
    6060          18 :                         mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG;
    6061          18 :                         mode->aead_ivlen_flag = EVP_CTRL_GCM_SET_IVLEN;
    6062          18 :                         break;
    6063             : #endif
    6064             : #ifdef EVP_CIPH_CCM_MODE
    6065             :                 case EVP_CIPH_CCM_MODE:
    6066           7 :                         mode->is_aead = 1;
    6067           7 :                         mode->is_single_run_aead = 1;
    6068           7 :                         mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG;
    6069           7 :                         mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG;
    6070           7 :                         mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN;
    6071           7 :                         break;
    6072             : #endif
    6073             :                 default:
    6074          38 :                         memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
    6075             :         }
    6076          63 : }
    6077             : /* }}} */
    6078             : 
    6079          62 : static int php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_required_len,
    6080             :                 zend_bool *free_iv, EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode) /* {{{ */
    6081             : {
    6082             :         char *iv_new;
    6083             : 
    6084             :         /* Best case scenario, user behaved */
    6085          62 :         if (*piv_len == iv_required_len) {
    6086          41 :                 return SUCCESS;
    6087             :         }
    6088             : 
    6089          21 :         if (mode->is_aead) {
    6090          17 :                 if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_ivlen_flag, *piv_len, NULL) != 1) {
    6091           4 :                         php_error_docref(NULL, E_WARNING,
    6092             :                                         "Setting of IV length for AEAD mode failed, the expected length is %zd bytes",
    6093             :                                         iv_required_len);
    6094           4 :                         return FAILURE;
    6095             :                 }
    6096          13 :                 return SUCCESS;
    6097             :         }
    6098             : 
    6099           4 :         iv_new = ecalloc(1, iv_required_len + 1);
    6100             : 
    6101           4 :         if (*piv_len == 0) {
    6102             :                 /* BC behavior */
    6103           4 :                 *piv_len = iv_required_len;
    6104           4 :                 *piv = iv_new;
    6105           4 :                 *free_iv = 1;
    6106           4 :                 return SUCCESS;
    6107             : 
    6108             :         }
    6109             : 
    6110           0 :         if (*piv_len < iv_required_len) {
    6111           0 :                 php_error_docref(NULL, E_WARNING,
    6112             :                                 "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0",
    6113             :                                 *piv_len, iv_required_len);
    6114           0 :                 memcpy(iv_new, *piv, *piv_len);
    6115           0 :                 *piv_len = iv_required_len;
    6116           0 :                 *piv = iv_new;
    6117           0 :                 *free_iv = 1;
    6118           0 :                 return SUCCESS;
    6119             :         }
    6120             : 
    6121           0 :         php_error_docref(NULL, E_WARNING,
    6122             :                         "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating",
    6123             :                         *piv_len, iv_required_len);
    6124           0 :         memcpy(iv_new, *piv, iv_required_len);
    6125           0 :         *piv_len = iv_required_len;
    6126           0 :         *piv = iv_new;
    6127           0 :         *free_iv = 1;
    6128           0 :         return SUCCESS;
    6129             : 
    6130             : }
    6131             : /* }}} */
    6132             : 
    6133          62 : static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
    6134             :                 EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode,
    6135             :                 char **ppassword, size_t *ppassword_len, zend_bool *free_password,
    6136             :                 char **piv, size_t *piv_len, zend_bool *free_iv,
    6137             :                 char *tag, int tag_len, zend_long options, int enc)  /* {{{ */
    6138             : {
    6139             :         unsigned char *key;
    6140             :         int key_len, password_len;
    6141             :         size_t max_iv_len;
    6142             : 
    6143             :         /* check and set key */
    6144          62 :         password_len = (int) *ppassword_len;
    6145          62 :         key_len = EVP_CIPHER_key_length(cipher_type);
    6146          62 :         if (key_len > password_len) {
    6147          21 :                 key = emalloc(key_len);
    6148          21 :                 memset(key, 0, key_len);
    6149          21 :                 memcpy(key, *ppassword, password_len);
    6150          21 :                 *ppassword = (char *) key;
    6151          21 :                 *ppassword_len = key_len;
    6152          21 :                 *free_password = 1;
    6153             :         } else {
    6154          41 :                 key = (unsigned char*)*ppassword;
    6155          41 :                 *free_password = 0;
    6156             :         }
    6157             : 
    6158          62 :         max_iv_len = EVP_CIPHER_iv_length(cipher_type);
    6159          62 :         if (enc && *piv_len == 0 && max_iv_len > 0 && !mode->is_aead) {
    6160           2 :                 php_error_docref(NULL, E_WARNING,
    6161             :                                 "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
    6162             :         }
    6163             : 
    6164          62 :         if (!EVP_CipherInit_ex(cipher_ctx, cipher_type, NULL, NULL, NULL, enc)) {
    6165           0 :                 return FAILURE;
    6166             :         }
    6167          62 :         if (php_openssl_validate_iv(piv, piv_len, max_iv_len, free_iv, cipher_ctx, mode) == FAILURE) {
    6168           4 :                 return FAILURE;
    6169             :         }
    6170          60 :         if (mode->is_single_run_aead && enc) {
    6171           2 :                 EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL);
    6172          56 :         } else if (!enc && tag && tag_len > 0) {
    6173          11 :                 if (!mode->is_aead) {
    6174           0 :                         php_error_docref(NULL, E_WARNING, "The tag cannot be used because the cipher method does not support AEAD");
    6175          11 :                 } else if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, (unsigned char *) tag)) {
    6176           0 :                         php_error_docref(NULL, E_WARNING, "Setting tag for AEAD cipher decryption failed");
    6177           0 :                         return FAILURE;
    6178             :                 }
    6179             :         }
    6180          58 :         if (password_len > key_len) {
    6181          21 :                 EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len);
    6182             :         }
    6183          58 :         if (!EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)*piv, enc)) {
    6184           0 :                 return FAILURE;
    6185             :         }
    6186          58 :         if (options & OPENSSL_ZERO_PADDING) {
    6187           2 :                 EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
    6188             :         }
    6189             : 
    6190          58 :         return SUCCESS;
    6191             : }
    6192             : /* }}} */
    6193             : 
    6194          58 : static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
    6195             :                 EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode,
    6196             :                 zend_string **poutbuf, int *poutlen, char *data, size_t data_len,
    6197             :                 char *aad, size_t aad_len, int enc)  /* {{{ */
    6198             : {
    6199          58 :         int i = 0;
    6200             : 
    6201          58 :         if (mode->is_single_run_aead && !EVP_EncryptUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) {
    6202           0 :                 php_error_docref(NULL, E_WARNING, "Setting of data length failed");
    6203           0 :                 return FAILURE;
    6204             :         }
    6205             : 
    6206          58 :         if (mode->is_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, (unsigned char *)aad, (int)aad_len)) {
    6207           0 :                 php_error_docref(NULL, E_WARNING, "Setting of additional application data failed");
    6208           0 :                 return FAILURE;
    6209             :         }
    6210             : 
    6211         116 :         *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0);
    6212             : 
    6213         114 :         if ((!enc || data_len > 0) &&
    6214          56 :                         !EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf),
    6215             :                                         &i, (unsigned char *)data, (int)data_len)) {
    6216             :                 /* we don't show warning when we fail but if we ever do, then it should look like this:
    6217             :                 if (mode->is_single_run_aead && !enc) {
    6218             :                         php_error_docref(NULL, E_WARNING, "Tag verifycation failed");
    6219             :                 } else {
    6220             :                         php_error_docref(NULL, E_WARNING, enc ? "Encryption failed" : "Decryption failed");
    6221             :                 }
    6222             :                 */
    6223           2 :                 zend_string_release(*poutbuf);
    6224           2 :                 return FAILURE;
    6225             :         }
    6226             : 
    6227          56 :         *poutlen = i;
    6228             : 
    6229          56 :         return SUCCESS;
    6230             : }
    6231             : /* }}} */
    6232             : 
    6233             : /* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv=''[, string &$tag = ''[, string $aad = ''[, long $tag_length = 16]]]]])
    6234             :    Encrypts given data with given method and key, returns raw or base64 encoded string */
    6235          50 : PHP_FUNCTION(openssl_encrypt)
    6236             : {
    6237          50 :         zend_long options = 0, tag_len = 16;
    6238          50 :         char *data, *method, *password, *iv = "", *aad = "";
    6239          50 :         size_t data_len, method_len, password_len, iv_len = 0, aad_len = 0;
    6240          50 :         zval *tag = NULL;
    6241             :         const EVP_CIPHER *cipher_type;
    6242             :         EVP_CIPHER_CTX *cipher_ctx;
    6243             :         struct php_openssl_cipher_mode mode;
    6244          50 :         int i=0, outlen;
    6245             :         zend_string *outbuf;
    6246          50 :         zend_bool free_iv = 0, free_password = 0;
    6247             : 
    6248          50 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsz/sl", &data, &data_len, &method, &method_len,
    6249             :                                         &password, &password_len, &options, &iv, &iv_len, &tag, &aad, &aad_len, &tag_len) == FAILURE) {
    6250           6 :                 return;
    6251             :         }
    6252             : 
    6253          44 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    6254          44 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
    6255          44 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad);
    6256          44 :         PHP_OPENSSL_CHECK_LONG_TO_INT(tag_len, tag_len);
    6257             : 
    6258          44 :         cipher_type = EVP_get_cipherbyname(method);
    6259          44 :         if (!cipher_type) {
    6260           1 :                 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
    6261           1 :                 RETURN_FALSE;
    6262             :         }
    6263             : 
    6264          43 :         cipher_ctx = EVP_CIPHER_CTX_new();
    6265          43 :         if (!cipher_ctx) {
    6266           0 :                 php_error_docref(NULL, E_WARNING, "Failed to create cipher context");
    6267           0 :                 RETURN_FALSE;
    6268             :         }
    6269             : 
    6270          43 :         php_openssl_load_cipher_mode(&mode, cipher_type);
    6271             : 
    6272             : 
    6273          86 :         if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode,
    6274             :                                 &password, &password_len, &free_password,
    6275          43 :                                 &iv, &iv_len, &free_iv, NULL, tag_len, options, 1) == FAILURE ||
    6276             :                         php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen,
    6277          41 :                                 data, data_len, aad, aad_len, 1) == FAILURE) {
    6278           2 :                 RETVAL_FALSE;
    6279          41 :         } else if (EVP_EncryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) {
    6280          41 :                 outlen += i;
    6281          41 :                 if (options & OPENSSL_RAW_DATA) {
    6282           9 :                         ZSTR_VAL(outbuf)[outlen] = '\0';
    6283           9 :                         ZSTR_LEN(outbuf) = outlen;
    6284           9 :                         RETVAL_STR(outbuf);
    6285             :                 } else {
    6286             :                         zend_string *base64_str;
    6287             : 
    6288          32 :                         base64_str = php_base64_encode((unsigned char*)ZSTR_VAL(outbuf), outlen);
    6289          32 :                         zend_string_release(outbuf);
    6290          32 :                         outbuf = base64_str;
    6291          32 :                         RETVAL_STR(base64_str);
    6292             :                 }
    6293          50 :                 if (mode.is_aead && tag) {
    6294          18 :                         zend_string *tag_str = zend_string_alloc(tag_len, 0);
    6295             : 
    6296           9 :                         if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode.aead_get_tag_flag, tag_len, ZSTR_VAL(tag_str)) == 1) {
    6297           8 :                                 zval_dtor(tag);
    6298           8 :                                 ZSTR_VAL(tag_str)[tag_len] = '\0';
    6299           8 :                                 ZSTR_LEN(tag_str) = tag_len;
    6300           8 :                                 ZVAL_NEW_STR(tag, tag_str);
    6301             :                         } else {
    6302           1 :                                 php_error_docref(NULL, E_WARNING, "Retrieving verification tag failed");
    6303             :                                 zend_string_release(tag_str);
    6304           1 :                                 zend_string_release(outbuf);
    6305           1 :                                 RETVAL_FALSE;
    6306             :                         }
    6307          32 :                 } else if (tag) {
    6308           2 :                         zval_dtor(tag);
    6309           2 :                         ZVAL_NULL(tag);
    6310           2 :                         php_error_docref(NULL, E_WARNING,
    6311             :                                         "The authenticated tag cannot be provided for cipher that doesn not support AEAD");
    6312          30 :                 } else if (mode.is_aead) {
    6313           1 :                         php_error_docref(NULL, E_WARNING, "A tag should be provided when using AEAD mode");
    6314           1 :                         zend_string_release(outbuf);
    6315           1 :                         RETVAL_FALSE;
    6316             :                 }
    6317             :         } else {
    6318           0 :                 php_openssl_store_errors();
    6319           0 :                 zend_string_release(outbuf);
    6320           0 :                 RETVAL_FALSE;
    6321             :         }
    6322             : 
    6323          43 :         if (free_password) {
    6324          15 :                 efree(password);
    6325             :         }
    6326          43 :         if (free_iv) {
    6327           2 :                 efree(iv);
    6328             :         }
    6329          43 :         EVP_CIPHER_CTX_cleanup(cipher_ctx);
    6330          43 :         EVP_CIPHER_CTX_free(cipher_ctx);
    6331             : }
    6332             : /* }}} */
    6333             : 
    6334             : /* {{{ proto string openssl_decrypt(string data, string method, string password [, long options=0 [, string $iv = ''[, string $tag = ''[, string $aad = '']]]])
    6335             :    Takes raw or base64 encoded string and decrypts it using given method and key */
    6336          27 : PHP_FUNCTION(openssl_decrypt)
    6337             : {
    6338          27 :         zend_long options = 0;
    6339          27 :         char *data, *method, *password, *iv = "", *tag = NULL, *aad = "";
    6340          27 :         size_t data_len, method_len, password_len, iv_len = 0, tag_len = 0, aad_len = 0;
    6341             :         const EVP_CIPHER *cipher_type;
    6342             :         EVP_CIPHER_CTX *cipher_ctx;
    6343             :         struct php_openssl_cipher_mode mode;
    6344          27 :         int outlen, i = 0;
    6345             :         zend_string *outbuf;
    6346          27 :         zend_string *base64_str = NULL;
    6347          27 :         zend_bool free_iv = 0, free_password = 0;
    6348             : 
    6349          27 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsss", &data, &data_len, &method, &method_len,
    6350             :                                         &password, &password_len, &options, &iv, &iv_len, &tag, &tag_len, &aad, &aad_len) == FAILURE) {
    6351           3 :                 return;
    6352             :         }
    6353             : 
    6354          24 :         if (!method_len) {
    6355           0 :                 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
    6356           0 :                 RETURN_FALSE;
    6357             :         }
    6358             : 
    6359          24 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
    6360          24 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
    6361          24 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad);
    6362          24 :         PHP_OPENSSL_CHECK_SIZE_T_TO_INT(tag_len, tag);
    6363             : 
    6364          24 :         cipher_type = EVP_get_cipherbyname(method);
    6365          24 :         if (!cipher_type) {
    6366           4 :                 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
    6367           4 :                 RETURN_FALSE;
    6368             :         }
    6369             : 
    6370          20 :         cipher_ctx = EVP_CIPHER_CTX_new();
    6371          20 :         if (!cipher_ctx) {
    6372           0 :                 php_error_docref(NULL, E_WARNING, "Failed to create cipher context");
    6373           0 :                 RETURN_FALSE;
    6374             :         }
    6375             : 
    6376          20 :         php_openssl_load_cipher_mode(&mode, cipher_type);
    6377             : 
    6378          20 :         if (!(options & OPENSSL_RAW_DATA)) {
    6379           5 :                 base64_str = php_base64_decode_ex((unsigned char*)data, (int)data_len, 1);
    6380           5 :                 if (!base64_str) {
    6381           1 :                         php_error_docref(NULL, E_WARNING, "Failed to base64 decode the input");
    6382           1 :                         EVP_CIPHER_CTX_free(cipher_ctx);
    6383           1 :                         RETURN_FALSE;
    6384             :                 }
    6385           4 :                 data_len = ZSTR_LEN(base64_str);
    6386           4 :                 data = ZSTR_VAL(base64_str);
    6387             :         }
    6388             : 
    6389          40 :         if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode,
    6390             :                                 &password, &password_len, &free_password,
    6391          19 :                                 &iv, &iv_len, &free_iv, tag, tag_len, options, 0) == FAILURE ||
    6392             :                         php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen,
    6393          17 :                                 data, data_len, aad, aad_len, 0) == FAILURE) {
    6394           4 :                 RETVAL_FALSE;
    6395          40 :         } else if (mode.is_single_run_aead ||
    6396          14 :                         EVP_DecryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) {
    6397          11 :                 outlen += i;
    6398          11 :                 ZSTR_VAL(outbuf)[outlen] = '\0';
    6399          11 :                 ZSTR_LEN(outbuf) = outlen;
    6400          11 :                 RETVAL_STR(outbuf);
    6401             :         } else {
    6402           4 :                 php_openssl_store_errors();
    6403           4 :                 zend_string_release(outbuf);
    6404           4 :                 RETVAL_FALSE;
    6405             :         }
    6406             : 
    6407          19 :         if (free_password) {
    6408           6 :                 efree(password);
    6409             :         }
    6410          19 :         if (free_iv) {
    6411           2 :                 efree(iv);
    6412             :         }
    6413          19 :         if (base64_str) {
    6414             :                 zend_string_release(base64_str);
    6415             :         }
    6416          19 :         EVP_CIPHER_CTX_cleanup(cipher_ctx);
    6417          19 :         EVP_CIPHER_CTX_free(cipher_ctx);
    6418             : }
    6419             : /* }}} */
    6420             : 
    6421             : /* {{{ proto int openssl_cipher_iv_length(string $method) */
    6422           3 : PHP_FUNCTION(openssl_cipher_iv_length)
    6423             : {
    6424             :         char *method;
    6425             :         size_t method_len;
    6426             :         const EVP_CIPHER *cipher_type;
    6427             : 
    6428           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len) == FAILURE) {
    6429           0 :                 return;
    6430             :         }
    6431             : 
    6432           3 :         if (!method_len) {
    6433           0 :                 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
    6434           0 :                 RETURN_FALSE;
    6435             :         }
    6436             : 
    6437           3 :         cipher_type = EVP_get_cipherbyname(method);
    6438           3 :         if (!cipher_type) {
    6439           0 :                 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
    6440           0 :                 RETURN_FALSE;
    6441             :         }
    6442             : 
    6443           3 :         RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
    6444             : }
    6445             : /* }}} */
    6446             : 
    6447             : 
    6448             : /* {{{ proto string openssl_random_pseudo_bytes(integer length [, &bool returned_strong_result])
    6449             :    Returns a string of the length specified filled with random pseudo bytes */
    6450          10 : PHP_FUNCTION(openssl_random_pseudo_bytes)
    6451             : {
    6452             :         zend_long buffer_length;
    6453          10 :         zend_string *buffer = NULL;
    6454          10 :         zval *zstrong_result_returned = NULL;
    6455             : 
    6456          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) {
    6457           0 :                 return;
    6458             :         }
    6459             : 
    6460          10 :         if (buffer_length <= 0) {
    6461           1 :                 RETURN_FALSE;
    6462             :         }
    6463             : 
    6464           9 :         if (zstrong_result_returned) {
    6465           9 :                 zval_dtor(zstrong_result_returned);
    6466           9 :                 ZVAL_FALSE(zstrong_result_returned);
    6467             :         }
    6468             : 
    6469          18 :         buffer = zend_string_alloc(buffer_length, 0);
    6470             : 
    6471             : #ifdef PHP_WIN32
    6472             :         /* random/urandom equivalent on Windows */
    6473             :         if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){
    6474             :                 zend_string_release(buffer);
    6475             :                 if (zstrong_result_returned) {
    6476             :                         ZVAL_FALSE(zstrong_result_returned);
    6477             :                 }
    6478             :                 RETURN_FALSE;
    6479             :         }
    6480             : #else
    6481             : 
    6482           9 :         PHP_OPENSSL_CHECK_LONG_TO_INT(buffer_length, length);
    6483           9 :         PHP_OPENSSL_RAND_ADD_TIME();
    6484           9 :         if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) {
    6485             :                 zend_string_release(buffer);
    6486           0 :                 if (zstrong_result_returned) {
    6487           0 :                         ZVAL_FALSE(zstrong_result_returned);
    6488             :                 }
    6489           0 :                 RETURN_FALSE;
    6490             :         } else {
    6491           9 :                 php_openssl_store_errors();
    6492             :         }
    6493             : #endif
    6494             : 
    6495           9 :         ZSTR_VAL(buffer)[buffer_length] = 0;
    6496           9 :         RETVAL_STR(buffer);
    6497             : 
    6498           9 :         if (zstrong_result_returned) {
    6499           9 :                 ZVAL_BOOL(zstrong_result_returned, 1);
    6500             :         }
    6501             : }
    6502             : /* }}} */
    6503             : 
    6504             : /*
    6505             :  * Local variables:
    6506             :  * tab-width: 8
    6507             :  * c-basic-offset: 8
    6508             :  * End:
    6509             :  * vim600: sw=4 ts=4 fdm=marker
    6510             :  * vim<600: sw=4 ts=4
    6511             :  */
    6512             : 

Generated by: LCOV version 1.10

Generated at Sun, 18 Sep 2016 08:20:12 +0000 (7 days ago)

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