root/ext/openssl/openssl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. php_pkey_free
  3. php_x509_free
  4. php_csr_free
  5. php_openssl_open_base_dir_chk
  6. php_openssl_get_stream_from_ssl_handle
  7. php_openssl_get_ssl_stream_data_index
  8. STACK_OF
  9. add_assoc_asn1_string
  10. asn1_time_to_time_t
  11. php_openssl_config_check_syntax
  12. add_oid_section
  13. php_openssl_parse_config
  14. php_openssl_dispose_config
  15. php_openssl_load_rand_file
  16. php_openssl_write_rand_file
  17. php_openssl_get_evp_md_from_algo
  18. php_openssl_get_evp_cipher_from_algo
  19. PHP_INI_BEGIN
  20. PHP_MINFO_FUNCTION
  21. PHP_MSHUTDOWN_FUNCTION
  22. PHP_FUNCTION
  23. php_openssl_x509_from_zval
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. openssl_spki_cleanup
  30. PHP_FUNCTION
  31. php_openssl_x509_fingerprint
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. openssl_x509v3_subjectAltName
  35. PHP_FUNCTION
  36. STACK_OF
  37. check_cert
  38. PHP_FUNCTION
  39. setup_verify
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. php_sk_X509_free
  43. STACK_OF
  44. PHP_FUNCTION
  45. PHP_FUNCTION
  46. PHP_FUNCTION
  47. php_openssl_make_REQ
  48. php_openssl_csr_from_zval
  49. PHP_FUNCTION
  50. PHP_FUNCTION
  51. PHP_FUNCTION
  52. PHP_FUNCTION
  53. PHP_FUNCTION
  54. PHP_FUNCTION
  55. php_openssl_evp_from_zval
  56. php_openssl_generate_private_key
  57. php_openssl_is_private_key
  58. PHP_FUNCTION
  59. PHP_FUNCTION
  60. PHP_FUNCTION
  61. PHP_FUNCTION
  62. PHP_FUNCTION
  63. PHP_FUNCTION
  64. PHP_FUNCTION
  65. PHP_FUNCTION
  66. PHP_FUNCTION
  67. PHP_FUNCTION
  68. PHP_FUNCTION
  69. PHP_FUNCTION
  70. PHP_FUNCTION
  71. PHP_FUNCTION
  72. PHP_FUNCTION
  73. PHP_FUNCTION
  74. PHP_FUNCTION
  75. PHP_FUNCTION
  76. PHP_FUNCTION
  77. PHP_FUNCTION
  78. PHP_FUNCTION
  79. openssl_add_method_or_alias
  80. openssl_add_method
  81. PHP_FUNCTION
  82. PHP_FUNCTION
  83. PHP_FUNCTION
  84. php_openssl_validate_iv
  85. PHP_FUNCTION
  86. PHP_FUNCTION
  87. PHP_FUNCTION
  88. PHP_FUNCTION
  89. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */