root/ext/openssl/openssl.c

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

DEFINITIONS

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

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