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: 1488 2255 66.0 %
Date: 2014-07-27 Functions: 65 82 79.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 27 Jul 2014 12:58:32 +0000 (2 days ago)

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