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

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

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