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: 1610 2355 68.4 %
Date: 2015-01-26 Functions: 72 89 80.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 26 Jan 2015 14:46:49 +0000 (6 days ago)

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