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: 1812 2415 75.0 %
Date: 2016-04-27 Functions: 80 89 89.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 27 Apr 2016 15:51:45 +0000 (5 days ago)

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