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

LTP GCOV extension - code coverage report
Current view: directory - openssl - openssl.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 2282
Code covered: 63.5 % Executed lines: 1450
Legend: not executed executed

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