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: 1604 2396 66.9 %
Date: 2014-07-21 Functions: 72 91 79.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:14 +0000 (6 days ago)

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