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

Generated by: LCOV version 1.10

Generated at Wed, 20 Jul 2016 02:56:23 +0000 (5 days ago)

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