Annotation of embedaddon/php/ext/openssl/openssl.c, revision 1.1.1.5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>