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: 1581 2330 67.9 %
Date: 2014-10-30 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          41 : static void php_pkey_free(zend_resource *rsrc TSRMLS_DC)
     546             : {
     547          41 :         EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
     548             : 
     549             :         assert(pkey != NULL);
     550             : 
     551          41 :         EVP_PKEY_free(pkey);
     552          41 : }
     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         130 : inline static int php_openssl_open_base_dir_chk(char *filename TSRMLS_DC)
     569             : {
     570         130 :         if (php_check_open_basedir(filename TSRMLS_CC)) {
     571           0 :                 return -1;
     572             :         }
     573             :         
     574         130 :         return 0;
     575             : }
     576             : /* }}} */
     577             : 
     578          56 : php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
     579             : {
     580          56 :         return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
     581             : }
     582             : 
     583         135 : int php_openssl_get_ssl_stream_data_index()
     584             : {
     585         135 :         return ssl_stream_data_index;
     586             : }
     587             : 
     588             : /* openssl -> PHP "bridging" */
     589             : /* true global; readonly after module startup */
     590             : static char default_ssl_conf_filename[MAXPATHLEN];
     591             : 
     592             : struct php_x509_request { /* {{{ */
     593             : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
     594             :         LHASH_OF(CONF_VALUE) * global_config;   /* Global SSL config */
     595             :         LHASH_OF(CONF_VALUE) * req_config;              /* SSL config for this request */
     596             : #else
     597             :         LHASH * global_config;  /* Global SSL config */
     598             :         LHASH * req_config;             /* SSL config for this request */
     599             : #endif
     600             :         const EVP_MD * md_alg;
     601             :         const EVP_MD * digest;
     602             :         char    * section_name,
     603             :                         * config_filename,
     604             :                         * digest_name,
     605             :                         * extensions_section,
     606             :                         * request_extensions_section;
     607             :         int priv_key_bits;
     608             :         int priv_key_type;
     609             : 
     610             :         int priv_key_encrypt;
     611             : 
     612             :         EVP_PKEY * priv_key;
     613             : 
     614             :     const EVP_CIPHER * priv_key_encrypt_cipher;
     615             : };
     616             : /* }}} */
     617             : 
     618             : static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval 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          57 : 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          57 :         X509V3_set_ctx_test(&ctx);
     794          57 :         X509V3_set_conf_lhash(&ctx, config);
     795          57 :         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          57 :         return SUCCESS;
     803             : }
     804             : /* }}} */
     805             : 
     806          54 : 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          54 :         str = CONF_get_string(req->req_config, NULL, "oid_section");
     814          54 :         if (str == NULL) {
     815          17 :                 return SUCCESS;
     816             :         }
     817          37 :         sktmp = CONF_get_section(req->req_config, str);
     818          37 :         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         148 :         for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
     823         111 :                 cnf = sk_CONF_VALUE_value(sktmp, i);
     824         111 :                 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          37 :         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          54 : 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          71 :         SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
     862          54 :         SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
     863          54 :         req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
     864          54 :         req->req_config = CONF_load(NULL, req->config_filename, NULL);
     865             : 
     866          54 :         if (req->req_config == NULL) {
     867           0 :                 return FAILURE;
     868             :         }
     869             : 
     870             :         /* read in the oids */
     871          54 :         str = CONF_get_string(req->req_config, NULL, "oid_file");
     872          54 :         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          54 :         if (add_oid_section(req TSRMLS_CC) == FAILURE) {
     880           0 :                 return FAILURE;
     881             :         }
     882          70 :         SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
     883             :                 CONF_get_string(req->req_config, req->section_name, "default_md"));
     884          58 :         SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
     885             :                 CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
     886          57 :         SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
     887             :                 CONF_get_string(req->req_config, req->section_name, "req_extensions"));
     888          70 :         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          70 :         SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
     892             : 
     893          58 :         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          50 :                 str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
     897          50 :                 if (str == NULL) {
     898          50 :                         str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
     899             :                 }
     900          50 :                 if (str && strcmp(str, "no") == 0) {
     901           0 :                         req->priv_key_encrypt = 0;
     902             :                 } else {
     903          50 :                         req->priv_key_encrypt = 1;
     904             :                 }
     905             :         }
     906             : 
     907          54 :         if (req->priv_key_encrypt && optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL
     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          54 :                 req->priv_key_encrypt_cipher = NULL;
     919             :         }
     920             : 
     921             : 
     922             :         
     923             :         /* digest alg */
     924          54 :         if (req->digest_name == NULL) {
     925          14 :                 req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
     926             :         }
     927          54 :         if (req->digest_name) {
     928          40 :                 req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
     929             :         }
     930          54 :         if (req->md_alg == NULL) {
     931          14 :                 req->md_alg = req->digest = EVP_sha1();
     932             :         }
     933             : 
     934          54 :         PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
     935             : 
     936             :         /* set the string mask */
     937          54 :         str = CONF_get_string(req->req_config, req->section_name, "string_mask");
     938          54 :         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          54 :         PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
     944             :         
     945          54 :         return SUCCESS;
     946             : }
     947             : /* }}} */
     948             : 
     949          58 : static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */
     950             : {
     951          58 :         if (req->priv_key) {
     952           1 :                 EVP_PKEY_free(req->priv_key);
     953           1 :                 req->priv_key = NULL;
     954             :         }
     955          58 :         if (req->global_config) {
     956          54 :                 CONF_free(req->global_config);
     957          54 :                 req->global_config = NULL;
     958             :         }
     959          58 :         if (req->req_config) {
     960          54 :                 CONF_free(req->req_config);
     961          54 :                 req->req_config = NULL;
     962             :         }
     963          58 : }
     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       20423 : PHP_MINIT_FUNCTION(openssl)
    1114             : {
    1115             :         char * config_filename;
    1116             : 
    1117       20423 :         le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
    1118       20423 :         le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
    1119       20423 :         le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
    1120             : 
    1121       20423 :         SSL_library_init();
    1122       20423 :         OpenSSL_add_all_ciphers();
    1123       20423 :         OpenSSL_add_all_digests();
    1124       20423 :         OpenSSL_add_all_algorithms();
    1125             : 
    1126       20423 :         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       20423 :         ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
    1131             :         
    1132       20423 :         REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
    1133       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
    1134             :         
    1135             :         /* purposes for cert purpose checking */
    1136       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
    1137       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1138       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
    1139       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
    1140       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
    1141       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
    1142             : #ifdef X509_PURPOSE_ANY
    1143       20423 :         REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
    1144             : #endif
    1145             : 
    1146             :         /* signature algorithm constants */
    1147       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
    1148       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
    1149       20423 :         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       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
    1154             : #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
    1155       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
    1156       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
    1157       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
    1158       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
    1159       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
    1160             : #endif
    1161             : 
    1162             :         /* flags for S/MIME */
    1163       20423 :         REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
    1164       20423 :         REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
    1165       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
    1166       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
    1167       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
    1168       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
    1169       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
    1170       20423 :         REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
    1171       20423 :         REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
    1172             : 
    1173       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
    1174       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
    1175       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
    1176       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
    1177             : 
    1178             :         /* Informational stream wrapper constants */
    1179       20423 :         REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
    1180             : 
    1181             :         /* Ciphers */
    1182             : #ifndef OPENSSL_NO_RC2
    1183       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
    1184       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
    1185       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
    1186             : #endif
    1187             : #ifndef OPENSSL_NO_DES
    1188       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
    1189       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
    1190             : #endif
    1191             : #ifndef OPENSSL_NO_AES
    1192       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
    1193       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
    1194       20423 :         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       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
    1199             : #ifndef NO_DSA
    1200       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
    1201             : #endif
    1202       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
    1203             : #ifdef HAVE_EVP_PKEY_EC
    1204       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
    1205             : #endif
    1206             : 
    1207       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
    1208       20423 :         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       20423 :         REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
    1213             : #endif
    1214             : 
    1215             :         /* Determine default SSL configuration file */
    1216       20423 :         config_filename = getenv("OPENSSL_CONF");
    1217       20423 :         if (config_filename == NULL) {
    1218       20423 :                 config_filename = getenv("SSLEAY_CONF");
    1219             :         }
    1220             : 
    1221             :         /* default to 'openssl.cnf' if no environment variable is set */
    1222       20423 :         if (config_filename == NULL) {
    1223       20423 :                 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       20423 :         php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC);
    1231       20423 :         php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC);
    1232             : #ifndef OPENSSL_NO_SSL2
    1233       20423 :         php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
    1234             : #endif
    1235       20423 :         php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC);
    1236       20423 :         php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory TSRMLS_CC);
    1237             : #if OPENSSL_VERSION_NUMBER >= 0x10001001L
    1238       20423 :         php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory TSRMLS_CC);
    1239       20423 :         php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory TSRMLS_CC);
    1240             : #endif
    1241             : 
    1242             :         /* override the default tcp socket provider */
    1243       20423 :         php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
    1244             : 
    1245       20423 :         php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC);
    1246       20423 :         php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC);
    1247             : 
    1248       20423 :         REGISTER_INI_ENTRIES();
    1249             : 
    1250       20423 :         return SUCCESS;
    1251             : }
    1252             : /* }}} */
    1253             : 
    1254             : /* {{{ PHP_MINFO_FUNCTION
    1255             :  */
    1256         143 : PHP_MINFO_FUNCTION(openssl)
    1257             : {
    1258         143 :         php_info_print_table_start();
    1259         143 :         php_info_print_table_row(2, "OpenSSL support", "enabled");
    1260         143 :         php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
    1261         143 :         php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
    1262         143 :         php_info_print_table_end();
    1263         143 :         DISPLAY_INI_ENTRIES();
    1264         143 : }
    1265             : /* }}} */
    1266             : 
    1267             : /* {{{ PHP_MSHUTDOWN_FUNCTION
    1268             :  */
    1269       20457 : PHP_MSHUTDOWN_FUNCTION(openssl)
    1270             : {
    1271       20457 :         EVP_cleanup();
    1272             : 
    1273       20457 :         php_unregister_url_stream_wrapper("https" TSRMLS_CC);
    1274       20457 :         php_unregister_url_stream_wrapper("ftps" TSRMLS_CC);
    1275             : 
    1276       20457 :         php_stream_xport_unregister("ssl" TSRMLS_CC);
    1277             : #ifndef OPENSSL_NO_SSL2
    1278       20457 :         php_stream_xport_unregister("sslv2" TSRMLS_CC);
    1279             : #endif
    1280       20457 :         php_stream_xport_unregister("sslv3" TSRMLS_CC);
    1281       20457 :         php_stream_xport_unregister("tls" TSRMLS_CC);
    1282       20457 :         php_stream_xport_unregister("tlsv1.0" TSRMLS_CC);
    1283             : #if OPENSSL_VERSION_NUMBER >= 0x10001001L
    1284       20457 :         php_stream_xport_unregister("tlsv1.1" TSRMLS_CC);
    1285       20457 :         php_stream_xport_unregister("tlsv1.2" TSRMLS_CC);
    1286             : #endif
    1287             : 
    1288             :         /* reinstate the default tcp handler */
    1289       20457 :         php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
    1290             : 
    1291       20457 :         UNREGISTER_INI_ENTRIES();
    1292             : 
    1293       20457 :         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         124 : static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval TSRMLS_DC)
    1329             : {
    1330         124 :         X509 *cert = NULL;
    1331             : 
    1332         124 :         if (resourceval) {
    1333         124 :                 *resourceval = NULL;
    1334             :         }
    1335         124 :         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         124 :         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          94 :         convert_to_string_ex(val);
    1363             : 
    1364         143 :         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          53 :                 if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1) TSRMLS_CC)) {
    1369           0 :                         return NULL;
    1370             :                 }
    1371             : 
    1372          53 :                 in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), "r");
    1373          53 :                 if (in == NULL) {
    1374           0 :                         return NULL;
    1375             :                 }
    1376          53 :                 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
    1377          53 :                 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          90 :         if (cert && makeresource && resourceval) {
    1394           4 :                 *resourceval = zend_register_resource(NULL, cert, le_x509 TSRMLS_CC);
    1395             :         }
    1396          90 :         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         208 : static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval TSRMLS_DC)
    3171             : {
    3172         208 :         EVP_PKEY * key = NULL;
    3173         208 :         X509 * cert = NULL;
    3174         208 :         int free_cert = 0;
    3175         208 :         zend_resource *cert_res = NULL;
    3176         208 :         char * filename = NULL;
    3177             :         zval tmp;
    3178             : 
    3179         208 :         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         208 :         if (resourceval) {
    3188         208 :                 *resourceval = NULL;
    3189             :         }
    3190         208 :         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         203 :         if (Z_TYPE_P(val) == IS_RESOURCE) {
    3216             :                 void * what;
    3217             :                 int type;
    3218             : 
    3219         123 :                 what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key);
    3220         123 :                 if (!what) {
    3221           0 :                         TMP_CLEAN;
    3222             :                 }
    3223         123 :                 if (resourceval) { 
    3224         123 :                         *resourceval = Z_RES_P(val);
    3225             :                         Z_ADDREF_P(val);
    3226             :                 }
    3227         123 :                 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         123 :                 } else if (type == le_key) {
    3232             :                         int is_priv;
    3233             : 
    3234         123 :                         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         123 :                         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         123 :                         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         122 :                                 if (Z_TYPE(tmp) == IS_STRING) {
    3247             :                                         zval_dtor(&tmp);
    3248             :                                 }
    3249             :                                 /* got the key - return it */
    3250         122 :                                 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          87 :                 if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
    3262          10 :                         TMP_CLEAN;
    3263             :                 }
    3264          77 :                 convert_to_string_ex(val);
    3265             : 
    3266          75 :                 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
    3267          51 :                         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          75 :                 if (public_key) {
    3271          28 :                         cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC);
    3272          28 :                         free_cert = (cert_res == NULL);
    3273             :                         /* actual extraction done later */
    3274          28 :                         if (!cert) {
    3275             :                                 /* not a X509 certificate, try to retrieve public key */
    3276             :                                 BIO* in;
    3277          26 :                                 if (filename) {
    3278          20 :                                         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          26 :                                 if (in == NULL) {
    3283           0 :                                         TMP_CLEAN;
    3284             :                                 }
    3285          26 :                                 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    3286          26 :                                 BIO_free(in);
    3287             :                         }
    3288             :                 } else {
    3289             :                         /* we want the private key */
    3290             :                         BIO *in;
    3291             : 
    3292          47 :                         if (filename) {
    3293          31 :                                 if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    3294           0 :                                         TMP_CLEAN;
    3295             :                                 }
    3296          31 :                                 in = BIO_new_file(filename, "r");
    3297             :                         } else {
    3298          16 :                                 in = BIO_new_mem_buf(Z_STRVAL_P(val), Z_STRLEN_P(val));
    3299             :                         }
    3300             : 
    3301          47 :                         if (in == NULL) {
    3302           0 :                                 TMP_CLEAN;
    3303             :                         }
    3304          47 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
    3305          47 :                         BIO_free(in);
    3306             :                 }
    3307             :         }
    3308             : 
    3309          75 :         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          75 :         if (free_cert && cert) {
    3315           2 :                 X509_free(cert);
    3316             :         }
    3317          75 :         if (key && makeresource && resourceval) {
    3318          14 :                 *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key);
    3319             :         }
    3320          75 :         if (Z_TYPE(tmp) == IS_STRING) {
    3321             :                 zval_dtor(&tmp);
    3322             :         }
    3323          75 :         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         123 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
    3406             : {
    3407             :         assert(pkey != NULL);
    3408             : 
    3409         123 :         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           1 :                         if ( NULL == EC_KEY_get0_private_key(pkey->pkey.ec)) {
    3446           0 :                                 return 0;
    3447             :                         }
    3448           1 :                         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         119 :         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           1 : PHP_FUNCTION(openssl_pkey_export_to_file)
    3590             : {
    3591             :         struct php_x509_request req;
    3592           1 :         zval * zpkey, * args = NULL;
    3593           1 :         char * passphrase = NULL;
    3594           1 :         size_t passphrase_len = 0;
    3595           1 :         char * filename = NULL;
    3596           1 :         size_t filename_len = 0;
    3597           1 :         zend_resource *key_resource = NULL;
    3598             :         EVP_PKEY * key;
    3599           1 :         BIO * bio_out = NULL;
    3600             :         const EVP_CIPHER * cipher;
    3601             :         
    3602           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
    3603           0 :                 return;
    3604             :         }
    3605           1 :         RETVAL_FALSE;
    3606             : 
    3607           1 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    3608             : 
    3609           1 :         if (key == NULL) {
    3610           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    3611           0 :                 RETURN_FALSE;
    3612             :         }
    3613             :         
    3614           1 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    3615           0 :                 RETURN_FALSE;
    3616             :         }
    3617             :         
    3618           1 :         PHP_SSL_REQ_INIT(&req);
    3619             : 
    3620           1 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    3621           1 :                 bio_out = BIO_new_file(filename, "w");
    3622             : 
    3623           2 :                 if (passphrase && req.priv_key_encrypt) {
    3624           1 :                         if (req.priv_key_encrypt_cipher) {
    3625           0 :                                 cipher = req.priv_key_encrypt_cipher;
    3626             :                         } else {
    3627           1 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    3628             :                         }
    3629             :                 } else {
    3630           0 :                         cipher = NULL;
    3631             :                 }
    3632           1 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    3633             :                         /* Success!
    3634             :                          * If returning the output as a string, do so now */
    3635           1 :                         RETVAL_TRUE;
    3636             :                 }
    3637             :         }
    3638           1 :         PHP_SSL_REQ_DISPOSE(&req);
    3639             : 
    3640           1 :         if (key_resource == NULL && key) {
    3641           0 :                 EVP_PKEY_free(key);
    3642             :         }
    3643           1 :         if (bio_out) {
    3644           1 :                 BIO_free(bio_out);
    3645             :         }
    3646             : }
    3647             : /* }}} */
    3648             : 
    3649             : /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
    3650             :    Gets an exportable representation of a key into a string or file */
    3651          15 : PHP_FUNCTION(openssl_pkey_export)
    3652             : {
    3653             :         struct php_x509_request req;
    3654          15 :         zval * zpkey, * args = NULL, *out;
    3655          15 :         char * passphrase = NULL; size_t passphrase_len = 0;
    3656          15 :         zend_resource *key_resource = NULL;
    3657             :         EVP_PKEY * key;
    3658          15 :         BIO * bio_out = NULL;
    3659             :         const EVP_CIPHER * cipher;
    3660             :         
    3661          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
    3662           0 :                 return;
    3663             :         }
    3664          15 :         RETVAL_FALSE;
    3665             : 
    3666          15 :         key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
    3667             : 
    3668          15 :         if (key == NULL) {
    3669           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
    3670           0 :                 RETURN_FALSE;
    3671             :         }
    3672             :         
    3673          15 :         PHP_SSL_REQ_INIT(&req);
    3674             : 
    3675          15 :         if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
    3676          15 :                 bio_out = BIO_new(BIO_s_mem());
    3677             : 
    3678          15 :                 if (passphrase && req.priv_key_encrypt) {
    3679           0 :                         if (req.priv_key_encrypt_cipher) {
    3680           0 :                                 cipher = req.priv_key_encrypt_cipher;
    3681             :                         } else {
    3682           0 :                                 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
    3683             :                         }
    3684             :                 } else {
    3685          15 :                         cipher = NULL;
    3686             :                 }
    3687          15 :                 if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
    3688             :                         /* Success!
    3689             :                          * If returning the output as a string, do so now */
    3690             : 
    3691             :                         char * bio_mem_ptr;
    3692             :                         long bio_mem_len;
    3693          15 :                         RETVAL_TRUE;
    3694             : 
    3695          15 :                         bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
    3696          15 :                         zval_dtor(out);
    3697          30 :                         ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len);
    3698             :                 }
    3699             :         }
    3700          15 :         PHP_SSL_REQ_DISPOSE(&req);
    3701             : 
    3702          15 :         if (key_resource == NULL && key) {
    3703           0 :                 EVP_PKEY_free(key);
    3704             :         }
    3705          15 :         if (bio_out) {
    3706          15 :                 BIO_free(bio_out);
    3707             :         }
    3708             : }
    3709             : /* }}} */
    3710             : 
    3711             : /* {{{ proto int openssl_pkey_get_public(mixed cert)
    3712             :    Gets public key from X.509 certificate */
    3713           5 : PHP_FUNCTION(openssl_pkey_get_public)
    3714             : {
    3715             :         zval *cert;
    3716             :         EVP_PKEY *pkey;
    3717             :         zend_resource *res;
    3718             : 
    3719           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &cert) == FAILURE) {
    3720           0 :                 return;
    3721             :         }
    3722           5 :         pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &res TSRMLS_CC);
    3723           5 :         if (pkey == NULL) {
    3724           1 :                 RETURN_FALSE;
    3725             :         }
    3726           4 :         ZVAL_RES(return_value, res);
    3727             :         Z_ADDREF_P(return_value);
    3728             : }
    3729             : /* }}} */
    3730             : 
    3731             : /* {{{ proto void openssl_pkey_free(int key)
    3732             :    Frees a key */
    3733          15 : PHP_FUNCTION(openssl_pkey_free)
    3734             : {
    3735             :         zval *key;
    3736             :         EVP_PKEY *pkey;
    3737             : 
    3738          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    3739           0 :                 return;
    3740             :         }
    3741          15 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, key, -1, "OpenSSL key", le_key);
    3742          15 :         zend_list_close(Z_RES_P(key));
    3743             : }
    3744             : /* }}} */
    3745             : 
    3746             : /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
    3747             :    Gets private keys */
    3748           8 : PHP_FUNCTION(openssl_pkey_get_private)
    3749             : {
    3750             :         zval *cert;
    3751             :         EVP_PKEY *pkey;
    3752           8 :         char * passphrase = "";
    3753           8 :         size_t passphrase_len = sizeof("")-1;
    3754             :         zend_resource *res;
    3755             : 
    3756           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
    3757           0 :                 return;
    3758             :         }
    3759           8 :         pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &res TSRMLS_CC);
    3760             : 
    3761           8 :         if (pkey == NULL) {
    3762           0 :                 RETURN_FALSE;
    3763             :         }
    3764           8 :         ZVAL_RES(return_value, res);
    3765             :         Z_ADDREF_P(return_value);
    3766             : }
    3767             : 
    3768             : /* }}} */
    3769             : 
    3770             : /* {{{ proto resource openssl_pkey_get_details(resource key)
    3771             :         returns an array with the key details (bits, pkey, type)*/
    3772           4 : PHP_FUNCTION(openssl_pkey_get_details)
    3773             : {
    3774             :         zval *key;
    3775             :         EVP_PKEY *pkey;
    3776             :         BIO *out;
    3777             :         unsigned int pbio_len;
    3778             :         char *pbio;
    3779             :         zend_long ktype;
    3780             : 
    3781           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
    3782           3 :                 return;
    3783             :         }
    3784           1 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, key, -1, "OpenSSL key", le_key);
    3785           1 :         if (!pkey) {
    3786           0 :                 RETURN_FALSE;
    3787             :         }
    3788           1 :         out = BIO_new(BIO_s_mem());
    3789           1 :         PEM_write_bio_PUBKEY(out, pkey);
    3790           1 :         pbio_len = BIO_get_mem_data(out, &pbio);
    3791             : 
    3792           1 :         array_init(return_value);
    3793           1 :         add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
    3794           1 :         add_assoc_stringl(return_value, "key", pbio, pbio_len);
    3795             :         /*TODO: Use the real values once the openssl constants are used 
    3796             :          * See the enum at the top of this file
    3797             :          */
    3798           1 :         switch (EVP_PKEY_type(pkey->type)) {
    3799             :                 case EVP_PKEY_RSA:
    3800             :                 case EVP_PKEY_RSA2:
    3801           1 :                         ktype = OPENSSL_KEYTYPE_RSA;
    3802             : 
    3803           1 :                         if (pkey->pkey.rsa != NULL) {
    3804             :                                 zval rsa;
    3805             : 
    3806           1 :                                 array_init(&rsa);
    3807           2 :                                 OPENSSL_PKEY_GET_BN(rsa, n);
    3808           2 :                                 OPENSSL_PKEY_GET_BN(rsa, e);
    3809           2 :                                 OPENSSL_PKEY_GET_BN(rsa, d);
    3810           2 :                                 OPENSSL_PKEY_GET_BN(rsa, p);
    3811           2 :                                 OPENSSL_PKEY_GET_BN(rsa, q);
    3812           2 :                                 OPENSSL_PKEY_GET_BN(rsa, dmp1);
    3813           2 :                                 OPENSSL_PKEY_GET_BN(rsa, dmq1);
    3814           2 :                                 OPENSSL_PKEY_GET_BN(rsa, iqmp);
    3815           1 :                                 add_assoc_zval(return_value, "rsa", &rsa);
    3816             :                         }
    3817             : 
    3818           1 :                         break;  
    3819             :                 case EVP_PKEY_DSA:
    3820             :                 case EVP_PKEY_DSA2:
    3821             :                 case EVP_PKEY_DSA3:
    3822             :                 case EVP_PKEY_DSA4:
    3823           0 :                         ktype = OPENSSL_KEYTYPE_DSA;
    3824             : 
    3825           0 :                         if (pkey->pkey.dsa != NULL) {
    3826             :                                 zval dsa;
    3827             : 
    3828           0 :                                 array_init(&dsa);
    3829           0 :                                 OPENSSL_PKEY_GET_BN(dsa, p);
    3830           0 :                                 OPENSSL_PKEY_GET_BN(dsa, q);
    3831           0 :                                 OPENSSL_PKEY_GET_BN(dsa, g);
    3832           0 :                                 OPENSSL_PKEY_GET_BN(dsa, priv_key);
    3833           0 :                                 OPENSSL_PKEY_GET_BN(dsa, pub_key);
    3834           0 :                                 add_assoc_zval(return_value, "dsa", &dsa);
    3835             :                         }
    3836           0 :                         break;
    3837             :                 case EVP_PKEY_DH:
    3838             :                         
    3839           0 :                         ktype = OPENSSL_KEYTYPE_DH;
    3840             : 
    3841           0 :                         if (pkey->pkey.dh != NULL) {
    3842             :                                 zval dh;
    3843             : 
    3844           0 :                                 array_init(&dh);
    3845           0 :                                 OPENSSL_PKEY_GET_BN(dh, p);
    3846           0 :                                 OPENSSL_PKEY_GET_BN(dh, g);
    3847           0 :                                 OPENSSL_PKEY_GET_BN(dh, priv_key);
    3848           0 :                                 OPENSSL_PKEY_GET_BN(dh, pub_key);
    3849           0 :                                 add_assoc_zval(return_value, "dh", &dh);
    3850             :                         }
    3851             : 
    3852           0 :                         break;
    3853             : #ifdef HAVE_EVP_PKEY_EC
    3854             :                 case EVP_PKEY_EC:
    3855           0 :                         ktype = OPENSSL_KEYTYPE_EC;
    3856           0 :                         break;
    3857             : #endif
    3858             :                 default:
    3859           0 :                         ktype = -1;
    3860             :                         break;
    3861             :         }
    3862           1 :         add_assoc_long(return_value, "type", ktype);
    3863             : 
    3864           1 :         BIO_free(out);
    3865             : }
    3866             : /* }}} */
    3867             : 
    3868             : /* }}} */
    3869             : 
    3870             : #if OPENSSL_VERSION_NUMBER >= 0x10000000L
    3871             : 
    3872             : /* {{{ proto string openssl_pbkdf2(string password, string salt, long key_length, long iterations [, string digest_method = "sha1"])
    3873             :    Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */
    3874           5 : PHP_FUNCTION(openssl_pbkdf2)
    3875             : {
    3876           5 :         zend_long key_length = 0, iterations = 0;
    3877             :         char *password;
    3878             :         size_t password_len;
    3879             :         char *salt;
    3880             :         size_t salt_len;
    3881             :         char *method;
    3882           5 :         size_t method_len = 0;
    3883             :         zend_string *out_buffer;
    3884             : 
    3885             :         const EVP_MD *digest;
    3886             : 
    3887           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssll|s",
    3888             :                                 &password, &password_len,
    3889             :                                 &salt, &salt_len,
    3890             :                                 &key_length, &iterations,
    3891             :                                 &method, &method_len) == FAILURE) {
    3892           0 :                 return;
    3893             :         }
    3894             : 
    3895           5 :         if (key_length <= 0) {
    3896           0 :                 RETURN_FALSE;
    3897             :         }
    3898             : 
    3899           5 :         if (method_len) {
    3900           0 :                 digest = EVP_get_digestbyname(method);
    3901             :         } else {
    3902           5 :                 digest = EVP_sha1();
    3903             :         }
    3904             : 
    3905           5 :         if (!digest) {
    3906           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
    3907           0 :                 RETURN_FALSE;
    3908             :         }
    3909             : 
    3910          10 :         out_buffer = zend_string_alloc(key_length, 0);
    3911             : 
    3912           5 :         if (PKCS5_PBKDF2_HMAC(password, password_len, (unsigned char *)salt, salt_len, iterations, digest, key_length, (unsigned char*)out_buffer->val) == 1) {
    3913           5 :                 out_buffer->val[key_length] = 0;
    3914           5 :                 RETURN_STR(out_buffer);
    3915             :         } else {
    3916             :                 zend_string_release(out_buffer);
    3917           0 :                 RETURN_FALSE;
    3918             :         }
    3919             : }
    3920             : /* }}} */
    3921             : 
    3922             : #endif
    3923             : 
    3924             : /* {{{ PKCS7 S/MIME functions */
    3925             : 
    3926             : /* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
    3927             :    Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
    3928           0 : PHP_FUNCTION(openssl_pkcs7_verify)
    3929             : {
    3930           0 :         X509_STORE * store = NULL;
    3931           0 :         zval * cainfo = NULL;
    3932           0 :         STACK_OF(X509) *signers= NULL;
    3933           0 :         STACK_OF(X509) *others = NULL;
    3934           0 :         PKCS7 * p7 = NULL;
    3935           0 :         BIO * in = NULL, * datain = NULL, * dataout = NULL;
    3936           0 :         zend_long flags = 0;
    3937             :         char * filename;
    3938             :         size_t filename_len;
    3939           0 :         char * extracerts = NULL;
    3940           0 :         size_t extracerts_len = 0;
    3941           0 :         char * signersfilename = NULL;
    3942           0 :         size_t signersfilename_len = 0;
    3943           0 :         char * datafilename = NULL;
    3944           0 :         size_t datafilename_len = 0;
    3945             :         
    3946           0 :         RETVAL_LONG(-1);
    3947             : 
    3948           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pl|papp", &filename, &filename_len,
    3949             :                                 &flags, &signersfilename, &signersfilename_len, &cainfo,
    3950             :                                 &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
    3951           0 :                 return;
    3952             :         }
    3953             :         
    3954           0 :         if (extracerts) {
    3955           0 :                 others = load_all_certs_from_file(extracerts);
    3956           0 :                 if (others == NULL) {
    3957           0 :                         goto clean_exit;
    3958             :                 }
    3959             :         }
    3960             : 
    3961           0 :         flags = flags & ~PKCS7_DETACHED;
    3962             : 
    3963           0 :         store = setup_verify(cainfo TSRMLS_CC);
    3964             : 
    3965           0 :         if (!store) {
    3966           0 :                 goto clean_exit;
    3967             :         }
    3968           0 :         if (php_openssl_open_base_dir_chk(filename TSRMLS_CC)) {
    3969           0 :                 goto clean_exit;
    3970             :         }
    3971             : 
    3972           0 :         in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
    3973           0 :         if (in == NULL) {
    3974           0 :                 goto clean_exit;
    3975             :         }
    3976           0 :         p7 = SMIME_read_PKCS7(in, &datain);
    3977           0 :         if (p7 == NULL) {
    3978             : #if DEBUG_SMIME
    3979             :                 zend_printf("SMIME_read_PKCS7 failed\n");
    3980             : #endif
    3981           0 :                 goto clean_exit;
    3982             :         }
    3983             : 
    3984           0 :         if (datafilename) {
    3985             : 
    3986           0 :                 if (php_openssl_open_base_dir_chk(datafilename TSRMLS_CC)) {
    3987           0 :                         goto clean_exit;
    3988             :                 }
    3989             : 
    3990           0 :                 dataout = BIO_new_file(datafilename, "w");
    3991           0 :                 if (dataout == NULL) {
    3992           0 :                         goto clean_exit;
    3993             :                 }
    3994             :         }
    3995             : #if DEBUG_SMIME
    3996             :         zend_printf("Calling PKCS7 verify\n");
    3997             : #endif
    3998             : 
    3999           0 :         if (PKCS7_verify(p7, others, store, datain, dataout, flags)) {
    4000             : 
    4001           0 :                 RETVAL_TRUE;
    4002             : 
    4003           0 :                 if (signersfilename) {
    4004             :                         BIO *certout;
    4005             :                 
    4006           0 :                         if (php_openssl_open_base_dir_chk(signersfilename TSRMLS_CC)) {
    4007           0 :                                 goto clean_exit;
    4008             :                         }
    4009             :                 
    4010           0 :                         certout = BIO_new_file(signersfilename, "w");
    4011           0 :                         if (certout) {
    4012             :                                 int i;
    4013           0 :                                 signers = PKCS7_get0_signers(p7, NULL, flags);
    4014             : 
    4015           0 :                                 for(i = 0; i < sk_X509_num(signers); i++) {
    4016           0 :                                         PEM_write_bio_X509(certout, sk_X509_value(signers, i));
    4017             :                                 }
    4018           0 :                                 BIO_free(certout);
    4019           0 :                                 sk_X509_free(signers);
    4020             :                         } else {
    4021           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
    4022           0 :                                 RETVAL_LONG(-1);
    4023             :                         }
    4024             :                 }
    4025           0 :                 goto clean_exit;
    4026             :         } else {
    4027           0 :                 RETVAL_FALSE;
    4028             :         }
    4029             : clean_exit:
    4030           0 :         X509_STORE_free(store);
    4031           0 :         BIO_free(datain);
    4032           0 :         BIO_free(in);
    4033           0 :         BIO_free(dataout);
    4034           0 :         PKCS7_free(p7);
    4035           0 :         sk_X509_free(others);
    4036             : }
    4037             : /* }}} */
    4038             : 
    4039             : /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
    4040             :    Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
    4041          12 : PHP_FUNCTION(openssl_pkcs7_encrypt)
    4042             : {
    4043          12 :         zval * zrecipcerts, * zheaders = NULL;
    4044          12 :         STACK_OF(X509) * recipcerts = NULL;
    4045          12 :         BIO * infile = NULL, * outfile = NULL;
    4046          12 :         zend_long flags = 0;
    4047          12 :         PKCS7 * p7 = NULL;
    4048             :         zval * zcertval;
    4049             :         X509 * cert;
    4050          12 :         const EVP_CIPHER *cipher = NULL;
    4051          12 :         zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
    4052             :         zend_string * strindex;
    4053          12 :         char * infilename = NULL;
    4054             :         size_t infilename_len;
    4055          12 :         char * outfilename = NULL;
    4056             :         size_t outfilename_len;
    4057             :         
    4058          12 :         RETVAL_FALSE;
    4059             : 
    4060          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppza!|ll", &infilename, &infilename_len,
    4061             :                                 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
    4062           2 :                 return;
    4063             : 
    4064             :         
    4065          10 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    4066           0 :                 return;
    4067             :         }
    4068             : 
    4069          10 :         infile = BIO_new_file(infilename, "r");
    4070          10 :         if (infile == NULL) {
    4071           2 :                 goto clean_exit;
    4072             :         }
    4073             : 
    4074           8 :         outfile = BIO_new_file(outfilename, "w");
    4075           8 :         if (outfile == NULL) { 
    4076           1 :                 goto clean_exit;
    4077             :         }
    4078             : 
    4079           7 :         recipcerts = sk_X509_new_null();
    4080             : 
    4081             :         /* get certs */
    4082          14 :         if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) {
    4083          10 :                 ZEND_HASH_FOREACH_VAL(HASH_OF(zrecipcerts), zcertval) {
    4084             :                         zend_resource *certresource;
    4085             : 
    4086           2 :                         cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
    4087           2 :                         if (cert == NULL) {
    4088           0 :                                 goto clean_exit;
    4089             :                         }
    4090             : 
    4091           2 :                         if (certresource != NULL) {
    4092             :                                 /* we shouldn't free this particular cert, as it is a resource.
    4093             :                                         make a copy and push that on the stack instead */
    4094           0 :                                 cert = X509_dup(cert);
    4095           0 :                                 if (cert == NULL) {
    4096           0 :                                         goto clean_exit;
    4097             :                                 }
    4098             :                         }
    4099           2 :                         sk_X509_push(recipcerts, cert);
    4100             :                 } ZEND_HASH_FOREACH_END();
    4101             :         } else {
    4102             :                 /* a single certificate */
    4103             :                 zend_resource *certresource;
    4104             : 
    4105           6 :                 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource TSRMLS_CC);
    4106           6 :                 if (cert == NULL) {
    4107           2 :                         goto clean_exit;
    4108             :                 }
    4109             : 
    4110           4 :                 if (certresource != NULL) {
    4111             :                         /* we shouldn't free this particular cert, as it is a resource.
    4112             :                                 make a copy and push that on the stack instead */
    4113           0 :                         cert = X509_dup(cert);
    4114           0 :                         if (cert == NULL) {
    4115           0 :                                 goto clean_exit;
    4116             :                         }
    4117             :                 }
    4118           4 :                 sk_X509_push(recipcerts, cert);
    4119             :         }
    4120             : 
    4121             :         /* sanity check the cipher */
    4122           5 :         cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
    4123           5 :         if (cipher == NULL) {
    4124             :                 /* shouldn't happen */
    4125           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher");
    4126           0 :                 goto clean_exit;
    4127             :         }
    4128             : 
    4129           5 :         p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, flags);
    4130             : 
    4131           5 :         if (p7 == NULL) {
    4132           0 :                 goto clean_exit;
    4133             :         }
    4134             : 
    4135             :         /* tack on extra headers */
    4136           5 :         if (zheaders) {
    4137          42 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(HASH_OF(zheaders), strindex, zcertval) {
    4138           8 :                         convert_to_string_ex(zcertval);
    4139             : 
    4140           8 :                         if (strindex) {
    4141           2 :                                 BIO_printf(outfile, "%s: %s\n", strindex->val, Z_STRVAL_P(zcertval));
    4142             :                         } else {
    4143           6 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval));
    4144             :                         }
    4145             :                 } ZEND_HASH_FOREACH_END();
    4146             :         }
    4147             : 
    4148           5 :         (void)BIO_reset(infile);
    4149             : 
    4150             :         /* write the encrypted data */
    4151           5 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    4152             : 
    4153           5 :         RETVAL_TRUE;
    4154             : 
    4155             : clean_exit:
    4156          10 :         PKCS7_free(p7);
    4157          10 :         BIO_free(infile);
    4158          10 :         BIO_free(outfile);
    4159          10 :         if (recipcerts) {
    4160           7 :                 sk_X509_pop_free(recipcerts, X509_free);
    4161             :         }
    4162             : }
    4163             : /* }}} */
    4164             : 
    4165             : /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
    4166             :    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 */
    4167             : 
    4168          11 : PHP_FUNCTION(openssl_pkcs7_sign)
    4169             : {
    4170             :         zval * zcert, * zprivkey, * zheaders;
    4171             :         zval * hval;
    4172          11 :         X509 * cert = NULL;
    4173          11 :         EVP_PKEY * privkey = NULL;
    4174          11 :         zend_long flags = PKCS7_DETACHED;
    4175          11 :         PKCS7 * p7 = NULL;
    4176          11 :         BIO * infile = NULL, * outfile = NULL;
    4177          11 :         STACK_OF(X509) *others = NULL;
    4178          11 :         zend_resource *certresource = NULL, *keyresource = NULL;
    4179             :         zend_string * strindex;
    4180             :         char * infilename;
    4181             :         size_t infilename_len;
    4182             :         char * outfilename;
    4183             :         size_t outfilename_len;
    4184          11 :         char * extracertsfilename = NULL;
    4185             :         size_t extracertsfilename_len;
    4186             : 
    4187          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppzza!|lp",
    4188             :                                 &infilename, &infilename_len, &outfilename, &outfilename_len,
    4189             :                                 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
    4190             :                                 &extracertsfilename_len) == FAILURE) {
    4191           2 :                 return;
    4192             :         }
    4193             :         
    4194           9 :         RETVAL_FALSE;
    4195             : 
    4196           9 :         if (extracertsfilename) {
    4197           0 :                 others = load_all_certs_from_file(extracertsfilename);
    4198           0 :                 if (others == NULL) { 
    4199           0 :                         goto clean_exit;
    4200             :                 }
    4201             :         }
    4202             : 
    4203           9 :         privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource TSRMLS_CC);
    4204           9 :         if (privkey == NULL) {
    4205           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting private key");
    4206           1 :                 goto clean_exit;
    4207             :         }
    4208             : 
    4209           8 :         cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
    4210           8 :         if (cert == NULL) {
    4211           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting cert");
    4212           2 :                 goto clean_exit;
    4213             :         }
    4214             : 
    4215           6 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    4216             :                 goto clean_exit;
    4217             :         }
    4218             : 
    4219           6 :         infile = BIO_new_file(infilename, "r");
    4220           6 :         if (infile == NULL) {
    4221           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening input file %s!", infilename);
    4222           2 :                 goto clean_exit;
    4223             :         }
    4224             : 
    4225           4 :         outfile = BIO_new_file(outfilename, "w");
    4226           4 :         if (outfile == NULL) {
    4227           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening output file %s!", outfilename);
    4228           1 :                 goto clean_exit;
    4229             :         }
    4230             : 
    4231           3 :         p7 = PKCS7_sign(cert, privkey, others, infile, flags);
    4232           3 :         if (p7 == NULL) {
    4233           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "error creating PKCS7 structure!");
    4234           0 :                 goto clean_exit;
    4235             :         }
    4236             : 
    4237           3 :         (void)BIO_reset(infile);
    4238             : 
    4239             :         /* tack on extra headers */
    4240           3 :         if (zheaders) {
    4241          22 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(HASH_OF(zheaders), strindex, hval) {
    4242           4 :                         convert_to_string_ex(hval);
    4243             : 
    4244           4 :                         if (strindex) {
    4245           2 :                                 BIO_printf(outfile, "%s: %s\n", strindex->val, Z_STRVAL_P(hval));
    4246             :                         } else {
    4247           2 :                                 BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval));
    4248             :                         }
    4249             :                 } ZEND_HASH_FOREACH_END();
    4250             :         }
    4251             :         /* write the signed data */
    4252           3 :         SMIME_write_PKCS7(outfile, p7, infile, flags);
    4253             : 
    4254           3 :         RETVAL_TRUE;
    4255             : 
    4256             : clean_exit:
    4257           9 :         PKCS7_free(p7);
    4258           9 :         BIO_free(infile);
    4259           9 :         BIO_free(outfile);
    4260           9 :         if (others) {
    4261           0 :                 sk_X509_pop_free(others, X509_free);
    4262             :         }
    4263           9 :         if (privkey && keyresource == NULL) {
    4264           8 :                 EVP_PKEY_free(privkey);
    4265             :         }
    4266           9 :         if (cert && certresource == NULL) {
    4267           6 :                 X509_free(cert);
    4268             :         }
    4269             : }
    4270             : /* }}} */
    4271             : 
    4272             : /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
    4273             :    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 */
    4274             : 
    4275          15 : PHP_FUNCTION(openssl_pkcs7_decrypt)
    4276             : {
    4277          15 :         zval * recipcert, * recipkey = NULL;
    4278          15 :         X509 * cert = NULL;
    4279          15 :         EVP_PKEY * key = NULL;
    4280             :         zend_resource *certresval, *keyresval;
    4281          15 :         BIO * in = NULL, * out = NULL, * datain = NULL;
    4282          15 :         PKCS7 * p7 = NULL;
    4283             :         char * infilename;
    4284             :         size_t infilename_len;
    4285             :         char * outfilename;
    4286             :         size_t outfilename_len;
    4287             : 
    4288          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ppz|z", &infilename, &infilename_len,
    4289             :                                 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
    4290           0 :                 return;
    4291             :         }
    4292             : 
    4293          15 :         RETVAL_FALSE;
    4294             : 
    4295          15 :         cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC);
    4296          15 :         if (cert == NULL) {
    4297           8 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert");
    4298           8 :                 goto clean_exit;
    4299             :         }
    4300             : 
    4301           7 :         key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval TSRMLS_CC);
    4302           7 :         if (key == NULL) {
    4303           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key");
    4304           2 :                 goto clean_exit;
    4305             :         }
    4306             :         
    4307           5 :         if (php_openssl_open_base_dir_chk(infilename TSRMLS_CC) || php_openssl_open_base_dir_chk(outfilename TSRMLS_CC)) {
    4308             :                 goto clean_exit;
    4309             :         }
    4310             : 
    4311           5 :         in = BIO_new_file(infilename, "r");
    4312           5 :         if (in == NULL) {
    4313           2 :                 goto clean_exit;
    4314             :         }
    4315           3 :         out = BIO_new_file(outfilename, "w");
    4316           3 :         if (out == NULL) {
    4317           1 :                 goto clean_exit;
    4318             :         }
    4319             : 
    4320           2 :         p7 = SMIME_read_PKCS7(in, &datain);
    4321             : 
    4322           2 :         if (p7 == NULL) {
    4323           0 :                 goto clean_exit;
    4324             :         }
    4325           2 :         if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) { 
    4326           2 :                 RETVAL_TRUE;
    4327             :         }
    4328             : clean_exit:
    4329          15 :         PKCS7_free(p7);
    4330          15 :         BIO_free(datain);
    4331          15 :         BIO_free(in);
    4332          15 :         BIO_free(out);
    4333          15 :         if (cert && certresval == NULL) {
    4334           7 :                 X509_free(cert);
    4335             :         }
    4336          15 :         if (key && keyresval == NULL) {
    4337           5 :                 EVP_PKEY_free(key);
    4338             :         }
    4339             : }
    4340             : /* }}} */
    4341             : 
    4342             : /* }}} */
    4343             : 
    4344             : /* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
    4345             :    Encrypts data with private key */
    4346           6 : PHP_FUNCTION(openssl_private_encrypt)
    4347             : {
    4348             :         zval *key, *crypted;
    4349             :         EVP_PKEY *pkey;
    4350             :         int cryptedlen;
    4351           6 :         zend_string *cryptedbuf = NULL;
    4352           6 :         int successful = 0;
    4353           6 :         zend_resource *keyresource = NULL;
    4354             :         char * data;
    4355             :         size_t data_len;
    4356           6 :         zend_long padding = RSA_PKCS1_PADDING;
    4357             : 
    4358           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { 
    4359           0 :                 return;
    4360             :         }
    4361           6 :         RETVAL_FALSE;
    4362             : 
    4363           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    4364             : 
    4365           6 :         if (pkey == NULL) {
    4366           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key param is not a valid private key");
    4367           3 :                 RETURN_FALSE;
    4368             :         }
    4369             : 
    4370           3 :         cryptedlen = EVP_PKEY_size(pkey);
    4371           6 :         cryptedbuf = zend_string_alloc(cryptedlen, 0);
    4372             : 
    4373           3 :         switch (pkey->type) {
    4374             :                 case EVP_PKEY_RSA:
    4375             :                 case EVP_PKEY_RSA2:
    4376           6 :                         successful =  (RSA_private_encrypt(data_len, 
    4377             :                                                 (unsigned char *)data, 
    4378             :                                                 (unsigned char *)cryptedbuf->val,
    4379           3 :                                                 pkey->pkey.rsa, 
    4380             :                                                 padding) == cryptedlen);
    4381           3 :                         break;
    4382             :                 default:
    4383           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4384             :         }
    4385             : 
    4386           3 :         if (successful) {
    4387           3 :                 zval_dtor(crypted);
    4388           3 :                 cryptedbuf->val[cryptedlen] = '\0';
    4389           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    4390           3 :                 cryptedbuf = NULL;
    4391           3 :                 RETVAL_TRUE;
    4392             :         }
    4393           3 :         if (cryptedbuf) {
    4394             :                 zend_string_release(cryptedbuf);
    4395             :         }
    4396           3 :         if (keyresource == NULL) { 
    4397           3 :                 EVP_PKEY_free(pkey);
    4398             :         }
    4399             : }
    4400             : /* }}} */
    4401             : 
    4402             : /* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding])
    4403             :    Decrypts data with private key */
    4404           6 : PHP_FUNCTION(openssl_private_decrypt)
    4405             : {
    4406             :         zval *key, *crypted;
    4407             :         EVP_PKEY *pkey;
    4408             :         int cryptedlen;
    4409           6 :         zend_string *cryptedbuf = NULL;
    4410             :         unsigned char *crypttemp;
    4411           6 :         int successful = 0;
    4412           6 :         zend_long padding = RSA_PKCS1_PADDING;
    4413           6 :         zend_resource *keyresource = NULL;
    4414             :         char * data;
    4415             :         size_t data_len;
    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           6 :         if (pkey == NULL) {
    4424           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid private key");
    4425           2 :                 RETURN_FALSE;
    4426             :         }
    4427             : 
    4428           4 :         cryptedlen = EVP_PKEY_size(pkey);
    4429           4 :         crypttemp = emalloc(cryptedlen + 1);
    4430             : 
    4431           4 :         switch (pkey->type) {
    4432             :                 case EVP_PKEY_RSA:
    4433             :                 case EVP_PKEY_RSA2:
    4434           8 :                         cryptedlen = RSA_private_decrypt(data_len, 
    4435             :                                         (unsigned char *)data, 
    4436             :                                         crypttemp, 
    4437           4 :                                         pkey->pkey.rsa, 
    4438             :                                         padding);
    4439           4 :                         if (cryptedlen != -1) {
    4440           6 :                                 cryptedbuf = zend_string_alloc(cryptedlen, 0);
    4441           3 :                                 memcpy(cryptedbuf->val, crypttemp, cryptedlen);
    4442           3 :                                 successful = 1;
    4443             :                         }
    4444           4 :                         break;
    4445             :                 default:
    4446           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4447             :         }
    4448             : 
    4449           4 :         efree(crypttemp);
    4450             : 
    4451           4 :         if (successful) {
    4452           3 :                 zval_dtor(crypted);
    4453           3 :                 cryptedbuf->val[cryptedlen] = '\0';
    4454           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    4455           3 :                 cryptedbuf = NULL;
    4456           3 :                 RETVAL_TRUE;
    4457             :         }
    4458             : 
    4459           4 :         if (keyresource == NULL) {
    4460           4 :                 EVP_PKEY_free(pkey);
    4461             :         }
    4462           4 :         if (cryptedbuf) { 
    4463             :                 zend_string_release(cryptedbuf);
    4464             :         }
    4465             : }
    4466             : /* }}} */
    4467             : 
    4468             : /* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding])
    4469             :    Encrypts data with public key */
    4470           6 : PHP_FUNCTION(openssl_public_encrypt)
    4471             : {
    4472             :         zval *key, *crypted;
    4473             :         EVP_PKEY *pkey;
    4474             :         int cryptedlen;
    4475             :         zend_string *cryptedbuf;
    4476           6 :         int successful = 0;
    4477           6 :         zend_resource *keyresource = NULL;
    4478           6 :         zend_long padding = RSA_PKCS1_PADDING;
    4479             :         char * data;
    4480             :         size_t data_len;
    4481             : 
    4482           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
    4483           0 :                 return;
    4484           6 :         RETVAL_FALSE;
    4485             :         
    4486           6 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4487           6 :         if (pkey == NULL) {
    4488           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
    4489           3 :                 RETURN_FALSE;
    4490             :         }
    4491             : 
    4492           3 :         cryptedlen = EVP_PKEY_size(pkey);
    4493           6 :         cryptedbuf = zend_string_alloc(cryptedlen, 0);
    4494             : 
    4495           3 :         switch (pkey->type) {
    4496             :                 case EVP_PKEY_RSA:
    4497             :                 case EVP_PKEY_RSA2:
    4498           6 :                         successful = (RSA_public_encrypt(data_len, 
    4499             :                                                 (unsigned char *)data, 
    4500             :                                                 (unsigned char *)cryptedbuf->val, 
    4501           3 :                                                 pkey->pkey.rsa, 
    4502             :                                                 padding) == cryptedlen);
    4503           3 :                         break;
    4504             :                 default:
    4505           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4506             : 
    4507             :         }
    4508             : 
    4509           3 :         if (successful) {
    4510           3 :                 zval_dtor(crypted);
    4511           3 :                 cryptedbuf->val[cryptedlen] = '\0';
    4512           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    4513           3 :                 cryptedbuf = NULL;
    4514           3 :                 RETVAL_TRUE;
    4515             :         }
    4516           3 :         if (keyresource == NULL) {
    4517           3 :                 EVP_PKEY_free(pkey);
    4518             :         }
    4519           3 :         if (cryptedbuf) {
    4520             :                 zend_string_release(cryptedbuf);
    4521             :         }
    4522             : }
    4523             : /* }}} */
    4524             : 
    4525             : /* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding])
    4526             :    Decrypts data with public key */
    4527           7 : PHP_FUNCTION(openssl_public_decrypt)
    4528             : {
    4529             :         zval *key, *crypted;
    4530             :         EVP_PKEY *pkey;
    4531             :         int cryptedlen;
    4532           7 :         zend_string *cryptedbuf = NULL;
    4533             :         unsigned char *crypttemp;
    4534           7 :         int successful = 0;
    4535           7 :         zend_resource *keyresource = NULL;
    4536           7 :         zend_long padding = RSA_PKCS1_PADDING;
    4537             :         char * data;
    4538             :         size_t data_len;
    4539             : 
    4540           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
    4541           0 :                 return;
    4542             :         }
    4543           7 :         RETVAL_FALSE;
    4544             :         
    4545           7 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4546           7 :         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           4 :         cryptedlen = EVP_PKEY_size(pkey);
    4552           4 :         crypttemp = emalloc(cryptedlen + 1);
    4553             : 
    4554           4 :         switch (pkey->type) {
    4555             :                 case EVP_PKEY_RSA:
    4556             :                 case EVP_PKEY_RSA2:
    4557           8 :                         cryptedlen = RSA_public_decrypt(data_len, 
    4558             :                                         (unsigned char *)data, 
    4559             :                                         crypttemp, 
    4560           4 :                                         pkey->pkey.rsa, 
    4561             :                                         padding);
    4562           4 :                         if (cryptedlen != -1) {
    4563           6 :                                 cryptedbuf = zend_string_alloc(cryptedlen, 0);
    4564           3 :                                 memcpy(cryptedbuf->val, crypttemp, cryptedlen);
    4565           3 :                                 successful = 1;
    4566             :                         }
    4567           4 :                         break;
    4568             :                         
    4569             :                 default:
    4570           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
    4571             :                  
    4572             :         }
    4573             : 
    4574           4 :         efree(crypttemp);
    4575             : 
    4576           4 :         if (successful) {
    4577           3 :                 zval_dtor(crypted);
    4578           3 :                 cryptedbuf->val[cryptedlen] = '\0';
    4579           3 :                 ZVAL_NEW_STR(crypted, cryptedbuf);
    4580           3 :                 cryptedbuf = NULL;
    4581           3 :                 RETVAL_TRUE;
    4582             :         }
    4583             : 
    4584           4 :         if (cryptedbuf) {
    4585             :                 zend_string_release(cryptedbuf);
    4586             :         }
    4587           4 :         if (keyresource == NULL) {
    4588           4 :                 EVP_PKEY_free(pkey);
    4589             :         }
    4590             : }
    4591             : /* }}} */
    4592             : 
    4593             : /* {{{ proto mixed openssl_error_string(void)
    4594             :    Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
    4595           2 : PHP_FUNCTION(openssl_error_string)
    4596             : {
    4597             :         char buf[512];
    4598             :         unsigned long val;
    4599             : 
    4600           2 :         if (zend_parse_parameters_none() == FAILURE) {
    4601           0 :                 return;
    4602             :         }
    4603             : 
    4604           2 :         val = ERR_get_error();
    4605           2 :         if (val) {
    4606           2 :                 RETURN_STRING(ERR_error_string(val, buf));
    4607             :         } else {
    4608           1 :                 RETURN_FALSE;
    4609             :         }
    4610             : }
    4611             : /* }}} */
    4612             : 
    4613             : /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
    4614             :    Signs data */
    4615           7 : PHP_FUNCTION(openssl_sign)
    4616             : {
    4617             :         zval *key, *signature;
    4618             :         EVP_PKEY *pkey;
    4619             :         unsigned int siglen;
    4620             :         zend_string *sigbuf;
    4621           7 :         zend_resource *keyresource = NULL;
    4622             :         char * data;
    4623             :         size_t data_len;
    4624             :         EVP_MD_CTX md_ctx;
    4625           7 :         zval *method = NULL;
    4626           7 :         zend_long signature_algo = OPENSSL_ALGO_SHA1;
    4627             :         const EVP_MD *mdtype;
    4628             : 
    4629           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
    4630           1 :                 return;
    4631             :         }
    4632           6 :         pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
    4633           6 :         if (pkey == NULL) {
    4634           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a private key");
    4635           1 :                 RETURN_FALSE;
    4636             :         }
    4637             : 
    4638          12 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    4639           4 :                 if (method != NULL) {
    4640           2 :                         signature_algo = Z_LVAL_P(method);
    4641             :                 }
    4642           4 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    4643           2 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    4644           1 :                 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
    4645             :         } else {
    4646           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4647           0 :                 RETURN_FALSE;
    4648             :         }
    4649           5 :         if (!mdtype) {
    4650           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4651           0 :                 RETURN_FALSE;
    4652             :         }
    4653             : 
    4654           5 :         siglen = EVP_PKEY_size(pkey);
    4655          10 :         sigbuf = zend_string_alloc(siglen, 0);
    4656             : 
    4657           5 :         EVP_SignInit(&md_ctx, mdtype);
    4658           5 :         EVP_SignUpdate(&md_ctx, data, data_len);
    4659           5 :         if (EVP_SignFinal (&md_ctx, (unsigned char*)sigbuf->val, &siglen, pkey)) {
    4660           5 :                 zval_dtor(signature);
    4661           5 :                 sigbuf->val[siglen] = '\0';
    4662           5 :                 sigbuf->len = siglen;
    4663           5 :                 ZVAL_NEW_STR(signature, sigbuf);
    4664           5 :                 RETVAL_TRUE;
    4665             :         } else {
    4666           0 :                 efree(sigbuf);
    4667           0 :                 RETVAL_FALSE;
    4668             :         }
    4669           5 :         EVP_MD_CTX_cleanup(&md_ctx);
    4670           5 :         if (keyresource == NULL) {
    4671           2 :                 EVP_PKEY_free(pkey);
    4672             :         }
    4673             : }
    4674             : /* }}} */
    4675             : 
    4676             : /* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
    4677             :    Verifys data */
    4678          16 : PHP_FUNCTION(openssl_verify)
    4679             : {
    4680             :         zval *key;
    4681             :         EVP_PKEY *pkey;
    4682             :         int err;
    4683             :         EVP_MD_CTX     md_ctx;
    4684             :         const EVP_MD *mdtype;
    4685          16 :         zend_resource *keyresource = NULL;
    4686             :         char * data;
    4687             :         size_t data_len;
    4688             :         char * signature;
    4689             :         size_t signature_len;
    4690          16 :         zval *method = NULL;
    4691          16 :         zend_long signature_algo = OPENSSL_ALGO_SHA1;
    4692             :         
    4693          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
    4694           5 :                 return;
    4695             :         }
    4696             : 
    4697          27 :         if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
    4698          11 :                 if (method != NULL) {
    4699           5 :                         signature_algo = Z_LVAL_P(method);
    4700             :                 }
    4701          11 :                 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
    4702           0 :         } else if (Z_TYPE_P(method) == IS_STRING) {
    4703           0 :                 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          11 :         if (!mdtype) {
    4709           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4710           0 :                 RETURN_FALSE;
    4711             :         }
    4712             : 
    4713          11 :         pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
    4714          11 :         if (pkey == NULL) {
    4715           5 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a public key");
    4716           5 :                 RETURN_FALSE;
    4717             :         }
    4718             : 
    4719           6 :         EVP_VerifyInit   (&md_ctx, mdtype);
    4720           6 :         EVP_VerifyUpdate (&md_ctx, data, data_len);
    4721           6 :         err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
    4722           6 :         EVP_MD_CTX_cleanup(&md_ctx);
    4723             : 
    4724           6 :         if (keyresource == NULL) {
    4725           3 :                 EVP_PKEY_free(pkey);
    4726             :         }
    4727           6 :         RETURN_LONG(err);
    4728             : }
    4729             : /* }}} */
    4730             : 
    4731             : /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
    4732             :    Seals data */
    4733          11 : PHP_FUNCTION(openssl_seal)
    4734             : {
    4735             :         zval *pubkeys, *pubkey, *sealdata, *ekeys;
    4736             :         HashTable *pubkeysht;
    4737             :         EVP_PKEY **pkeys;
    4738             :         zend_resource ** key_resources; /* so we know what to cleanup */
    4739             :         int i, len1, len2, *eksl, nkeys;
    4740          11 :         unsigned char *buf = NULL, **eks;
    4741             :         char * data;
    4742             :         size_t data_len;
    4743          11 :         char *method =NULL;
    4744          11 :         size_t method_len = 0;
    4745             :         const EVP_CIPHER *cipher;
    4746             :         EVP_CIPHER_CTX ctx;
    4747             : 
    4748          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/z/a/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
    4749           3 :                 return;
    4750             :         }
    4751          16 :         pubkeysht = HASH_OF(pubkeys);
    4752           8 :         nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
    4753           8 :         if (!nkeys) {
    4754           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
    4755           2 :                 RETURN_FALSE;
    4756             :         }
    4757             : 
    4758           6 :         if (method) {
    4759           0 :                 cipher = EVP_get_cipherbyname(method);
    4760           0 :                 if (!cipher) {
    4761           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4762           0 :                         RETURN_FALSE;
    4763             :                 }
    4764             :         } else {
    4765           6 :                 cipher = EVP_rc4();
    4766             :         }
    4767             : 
    4768           6 :         pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
    4769           6 :         eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
    4770           6 :         eks = safe_emalloc(nkeys, sizeof(*eks), 0);
    4771           6 :         memset(eks, 0, sizeof(*eks) * nkeys);
    4772           6 :         key_resources = safe_emalloc(nkeys, sizeof(zend_resource), 0);
    4773           6 :         memset(key_resources, 0, sizeof(zend_resource) * nkeys);
    4774             : 
    4775             :         /* get the public keys we are using to seal this data */
    4776           6 :         i = 0;
    4777          23 :         ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) {
    4778          10 :                 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i] TSRMLS_CC);
    4779          10 :                 if (pkeys[i] == NULL) {
    4780           3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
    4781           3 :                         RETVAL_FALSE;
    4782           3 :                         goto clean_exit;
    4783             :                 }
    4784           7 :                 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
    4785           7 :                 i++;
    4786             :         } ZEND_HASH_FOREACH_END();
    4787             : 
    4788           3 :         if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
    4789           0 :                 RETVAL_FALSE;
    4790           0 :                 EVP_CIPHER_CTX_cleanup(&ctx);
    4791           0 :                 goto clean_exit;
    4792             :         }
    4793             : 
    4794             : #if 0
    4795             :         /* Need this if allow ciphers that require initialization vector */
    4796             :         ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
    4797             :         iv = ivlen ? emalloc(ivlen + 1) : NULL;
    4798             : #endif
    4799             :         /* allocate one byte extra to make room for \0 */
    4800           3 :         buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
    4801           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4802             : 
    4803           3 :         if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    4804           0 :                 RETVAL_FALSE;
    4805           0 :                 efree(buf);
    4806           0 :                 EVP_CIPHER_CTX_cleanup(&ctx);
    4807           0 :                 goto clean_exit;
    4808             :         }
    4809             : 
    4810           3 :         EVP_SealFinal(&ctx, buf + len1, &len2);
    4811             : 
    4812           3 :         if (len1 + len2 > 0) {
    4813           3 :                 zval_dtor(sealdata);
    4814           3 :                 buf[len1 + len2] = '\0';
    4815           6 :                 ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0));
    4816           3 :                 efree(buf);
    4817             : 
    4818           3 :                 zval_dtor(ekeys);
    4819           3 :                 array_init(ekeys);
    4820           9 :                 for (i=0; i<nkeys; i++) {
    4821           6 :                         eks[i][eksl[i]] = '\0';
    4822           6 :                         add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]);
    4823           6 :                         efree(eks[i]);
    4824           6 :                         eks[i] = NULL;
    4825             :                 }
    4826             : #if 0
    4827             :                 /* If allow ciphers that need IV, we need this */
    4828             :                 zval_dtor(*ivec);
    4829             :                 if (ivlen) {
    4830             :                         iv[ivlen] = '\0';
    4831             :                         ZVAL_STRINGL(*ivec, iv, ivlen);
    4832             :                         efree(iv);
    4833             :                 } else {
    4834             :                         ZVAL_EMPTY_STRING(*ivec);
    4835             :                 }
    4836             : #endif
    4837             :         } else {
    4838           0 :                 efree(buf);
    4839             :         }
    4840           3 :         RETVAL_LONG(len1 + len2);
    4841           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4842             : 
    4843             : clean_exit:
    4844          16 :         for (i=0; i<nkeys; i++) {
    4845          10 :                 if (key_resources[i] == NULL) {
    4846          10 :                         EVP_PKEY_free(pkeys[i]);
    4847             :                 }
    4848          10 :                 if (eks[i]) { 
    4849           1 :                         efree(eks[i]);
    4850             :                 }
    4851             :         }
    4852           6 :         efree(eks);
    4853           6 :         efree(eksl);
    4854           6 :         efree(pkeys);
    4855           6 :         efree(key_resources);
    4856             : }
    4857             : /* }}} */
    4858             : 
    4859             : /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
    4860             :    Opens data */
    4861           4 : PHP_FUNCTION(openssl_open)
    4862             : {
    4863             :         zval *privkey, *opendata;
    4864             :         EVP_PKEY *pkey;
    4865             :         int len1, len2;
    4866             :         unsigned char *buf;
    4867           4 :         zend_resource *keyresource = NULL;
    4868             :         EVP_CIPHER_CTX ctx;
    4869             :         char * data;
    4870             :         size_t data_len;
    4871             :         char * ekey;
    4872             :         size_t ekey_len;
    4873           4 :         char *method =NULL;
    4874           4 :         size_t method_len = 0;
    4875             :         const EVP_CIPHER *cipher;
    4876             : 
    4877           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) {
    4878           0 :                 return;
    4879             :         }
    4880             : 
    4881           4 :         pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource TSRMLS_CC);
    4882           4 :         if (pkey == NULL) {
    4883           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key");
    4884           1 :                 RETURN_FALSE;
    4885             :         }
    4886             : 
    4887           3 :         if (method) {
    4888           0 :                 cipher = EVP_get_cipherbyname(method);
    4889           0 :                 if (!cipher) {
    4890           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
    4891           0 :                         RETURN_FALSE;
    4892             :                 }
    4893             :         } else {
    4894           3 :                 cipher = EVP_rc4();
    4895             :         }
    4896             :         
    4897           3 :         buf = emalloc(data_len + 1);
    4898             : 
    4899           5 :         if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
    4900           2 :                 if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
    4901           0 :                         efree(buf);
    4902           0 :                         RETVAL_FALSE;
    4903             :                 } else {
    4904           2 :                         zval_dtor(opendata);
    4905           2 :                         buf[len1 + len2] = '\0';
    4906           4 :                         ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0));
    4907           2 :                         efree(buf);
    4908           2 :                         RETVAL_TRUE;
    4909             :                 }
    4910             :         } else {
    4911           1 :                 efree(buf);
    4912           1 :                 RETVAL_FALSE;
    4913             :         }
    4914           3 :         if (keyresource == NULL) {
    4915           3 :                 EVP_PKEY_free(pkey);
    4916             :         }
    4917           3 :         EVP_CIPHER_CTX_cleanup(&ctx);
    4918             : }
    4919             : /* }}} */
    4920             : 
    4921           0 : static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
    4922             : {
    4923           0 :         add_next_index_string((zval*)arg, (char*)name->name);
    4924           0 : }
    4925             : /* }}} */
    4926             : 
    4927           0 : static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
    4928             : {
    4929           0 :         if (name->alias == 0) {
    4930           0 :                 add_next_index_string((zval*)arg, (char*)name->name);
    4931             :         }
    4932           0 : }
    4933             : /* }}} */
    4934             : 
    4935             : /* {{{ proto array openssl_get_md_methods([bool aliases = false])
    4936             :    Return array of available digest methods */
    4937           0 : PHP_FUNCTION(openssl_get_md_methods)
    4938             : {
    4939           0 :         zend_bool aliases = 0;
    4940             : 
    4941           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
    4942           0 :                 return;
    4943             :         }
    4944           0 :         array_init(return_value);
    4945           0 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
    4946           0 :                 aliases ? openssl_add_method_or_alias: openssl_add_method, 
    4947             :                 return_value);
    4948             : }
    4949             : /* }}} */
    4950             : 
    4951             : /* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
    4952             :    Return array of available cipher methods */
    4953           0 : PHP_FUNCTION(openssl_get_cipher_methods)
    4954             : {
    4955           0 :         zend_bool aliases = 0;
    4956             : 
    4957           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
    4958           0 :                 return;
    4959             :         }
    4960           0 :         array_init(return_value);
    4961           0 :         OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
    4962           0 :                 aliases ? openssl_add_method_or_alias: openssl_add_method, 
    4963             :                 return_value);
    4964             : }
    4965             : /* }}} */
    4966             : 
    4967             : /* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
    4968             :    Computes digest hash value for given data using given method, returns raw or binhex encoded string */
    4969           2 : PHP_FUNCTION(openssl_digest)
    4970             : {
    4971           2 :         zend_bool raw_output = 0;
    4972             :         char *data, *method;
    4973             :         size_t data_len, method_len;
    4974             :         const EVP_MD *mdtype;
    4975             :         EVP_MD_CTX md_ctx;
    4976             :         unsigned int siglen;
    4977             :         zend_string *sigbuf;
    4978             : 
    4979           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
    4980           0 :                 return;
    4981             :         }
    4982           2 :         mdtype = EVP_get_digestbyname(method);
    4983           2 :         if (!mdtype) {
    4984           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
    4985           0 :                 RETURN_FALSE;
    4986             :         }
    4987             : 
    4988           2 :         siglen = EVP_MD_size(mdtype);
    4989           4 :         sigbuf = zend_string_alloc(siglen, 0);
    4990             : 
    4991           2 :         EVP_DigestInit(&md_ctx, mdtype);
    4992           2 :         EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
    4993           2 :         if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf->val, &siglen)) {
    4994           2 :                 if (raw_output) {
    4995           0 :                         sigbuf->val[siglen] = '\0';
    4996           0 :                         sigbuf->len = siglen;
    4997           0 :                         RETVAL_STR(sigbuf);
    4998             :                 } else {
    4999           2 :                         int digest_str_len = siglen * 2;
    5000           4 :                         zend_string *digest_str = zend_string_alloc(digest_str_len, 0);
    5001             : 
    5002           2 :                         make_digest_ex(digest_str->val, (unsigned char*)sigbuf->val, siglen);
    5003           2 :                         digest_str->val[digest_str_len] = '\0';
    5004             :                         zend_string_release(sigbuf);
    5005           2 :                         RETVAL_STR(digest_str);
    5006             :                 }
    5007             :         } else {
    5008             :                 zend_string_release(sigbuf);
    5009           0 :                 RETVAL_FALSE;
    5010             :         }
    5011             : }
    5012             : /* }}} */
    5013             : 
    5014          14 : static zend_bool php_openssl_validate_iv(char **piv, int *piv_len, int iv_required_len TSRMLS_DC)
    5015             : {
    5016             :         char *iv_new;
    5017             : 
    5018             :         /* Best case scenario, user behaved */
    5019          14 :         if (*piv_len == iv_required_len) {
    5020          10 :                 return 0;
    5021             :         }
    5022             : 
    5023           4 :         iv_new = ecalloc(1, iv_required_len + 1);
    5024             : 
    5025           4 :         if (*piv_len <= 0) {
    5026             :                 /* BC behavior */
    5027           4 :                 *piv_len = iv_required_len;
    5028           4 :                 *piv     = iv_new;
    5029           4 :                 return 1;
    5030             :         }
    5031             : 
    5032           0 :         if (*piv_len < iv_required_len) {
    5033           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);
    5034           0 :                 memcpy(iv_new, *piv, *piv_len);
    5035           0 :                 *piv_len = iv_required_len;
    5036           0 :                 *piv     = iv_new;
    5037           0 :                 return 1;
    5038             :         }
    5039             : 
    5040           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);
    5041           0 :         memcpy(iv_new, *piv, iv_required_len);
    5042           0 :         *piv_len = iv_required_len;
    5043           0 :         *piv     = iv_new;
    5044           0 :         return 1;
    5045             : 
    5046             : }
    5047             : 
    5048             : /* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv='']])
    5049             :    Encrypts given data with given method and key, returns raw or base64 encoded string */
    5050          15 : PHP_FUNCTION(openssl_encrypt)
    5051             : {
    5052          15 :         zend_long options = 0;
    5053          15 :         char *data, *method, *password, *iv = "";
    5054          15 :         size_t data_len, method_len, password_len, iv_len = 0, max_iv_len;
    5055             :         const EVP_CIPHER *cipher_type;
    5056             :         EVP_CIPHER_CTX cipher_ctx;
    5057          15 :         int i=0, outlen, keylen;
    5058             :         zend_string *outbuf;
    5059             :         unsigned char *key;
    5060             :         zend_bool free_iv;
    5061             : 
    5062          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) {
    5063           6 :                 return;
    5064             :         }
    5065           9 :         cipher_type = EVP_get_cipherbyname(method);
    5066           9 :         if (!cipher_type) {
    5067           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5068           1 :                 RETURN_FALSE;
    5069             :         }
    5070             : 
    5071           8 :         keylen = EVP_CIPHER_key_length(cipher_type);
    5072           8 :         if (keylen > password_len) {
    5073           8 :                 key = emalloc(keylen);
    5074           8 :                 memset(key, 0, keylen);
    5075           8 :                 memcpy(key, password, password_len);
    5076             :         } else {
    5077           0 :                 key = (unsigned char*)password;
    5078             :         }
    5079             : 
    5080           8 :         max_iv_len = EVP_CIPHER_iv_length(cipher_type);
    5081           8 :         if (iv_len <= 0 && max_iv_len > 0) {
    5082           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
    5083             :         }
    5084           8 :         free_iv = php_openssl_validate_iv(&iv, (int *)&iv_len, max_iv_len TSRMLS_CC);
    5085             : 
    5086           8 :         outlen = data_len + EVP_CIPHER_block_size(cipher_type);
    5087          16 :         outbuf = zend_string_alloc(outlen, 0);
    5088             : 
    5089           8 :         EVP_EncryptInit(&cipher_ctx, cipher_type, NULL, NULL);
    5090           8 :         if (password_len > keylen) {
    5091           0 :                 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
    5092             :         }
    5093           8 :         EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
    5094           8 :         if (options & OPENSSL_ZERO_PADDING) {
    5095           1 :                 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
    5096             :         }
    5097           8 :         if (data_len > 0) {
    5098           7 :                 EVP_EncryptUpdate(&cipher_ctx, (unsigned char*)outbuf->val, &i, (unsigned char *)data, data_len);
    5099             :         }
    5100           8 :         outlen = i;
    5101           8 :         if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf->val + i, &i)) {
    5102           8 :                 outlen += i;
    5103           8 :                 if (options & OPENSSL_RAW_DATA) {
    5104           2 :                         outbuf->val[outlen] = '\0';
    5105           2 :                         outbuf->len = outlen;
    5106           2 :                         RETVAL_STR(outbuf);
    5107             :                 } else {
    5108             :                         zend_string *base64_str;
    5109             : 
    5110           6 :                         base64_str = php_base64_encode((unsigned char*)outbuf->val, outlen);
    5111             :                         zend_string_release(outbuf);
    5112           6 :                         RETVAL_STR(base64_str);
    5113             :                 }
    5114             :         } else {
    5115             :                 zend_string_release(outbuf);
    5116           0 :                 RETVAL_FALSE;
    5117             :         }
    5118           8 :         if (key != (unsigned char*)password) {
    5119           8 :                 efree(key);
    5120             :         }
    5121           8 :         if (free_iv) {
    5122           2 :                 efree(iv);
    5123             :         }
    5124           8 :         EVP_CIPHER_CTX_cleanup(&cipher_ctx);
    5125             : }
    5126             : /* }}} */
    5127             : 
    5128             : /* {{{ proto string openssl_decrypt(string data, string method, string password [, long options=0 [, string $iv = '']])
    5129             :    Takes raw or base64 encoded string and dectupt it using given method and key */
    5130          14 : PHP_FUNCTION(openssl_decrypt)
    5131             : {
    5132          14 :         zend_long options = 0;
    5133          14 :         char *data, *method, *password, *iv = "";
    5134          14 :         size_t data_len, method_len, password_len, iv_len = 0;
    5135             :         const EVP_CIPHER *cipher_type;
    5136             :         EVP_CIPHER_CTX cipher_ctx;
    5137             :         int i, outlen, keylen;
    5138             :         zend_string *outbuf;
    5139             :         unsigned char *key;
    5140          14 :         zend_string *base64_str = NULL;
    5141             :         zend_bool free_iv;
    5142             : 
    5143          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) {
    5144           3 :                 return;
    5145             :         }
    5146             : 
    5147          11 :         if (!method_len) {
    5148           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5149           0 :                 RETURN_FALSE;
    5150             :         }
    5151             : 
    5152          11 :         cipher_type = EVP_get_cipherbyname(method);
    5153          11 :         if (!cipher_type) {
    5154           4 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5155           4 :                 RETURN_FALSE;
    5156             :         }
    5157             : 
    5158           7 :         if (!(options & OPENSSL_RAW_DATA)) {
    5159           5 :                 base64_str = php_base64_decode((unsigned char*)data, data_len);
    5160           5 :                 if (!base64_str) {
    5161           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to base64 decode the input");
    5162           1 :                         RETURN_FALSE;
    5163             :                 }
    5164           4 :                 data_len = base64_str->len;
    5165           4 :                 data = base64_str->val;
    5166             :         }
    5167             : 
    5168           6 :         keylen = EVP_CIPHER_key_length(cipher_type);
    5169           6 :         if (keylen > password_len) {
    5170           6 :                 key = emalloc(keylen);
    5171           6 :                 memset(key, 0, keylen);
    5172           6 :                 memcpy(key, password, password_len);
    5173             :         } else {
    5174           0 :                 key = (unsigned char*)password;
    5175             :         }
    5176             : 
    5177           6 :         free_iv = php_openssl_validate_iv(&iv, (int *)&iv_len, EVP_CIPHER_iv_length(cipher_type) TSRMLS_CC);
    5178             : 
    5179           6 :         outlen = data_len + EVP_CIPHER_block_size(cipher_type);
    5180          12 :         outbuf = zend_string_alloc(outlen, 0);
    5181             : 
    5182           6 :         EVP_DecryptInit(&cipher_ctx, cipher_type, NULL, NULL);
    5183           6 :         if (password_len > keylen) {
    5184           0 :                 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
    5185             :         }
    5186           6 :         EVP_DecryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
    5187           6 :         if (options & OPENSSL_ZERO_PADDING) {
    5188           1 :                 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
    5189             :         }
    5190           6 :         EVP_DecryptUpdate(&cipher_ctx, (unsigned char*)outbuf->val, &i, (unsigned char *)data, data_len);
    5191           6 :         outlen = i;
    5192           6 :         if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf->val + i, &i)) {
    5193           4 :                 outlen += i;
    5194           4 :                 outbuf->val[outlen] = '\0';
    5195           4 :                 outbuf->len = outlen;
    5196           4 :                 RETVAL_STR(outbuf);
    5197             :         } else {
    5198             :                 zend_string_release(outbuf);
    5199           2 :                 RETVAL_FALSE;
    5200             :         }
    5201           6 :         if (key != (unsigned char*)password) {
    5202           6 :                 efree(key);
    5203             :         }
    5204           6 :         if (free_iv) {
    5205           2 :                 efree(iv);
    5206             :         }
    5207           6 :         if (base64_str) {
    5208             :                 zend_string_release(base64_str);
    5209             :         }
    5210           6 :         EVP_CIPHER_CTX_cleanup(&cipher_ctx);
    5211             : }
    5212             : /* }}} */
    5213             : 
    5214             : /* {{{ proto int openssl_cipher_iv_length(string $method) */
    5215           2 : PHP_FUNCTION(openssl_cipher_iv_length)
    5216             : {
    5217             :         char *method;
    5218             :         size_t method_len;
    5219             :         const EVP_CIPHER *cipher_type;
    5220             : 
    5221           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len) == FAILURE) {
    5222           0 :                 return;
    5223             :         }
    5224             : 
    5225           2 :         if (!method_len) {
    5226           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5227           0 :                 RETURN_FALSE;
    5228             :         }
    5229             : 
    5230           2 :         cipher_type = EVP_get_cipherbyname(method);
    5231           2 :         if (!cipher_type) {
    5232           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
    5233           0 :                 RETURN_FALSE;
    5234             :         }
    5235             : 
    5236           2 :         RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
    5237             : }
    5238             : /* }}} */
    5239             : 
    5240             : 
    5241             : /* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
    5242             :    Computes shared secret for public value of remote DH key and local DH key */
    5243           0 : PHP_FUNCTION(openssl_dh_compute_key)
    5244             : {
    5245             :         zval *key;
    5246             :         char *pub_str;
    5247             :         size_t pub_len;
    5248             :         EVP_PKEY *pkey;
    5249             :         BIGNUM *pub;
    5250             :         zend_string *data;
    5251             :         int len;
    5252             : 
    5253           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, &pub_len, &key) == FAILURE) {
    5254           0 :                 return;
    5255             :         }
    5256           0 :         ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, key, -1, "OpenSSL key", le_key);
    5257           0 :         if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
    5258           0 :                 RETURN_FALSE;
    5259             :         }
    5260             : 
    5261           0 :         pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
    5262             : 
    5263           0 :         data = zend_string_alloc(DH_size(pkey->pkey.dh), 0);
    5264           0 :         len = DH_compute_key((unsigned char*)data->val, pub, pkey->pkey.dh);
    5265             : 
    5266           0 :         if (len >= 0) {
    5267           0 :                 data->len = len;
    5268           0 :                 data->val[len] = 0;
    5269           0 :                 RETVAL_STR(data);
    5270             :         } else {
    5271             :                 zend_string_release(data);
    5272           0 :                 RETVAL_FALSE;
    5273             :         }
    5274             : 
    5275           0 :         BN_free(pub);
    5276             : }
    5277             : /* }}} */
    5278             : 
    5279             : /* {{{ proto string openssl_random_pseudo_bytes(integer length [, &bool returned_strong_result])
    5280             :    Returns a string of the length specified filled with random pseudo bytes */
    5281          10 : PHP_FUNCTION(openssl_random_pseudo_bytes)
    5282             : {
    5283             :         zend_long buffer_length;
    5284          10 :         zend_string *buffer = NULL;
    5285          10 :         zval *zstrong_result_returned = NULL;
    5286          10 :         int strong_result = 0;
    5287             : 
    5288          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) {
    5289           0 :                 return;
    5290             :         }
    5291             : 
    5292          10 :         if (buffer_length <= 0) {
    5293           1 :                 RETURN_FALSE;
    5294             :         }
    5295             : 
    5296           9 :         if (zstrong_result_returned) {
    5297           9 :                 zval_dtor(zstrong_result_returned);
    5298           9 :                 ZVAL_BOOL(zstrong_result_returned, 0);
    5299             :         }
    5300             : 
    5301          18 :         buffer = zend_string_alloc(buffer_length, 0);
    5302             : 
    5303             : #ifdef PHP_WIN32
    5304             :         strong_result = 1;
    5305             :         /* random/urandom equivalent on Windows */
    5306             :         if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){
    5307             :                 zend_string_release(buffer);
    5308             :                 if (zstrong_result_returned) {
    5309             :                         ZVAL_BOOL(zstrong_result_returned, 0);
    5310             :                 }
    5311             :                 RETURN_FALSE;
    5312             :         }
    5313             : #else
    5314           9 :         if ((strong_result = RAND_pseudo_bytes((unsigned char*)buffer->val, buffer_length)) < 0) {
    5315             :                 zend_string_release(buffer);
    5316           0 :                 if (zstrong_result_returned) {
    5317           0 :                         ZVAL_BOOL(zstrong_result_returned, 0);
    5318             :                 }
    5319           0 :                 RETURN_FALSE;
    5320             :         }
    5321             : #endif
    5322             : 
    5323           9 :         buffer->val[buffer_length] = 0;
    5324           9 :         RETVAL_STR(buffer);
    5325             : 
    5326           9 :         if (zstrong_result_returned) {
    5327           9 :                 ZVAL_BOOL(zstrong_result_returned, strong_result);
    5328             :         }
    5329             : }
    5330             : /* }}} */
    5331             : 
    5332             : /*
    5333             :  * Local variables:
    5334             :  * tab-width: 8
    5335             :  * c-basic-offset: 8
    5336             :  * End:
    5337             :  * vim600: sw=4 ts=4 fdm=marker
    5338             :  * vim<600: sw=4 ts=4
    5339             :  */
    5340             : 

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:35 +0000 (43 hours ago)

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