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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:09 +0000 (22 days ago)

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