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-21 Instrumented lines: 2135
Code covered: 64.5 % Executed lines: 1377
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:04 +0000 (3 days ago)

Copyright © 2005-2009 The PHP Group