PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/openssl - openssl.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1610 2355 68.4 %
Date: 2014-12-13 Functions: 72 89 80.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:17 +0000 (9 days ago)

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