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

Generated by: LCOV version 1.10

Generated at Fri, 20 Mar 2015 23:40:31 +0000 (6 days ago)

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