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: 2458 3131 78.5 %
Date: 2022-01-16 Functions: 113 118 95.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 16 Jan 2022 08:19:17 +0000 (6 days ago)

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