diff --git a/php/ext/openssl/CREDITS b/php/ext/openssl/CREDITS new file mode 100644 index 00000000..b685ce13 --- /dev/null +++ b/php/ext/openssl/CREDITS @@ -0,0 +1,2 @@ +OpenSSL +Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar diff --git a/php/ext/openssl/README b/php/ext/openssl/README new file mode 100644 index 00000000..20a38332 --- /dev/null +++ b/php/ext/openssl/README @@ -0,0 +1,322 @@ +OpenSSL extension for PHP + +$Id$ + +The functions implemented so far make it possible to seal and open data, and +also create and verify signatures. + +NEW: support for S/MIME encrypt/decrypt/sign/verify, as well as more +flexibility for specifying certificates/keys. + +To enable the extension, configure PHP with --with-openssl. + +Specifying keys/certificates +---------------------------- + +Most of the functions require a key or a certificate as a parameter; to make +things easy for you to use openssl, this extension allows you +to specify certificates in the following way: + +1. As an X.509 resource returned from openssl_x509_read +2. As a string in the format file://filename, where filename is the path to the + certificate file (it will be opened and read automatically) +3. As a string containing the data from the certificate file + +Similarly, you can use the following methods of specifying a public key: + +1. As a key resource returned from openssl_get_publickey +2. An X509 resource - public key only +3. As a string in the format file://filename +4. As a string containing the data from the key file + +Additionally, for a private key, when the openssl extension function does not +allow you to enter the passphrase as a parameter you may use the syntax +array($key, "passphrase") where $key can be a key specified using one of the +methods listed above. + +Certificate Verification +------------------------ +When calling a function that will verify a signature/certificate, the cainfo +parameter is an array containing file and directory names that specifiy the +locations of trusted CA files. If a directory is specified, then it must be a +correctly hashed directory. + +Misc: +----- + +mixed openssl_error_string() + +returns the message from the last error that the OpenSSL library encountered +and moves it's internal error pointer to the next message. If there are no +more error messages, returns false. + +General Key/Cert Functions: +--------------------------- + +resource openssl_get_privatekey(mixed key [, string passphrase]) + +Parses the key data and returns a key resource identifier. If the key is +encrypted a passphrase is needed. This can be supplied as second argument. + + +resource openssl_get_publickey(mixed cert) + +Extracts the public key from the given certificate or public key and returns +a key resource identifier. + + +void openssl_free_key(resource key) + +Frees the resource given by the key resource identifier. +Note that this function does not accept the extended key specification +syntax mentioned above, as it doesn't make sense in this case! + +array openssl_x509_parse(mixed x509[, bool shortnames=true]) + +Parses the certificate data and returns an array containing information +about the certificate, it's intended purposes, subject, issuer, validity +etc. etc. If shortnames is true (the default) then the fields will be +keyed by the shortname forms eg: CN as opposed to commonName (shortnames += false). + + +bool openssl_x509_checkpurpose(mixed x509cert, int purpose, + array cainfo[, string untrustedfile]) + +Verifies if the certificate can be used for a specific purpose. +Purpose can be one of the following values: + X509_PURPOSE_SSL_CLIENT + X509_PURPOSE_SSL_SERVER + X509_PURPOSE_NS_SSL_SERVER + X509_PURPOSE_SMIME_SIGN + X509_PURPOSE_SMIME_ENCRYPT + X509_PURPOSE_CRL_SIGN + X509_PURPOSE_ANY + +cainfo is an array of CA information (as mentioned above). +untrusted file specifies a file containing a bunch of certs that +are not trusted but may be useful in validating the certificate. + + +resource openssl_read_x509(mixed cert) + +Parses the cert and returns a resource that can be used with the +other openssl functions + + +void openssl_free_x509(resource x509) + +Frees the resource given by the x509 resource identifier. +Note that this function does not accept the extended cert specification +syntax mentioned above, as it doesn't make sense in this case! + + +PKCS7 (S/MIME) Sign/Verify/Encrypt/Decrypt Functions: +----------------------------------------------------- + +These functions allow you to manipulate S/MIME messages! + +They are based on apps/smime.c from the openssl dist, so for information, +see the documentation for openssl. + +You may pass in some flags that affect how these functions work using +and array containing the following values: +"detached", "nodetached", "text", "nointern", "noverify", "nochain", +"nocerts", "noattr", "binary", "nosigs". +The options correspond to the options of the same name for the +"openssl smime" command (smime(1)). + + +bool openssl_pkcs7_verify(string filename, array flags[, string signerscerts][, + array cainfo]) + +Verifies that the signature on the MIME message contained in the file +named by filename is valid. If signerscerts is passed in, it holds the +name of a file into which the certificates of those that signed the +message will be stored. +cainfo and flags are CA information and flag information as described +above. + + +bool openssl_pkcs7_encrypt(string infile, string outfile, array recipcerts, + array headers[, array flags]) + +Encrypts the MIME message contained in the file named by infile using +the certificates held in recipcerts. The result is place in the file +named outfile. +recipcerts is an array of certificate identifiers representing the certs +of the intended recipients of the message. +headers is an array of headers to prepend to the message: they will +not be included in the encoded section. +flags is flag information as described above. +Hint: you will want to put "To", "From", and "Subject" headers in headers. +Headers can be either an assoc array keyed by header named, or can be +and indexed array containing a single header line per value. +The message will be encoded using a RC2-40 bit cipher. +TODO: allow user to specify cipher. + +bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed + signkey, array headers[, array flags][, string extracertsfilename]) + +Signs the MIME message contained in the file named by infile using the +certificate and key pair identified by signcert/signkey. +Signkey must be the private key corresponding to signcert. +The result is placed in the file named by outfile. +Headers and flags have the same effects as mentioned above. +extracertsfilename names a file containing a bunch of additional certificates +to include in the signature, in order to aid the recipient in verifying the +message. + + +bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed + recipcert, mixed recipkey) + +Decrypts the MIME message contained in the file named by infilename +using the certificate and private key pair recipcert/recipkey. +The descrypted result is placed in outfilename. +TODO: add flags parameter, if needed? + + +EVP Sign/Verify/Encrypt/Decrypt Functions: +------------------------------------------ + +bool openssl_sign(string data, &string signature, mixed key) + +Uses key to create signature for data, returns true on success and false +on failure. signature is passed by reference and contains the newly created +signature on success. + + +int openssl_verify(string data, string signature, mixed key) + +Uses key to verify that the signature is correct for the given data. +Returns 1 if correct, 0 if incorrect, and -1 on error. + + +int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys) + +Encrypts data using pubkeys, so that only owners of the respective private +keys and ekeys can decrypt and read the data. Returns the length of the +sealed data on success, else false. On success, sealdata and ekeys hold +the sealed data and envelope keys. + + +bool openssl_open(string data, &string opendata, string ekey, int privkey) + +Opens (decrypts) sealed data using a private key and the corresponding +envelope key. Returns true on success and false on failure. On success, +opendata will hold the descypted data. + + +See below for more details on usage. Also feel free to mail me at +venaas@php.net if you have questions. The OpenSSL documentation, +especially the EVP documentation at +http://www.openssl.org/docs/crypto/evp.html, might also be of help. + + +HOWTO: + +To do anything you need a private key and a certificate containing the +corresponding public key. This is similar to what you have using say an +Apache webserver with OpenSSL. For testing you could try keys that come +with OpenSSL, that's what the sample scripts below do. You can also get +keys from some CA, or you can create them yourself. + + +Creating private key + +To generate an unprotected 1024 bit RSA private key you can do + + openssl genrsa -out /tmp/test.key 1024 + +Private keys should be protected by a passphrase though. + + +Creating a self signed certificate + +To generate a self signed certificate from the key that is valid for +365 days, do + + openssl req -new -key /tmp/test.key -out /tmp/test.crt -days 365 -x509 + + +Example usage + +These examples use keys that come with OpenSSL, you should perhaps test with +those first. + + +Seal and open + + + + +Sign and verify + + diff --git a/php/ext/openssl/config.w32 b/php/ext/openssl/config.w32 new file mode 100644 index 00000000..ade17d40 --- /dev/null +++ b/php/ext/openssl/config.w32 @@ -0,0 +1,26 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("openssl", "OpenSSL support", "no,shared"); + +if (PHP_OPENSSL != "no") { + var ret = SETUP_OPENSSL("openssl", PHP_OPENSSL); + + if (ret > 0) { + EXTENSION("openssl", "openssl.c xp_ssl.c"); + AC_DEFINE("HAVE_OPENSSL_EXT", PHP_OPENSSL_SHARED ? 0 : 1, "Have openssl"); + AC_DEFINE("HAVE_OPENSSL", 1); + + switch (ret) { + /* Openssl 1.0.x and lower */ + case 1: + AC_DEFINE("HAVE_DSA_DEFAULT_METHOD", 1); + break; + /* Openssl 1.1.x */ + case 2: + break; + } + } +} + + diff --git a/php/ext/openssl/config0.m4 b/php/ext/openssl/config0.m4 new file mode 100644 index 00000000..a7bbf05f --- /dev/null +++ b/php/ext/openssl/config0.m4 @@ -0,0 +1,33 @@ +dnl +dnl $Id$ +dnl + +PHP_ARG_WITH(openssl, for OpenSSL support, +[ --with-openssl[=DIR] Include OpenSSL support (requires OpenSSL >= 1.0.1)]) + +PHP_ARG_WITH(kerberos, for Kerberos support, +[ --with-kerberos[=DIR] OPENSSL: Include Kerberos support], no, no) + +PHP_ARG_WITH(system-ciphers, whether to use system default cipher list instead of hardcoded value, +[ --with-system-ciphers OPENSSL: Use system default cipher list instead of hardcoded value], no, no) + +if test "$PHP_OPENSSL" != "no"; then + PHP_NEW_EXTENSION(openssl, openssl.c xp_ssl.c, $ext_shared) + PHP_SUBST(OPENSSL_SHARED_LIBADD) + + if test "$PHP_KERBEROS" != "no"; then + PHP_SETUP_KERBEROS(OPENSSL_SHARED_LIBADD) + fi + + AC_CHECK_FUNCS([RAND_egd]) + + PHP_SETUP_OPENSSL(OPENSSL_SHARED_LIBADD, + [ + AC_DEFINE(HAVE_OPENSSL_EXT,1,[ ]) + ], [ + AC_MSG_ERROR([OpenSSL check failed. Please check config.log for more information.]) + ]) + if test "$PHP_SYSTEM_CIPHERS" != "no"; then + AC_DEFINE(USE_OPENSSL_SYSTEM_CIPHERS,1,[ Use system default cipher list instead of hardcoded value ]) + fi +fi diff --git a/php/ext/openssl/openssl.c b/php/ext/openssl/openssl.c new file mode 100644 index 00000000..7c7a99e9 --- /dev/null +++ b/php/ext/openssl/openssl.c @@ -0,0 +1,6920 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2018 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2018 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Stig Venaas | + | Wez Furlong | + | Sascha Kettler | + | Pierre-Alain Joye | + | Marc Delling (PKCS12 functions) | + | Jakub Zelenka | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_openssl.h" + +/* PHP Includes */ +#include "ext/standard/file.h" +#include "ext/standard/info.h" +#include "ext/standard/php_fopen_wrappers.h" +#include "ext/standard/md5.h" +#include "ext/standard/base64.h" +#ifdef PHP_WIN32 +# include "win32/winutil.h" +#endif + +/* OpenSSL includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Common */ +#include + +#if (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900) +#define timezone _timezone /* timezone is called _timezone in LibC */ +#endif + +#define MIN_KEY_LENGTH 384 + +#define OPENSSL_ALGO_SHA1 1 +#define OPENSSL_ALGO_MD5 2 +#define OPENSSL_ALGO_MD4 3 +#ifdef HAVE_OPENSSL_MD2_H +#define OPENSSL_ALGO_MD2 4 +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) +#define OPENSSL_ALGO_DSS1 5 +#endif +#define OPENSSL_ALGO_SHA224 6 +#define OPENSSL_ALGO_SHA256 7 +#define OPENSSL_ALGO_SHA384 8 +#define OPENSSL_ALGO_SHA512 9 +#define OPENSSL_ALGO_RMD160 10 +#define OPENSSL_ALGO_SM3 11 +#define DEBUG_SMIME 0 + +#if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC) +#define HAVE_EVP_PKEY_EC 1 +#endif + +ZEND_DECLARE_MODULE_GLOBALS(openssl) + +/* FIXME: Use the openssl constants instead of + * enum. It is now impossible to match real values + * against php constants. Also sorry to break the + * enum principles here, BC... + */ +enum php_openssl_key_type { + OPENSSL_KEYTYPE_RSA, + OPENSSL_KEYTYPE_DSA, + OPENSSL_KEYTYPE_DH, + OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA, +#ifdef HAVE_EVP_PKEY_EC + OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1 +#endif +}; + +enum php_openssl_cipher_type { + PHP_OPENSSL_CIPHER_RC2_40, + PHP_OPENSSL_CIPHER_RC2_128, + PHP_OPENSSL_CIPHER_RC2_64, + PHP_OPENSSL_CIPHER_DES, + PHP_OPENSSL_CIPHER_3DES, + PHP_OPENSSL_CIPHER_AES_128_CBC, + PHP_OPENSSL_CIPHER_AES_192_CBC, + PHP_OPENSSL_CIPHER_AES_256_CBC, + PHP_OPENSSL_CIPHER_SMS4_CBC, + + PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_SMS4_CBC +}; + +PHP_FUNCTION(openssl_get_md_methods); +PHP_FUNCTION(openssl_get_cipher_methods); +#ifdef HAVE_EVP_PKEY_EC +PHP_FUNCTION(openssl_get_curve_names); +#endif + +PHP_FUNCTION(openssl_digest); +PHP_FUNCTION(openssl_encrypt); +PHP_FUNCTION(openssl_decrypt); +PHP_FUNCTION(openssl_cipher_iv_length); + +PHP_FUNCTION(openssl_dh_compute_key); +PHP_FUNCTION(openssl_random_pseudo_bytes); + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(0, outfilename) + ZEND_ARG_INFO(0, notext) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(1, out) + ZEND_ARG_INFO(0, notext) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_fingerprint, 0, 0, 1) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, raw_output) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0) + ZEND_ARG_INFO(0, cert) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_parse, 0) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(0, shortname) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 3) + ZEND_ARG_INFO(0, x509cert) + ZEND_ARG_INFO(0, purpose) + ZEND_ARG_INFO(0, cainfo) /* array */ + ZEND_ARG_INFO(0, untrustedfile) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0) + ZEND_ARG_INFO(0, cert) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0) + ZEND_ARG_INFO(0, x509) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(0, filename) + ZEND_ARG_INFO(0, priv_key) + ZEND_ARG_INFO(0, pass) + ZEND_ARG_INFO(0, args) /* array */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_export, 0) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(1, out) + ZEND_ARG_INFO(0, priv_key) + ZEND_ARG_INFO(0, pass) + ZEND_ARG_INFO(0, args) /* array */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0) + ZEND_ARG_INFO(0, PKCS12) + ZEND_ARG_INFO(1, certs) /* array */ + ZEND_ARG_INFO(0, pass) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2) + ZEND_ARG_INFO(0, csr) + ZEND_ARG_INFO(0, outfilename) + ZEND_ARG_INFO(0, notext) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2) + ZEND_ARG_INFO(0, csr) + ZEND_ARG_INFO(1, out) + ZEND_ARG_INFO(0, notext) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4) + ZEND_ARG_INFO(0, csr) + ZEND_ARG_INFO(0, x509) + ZEND_ARG_INFO(0, priv_key) + ZEND_ARG_INFO(0, days) + ZEND_ARG_INFO(0, config_args) /* array */ + ZEND_ARG_INFO(0, serial) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2) + ZEND_ARG_INFO(0, dn) /* array */ + ZEND_ARG_INFO(1, privkey) + ZEND_ARG_INFO(0, configargs) + ZEND_ARG_INFO(0, extraattribs) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_subject, 0) + ZEND_ARG_INFO(0, csr) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_public_key, 0) + ZEND_ARG_INFO(0, csr) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0) + ZEND_ARG_INFO(0, configargs) /* array */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, outfilename) + ZEND_ARG_INFO(0, passphrase) + ZEND_ARG_INFO(0, config_args) /* array */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(1, out) + ZEND_ARG_INFO(0, passphrase) + ZEND_ARG_INFO(0, config_args) /* array */ +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0) + ZEND_ARG_INFO(0, cert) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, passphrase) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pbkdf2, 0, 0, 4) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, salt) + ZEND_ARG_INFO(0, key_length) + ZEND_ARG_INFO(0, iterations) + ZEND_ARG_INFO(0, digest_algorithm) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2) + ZEND_ARG_INFO(0, filename) + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, signerscerts) + ZEND_ARG_INFO(0, cainfo) /* array */ + ZEND_ARG_INFO(0, extracerts) + ZEND_ARG_INFO(0, content) + ZEND_ARG_INFO(0, pk7) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4) + ZEND_ARG_INFO(0, infile) + ZEND_ARG_INFO(0, outfile) + ZEND_ARG_INFO(0, recipcerts) + ZEND_ARG_INFO(0, headers) /* array */ + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, cipher) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5) + ZEND_ARG_INFO(0, infile) + ZEND_ARG_INFO(0, outfile) + ZEND_ARG_INFO(0, signcert) + ZEND_ARG_INFO(0, signkey) + ZEND_ARG_INFO(0, headers) /* array */ + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, extracertsfilename) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3) + ZEND_ARG_INFO(0, infilename) + ZEND_ARG_INFO(0, outfilename) + ZEND_ARG_INFO(0, recipcert) + ZEND_ARG_INFO(0, recipkey) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_read, 0, 0, 2) + ZEND_ARG_INFO(0, infilename) + ZEND_ARG_INFO(1, certs) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, crypted) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, padding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, crypted) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, padding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, crypted) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, padding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, crypted) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, padding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, signature) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, method) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, signature) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, method) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_seal, 0, 0, 4) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, sealdata) + ZEND_ARG_INFO(1, ekeys) /* array */ + ZEND_ARG_INFO(0, pubkeys) /* array */ + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(1, iv) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_open, 0, 0, 4) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(1, opendata) + ZEND_ARG_INFO(0, ekey) + ZEND_ARG_INFO(0, privkey) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, iv) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0) + ZEND_ARG_INFO(0, aliases) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0) + ZEND_ARG_INFO(0, aliases) +ZEND_END_ARG_INFO() + +#ifdef HAVE_EVP_PKEY_EC +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_curve_names, 0, 0, 0) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, raw_output) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, options) + ZEND_ARG_INFO(0, iv) + ZEND_ARG_INFO(1, tag) + ZEND_ARG_INFO(0, aad) + ZEND_ARG_INFO(0, tag_length) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, method) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, options) + ZEND_ARG_INFO(0, iv) + ZEND_ARG_INFO(0, tag) + ZEND_ARG_INFO(0, aad) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0) + ZEND_ARG_INFO(0, method) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0) + ZEND_ARG_INFO(0, pub_key) + ZEND_ARG_INFO(0, dh_key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1) + ZEND_ARG_INFO(0, length) + ZEND_ARG_INFO(1, result_is_strong) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 2) + ZEND_ARG_INFO(0, privkey) + ZEND_ARG_INFO(0, challenge) + ZEND_ARG_INFO(0, algo) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_get_cert_locations, 0) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ openssl_functions[] + */ +const zend_function_entry openssl_functions[] = { + PHP_FE(openssl_get_cert_locations, arginfo_openssl_get_cert_locations) + +/* spki functions */ + PHP_FE(openssl_spki_new, arginfo_openssl_spki_new) + PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify) + PHP_FE(openssl_spki_export, arginfo_openssl_spki_export) + PHP_FE(openssl_spki_export_challenge, arginfo_openssl_spki_export_challenge) + +/* public/private key functions */ + PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free) + PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new) + PHP_FE(openssl_pkey_export, arginfo_openssl_pkey_export) + PHP_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file) + PHP_FE(openssl_pkey_get_private, arginfo_openssl_pkey_get_private) + PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public) + PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details) + + PHP_FALIAS(openssl_free_key, openssl_pkey_free, arginfo_openssl_pkey_free) + PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, arginfo_openssl_pkey_get_private) + PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, arginfo_openssl_pkey_get_public) + +/* x.509 cert funcs */ + PHP_FE(openssl_x509_read, arginfo_openssl_x509_read) + PHP_FE(openssl_x509_free, arginfo_openssl_x509_free) + PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse) + PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose) + PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key) + PHP_FE(openssl_x509_export, arginfo_openssl_x509_export) + PHP_FE(openssl_x509_fingerprint, arginfo_openssl_x509_fingerprint) + PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file) + +/* PKCS12 funcs */ + PHP_FE(openssl_pkcs12_export, arginfo_openssl_pkcs12_export) + PHP_FE(openssl_pkcs12_export_to_file, arginfo_openssl_pkcs12_export_to_file) + PHP_FE(openssl_pkcs12_read, arginfo_openssl_pkcs12_read) + +/* CSR funcs */ + PHP_FE(openssl_csr_new, arginfo_openssl_csr_new) + PHP_FE(openssl_csr_export, arginfo_openssl_csr_export) + PHP_FE(openssl_csr_export_to_file, arginfo_openssl_csr_export_to_file) + PHP_FE(openssl_csr_sign, arginfo_openssl_csr_sign) + PHP_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject) + PHP_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key) + + PHP_FE(openssl_digest, arginfo_openssl_digest) + PHP_FE(openssl_encrypt, arginfo_openssl_encrypt) + PHP_FE(openssl_decrypt, arginfo_openssl_decrypt) + PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length) + PHP_FE(openssl_sign, arginfo_openssl_sign) + PHP_FE(openssl_verify, arginfo_openssl_verify) + PHP_FE(openssl_seal, arginfo_openssl_seal) + PHP_FE(openssl_open, arginfo_openssl_open) + + PHP_FE(openssl_pbkdf2, arginfo_openssl_pbkdf2) + +/* for S/MIME handling */ + PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify) + PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt) + PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign) + PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt) + PHP_FE(openssl_pkcs7_read, arginfo_openssl_pkcs7_read) + + PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt) + PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt) + PHP_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt) + PHP_FE(openssl_public_decrypt, arginfo_openssl_public_decrypt) + + PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods) + PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods) +#ifdef HAVE_EVP_PKEY_EC + PHP_FE(openssl_get_curve_names, arginfo_openssl_get_curve_names) +#endif + + PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key) + + PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes) + PHP_FE(openssl_error_string, arginfo_openssl_error_string) + PHP_FE_END +}; +/* }}} */ + +/* {{{ openssl_module_entry + */ +zend_module_entry openssl_module_entry = { + STANDARD_MODULE_HEADER, + "openssl", + openssl_functions, + PHP_MINIT(openssl), + PHP_MSHUTDOWN(openssl), + NULL, + NULL, + PHP_MINFO(openssl), + PHP_OPENSSL_VERSION, + PHP_MODULE_GLOBALS(openssl), + PHP_GINIT(openssl), + PHP_GSHUTDOWN(openssl), + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; +/* }}} */ + +#ifdef COMPILE_DL_OPENSSL +ZEND_GET_MODULE(openssl) +#endif + +/* {{{ OpenSSL compatibility functions and macros */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) +#define EVP_PKEY_get0_RSA(_pkey) _pkey->pkey.rsa +#define EVP_PKEY_get0_DH(_pkey) _pkey->pkey.dh +#define EVP_PKEY_get0_DSA(_pkey) _pkey->pkey.dsa +#define EVP_PKEY_get0_EC_KEY(_pkey) _pkey->pkey.ec + +static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) +{ + r->n = n; + r->e = e; + r->d = d; + + return 1; +} + +static int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) +{ + r->p = p; + r->q = q; + + return 1; +} + +static int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) +{ + r->dmp1 = dmp1; + r->dmq1 = dmq1; + r->iqmp = iqmp; + + return 1; +} + +static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + *n = r->n; + *e = r->e; + *d = r->d; +} + +static void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) +{ + *p = r->p; + *q = r->q; +} + +static void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp) +{ + *dmp1 = r->dmp1; + *dmq1 = r->dmq1; + *iqmp = r->iqmp; +} + +static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + *p = dh->p; + *q = dh->q; + *g = dh->g; +} + +static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + dh->p = p; + dh->q = q; + dh->g = g; + + return 1; +} + +static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + *pub_key = dh->pub_key; + *priv_key = dh->priv_key; +} + +static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + dh->pub_key = pub_key; + dh->priv_key = priv_key; + + return 1; +} + +static void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + *p = d->p; + *q = d->q; + *g = d->g; +} + +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + d->p = p; + d->q = q; + d->g = g; + + return 1; +} + +static void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + *pub_key = d->pub_key; + *priv_key = d->priv_key; +} + +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) +{ + d->pub_key = pub_key; + d->priv_key = priv_key; + + return 1; +} + +static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) +{ + return M_ASN1_STRING_data(asn1); +} + +#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined (LIBRESSL_VERSION_NUMBER) + +static int X509_get_signature_nid(const X509 *x) +{ + return OBJ_obj2nid(x->sig_alg->algorithm); +} + +#endif + +#endif +/* }}} */ + +/* number conversion flags checks */ +#define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name) \ + do { \ + if (_cond) { \ + php_error_docref(NULL, E_WARNING, #_name" is too long"); \ + RETURN_FALSE; \ + } \ + } while(0) +/* check if size_t can be safely casted to int */ +#define PHP_OPENSSL_CHECK_SIZE_T_TO_INT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_INT_OVFL(_var), _name) +/* check if size_t can be safely casted to unsigned int */ +#define PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_UINT_OVFL(_var), _name) +/* check if long can be safely casted to int */ +#define PHP_OPENSSL_CHECK_LONG_TO_INT(_var, _name) \ + PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_LONG_EXCEEDS_INT(_var), _name) + +/* {{{ php_openssl_store_errors */ +void php_openssl_store_errors() +{ + struct php_openssl_errors *errors; + int error_code = ERR_get_error(); + + if (!error_code) { + return; + } + + if (!OPENSSL_G(errors)) { + OPENSSL_G(errors) = pecalloc(1, sizeof(struct php_openssl_errors), 1); + } + + errors = OPENSSL_G(errors); + + do { + errors->top = (errors->top + 1) % ERR_NUM_ERRORS; + if (errors->top == errors->bottom) { + errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS; + } + errors->buffer[errors->top] = error_code; + } while ((error_code = ERR_get_error())); + +} +/* }}} */ + +static int le_key; +static int le_x509; +static int le_csr; +static int ssl_stream_data_index; + +int php_openssl_get_x509_list_id(void) /* {{{ */ +{ + return le_x509; +} +/* }}} */ + +/* {{{ resource destructors */ +static void php_openssl_pkey_free(zend_resource *rsrc) +{ + EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr; + + assert(pkey != NULL); + + EVP_PKEY_free(pkey); +} + +static void php_openssl_x509_free(zend_resource *rsrc) +{ + X509 *x509 = (X509 *)rsrc->ptr; + X509_free(x509); +} + +static void php_openssl_csr_free(zend_resource *rsrc) +{ + X509_REQ * csr = (X509_REQ*)rsrc->ptr; + X509_REQ_free(csr); +} +/* }}} */ + +/* {{{ openssl open_basedir check */ +inline static int php_openssl_open_base_dir_chk(char *filename) +{ + if (php_check_open_basedir(filename)) { + return -1; + } + + return 0; +} +/* }}} */ + +php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl) +{ + return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index); +} + +int php_openssl_get_ssl_stream_data_index() +{ + return ssl_stream_data_index; +} + +/* openssl -> PHP "bridging" */ +/* true global; readonly after module startup */ +static char default_ssl_conf_filename[MAXPATHLEN]; + +struct php_x509_request { /* {{{ */ + LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */ + LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */ + const EVP_MD * md_alg; + const EVP_MD * digest; + char * section_name, + * config_filename, + * digest_name, + * extensions_section, + * request_extensions_section; + int priv_key_bits; + int priv_key_type; + + int priv_key_encrypt; + +#ifdef HAVE_EVP_PKEY_EC + int curve_name; +#endif + + EVP_PKEY * priv_key; + + const EVP_CIPHER * priv_key_encrypt_cipher; +}; +/* }}} */ + +static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval); +static EVP_PKEY * php_openssl_evp_from_zval( + zval * val, int public_key, char *passphrase, size_t passphrase_len, + int makeresource, zend_resource **resourceval); +static int php_openssl_is_private_key(EVP_PKEY* pkey); +static X509_STORE * php_openssl_setup_verify(zval * calist); +static STACK_OF(X509) * php_openssl_load_all_certs_from_file(char *certfile); +static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource ** resourceval); +static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req); + +static void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) /* {{{ */ +{ + zval *data; + zval subitem, tmp; + int i; + char *sname; + int nid; + X509_NAME_ENTRY * ne; + ASN1_STRING * str = NULL; + ASN1_OBJECT * obj; + + if (key != NULL) { + array_init(&subitem); + } else { + ZVAL_COPY_VALUE(&subitem, val); + } + + for (i = 0; i < X509_NAME_entry_count(name); i++) { + const unsigned char *to_add = NULL; + int to_add_len = 0; + unsigned char *to_add_buf = NULL; + + ne = X509_NAME_get_entry(name, i); + obj = X509_NAME_ENTRY_get_object(ne); + nid = OBJ_obj2nid(obj); + + if (shortname) { + sname = (char *) OBJ_nid2sn(nid); + } else { + sname = (char *) OBJ_nid2ln(nid); + } + + str = X509_NAME_ENTRY_get_data(ne); + if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) { + /* ASN1_STRING_to_UTF8(3): The converted data is copied into a newly allocated buffer */ + to_add_len = ASN1_STRING_to_UTF8(&to_add_buf, str); + to_add = to_add_buf; + } else { + /* ASN1_STRING_get0_data(3): Since this is an internal pointer it should not be freed or modified in any way */ + to_add = ASN1_STRING_get0_data(str); + to_add_len = ASN1_STRING_length(str); + } + + if (to_add_len != -1) { + if ((data = zend_hash_str_find(Z_ARRVAL(subitem), sname, strlen(sname))) != NULL) { + if (Z_TYPE_P(data) == IS_ARRAY) { + add_next_index_stringl(data, (const char *)to_add, to_add_len); + } else if (Z_TYPE_P(data) == IS_STRING) { + array_init(&tmp); + add_next_index_str(&tmp, zend_string_copy(Z_STR_P(data))); + add_next_index_stringl(&tmp, (const char *)to_add, to_add_len); + zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp); + } + } else { + /* it might be better to expand it and pass zval from ZVAL_STRING + * to zend_symtable_str_update so we do not silently drop const + * but we need a test to cover this part first */ + add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len); + } + } else { + php_openssl_store_errors(); + } + + if (to_add_buf != NULL) { + OPENSSL_free(to_add_buf); + } + } + + if (key != NULL) { + zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem); + } +} +/* }}} */ + +static void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */ +{ + add_assoc_stringl(val, key, (char *)str->data, str->length); +} +/* }}} */ + +static time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */ +{ +/* + This is how the time string is formatted: + + snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100, + ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec); +*/ + + time_t ret; + struct tm thetime; + char * strbuf; + char * thestr; + long gmadjust = 0; + size_t timestr_len; + + if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) { + php_error_docref(NULL, E_WARNING, "illegal ASN1 data type for timestamp"); + return (time_t)-1; + } + + timestr_len = (size_t)ASN1_STRING_length(timestr); + + if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) { + php_error_docref(NULL, E_WARNING, "illegal length in timestamp"); + return (time_t)-1; + } + + if (timestr_len < 13 && timestr_len != 11) { + php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data); + return (time_t)-1; + } + + if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && timestr_len < 15) { + php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data); + return (time_t)-1; + } + + strbuf = estrdup((const char *)ASN1_STRING_get0_data(timestr)); + + memset(&thetime, 0, sizeof(thetime)); + + /* we work backwards so that we can use atoi more easily */ + + thestr = strbuf + timestr_len - 3; + + if (timestr_len == 11) { + thetime.tm_sec = 0; + } else { + thetime.tm_sec = atoi(thestr); + *thestr = '\0'; + thestr -= 2; + } + thetime.tm_min = atoi(thestr); + *thestr = '\0'; + thestr -= 2; + thetime.tm_hour = atoi(thestr); + *thestr = '\0'; + thestr -= 2; + thetime.tm_mday = atoi(thestr); + *thestr = '\0'; + thestr -= 2; + thetime.tm_mon = atoi(thestr)-1; + + *thestr = '\0'; + if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) { + thestr -= 2; + thetime.tm_year = atoi(thestr); + + if (thetime.tm_year < 68) { + thetime.tm_year += 100; + } + } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) { + thestr -= 4; + thetime.tm_year = atoi(thestr) - 1900; + } + + + thetime.tm_isdst = -1; + ret = mktime(&thetime); + +#if HAVE_TM_GMTOFF + gmadjust = thetime.tm_gmtoff; +#else + /* + ** If correcting for daylight savings time, we set the adjustment to + ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and + ** set the adjustment to the main timezone + 3600 seconds. + */ + gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone); +#endif + ret += gmadjust; + + efree(strbuf); + + return ret; +} +/* }}} */ + +static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config) /* {{{ */ +{ + X509V3_CTX ctx; + + X509V3_set_ctx_test(&ctx); + X509V3_set_conf_lhash(&ctx, config); + if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s", + section_label, + section, + config_filename); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */ +{ + char * str; + STACK_OF(CONF_VALUE) * sktmp; + CONF_VALUE * cnf; + int i; + + str = CONF_get_string(req->req_config, NULL, "oid_section"); + if (str == NULL) { + php_openssl_store_errors(); + return SUCCESS; + } + sktmp = CONF_get_section(req->req_config, str); + if (sktmp == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "problem loading oid section %s", str); + return FAILURE; + } + for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { + cnf = sk_CONF_VALUE_value(sktmp, i); + if (OBJ_sn2nid(cnf->name) == NID_undef && OBJ_ln2nid(cnf->name) == NID_undef && + OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value); + return FAILURE; + } + } + return SUCCESS; +} +/* }}} */ + +#define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req)) +#define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req) +#define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval) + +#define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \ + req->config_filename, req->var, req->req_config) == FAILURE) return FAILURE + +#define SET_OPTIONAL_STRING_ARG(key, varname, defval) \ + do { \ + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_STRING) { \ + varname = Z_STRVAL_P(item); \ + } else { \ + varname = defval; \ + if (varname == NULL) { \ + php_openssl_store_errors(); \ + } \ + } \ + } while(0) + +#define SET_OPTIONAL_LONG_ARG(key, varname, defval) \ + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_LONG) \ + varname = (int)Z_LVAL_P(item); \ + else \ + varname = defval + +static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo); + +/* {{{ strip line endings from spkac */ +static int php_openssl_spki_cleanup(const char *src, char *dest) +{ + int removed = 0; + + while (*src) { + if (*src != '\n' && *src != '\r') { + *dest++ = *src; + } else { + ++removed; + } + ++src; + } + *dest = 0; + return removed; +} +/* }}} */ + +static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args) /* {{{ */ +{ + char * str; + zval * item; + + SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename); + SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req"); + req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL); + if (req->global_config == NULL) { + php_openssl_store_errors(); + } + req->req_config = CONF_load(NULL, req->config_filename, NULL); + if (req->req_config == NULL) { + php_openssl_store_errors(); + return FAILURE; + } + + /* read in the oids */ + str = CONF_get_string(req->req_config, NULL, "oid_file"); + if (str == NULL) { + php_openssl_store_errors(); + } else if (!php_openssl_open_base_dir_chk(str)) { + BIO *oid_bio = BIO_new_file(str, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + if (oid_bio) { + OBJ_create_objects(oid_bio); + BIO_free(oid_bio); + php_openssl_store_errors(); + } + } + if (php_openssl_add_oid_section(req) == FAILURE) { + return FAILURE; + } + SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name, + CONF_get_string(req->req_config, req->section_name, "default_md")); + SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section, + CONF_get_string(req->req_config, req->section_name, "x509_extensions")); + SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section, + CONF_get_string(req->req_config, req->section_name, "req_extensions")); + SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits, + CONF_get_number(req->req_config, req->section_name, "default_bits")); + + SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT); + + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) { + req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0; + } else { + str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key"); + if (str == NULL) { + str = CONF_get_string(req->req_config, req->section_name, "encrypt_key"); + /* it is sure that there are some errrors as str was NULL for encrypt_rsa_key */ + php_openssl_store_errors(); + } + if (str != NULL && strcmp(str, "no") == 0) { + req->priv_key_encrypt = 0; + } else { + req->priv_key_encrypt = 1; + } + } + + if (req->priv_key_encrypt && + optional_args && + (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL && + Z_TYPE_P(item) == IS_LONG + ) { + zend_long cipher_algo = Z_LVAL_P(item); + const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo); + if (cipher == NULL) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm for private key."); + return FAILURE; + } else { + req->priv_key_encrypt_cipher = cipher; + } + } else { + req->priv_key_encrypt_cipher = NULL; + } + + /* digest alg */ + if (req->digest_name == NULL) { + req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md"); + } + if (req->digest_name != NULL) { + req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name); + } else { + php_openssl_store_errors(); + } + if (req->md_alg == NULL) { + req->md_alg = req->digest = EVP_sha1(); + php_openssl_store_errors(); + } + + PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section); +#ifdef HAVE_EVP_PKEY_EC + /* set the ec group curve name */ + req->curve_name = NID_undef; + if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "curve_name", sizeof("curve_name")-1)) != NULL + && Z_TYPE_P(item) == IS_STRING) { + req->curve_name = OBJ_sn2nid(Z_STRVAL_P(item)); + if (req->curve_name == NID_undef) { + php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(item)); + return FAILURE; + } + } +#endif + + /* set the string mask */ + str = CONF_get_string(req->req_config, req->section_name, "string_mask"); + if (str == NULL) { + php_openssl_store_errors(); + } else if (!ASN1_STRING_set_default_mask_asc(str)) { + php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str); + return FAILURE; + } + + PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section); + + return SUCCESS; +} +/* }}} */ + +static void php_openssl_dispose_config(struct php_x509_request * req) /* {{{ */ +{ + if (req->priv_key) { + EVP_PKEY_free(req->priv_key); + req->priv_key = NULL; + } + if (req->global_config) { + CONF_free(req->global_config); + req->global_config = NULL; + } + if (req->req_config) { + CONF_free(req->req_config); + req->req_config = NULL; + } +} +/* }}} */ + +#if defined(PHP_WIN32) || (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) +#define PHP_OPENSSL_RAND_ADD_TIME() ((void) 0) +#else +#define PHP_OPENSSL_RAND_ADD_TIME() php_openssl_rand_add_timeval() + +static inline void php_openssl_rand_add_timeval() /* {{{ */ +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + RAND_add(&tv, sizeof(tv), 0.0); +} +/* }}} */ + +#endif + +static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */ +{ + char buffer[MAXPATHLEN]; + + *egdsocket = 0; + *seeded = 0; + + if (file == NULL) { + file = RAND_file_name(buffer, sizeof(buffer)); +#ifdef HAVE_RAND_EGD + } else if (RAND_egd(file) > 0) { + /* if the given filename is an EGD socket, don't + * write anything back to it */ + *egdsocket = 1; + return SUCCESS; +#endif + } + if (file == NULL || !RAND_load_file(file, -1)) { + if (RAND_status() == 0) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "unable to load random state; not enough random data!"); + return FAILURE; + } + return FAILURE; + } + *seeded = 1; + return SUCCESS; +} +/* }}} */ + +static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */ +{ + char buffer[MAXPATHLEN]; + + + if (egdsocket || !seeded) { + /* if we did not manage to read the seed file, we should not write + * a low-entropy seed file back */ + return FAILURE; + } + if (file == NULL) { + file = RAND_file_name(buffer, sizeof(buffer)); + } + PHP_OPENSSL_RAND_ADD_TIME(); + if (file == NULL || !RAND_write_file(file)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "unable to write random state"); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */ + EVP_MD *mdtype; + + switch (algo) { + case OPENSSL_ALGO_SHA1: + mdtype = (EVP_MD *) EVP_sha1(); + break; + case OPENSSL_ALGO_MD5: + mdtype = (EVP_MD *) EVP_md5(); + break; + case OPENSSL_ALGO_MD4: + mdtype = (EVP_MD *) EVP_md4(); + break; +#ifdef HAVE_OPENSSL_MD2_H + case OPENSSL_ALGO_MD2: + mdtype = (EVP_MD *) EVP_md2(); + break; +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) + case OPENSSL_ALGO_DSS1: + mdtype = (EVP_MD *) EVP_dss1(); + break; +#endif + case OPENSSL_ALGO_SHA224: + mdtype = (EVP_MD *) EVP_sha224(); + break; + case OPENSSL_ALGO_SHA256: + mdtype = (EVP_MD *) EVP_sha256(); + break; + case OPENSSL_ALGO_SHA384: + mdtype = (EVP_MD *) EVP_sha384(); + break; + case OPENSSL_ALGO_SHA512: + mdtype = (EVP_MD *) EVP_sha512(); + break; + case OPENSSL_ALGO_RMD160: + mdtype = (EVP_MD *) EVP_ripemd160(); + break; +#ifndef OPENSSL_NO_SM3 + case OPENSSL_ALGO_SM3: + mdtype = (EVP_MD *) EVP_sm3(); + break; +#endif + default: + return NULL; + break; + } + return mdtype; +} +/* }}} */ + +static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo) { /* {{{ */ + switch (algo) { +#ifndef OPENSSL_NO_RC2 + case PHP_OPENSSL_CIPHER_RC2_40: + return EVP_rc2_40_cbc(); + break; + case PHP_OPENSSL_CIPHER_RC2_64: + return EVP_rc2_64_cbc(); + break; + case PHP_OPENSSL_CIPHER_RC2_128: + return EVP_rc2_cbc(); + break; +#endif + +#ifndef OPENSSL_NO_DES + case PHP_OPENSSL_CIPHER_DES: + return EVP_des_cbc(); + break; + case PHP_OPENSSL_CIPHER_3DES: + return EVP_des_ede3_cbc(); + break; +#endif + +#ifndef OPENSSL_NO_AES + case PHP_OPENSSL_CIPHER_AES_128_CBC: + return EVP_aes_128_cbc(); + break; + case PHP_OPENSSL_CIPHER_AES_192_CBC: + return EVP_aes_192_cbc(); + break; + case PHP_OPENSSL_CIPHER_AES_256_CBC: + return EVP_aes_256_cbc(); + break; +#endif + +#ifndef OPENSSL_NO_SMS4 + case PHP_OPENSSL_CIPHER_SMS4_CBC: + return EVP_sms4_cbc(); + break; +#endif + + default: + return NULL; + break; + } +} +/* }}} */ + +/* {{{ INI Settings */ +PHP_INI_BEGIN() + PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL) + PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL) +PHP_INI_END() +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(openssl) +{ + char * config_filename; + + le_key = zend_register_list_destructors_ex(php_openssl_pkey_free, NULL, "OpenSSL key", module_number); + le_x509 = zend_register_list_destructors_ex(php_openssl_x509_free, NULL, "OpenSSL X.509", module_number); + le_csr = zend_register_list_destructors_ex(php_openssl_csr_free, NULL, "OpenSSL X.509 CSR", module_number); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) + OPENSSL_config(NULL); + SSL_library_init(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + OpenSSL_add_all_algorithms(); + +#if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && OPENSSL_VERSION_NUMBER < 0x100020000 + EVP_add_cipher(EVP_aes_128_ccm()); + EVP_add_cipher(EVP_aes_192_ccm()); + EVP_add_cipher(EVP_aes_256_ccm()); +#endif + + SSL_load_error_strings(); +#else + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#endif + + /* register a resource id number with OpenSSL so that we can map SSL -> stream structures in + * OpenSSL callbacks */ + ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL); + + REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT); + + /* purposes for cert purpose checking */ + REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT); +#ifdef X509_PURPOSE_ANY + REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT); +#endif + + /* signature algorithm constants */ + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT); +#ifdef HAVE_OPENSSL_MD2_H + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT); +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT); +#ifndef OPENSSL_NO_SM3 + REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SM3", OPENSSL_ALGO_SM3, CONST_CS|CONST_PERSISTENT); +#endif + + /* flags for S/MIME */ + REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT); + + /* Informational stream wrapper constants */ + REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT); + + /* Ciphers */ +#ifndef OPENSSL_NO_RC2 + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT); +#endif +#ifndef OPENSSL_NO_DES + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT); +#endif +#ifndef OPENSSL_NO_AES + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT); +#endif +#ifndef OPENSSL_NO_SMS4 + REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_SMS4_CBC", PHP_OPENSSL_CIPHER_SMS4_CBC, CONST_CS|CONST_PERSISTENT); +#endif + + /* Values for key types */ + REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT); +#ifndef NO_DSA + REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT); +#ifdef HAVE_EVP_PKEY_EC + REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT); +#endif + + REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT); + +#ifndef OPENSSL_NO_TLSEXT + /* SNI support included */ + REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT); +#endif + + /* Determine default SSL configuration file */ + config_filename = getenv("OPENSSL_CONF"); + if (config_filename == NULL) { + config_filename = getenv("SSLEAY_CONF"); + } + + /* default to 'openssl.cnf' if no environment variable is set */ + if (config_filename == NULL) { + snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s", + X509_get_default_cert_area(), + "openssl.cnf"); + } else { + strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename)); + } + + php_stream_xport_register("ssl", php_openssl_ssl_socket_factory); +#ifndef OPENSSL_NO_SSL3 + php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory); +#endif + php_stream_xport_register("tls", php_openssl_ssl_socket_factory); + php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory); + php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory); + php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory); + + /* override the default tcp socket provider */ + php_stream_xport_register("tcp", php_openssl_ssl_socket_factory); + + php_register_url_stream_wrapper("https", &php_stream_http_wrapper); + php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper); + + REGISTER_INI_ENTRIES(); + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_GINIT_FUNCTION +*/ +PHP_GINIT_FUNCTION(openssl) +{ +#if defined(COMPILE_DL_OPENSSL) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + openssl_globals->errors = NULL; +} +/* }}} */ + +/* {{{ PHP_GSHUTDOWN_FUNCTION +*/ +PHP_GSHUTDOWN_FUNCTION(openssl) +{ + if (openssl_globals->errors) { + pefree(openssl_globals->errors, 1); + } +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(openssl) +{ + php_info_print_table_start(); + php_info_print_table_row(2, "OpenSSL support", "enabled"); + php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION)); + php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT); + php_info_print_table_row(2, "Openssl default config", default_ssl_conf_filename); + php_info_print_table_end(); + DISPLAY_INI_ENTRIES(); +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION + */ +PHP_MSHUTDOWN_FUNCTION(openssl) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) + EVP_cleanup(); + + /* prevent accessing locking callback from unloaded extension */ + CRYPTO_set_locking_callback(NULL); + /* free allocated error strings */ + ERR_free_strings(); + CONF_modules_free(); +#endif + + php_unregister_url_stream_wrapper("https"); + php_unregister_url_stream_wrapper("ftps"); + + php_stream_xport_unregister("ssl"); +#ifndef OPENSSL_NO_SSL3 + php_stream_xport_unregister("sslv3"); +#endif + php_stream_xport_unregister("tls"); + php_stream_xport_unregister("tlsv1.0"); + php_stream_xport_unregister("tlsv1.1"); + php_stream_xport_unregister("tlsv1.2"); + + /* reinstate the default tcp handler */ + php_stream_xport_register("tcp", php_stream_generic_socket_factory); + + UNREGISTER_INI_ENTRIES(); + + return SUCCESS; +} +/* }}} */ + +/* {{{ x509 cert functions */ + +/* {{{ proto array openssl_get_cert_locations(void) + Retrieve an array mapping available certificate locations */ +PHP_FUNCTION(openssl_get_cert_locations) +{ + array_init(return_value); + + add_assoc_string(return_value, "default_cert_file", (char *) X509_get_default_cert_file()); + add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env()); + add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir()); + add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env()); + add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir()); + add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area()); + add_assoc_string(return_value, "ini_cafile", + zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0)); + add_assoc_string(return_value, "ini_capath", + zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0)); +} +/* }}} */ + + +/* {{{ php_openssl_x509_from_zval + Given a zval, coerce it into an X509 object. + The zval can be: + . X509 resource created using openssl_read_x509() + . if it starts with file:// then it will be interpreted as the path to that cert + . it will be interpreted as the cert data + If you supply makeresource, the result will be registered as an x509 resource and + it's value returned in makeresource. +*/ +static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval) +{ + X509 *cert = NULL; + BIO *in; + + if (resourceval) { + *resourceval = NULL; + } + if (Z_TYPE_P(val) == IS_RESOURCE) { + /* is it an x509 resource ? */ + void * what; + zend_resource *res = Z_RES_P(val); + + what = zend_fetch_resource(res, "OpenSSL X.509", le_x509); + if (!what) { + return NULL; + } + if (resourceval) { + *resourceval = res; + if (makeresource) { + Z_ADDREF_P(val); + } + } + return (X509*)what; + } + + if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { + return NULL; + } + + /* force it to be a string and check if it refers to a file */ + convert_to_string_ex(val); + + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { + + if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) { + return NULL; + } + + in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + if (in == NULL) { + php_openssl_store_errors(); + return NULL; + } + cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + + } else { + + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); + if (in == NULL) { + php_openssl_store_errors(); + return NULL; + } +#ifdef TYPEDEF_D2I_OF + cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL); +#else + cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL); +#endif + } + + if (!BIO_free(in)) { + php_openssl_store_errors(); + } + + if (cert == NULL) { + php_openssl_store_errors(); + return NULL; + } + + if (makeresource && resourceval) { + *resourceval = zend_register_resource(cert, le_x509); + } + return cert; +} + +/* }}} */ + +/* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true]) + Exports a CERT to file or a var */ +PHP_FUNCTION(openssl_x509_export_to_file) +{ + X509 * cert; + zval * zcert; + zend_bool notext = 1; + BIO * bio_out; + char * filename; + size_t filename_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) { + return; + } + RETVAL_FALSE; + + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); + return; + } + + if (php_openssl_open_base_dir_chk(filename)) { + return; + } + + bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (bio_out) { + if (!notext && !X509_print(bio_out, cert)) { + php_openssl_store_errors(); + } + if (!PEM_write_bio_X509(bio_out, cert)) { + php_openssl_store_errors(); + } + + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); + } + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } + + if (!BIO_free(bio_out)) { + php_openssl_store_errors(); + } +} +/* }}} */ + +/* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method]) + Creates new private key (or uses existing) and creates a new spki cert + outputting results to var */ +PHP_FUNCTION(openssl_spki_new) +{ + size_t challenge_len; + char * challenge = NULL, * spkstr = NULL; + zend_string * s = NULL; + zend_resource *keyresource = NULL; + const char *spkac = "SPKAC="; + zend_long algo = OPENSSL_ALGO_MD5; + + zval *method = NULL; + zval * zpkey = NULL; + EVP_PKEY * pkey = NULL; + NETSCAPE_SPKI *spki=NULL; + const EVP_MD *mdtype; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) { + return; + } + RETVAL_FALSE; + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(challenge_len, challenge); + pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, challenge_len, 1, &keyresource); + + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "Unable to use supplied private key"); + goto cleanup; + } + + if (method != NULL) { + if (Z_TYPE_P(method) == IS_LONG) { + algo = Z_LVAL_P(method); + } else { + php_error_docref(NULL, E_WARNING, "Algorithm must be of supported type"); + goto cleanup; + } + } + mdtype = php_openssl_get_evp_md_from_algo(algo); + + if (!mdtype) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); + goto cleanup; + } + + if ((spki = NETSCAPE_SPKI_new()) == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC"); + goto cleanup; + } + + if (challenge) { + if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to set challenge data"); + goto cleanup; + } + } + + if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to embed public key"); + goto cleanup; + } + + if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to sign with specified algorithm"); + goto cleanup; + } + + spkstr = NETSCAPE_SPKI_b64_encode(spki); + if (!spkstr){ + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC"); + goto cleanup; + } + + s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0); + sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr); + ZSTR_LEN(s) = strlen(ZSTR_VAL(s)); + OPENSSL_free(spkstr); + + RETVAL_STR(s); + goto cleanup; + +cleanup: + + if (spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (keyresource == NULL && pkey != NULL) { + EVP_PKEY_free(pkey); + } + + if (s && ZSTR_LEN(s) <= 0) { + RETVAL_FALSE; + } + + if (keyresource == NULL && s != NULL) { + zend_string_release(s); + } +} +/* }}} */ + +/* {{{ proto bool openssl_spki_verify(string spki) + Verifies spki returns boolean */ +PHP_FUNCTION(openssl_spki_verify) +{ + size_t spkstr_len; + int i = 0, spkstr_cleaned_len = 0; + char *spkstr = NULL, * spkstr_cleaned = NULL; + + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned)); + + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); + if (spki == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC"); + goto cleanup; + } + + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key"); + goto cleanup; + } + + i = NETSCAPE_SPKI_verify(spki, pkey); + goto cleanup; + +cleanup: + if (spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } + + if (i > 0) { + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } +} +/* }}} */ + +/* {{{ proto string openssl_spki_export(string spki) + Exports public key from existing spki to var */ +PHP_FUNCTION(openssl_spki_export) +{ + size_t spkstr_len; + char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL; + int spkstr_cleaned_len; + + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + BIO *out = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned)); + + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); + if (spki == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC"); + goto cleanup; + } + + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key"); + goto cleanup; + } + + out = BIO_new(BIO_s_mem()); + if (out && PEM_write_bio_PUBKEY(out, pkey)) { + BUF_MEM *bio_buf; + + BIO_get_mem_ptr(out, &bio_buf); + RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length); + } else { + php_openssl_store_errors(); + } + goto cleanup; + +cleanup: + + if (spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (out != NULL) { + BIO_free_all(out); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } + if (s != NULL) { + efree(s); + } +} +/* }}} */ + +/* {{{ proto string openssl_spki_export_challenge(string spki) + Exports spkac challenge from existing spki to var */ +PHP_FUNCTION(openssl_spki_export_challenge) +{ + size_t spkstr_len; + char *spkstr = NULL, * spkstr_cleaned = NULL; + int spkstr_cleaned_len; + + NETSCAPE_SPKI *spki = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned)); + + if (spkstr_cleaned_len == 0) { + php_error_docref(NULL, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len); + if (spki == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC"); + goto cleanup; + } + + RETVAL_STRING((const char *)ASN1_STRING_get0_data(spki->spkac->challenge)); + goto cleanup; + +cleanup: + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } +} +/* }}} */ + +/* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true]) + Exports a CERT to file or a var */ +PHP_FUNCTION(openssl_x509_export) +{ + X509 * cert; + zval * zcert, *zout; + zend_bool notext = 1; + BIO * bio_out; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|b", &zcert, &zout, ¬ext) == FAILURE) { + return; + } + RETVAL_FALSE; + + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); + return; + } + + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + php_openssl_store_errors(); + goto cleanup; + } + if (!notext && !X509_print(bio_out, cert)) { + php_openssl_store_errors(); + } + if (PEM_write_bio_X509(bio_out, cert)) { + BUF_MEM *bio_buf; + + zval_dtor(zout); + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + + BIO_free(bio_out); + +cleanup: + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} +/* }}} */ + +zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + const EVP_MD *mdtype; + unsigned int n; + zend_string *ret; + + if (!(mdtype = EVP_get_digestbyname(method))) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); + return NULL; + } else if (!X509_digest(peer, mdtype, md, &n)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_ERROR, "Could not generate signature"); + return NULL; + } + + if (raw) { + ret = zend_string_init((char*)md, n, 0); + } else { + ret = zend_string_alloc(n * 2, 0); + make_digest_ex(ZSTR_VAL(ret), md, n); + ZSTR_VAL(ret)[n * 2] = '\0'; + } + + return ret; +} + +PHP_FUNCTION(openssl_x509_fingerprint) +{ + X509 *cert; + zval *zcert; + zend_bool raw_output = 0; + char *method = "sha1"; + size_t method_len; + zend_string *fingerprint; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) { + return; + } + + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); + RETURN_FALSE; + } + + fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output); + if (fingerprint) { + RETVAL_STR(fingerprint); + } else { + RETVAL_FALSE; + } + + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} + +/* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key) + Checks if a private key corresponds to a CERT */ +PHP_FUNCTION(openssl_x509_check_private_key) +{ + zval * zcert, *zkey; + X509 * cert = NULL; + EVP_PKEY * key = NULL; + zend_resource *keyresource = NULL; + + RETVAL_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) { + return; + } + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + RETURN_FALSE; + } + key = php_openssl_evp_from_zval(zkey, 0, "", 0, 1, &keyresource); + if (key) { + RETVAL_BOOL(X509_check_private_key(cert, key)); + } + + if (keyresource == NULL && key) { + EVP_PKEY_free(key); + } + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} +/* }}} */ + +/* Special handling of subjectAltName, see CVE-2013-4073 + * Christian Heimes + */ + +static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) +{ + GENERAL_NAMES *names; + const X509V3_EXT_METHOD *method = NULL; + ASN1_OCTET_STRING *extension_data; + long i, length, num; + const unsigned char *p; + + method = X509V3_EXT_get(extension); + if (method == NULL) { + return -1; + } + + extension_data = X509_EXTENSION_get_data(extension); + p = extension_data->data; + length = extension_data->length; + if (method->it) { + names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length, + ASN1_ITEM_ptr(method->it))); + } else { + names = (GENERAL_NAMES*) (method->d2i(NULL, &p, length)); + } + if (names == NULL) { + php_openssl_store_errors(); + return -1; + } + + num = sk_GENERAL_NAME_num(names); + for (i = 0; i < num; i++) { + GENERAL_NAME *name; + ASN1_STRING *as; + name = sk_GENERAL_NAME_value(names, i); + switch (name->type) { + case GEN_EMAIL: + BIO_puts(bio, "email:"); + as = name->d.rfc822Name; + BIO_write(bio, ASN1_STRING_get0_data(as), + ASN1_STRING_length(as)); + break; + case GEN_DNS: + BIO_puts(bio, "DNS:"); + as = name->d.dNSName; + BIO_write(bio, ASN1_STRING_get0_data(as), + ASN1_STRING_length(as)); + break; + case GEN_URI: + BIO_puts(bio, "URI:"); + as = name->d.uniformResourceIdentifier; + BIO_write(bio, ASN1_STRING_get0_data(as), + ASN1_STRING_length(as)); + break; + default: + /* use builtin print for GEN_OTHERNAME, GEN_X400, + * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID + */ + GENERAL_NAME_print(bio, name); + } + /* trailing ', ' except for last element */ + if (i < (num - 1)) { + BIO_puts(bio, ", "); + } + } + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + + return 0; +} + +/* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true]) + Returns an array of the fields/values of the CERT */ +PHP_FUNCTION(openssl_x509_parse) +{ + zval * zcert; + X509 * cert = NULL; + int i, sig_nid; + zend_bool useshortnames = 1; + char * tmpstr; + zval subitem; + X509_EXTENSION *extension; + X509_NAME *subject_name; + char *cert_name; + char *extname; + BIO *bio_out; + BUF_MEM *bio_buf; + ASN1_INTEGER *asn1_serial; + BIGNUM *bn_serial; + char *str_serial; + char *hex_serial; + char buf[256]; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcert, &useshortnames) == FAILURE) { + return; + } + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + RETURN_FALSE; + } + array_init(return_value); + + subject_name = X509_get_subject_name(cert); + cert_name = X509_NAME_oneline(subject_name, NULL, 0); + add_assoc_string(return_value, "name", cert_name); + OPENSSL_free(cert_name); + + php_openssl_add_assoc_name_entry(return_value, "subject", subject_name, useshortnames); + /* hash as used in CA directories to lookup cert by subject name */ + { + char buf[32]; + snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert)); + add_assoc_string(return_value, "hash", buf); + } + + php_openssl_add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames); + add_assoc_long(return_value, "version", X509_get_version(cert)); + + asn1_serial = X509_get_serialNumber(cert); + + bn_serial = ASN1_INTEGER_to_BN(asn1_serial, NULL); + /* Can return NULL on error or memory allocation failure */ + if (!bn_serial) { + php_openssl_store_errors(); + RETURN_FALSE; + } + + hex_serial = BN_bn2hex(bn_serial); + BN_free(bn_serial); + /* Can return NULL on error or memory allocation failure */ + if (!hex_serial) { + php_openssl_store_errors(); + RETURN_FALSE; + } + + str_serial = i2s_ASN1_INTEGER(NULL, asn1_serial); + add_assoc_string(return_value, "serialNumber", str_serial); + OPENSSL_free(str_serial); + + /* Return the hex representation of the serial number, as defined by OpenSSL */ + add_assoc_string(return_value, "serialNumberHex", hex_serial); + OPENSSL_free(hex_serial); + + php_openssl_add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert)); + php_openssl_add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert)); + + add_assoc_long(return_value, "validFrom_time_t", php_openssl_asn1_time_to_time_t(X509_get_notBefore(cert))); + add_assoc_long(return_value, "validTo_time_t", php_openssl_asn1_time_to_time_t(X509_get_notAfter(cert))); + + tmpstr = (char *)X509_alias_get0(cert, NULL); + if (tmpstr) { + add_assoc_string(return_value, "alias", tmpstr); + } + + sig_nid = X509_get_signature_nid(cert); + add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid)); + add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid)); + add_assoc_long(return_value, "signatureTypeNID", sig_nid); + array_init(&subitem); + + /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines + in x509v3.h */ + for (i = 0; i < X509_PURPOSE_get_count(); i++) { + int id, purpset; + char * pname; + X509_PURPOSE * purp; + zval subsub; + + array_init(&subsub); + + purp = X509_PURPOSE_get0(i); + id = X509_PURPOSE_get_id(purp); + + purpset = X509_check_purpose(cert, id, 0); + add_index_bool(&subsub, 0, purpset); + + purpset = X509_check_purpose(cert, id, 1); + add_index_bool(&subsub, 1, purpset); + + pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp); + add_index_string(&subsub, 2, pname); + + /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */ + + add_index_zval(&subitem, id, &subsub); + } + add_assoc_zval(return_value, "purposes", &subitem); + + array_init(&subitem); + + + for (i = 0; i < X509_get_ext_count(cert); i++) { + int nid; + extension = X509_get_ext(cert, i); + nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); + if (nid != NID_undef) { + extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension))); + } else { + OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1); + extname = buf; + } + bio_out = BIO_new(BIO_s_mem()); + if (bio_out == NULL) { + php_openssl_store_errors(); + RETURN_FALSE; + } + if (nid == NID_subject_alt_name) { + if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) { + BIO_get_mem_ptr(bio_out, &bio_buf); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); + } else { + zval_dtor(return_value); + BIO_free(bio_out); + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } + RETURN_FALSE; + } + } + else if (X509V3_EXT_print(bio_out, extension, 0, 0)) { + BIO_get_mem_ptr(bio_out, &bio_buf); + add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length); + } else { + php_openssl_add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension)); + } + BIO_free(bio_out); + } + add_assoc_zval(return_value, "extensions", &subitem); + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} +/* }}} */ + +/* {{{ php_openssl_load_all_certs_from_file */ +static STACK_OF(X509) *php_openssl_load_all_certs_from_file(char *certfile) +{ + STACK_OF(X509_INFO) *sk=NULL; + STACK_OF(X509) *stack=NULL, *ret=NULL; + BIO *in=NULL; + X509_INFO *xi; + + if(!(stack = sk_X509_new_null())) { + php_openssl_store_errors(); + php_error_docref(NULL, E_ERROR, "memory allocation failure"); + goto end; + } + + if (php_openssl_open_base_dir_chk(certfile)) { + sk_X509_free(stack); + goto end; + } + + if (!(in=BIO_new_file(certfile, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)))) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening the file, %s", certfile); + sk_X509_free(stack); + goto end; + } + + /* This loads from a file, a stack of x509/crl/pkey sets */ + if (!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error reading the file, %s", certfile); + sk_X509_free(stack); + goto end; + } + + /* scan over it and pull out the certs */ + while (sk_X509_INFO_num(sk)) { + xi=sk_X509_INFO_shift(sk); + if (xi->x509 != NULL) { + sk_X509_push(stack,xi->x509); + xi->x509=NULL; + } + X509_INFO_free(xi); + } + if (!sk_X509_num(stack)) { + php_error_docref(NULL, E_WARNING, "no certificates in file, %s", certfile); + sk_X509_free(stack); + goto end; + } + ret = stack; +end: + BIO_free(in); + sk_X509_INFO_free(sk); + + return ret; +} +/* }}} */ + +/* {{{ check_cert */ +static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose) +{ + int ret=0; + X509_STORE_CTX *csc; + + csc = X509_STORE_CTX_new(); + if (csc == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_ERROR, "memory allocation failure"); + return 0; + } + if (!X509_STORE_CTX_init(csc, ctx, x, untrustedchain)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "cert store initialization failed"); + return 0; + } + if (purpose >= 0 && !X509_STORE_CTX_set_purpose(csc, purpose)) { + php_openssl_store_errors(); + } + ret = X509_verify_cert(csc); + if (ret < 0) { + php_openssl_store_errors(); + } + X509_STORE_CTX_free(csc); + + return ret; +} +/* }}} */ + +/* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile]) + Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */ +PHP_FUNCTION(openssl_x509_checkpurpose) +{ + zval * zcert, * zcainfo = NULL; + X509_STORE * cainfo = NULL; + X509 * cert = NULL; + STACK_OF(X509) * untrustedchain = NULL; + zend_long purpose; + char * untrusted = NULL; + size_t untrusted_len = 0; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) { + return; + } + + RETVAL_LONG(-1); + + if (untrusted) { + untrustedchain = php_openssl_load_all_certs_from_file(untrusted); + if (untrustedchain == NULL) { + goto clean_exit; + } + } + + cainfo = php_openssl_setup_verify(zcainfo); + if (cainfo == NULL) { + goto clean_exit; + } + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + goto clean_exit; + } + + ret = check_cert(cainfo, cert, untrustedchain, (int)purpose); + if (ret != 0 && ret != 1) { + RETVAL_LONG(ret); + } else { + RETVAL_BOOL(ret); + } + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +clean_exit: + if (cainfo) { + X509_STORE_free(cainfo); + } + if (untrustedchain) { + sk_X509_pop_free(untrustedchain, X509_free); + } +} +/* }}} */ + +/* {{{ php_openssl_setup_verify + * calist is an array containing file and directory names. create a + * certificate store and add those certs to it for use in verification. +*/ +static X509_STORE *php_openssl_setup_verify(zval *calist) +{ + X509_STORE *store; + X509_LOOKUP * dir_lookup, * file_lookup; + int ndirs = 0, nfiles = 0; + zval * item; + zend_stat_t sb; + + store = X509_STORE_new(); + + if (store == NULL) { + php_openssl_store_errors(); + return NULL; + } + + if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(calist), item) { + convert_to_string_ex(item); + + if (VCWD_STAT(Z_STRVAL_P(item), &sb) == -1) { + php_error_docref(NULL, E_WARNING, "unable to stat %s", Z_STRVAL_P(item)); + continue; + } + + if ((sb.st_mode & S_IFREG) == S_IFREG) { + file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error loading file %s", Z_STRVAL_P(item)); + } else { + nfiles++; + } + file_lookup = NULL; + } else { + dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error loading directory %s", Z_STRVAL_P(item)); + } else { + ndirs++; + } + dir_lookup = NULL; + } + } ZEND_HASH_FOREACH_END(); + } + if (nfiles == 0) { + file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT)) { + php_openssl_store_errors(); + } + } + if (ndirs == 0) { + dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT)) { + php_openssl_store_errors(); + } + } + return store; +} +/* }}} */ + +/* {{{ proto resource openssl_x509_read(mixed cert) + Reads X.509 certificates */ +PHP_FUNCTION(openssl_x509_read) +{ + zval *cert; + X509 *x509; + zend_resource *res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) { + return; + } + x509 = php_openssl_x509_from_zval(cert, 1, &res); + ZVAL_RES(return_value, res); + + if (x509 == NULL) { + php_error_docref(NULL, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!"); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto void openssl_x509_free(resource x509) + Frees X.509 certificates */ +PHP_FUNCTION(openssl_x509_free) +{ + zval *x509; + X509 *cert; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &x509) == FAILURE) { + return; + } + if ((cert = (X509 *)zend_fetch_resource(Z_RES_P(x509), "OpenSSL X.509", le_x509)) == NULL) { + RETURN_FALSE; + } + zend_list_close(Z_RES_P(x509)); +} +/* }}} */ + +/* }}} */ + +/* Pop all X509 from Stack and free them, free the stack afterwards */ +static void php_sk_X509_free(STACK_OF(X509) * sk) /* {{{ */ +{ + for (;;) { + X509* x = sk_X509_pop(sk); + if (!x) break; + X509_free(x); + } + sk_X509_free(sk); +} +/* }}} */ + +static STACK_OF(X509) * php_array_to_X509_sk(zval * zcerts) /* {{{ */ +{ + zval * zcertval; + STACK_OF(X509) * sk = NULL; + X509 * cert; + zend_resource *certresource; + + sk = sk_X509_new_null(); + + /* get certs */ + if (Z_TYPE_P(zcerts) == IS_ARRAY) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zcerts), zcertval) { + cert = php_openssl_x509_from_zval(zcertval, 0, &certresource); + if (cert == NULL) { + goto clean_exit; + } + + if (certresource != NULL) { + cert = X509_dup(cert); + + if (cert == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + } + sk_X509_push(sk, cert); + } ZEND_HASH_FOREACH_END(); + } else { + /* a single certificate */ + cert = php_openssl_x509_from_zval(zcerts, 0, &certresource); + + if (cert == NULL) { + goto clean_exit; + } + + if (certresource != NULL) { + cert = X509_dup(cert); + if (cert == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + } + sk_X509_push(sk, cert); + } + +clean_exit: + return sk; +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args]) + Creates and exports a PKCS to file */ +PHP_FUNCTION(openssl_pkcs12_export_to_file) +{ + X509 * cert = NULL; + BIO * bio_out = NULL; + PKCS12 * p12 = NULL; + char * filename; + char * friendly_name = NULL; + size_t filename_len; + char * pass; + size_t pass_len; + zval *zcert = NULL, *zpkey = NULL, *args = NULL; + EVP_PKEY *priv_key = NULL; + zend_resource *keyresource; + zval * item; + STACK_OF(X509) *ca = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE) + return; + + RETVAL_FALSE; + + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); + return; + } + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); + if (priv_key == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); + goto cleanup; + } + if (!X509_check_private_key(cert, priv_key)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "private key does not correspond to cert"); + goto cleanup; + } + if (php_openssl_open_base_dir_chk(filename)) { + goto cleanup; + } + + /* parse extra config from args array, promote this to an extra function */ + if (args && + (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && + Z_TYPE_P(item) == IS_STRING + ) { + friendly_name = Z_STRVAL_P(item); + } + /* certpbe (default RC2-40) + keypbe (default 3DES) + friendly_caname + */ + + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { + ca = php_array_to_X509_sk(item); + } + /* end parse extra config */ + + /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca, + int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/ + + p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0); + if (p12 != NULL) { + bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (bio_out != NULL) { + + i2d_PKCS12_bio(bio_out, p12); + BIO_free(bio_out); + + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); + } + + PKCS12_free(p12); + } else { + php_openssl_store_errors(); + } + + php_sk_X509_free(ca); + +cleanup: + + if (keyresource == NULL && priv_key) { + EVP_PKEY_free(priv_key); + } + + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args]) + Creates and exports a PKCS12 to a var */ +PHP_FUNCTION(openssl_pkcs12_export) +{ + X509 * cert = NULL; + BIO * bio_out; + PKCS12 * p12 = NULL; + zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL; + EVP_PKEY *priv_key = NULL; + zend_resource *keyresource; + char * pass; + size_t pass_len; + char * friendly_name = NULL; + zval * item; + STACK_OF(X509) *ca = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/zs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE) + return; + + RETVAL_FALSE; + + cert = php_openssl_x509_from_zval(zcert, 0, NULL); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); + return; + } + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); + if (priv_key == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); + goto cleanup; + } + if (!X509_check_private_key(cert, priv_key)) { + php_error_docref(NULL, E_WARNING, "private key does not correspond to cert"); + goto cleanup; + } + + /* parse extra config from args array, promote this to an extra function */ + if (args && + (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && + Z_TYPE_P(item) == IS_STRING + ) { + friendly_name = Z_STRVAL_P(item); + } + + if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { + ca = php_array_to_X509_sk(item); + } + /* end parse extra config */ + + p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0); + + if (p12 != NULL) { + bio_out = BIO_new(BIO_s_mem()); + if (i2d_PKCS12_bio(bio_out, p12)) { + BUF_MEM *bio_buf; + + zval_dtor(zout); + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + + BIO_free(bio_out); + PKCS12_free(p12); + } else { + php_openssl_store_errors(); + } + php_sk_X509_free(ca); + +cleanup: + + if (keyresource == NULL && priv_key) { + EVP_PKEY_free(priv_key); + } + if (Z_TYPE_P(zcert) != IS_RESOURCE) { + X509_free(cert); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass) + Parses a PKCS12 to an array */ +PHP_FUNCTION(openssl_pkcs12_read) +{ + zval *zout = NULL, zextracerts, zcert, zpkey; + char *pass, *zp12; + size_t pass_len, zp12_len; + PKCS12 * p12 = NULL; + EVP_PKEY * pkey = NULL; + X509 * cert = NULL; + STACK_OF(X509) * ca = NULL; + BIO * bio_in = NULL; + int i; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/s", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE) + return; + + RETVAL_FALSE; + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(zp12_len, pkcs12); + + bio_in = BIO_new(BIO_s_mem()); + + if (0 >= BIO_write(bio_in, zp12, (int)zp12_len)) { + php_openssl_store_errors(); + goto cleanup; + } + + if (d2i_PKCS12_bio(bio_in, &p12) && PKCS12_parse(p12, pass, &pkey, &cert, &ca)) { + BIO * bio_out; + int cert_num; + + zval_dtor(zout); + array_init(zout); + + if (cert) { + bio_out = BIO_new(BIO_s_mem()); + if (PEM_write_bio_X509(bio_out, cert)) { + BUF_MEM *bio_buf; + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); + add_assoc_zval(zout, "cert", &zcert); + } else { + php_openssl_store_errors(); + } + BIO_free(bio_out); + } + + if (pkey) { + bio_out = BIO_new(BIO_s_mem()); + if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) { + BUF_MEM *bio_buf; + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(&zpkey, bio_buf->data, bio_buf->length); + add_assoc_zval(zout, "pkey", &zpkey); + } else { + php_openssl_store_errors(); + } + BIO_free(bio_out); + } + + cert_num = sk_X509_num(ca); + if (ca && cert_num) { + array_init(&zextracerts); + + for (i = 0; i < cert_num; i++) { + zval zextracert; + X509* aCA = sk_X509_pop(ca); + if (!aCA) break; + + bio_out = BIO_new(BIO_s_mem()); + if (PEM_write_bio_X509(bio_out, aCA)) { + BUF_MEM *bio_buf; + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(&zextracert, bio_buf->data, bio_buf->length); + add_index_zval(&zextracerts, i, &zextracert); + } + + X509_free(aCA); + BIO_free(bio_out); + } + + sk_X509_free(ca); + add_assoc_zval(zout, "extracerts", &zextracerts); + } + + RETVAL_TRUE; + + PKCS12_free(p12); + } else { + php_openssl_store_errors(); + } + + cleanup: + if (bio_in) { + BIO_free(bio_in); + } + if (pkey) { + EVP_PKEY_free(pkey); + } + if (cert) { + X509_free(cert); + } +} +/* }}} */ + +/* {{{ x509 CSR functions */ + +/* {{{ php_openssl_make_REQ */ +static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs) +{ + STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL; + char * str, *dn_sect, *attr_sect; + + dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name"); + if (dn_sect == NULL) { + php_openssl_store_errors(); + return FAILURE; + } + dn_sk = CONF_get_section(req->req_config, dn_sect); + if (dn_sk == NULL) { + php_openssl_store_errors(); + return FAILURE; + } + attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes"); + if (attr_sect == NULL) { + php_openssl_store_errors(); + attr_sk = NULL; + } else { + attr_sk = CONF_get_section(req->req_config, attr_sect); + if (attr_sk == NULL) { + php_openssl_store_errors(); + return FAILURE; + } + } + /* setup the version number: version 1 */ + if (X509_REQ_set_version(csr, 0L)) { + int i, nid; + char * type; + CONF_VALUE * v; + X509_NAME * subj; + zval * item; + zend_string * strindex = NULL; + + subj = X509_REQ_get_subject_name(csr); + /* apply values from the dn hash */ + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) { + if (strindex) { + int nid; + + convert_to_string_ex(item); + + nid = OBJ_txt2nid(ZSTR_VAL(strindex)); + if (nid != NID_undef) { + if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, + (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) + { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, + "dn: add_entry_by_NID %d -> %s (failed; check error" + " queue and value of string_mask OpenSSL option " + "if illegal characters are reported)", + nid, Z_STRVAL_P(item)); + return FAILURE; + } + } else { + php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); + } + } + } ZEND_HASH_FOREACH_END(); + + /* Finally apply defaults from config file */ + for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { + size_t len; + char buffer[200 + 1]; /*200 + \0 !*/ + + v = sk_CONF_VALUE_value(dn_sk, i); + type = v->name; + + len = strlen(type); + if (len < sizeof("_default")) { + continue; + } + len -= sizeof("_default") - 1; + if (strcmp("_default", type + len) != 0) { + continue; + } + if (len > 200) { + len = 200; + } + memcpy(buffer, type, len); + buffer[len] = '\0'; + type = buffer; + + /* Skip past any leading X. X: X, etc to allow for multiple + * instances */ + for (str = type; *str; str++) { + if (*str == ':' || *str == ',' || *str == '.') { + str++; + if (*str) { + type = str; + } + break; + } + } + /* if it is already set, skip this */ + nid = OBJ_txt2nid(type); + if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) { + continue; + } + if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value); + return FAILURE; + } + if (!X509_NAME_entry_count(subj)) { + php_error_docref(NULL, E_WARNING, "no objects specified in config file"); + return FAILURE; + } + } + if (attribs) { + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) { + int nid; + + if (NULL == strindex) { + php_error_docref(NULL, E_WARNING, "dn: numeric fild names are not supported"); + continue; + } + + convert_to_string_ex(item); + + nid = OBJ_txt2nid(ZSTR_VAL(strindex)); + if (nid != NID_undef) { + if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_P(item)); + return FAILURE; + } + } else { + php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex)); + } + } ZEND_HASH_FOREACH_END(); + for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { + v = sk_CONF_VALUE_value(attr_sk, i); + /* if it is already set, skip this */ + nid = OBJ_txt2nid(v->name); + if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) { + continue; + } + if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_UTF8, (unsigned char*)v->value, -1)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, + "add1_attr_by_txt %s -> %s (failed; check error queue " + "and value of string_mask OpenSSL option if illegal " + "characters are reported)", + v->name, v->value); + return FAILURE; + } + } + } + } else { + php_openssl_store_errors(); + } + + if (!X509_REQ_set_pubkey(csr, req->priv_key)) { + php_openssl_store_errors(); + } + return SUCCESS; +} +/* }}} */ + +/* {{{ php_openssl_csr_from_zval */ +static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource **resourceval) +{ + X509_REQ * csr = NULL; + char * filename = NULL; + BIO * in; + + if (resourceval) { + *resourceval = NULL; + } + if (Z_TYPE_P(val) == IS_RESOURCE) { + void * what; + zend_resource *res = Z_RES_P(val); + + what = zend_fetch_resource(res, "OpenSSL X.509 CSR", le_csr); + if (what) { + if (resourceval) { + *resourceval = res; + if (makeresource) { + Z_ADDREF_P(val); + } + } + return (X509_REQ*)what; + } + return NULL; + } else if (Z_TYPE_P(val) != IS_STRING) { + return NULL; + } + + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { + filename = Z_STRVAL_P(val) + (sizeof("file://") - 1); + } + if (filename) { + if (php_openssl_open_base_dir_chk(filename)) { + return NULL; + } + in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + } else { + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); + } + + if (in == NULL) { + php_openssl_store_errors(); + return NULL; + } + + csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL); + if (csr == NULL) { + php_openssl_store_errors(); + } + + BIO_free(in); + + return csr; +} +/* }}} */ + +/* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true]) + Exports a CSR to file */ +PHP_FUNCTION(openssl_csr_export_to_file) +{ + X509_REQ * csr; + zval * zcsr = NULL; + zend_bool notext = 1; + char * filename = NULL; + size_t filename_len; + BIO * bio_out; + zend_resource *csr_resource; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) { + return; + } + RETVAL_FALSE; + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); + if (csr == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); + return; + } + + if (php_openssl_open_base_dir_chk(filename)) { + return; + } + + bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (bio_out != NULL) { + if (!notext && !X509_REQ_print(bio_out, csr)) { + php_openssl_store_errors(); + } + if (!PEM_write_bio_X509_REQ(bio_out, csr)) { + php_error_docref(NULL, E_WARNING, "error writing PEM to file %s", filename); + php_openssl_store_errors(); + } else { + RETVAL_TRUE; + } + BIO_free(bio_out); + } else { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening file %s", filename); + } + + if (csr_resource == NULL && csr != NULL) { + X509_REQ_free(csr); + } +} +/* }}} */ + +/* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true]) + Exports a CSR to file or a var */ +PHP_FUNCTION(openssl_csr_export) +{ + X509_REQ * csr; + zval * zcsr = NULL, *zout=NULL; + zend_bool notext = 1; + BIO * bio_out; + zend_resource *csr_resource; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|b", &zcsr, &zout, ¬ext) == FAILURE) { + return; + } + + RETVAL_FALSE; + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); + if (csr == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); + return; + } + + /* export to a var */ + + bio_out = BIO_new(BIO_s_mem()); + if (!notext && !X509_REQ_print(bio_out, csr)) { + php_openssl_store_errors(); + } + + if (PEM_write_bio_X509_REQ(bio_out, csr)) { + BUF_MEM *bio_buf; + + BIO_get_mem_ptr(bio_out, &bio_buf); + zval_dtor(zout); + ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + + if (csr_resource == NULL && csr) { + X509_REQ_free(csr); + } + BIO_free(bio_out); +} +/* }}} */ + +/* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]]) + Signs a cert with another CERT */ +PHP_FUNCTION(openssl_csr_sign) +{ + zval * zcert = NULL, *zcsr, *zpkey, *args = NULL; + zend_long num_days; + zend_long serial = Z_L(0); + X509 * cert = NULL, *new_cert = NULL; + X509_REQ * csr; + EVP_PKEY * key = NULL, *priv_key = NULL; + zend_resource *csr_resource, *certresource = NULL, *keyresource = NULL; + int i; + struct php_x509_request req; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz!zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE) + return; + + RETVAL_FALSE; + PHP_SSL_REQ_INIT(&req); + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); + if (csr == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1"); + return; + } + if (zcert) { + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 2"); + goto cleanup; + } + } + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); + if (priv_key == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); + goto cleanup; + } + if (cert && !X509_check_private_key(cert, priv_key)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "private key does not correspond to signing cert"); + goto cleanup; + } + + if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) { + goto cleanup; + } + /* Check that the request matches the signature */ + key = X509_REQ_get_pubkey(csr); + if (key == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error unpacking public key"); + goto cleanup; + } + i = X509_REQ_verify(csr, key); + + if (i < 0) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Signature verification problems"); + goto cleanup; + } + else if (i == 0) { + php_error_docref(NULL, E_WARNING, "Signature did not match the certificate request"); + goto cleanup; + } + + /* Now we can get on with it */ + + new_cert = X509_new(); + if (new_cert == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "No memory"); + goto cleanup; + } + /* Version 3 cert */ + if (!X509_set_version(new_cert, 2)) { + goto cleanup; + } + + + ASN1_INTEGER_set(X509_get_serialNumber(new_cert), (long)serial); + + X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr)); + + if (cert == NULL) { + cert = new_cert; + } + if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) { + php_openssl_store_errors(); + goto cleanup; + } + X509_gmtime_adj(X509_get_notBefore(new_cert), 0); + X509_gmtime_adj(X509_get_notAfter(new_cert), 60*60*24*(long)num_days); + i = X509_set_pubkey(new_cert, key); + if (!i) { + php_openssl_store_errors(); + goto cleanup; + } + if (req.extensions_section) { + X509V3_CTX ctx; + + X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0); + X509V3_set_conf_lhash(&ctx, req.req_config); + if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) { + php_openssl_store_errors(); + goto cleanup; + } + } + + /* Now sign it */ + if (!X509_sign(new_cert, priv_key, req.digest)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "failed to sign it"); + goto cleanup; + } + + /* Succeeded; lets return the cert */ + ZVAL_RES(return_value, zend_register_resource(new_cert, le_x509)); + new_cert = NULL; + +cleanup: + + if (cert == new_cert) { + cert = NULL; + } + PHP_SSL_REQ_DISPOSE(&req); + + if (keyresource == NULL && priv_key) { + EVP_PKEY_free(priv_key); + } + if (key) { + EVP_PKEY_free(key); + } + if (csr_resource == NULL && csr) { + X509_REQ_free(csr); + } + if (zcert && certresource == NULL && cert) { + X509_free(cert); + } + if (new_cert) { + X509_free(new_cert); + } +} +/* }}} */ + +/* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs [, array extraattribs]]) + Generates a privkey and CSR */ +PHP_FUNCTION(openssl_csr_new) +{ + struct php_x509_request req; + zval * args = NULL, * dn, *attribs = NULL; + zval * out_pkey; + X509_REQ * csr = NULL; + int we_made_the_key = 1; + zend_resource *key_resource; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "az/|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) { + return; + } + RETVAL_FALSE; + + PHP_SSL_REQ_INIT(&req); + + if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { + /* Generate or use a private key */ + if (Z_TYPE_P(out_pkey) != IS_NULL) { + req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, 0, &key_resource); + if (req.priv_key != NULL) { + we_made_the_key = 0; + } + } + if (req.priv_key == NULL) { + php_openssl_generate_private_key(&req); + } + if (req.priv_key == NULL) { + php_error_docref(NULL, E_WARNING, "Unable to generate a private key"); + } else { + csr = X509_REQ_new(); + if (csr) { + if (php_openssl_make_REQ(&req, csr, dn, attribs) == SUCCESS) { + X509V3_CTX ext_ctx; + + X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0); + X509V3_set_conf_lhash(&ext_ctx, req.req_config); + + /* Add extensions */ + if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config, + &ext_ctx, req.request_extensions_section, csr)) + { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Error loading extension section %s", req.request_extensions_section); + } else { + RETVAL_TRUE; + + if (X509_REQ_sign(csr, req.priv_key, req.digest)) { + ZVAL_RES(return_value, zend_register_resource(csr, le_csr)); + csr = NULL; + } else { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Error signing request"); + } + + if (we_made_the_key) { + /* and a resource for the private key */ + zval_dtor(out_pkey); + ZVAL_RES(out_pkey, zend_register_resource(req.priv_key, le_key)); + req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ + } else if (key_resource != NULL) { + req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ + } + } + } + else { + if (!we_made_the_key) { + /* if we have not made the key we are not supposed to zap it by calling dispose! */ + req.priv_key = NULL; + } + } + } else { + php_openssl_store_errors(); + } + + } + } + if (csr) { + X509_REQ_free(csr); + } + PHP_SSL_REQ_DISPOSE(&req); +} +/* }}} */ + +/* {{{ proto mixed openssl_csr_get_subject(mixed csr) + Returns the subject of a CERT or FALSE on error */ +PHP_FUNCTION(openssl_csr_get_subject) +{ + zval * zcsr; + zend_bool use_shortnames = 1; + zend_resource *csr_resource; + X509_NAME * subject; + X509_REQ * csr; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) { + return; + } + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); + + if (csr == NULL) { + RETURN_FALSE; + } + + subject = X509_REQ_get_subject_name(csr); + + array_init(return_value); + php_openssl_add_assoc_name_entry(return_value, NULL, subject, use_shortnames); + return; +} +/* }}} */ + +/* {{{ proto mixed openssl_csr_get_public_key(mixed csr) + Returns the subject of a CERT or FALSE on error */ +PHP_FUNCTION(openssl_csr_get_public_key) +{ + zval * zcsr; + zend_bool use_shortnames = 1; + zend_resource *csr_resource; + + X509_REQ * csr; + EVP_PKEY *tpubkey; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) { + return; + } + + csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource); + + if (csr == NULL) { + RETURN_FALSE; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + /* Due to changes in OpenSSL 1.1 related to locking when decoding CSR, + * the pub key is not changed after assigning. It means if we pass + * a private key, it will be returned including the private part. + * If we duplicate it, then we get just the public part which is + * the same behavior as for OpenSSL 1.0 */ + csr = X509_REQ_dup(csr); +#endif + /* Retrieve the public key from the CSR */ + tpubkey = X509_REQ_get_pubkey(csr); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) + /* We need to free the CSR as it was duplicated */ + X509_REQ_free(csr); +#endif + + if (tpubkey == NULL) { + php_openssl_store_errors(); + RETURN_FALSE; + } + + RETURN_RES(zend_register_resource(tpubkey, le_key)); +} +/* }}} */ + +/* }}} */ + +/* {{{ EVP Public/Private key functions */ + +struct php_openssl_pem_password { + char *key; + int len; +}; + +/* {{{ php_openssl_pem_password_cb */ +static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata) +{ + struct php_openssl_pem_password *password = userdata; + + if (password == NULL || password->key == NULL) { + return -1; + } + + size = (password->len > size) ? size : password->len; + memcpy(buf, password->key, size); + + return size; +} +/* }}} */ + +/* {{{ php_openssl_evp_from_zval + Given a zval, coerce it into a EVP_PKEY object. + It can be: + 1. private key resource from openssl_get_privatekey() + 2. X509 resource -> public key will be extracted from it + 3. if it starts with file:// interpreted as path to key file + 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey() + 5. an array(0 => [items 2..4], 1 => passphrase) + 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key + NOTE: If you are requesting a private key but have not specified a passphrase, you should use an + empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in + the Apache error log! +*/ +static EVP_PKEY * php_openssl_evp_from_zval( + zval * val, int public_key, char *passphrase, size_t passphrase_len, + int makeresource, zend_resource **resourceval) +{ + EVP_PKEY * key = NULL; + X509 * cert = NULL; + int free_cert = 0; + zend_resource *cert_res = NULL; + char * filename = NULL; + zval tmp; + + ZVAL_NULL(&tmp); + +#define TMP_CLEAN \ + if (Z_TYPE(tmp) == IS_STRING) {\ + zval_dtor(&tmp); \ + } \ + return NULL; + + if (resourceval) { + *resourceval = NULL; + } + if (Z_TYPE_P(val) == IS_ARRAY) { + zval * zphrase; + + /* get passphrase */ + + if ((zphrase = zend_hash_index_find(Z_ARRVAL_P(val), 1)) == NULL) { + php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); + return NULL; + } + + if (Z_TYPE_P(zphrase) == IS_STRING) { + passphrase = Z_STRVAL_P(zphrase); + passphrase_len = Z_STRLEN_P(zphrase); + } else { + ZVAL_COPY(&tmp, zphrase); + convert_to_string(&tmp); + passphrase = Z_STRVAL(tmp); + passphrase_len = Z_STRLEN(tmp); + } + + /* now set val to be the key param and continue */ + if ((val = zend_hash_index_find(Z_ARRVAL_P(val), 0)) == NULL) { + php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)"); + TMP_CLEAN; + } + } + + if (Z_TYPE_P(val) == IS_RESOURCE) { + void * what; + zend_resource * res = Z_RES_P(val); + + what = zend_fetch_resource2(res, "OpenSSL X.509/key", le_x509, le_key); + if (!what) { + TMP_CLEAN; + } + if (resourceval) { + *resourceval = res; + Z_ADDREF_P(val); + } + if (res->type == le_x509) { + /* extract key from cert, depending on public_key param */ + cert = (X509*)what; + free_cert = 0; + } else if (res->type == le_key) { + int is_priv; + + is_priv = php_openssl_is_private_key((EVP_PKEY*)what); + + /* check whether it is actually a private key if requested */ + if (!public_key && !is_priv) { + php_error_docref(NULL, E_WARNING, "supplied key param is a public key"); + TMP_CLEAN; + } + + if (public_key && is_priv) { + php_error_docref(NULL, E_WARNING, "Don't know how to get public key from this private key"); + TMP_CLEAN; + } else { + if (Z_TYPE(tmp) == IS_STRING) { + zval_dtor(&tmp); + } + /* got the key - return it */ + return (EVP_PKEY*)what; + } + } else { + /* other types could be used here - eg: file pointers and read in the data from them */ + TMP_CLEAN; + } + } else { + /* force it to be a string and check if it refers to a file */ + /* passing non string values leaks, object uses toString, it returns NULL + * See bug38255.phpt + */ + if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) { + TMP_CLEAN; + } + convert_to_string_ex(val); + + if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) { + filename = Z_STRVAL_P(val) + (sizeof("file://") - 1); + } + /* it's an X509 file/cert of some kind, and we need to extract the data from that */ + if (public_key) { + cert = php_openssl_x509_from_zval(val, 0, &cert_res); + free_cert = (cert_res == NULL); + /* actual extraction done later */ + if (!cert) { + /* not a X509 certificate, try to retrieve public key */ + BIO* in; + if (filename) { + in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + } else { + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); + } + if (in == NULL) { + php_openssl_store_errors(); + TMP_CLEAN; + } + key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL); + BIO_free(in); + } + } else { + /* we want the private key */ + BIO *in; + + if (filename) { + if (php_openssl_open_base_dir_chk(filename)) { + TMP_CLEAN; + } + in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + } else { + in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val)); + } + + if (in == NULL) { + TMP_CLEAN; + } + if (passphrase == NULL) { + key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + } else { + struct php_openssl_pem_password password; + password.key = passphrase; + password.len = passphrase_len; + key = PEM_read_bio_PrivateKey(in, NULL, php_openssl_pem_password_cb, &password); + } + BIO_free(in); + } + } + + if (key == NULL) { + php_openssl_store_errors(); + + if (public_key && cert) { + /* extract public key from X509 cert */ + key = (EVP_PKEY *) X509_get_pubkey(cert); + if (key == NULL) { + php_openssl_store_errors(); + } + } + } + + if (free_cert && cert) { + X509_free(cert); + } + if (key && makeresource && resourceval) { + *resourceval = zend_register_resource(key, le_key); + } + if (Z_TYPE(tmp) == IS_STRING) { + zval_dtor(&tmp); + } + return key; +} +/* }}} */ + +/* {{{ php_openssl_generate_private_key */ +static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) +{ + char * randfile = NULL; + int egdsocket, seeded; + EVP_PKEY * return_val = NULL; + + if (req->priv_key_bits < MIN_KEY_LENGTH) { + php_error_docref(NULL, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d", + MIN_KEY_LENGTH, req->priv_key_bits); + return NULL; + } + + randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE"); + if (randfile == NULL) { + php_openssl_store_errors(); + } + php_openssl_load_rand_file(randfile, &egdsocket, &seeded); + + if ((req->priv_key = EVP_PKEY_new()) != NULL) { + switch(req->priv_key_type) { + case OPENSSL_KEYTYPE_RSA: + { + RSA* rsaparam; +#if OPENSSL_VERSION_NUMBER < 0x10002000L + /* OpenSSL 1.0.2 deprecates RSA_generate_key */ + PHP_OPENSSL_RAND_ADD_TIME(); + rsaparam = (RSA*)RSA_generate_key(req->priv_key_bits, RSA_F4, NULL, NULL); +#else + { + BIGNUM *bne = (BIGNUM *)BN_new(); + if (BN_set_word(bne, RSA_F4) != 1) { + BN_free(bne); + php_error_docref(NULL, E_WARNING, "failed setting exponent"); + return NULL; + } + rsaparam = RSA_new(); + PHP_OPENSSL_RAND_ADD_TIME(); + if (rsaparam == NULL || !RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL)) { + php_openssl_store_errors(); + } + BN_free(bne); + } +#endif + if (rsaparam && EVP_PKEY_assign_RSA(req->priv_key, rsaparam)) { + return_val = req->priv_key; + } else { + php_openssl_store_errors(); + } + } + break; +#if !defined(NO_DSA) + case OPENSSL_KEYTYPE_DSA: + PHP_OPENSSL_RAND_ADD_TIME(); + { + DSA *dsaparam = DSA_new(); + if (dsaparam && DSA_generate_parameters_ex(dsaparam, req->priv_key_bits, NULL, 0, NULL, NULL, NULL)) { + DSA_set_method(dsaparam, DSA_get_default_method()); + if (DSA_generate_key(dsaparam)) { + if (EVP_PKEY_assign_DSA(req->priv_key, dsaparam)) { + return_val = req->priv_key; + } else { + php_openssl_store_errors(); + } + } else { + php_openssl_store_errors(); + DSA_free(dsaparam); + } + } else { + php_openssl_store_errors(); + } + } + break; +#endif +#if !defined(NO_DH) + case OPENSSL_KEYTYPE_DH: + PHP_OPENSSL_RAND_ADD_TIME(); + { + int codes = 0; + DH *dhparam = DH_new(); + if (dhparam && DH_generate_parameters_ex(dhparam, req->priv_key_bits, 2, NULL)) { + DH_set_method(dhparam, DH_get_default_method()); + if (DH_check(dhparam, &codes) && codes == 0 && DH_generate_key(dhparam)) { + if (EVP_PKEY_assign_DH(req->priv_key, dhparam)) { + return_val = req->priv_key; + } else { + php_openssl_store_errors(); + } + } else { + php_openssl_store_errors(); + DH_free(dhparam); + } + } else { + php_openssl_store_errors(); + } + } + break; +#endif +#ifdef HAVE_EVP_PKEY_EC + case OPENSSL_KEYTYPE_EC: + { + EC_KEY *eckey; + if (req->curve_name == NID_undef) { + php_error_docref(NULL, E_WARNING, "Missing configuration value: 'curve_name' not set"); + return NULL; + } + eckey = EC_KEY_new_by_curve_name(req->curve_name); + if (eckey) { + EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_generate_key(eckey) && + EVP_PKEY_assign_EC_KEY(req->priv_key, eckey)) { + return_val = req->priv_key; + } else { + EC_KEY_free(eckey); + } + } + } + break; +#endif + default: + php_error_docref(NULL, E_WARNING, "Unsupported private key type"); + } + } else { + php_openssl_store_errors(); + } + + php_openssl_write_rand_file(randfile, egdsocket, seeded); + + if (return_val == NULL) { + EVP_PKEY_free(req->priv_key); + req->priv_key = NULL; + return NULL; + } + + return return_val; +} +/* }}} */ + +/* {{{ php_openssl_is_private_key + Check whether the supplied key is a private key by checking if the secret prime factors are set */ +static int php_openssl_is_private_key(EVP_PKEY* pkey) +{ + assert(pkey != NULL); + + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + { + RSA *rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa != NULL) { + const BIGNUM *p, *q; + + RSA_get0_factors(rsa, &p, &q); + if (p == NULL || q == NULL) { + return 0; + } + } + } + break; + case EVP_PKEY_DSA: + case EVP_PKEY_DSA1: + case EVP_PKEY_DSA2: + case EVP_PKEY_DSA3: + case EVP_PKEY_DSA4: + { + DSA *dsa = EVP_PKEY_get0_DSA(pkey); + if (dsa != NULL) { + const BIGNUM *p, *q, *g, *pub_key, *priv_key; + + DSA_get0_pqg(dsa, &p, &q, &g); + if (p == NULL || q == NULL) { + return 0; + } + + DSA_get0_key(dsa, &pub_key, &priv_key); + if (priv_key == NULL) { + return 0; + } + } + } + break; + case EVP_PKEY_DH: + { + DH *dh = EVP_PKEY_get0_DH(pkey); + if (dh != NULL) { + const BIGNUM *p, *q, *g, *pub_key, *priv_key; + + DH_get0_pqg(dh, &p, &q, &g); + if (p == NULL) { + return 0; + } + + DH_get0_key(dh, &pub_key, &priv_key); + if (priv_key == NULL) { + return 0; + } + } + } + break; +#ifdef HAVE_EVP_PKEY_EC + case EVP_PKEY_EC: + { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + if (ec != NULL && NULL == EC_KEY_get0_private_key(ec)) { + return 0; + } + } + break; +#endif + default: + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + break; + } + return 1; +} +/* }}} */ + +#define OPENSSL_GET_BN(_array, _bn, _name) do { \ + if (_bn != NULL) { \ + int len = BN_num_bytes(_bn); \ + zend_string *str = zend_string_alloc(len, 0); \ + BN_bn2bin(_bn, (unsigned char*)ZSTR_VAL(str)); \ + ZSTR_VAL(str)[len] = 0; \ + add_assoc_str(&_array, #_name, str); \ + } \ + } while (0); + +#define OPENSSL_PKEY_GET_BN(_type, _name) OPENSSL_GET_BN(_type, _name, _name) + +#define OPENSSL_PKEY_SET_BN(_data, _name) do { \ + zval *bn; \ + if ((bn = zend_hash_str_find(Z_ARRVAL_P(_data), #_name, sizeof(#_name)-1)) != NULL && \ + Z_TYPE_P(bn) == IS_STRING) { \ + _name = BN_bin2bn( \ + (unsigned char*)Z_STRVAL_P(bn), \ + (int)Z_STRLEN_P(bn), NULL); \ + } else { \ + _name = NULL; \ + } \ + } while (0); + +/* {{{ php_openssl_pkey_init_rsa */ +static zend_bool php_openssl_pkey_init_and_assign_rsa(EVP_PKEY *pkey, RSA *rsa, zval *data) +{ + BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; + + OPENSSL_PKEY_SET_BN(data, n); + OPENSSL_PKEY_SET_BN(data, e); + OPENSSL_PKEY_SET_BN(data, d); + if (!n || !d || !RSA_set0_key(rsa, n, e, d)) { + return 0; + } + + OPENSSL_PKEY_SET_BN(data, p); + OPENSSL_PKEY_SET_BN(data, q); + if ((p || q) && !RSA_set0_factors(rsa, p, q)) { + return 0; + } + + OPENSSL_PKEY_SET_BN(data, dmp1); + OPENSSL_PKEY_SET_BN(data, dmq1); + OPENSSL_PKEY_SET_BN(data, iqmp); + if ((dmp1 || dmq1 || iqmp) && !RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp)) { + return 0; + } + + if (!EVP_PKEY_assign_RSA(pkey, rsa)) { + php_openssl_store_errors(); + return 0; + } + + return 1; +} + +/* {{{ php_openssl_pkey_init_dsa */ +static zend_bool php_openssl_pkey_init_dsa(DSA *dsa, zval *data) +{ + BIGNUM *p, *q, *g, *priv_key, *pub_key; + const BIGNUM *priv_key_const, *pub_key_const; + + OPENSSL_PKEY_SET_BN(data, p); + OPENSSL_PKEY_SET_BN(data, q); + OPENSSL_PKEY_SET_BN(data, g); + if (!p || !q || !g || !DSA_set0_pqg(dsa, p, q, g)) { + return 0; + } + + OPENSSL_PKEY_SET_BN(data, pub_key); + OPENSSL_PKEY_SET_BN(data, priv_key); + if (pub_key) { + return DSA_set0_key(dsa, pub_key, priv_key); + } + + /* generate key */ + PHP_OPENSSL_RAND_ADD_TIME(); + if (!DSA_generate_key(dsa)) { + php_openssl_store_errors(); + return 0; + } + + /* if BN_mod_exp return -1, then DSA_generate_key succeed for failed key + * so we need to double check that public key is created */ + DSA_get0_key(dsa, &pub_key_const, &priv_key_const); + if (!pub_key_const || BN_is_zero(pub_key_const)) { + return 0; + } + /* all good */ + return 1; +} +/* }}} */ + +/* {{{ php_openssl_dh_pub_from_priv */ +static BIGNUM *php_openssl_dh_pub_from_priv(BIGNUM *priv_key, BIGNUM *g, BIGNUM *p) +{ + BIGNUM *pub_key, *priv_key_const_time; + BN_CTX *ctx; + + pub_key = BN_new(); + if (pub_key == NULL) { + php_openssl_store_errors(); + return NULL; + } + + priv_key_const_time = BN_new(); + if (priv_key_const_time == NULL) { + BN_free(pub_key); + php_openssl_store_errors(); + return NULL; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + BN_free(pub_key); + BN_free(priv_key_const_time); + php_openssl_store_errors(); + return NULL; + } + + BN_with_flags(priv_key_const_time, priv_key, BN_FLG_CONSTTIME); + + if (!BN_mod_exp_mont(pub_key, g, priv_key_const_time, p, ctx, NULL)) { + BN_free(pub_key); + php_openssl_store_errors(); + pub_key = NULL; + } + + BN_free(priv_key_const_time); + BN_CTX_free(ctx); + + return pub_key; +} +/* }}} */ + +/* {{{ php_openssl_pkey_init_dh */ +static zend_bool php_openssl_pkey_init_dh(DH *dh, zval *data) +{ + BIGNUM *p, *q, *g, *priv_key, *pub_key; + + OPENSSL_PKEY_SET_BN(data, p); + OPENSSL_PKEY_SET_BN(data, q); + OPENSSL_PKEY_SET_BN(data, g); + if (!p || !g || !DH_set0_pqg(dh, p, q, g)) { + return 0; + } + + OPENSSL_PKEY_SET_BN(data, priv_key); + OPENSSL_PKEY_SET_BN(data, pub_key); + if (pub_key) { + return DH_set0_key(dh, pub_key, priv_key); + } + if (priv_key) { + pub_key = php_openssl_dh_pub_from_priv(priv_key, g, p); + if (pub_key == NULL) { + return 0; + } + return DH_set0_key(dh, pub_key, priv_key); + } + + /* generate key */ + PHP_OPENSSL_RAND_ADD_TIME(); + if (!DH_generate_key(dh)) { + php_openssl_store_errors(); + return 0; + } + /* all good */ + return 1; +} +/* }}} */ + +/* {{{ proto resource openssl_pkey_new([array configargs]) + Generates a new private key */ +PHP_FUNCTION(openssl_pkey_new) +{ + struct php_x509_request req; + zval * args = NULL; + zval *data; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &args) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (args && Z_TYPE_P(args) == IS_ARRAY) { + EVP_PKEY *pkey; + + if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa")-1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { + RSA *rsa = RSA_new(); + if (rsa) { + if (php_openssl_pkey_init_and_assign_rsa(pkey, rsa, data)) { + RETURN_RES(zend_register_resource(pkey, le_key)); + } + RSA_free(rsa); + } else { + php_openssl_store_errors(); + } + EVP_PKEY_free(pkey); + } else { + php_openssl_store_errors(); + } + RETURN_FALSE; + } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { + DSA *dsa = DSA_new(); + if (dsa) { + if (php_openssl_pkey_init_dsa(dsa, data)) { + if (EVP_PKEY_assign_DSA(pkey, dsa)) { + RETURN_RES(zend_register_resource(pkey, le_key)); + } else { + php_openssl_store_errors(); + } + } + DSA_free(dsa); + } else { + php_openssl_store_errors(); + } + EVP_PKEY_free(pkey); + } else { + php_openssl_store_errors(); + } + RETURN_FALSE; + } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + pkey = EVP_PKEY_new(); + if (pkey) { + DH *dh = DH_new(); + if (dh) { + if (php_openssl_pkey_init_dh(dh, data)) { + if (EVP_PKEY_assign_DH(pkey, dh)) { + ZVAL_COPY_VALUE(return_value, zend_list_insert(pkey, le_key)); + return; + } else { + php_openssl_store_errors(); + } + } + DH_free(dh); + } else { + php_openssl_store_errors(); + } + EVP_PKEY_free(pkey); + } else { + php_openssl_store_errors(); + } + RETURN_FALSE; +#ifdef HAVE_EVP_PKEY_EC + } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ec", sizeof("ec") - 1)) != NULL && + Z_TYPE_P(data) == IS_ARRAY) { + EC_KEY *eckey = NULL; + EC_GROUP *group = NULL; + EC_POINT *pnt = NULL; + const BIGNUM *d; + pkey = EVP_PKEY_new(); + if (pkey) { + eckey = EC_KEY_new(); + if (eckey) { + EC_GROUP *group = NULL; + zval *bn; + zval *x; + zval *y; + + if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1)) != NULL && + Z_TYPE_P(bn) == IS_STRING) { + int nid = OBJ_sn2nid(Z_STRVAL_P(bn)); + if (nid != NID_undef) { + group = EC_GROUP_new_by_curve_name(nid); + if (!group) { + php_openssl_store_errors(); + goto clean_exit; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); + if (!EC_KEY_set_group(eckey, group)) { + php_openssl_store_errors(); + goto clean_exit; + } + } + } + + if (group == NULL) { + php_error_docref(NULL, E_WARNING, "Unknown curve_name"); + goto clean_exit; + } + + // The public key 'pnt' can be calculated from 'd' or is defined by 'x' and 'y' + if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "d", sizeof("d") - 1)) != NULL && + Z_TYPE_P(bn) == IS_STRING) { + d = BN_bin2bn((unsigned char*) Z_STRVAL_P(bn), Z_STRLEN_P(bn), NULL); + if (!EC_KEY_set_private_key(eckey, d)) { + php_openssl_store_errors(); + goto clean_exit; + } + // Calculate the public key by multiplying the Point Q with the public key + // P = d * Q + pnt = EC_POINT_new(group); + if (!pnt || !EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) { + php_openssl_store_errors(); + goto clean_exit; + } + } else if ((x = zend_hash_str_find(Z_ARRVAL_P(data), "x", sizeof("x") - 1)) != NULL && + Z_TYPE_P(x) == IS_STRING && + (y = zend_hash_str_find(Z_ARRVAL_P(data), "y", sizeof("y") - 1)) != NULL && + Z_TYPE_P(y) == IS_STRING) { + pnt = EC_POINT_new(group); + if (pnt == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + if (!EC_POINT_set_affine_coordinates_GFp( + group, pnt, BN_bin2bn((unsigned char*) Z_STRVAL_P(x), Z_STRLEN_P(x), NULL), + BN_bin2bn((unsigned char*) Z_STRVAL_P(y), Z_STRLEN_P(y), NULL), NULL)) { + php_openssl_store_errors(); + goto clean_exit; + } + } + + if (pnt != NULL) { + if (!EC_KEY_set_public_key(eckey, pnt)) { + php_openssl_store_errors(); + goto clean_exit; + } + EC_POINT_free(pnt); + pnt = NULL; + } + + if (!EC_KEY_check_key(eckey)) { + PHP_OPENSSL_RAND_ADD_TIME(); + EC_KEY_generate_key(eckey); + php_openssl_store_errors(); + } + if (EC_KEY_check_key(eckey) && EVP_PKEY_assign_EC_KEY(pkey, eckey)) { + EC_GROUP_free(group); + RETURN_RES(zend_register_resource(pkey, le_key)); + } else { + php_openssl_store_errors(); + } + } else { + php_openssl_store_errors(); + } + } else { + php_openssl_store_errors(); + } +clean_exit: + if (pnt != NULL) { + EC_POINT_free(pnt); + } + if (group != NULL) { + EC_GROUP_free(group); + } + if (eckey != NULL) { + EC_KEY_free(eckey); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + RETURN_FALSE; +#endif + } + } + + PHP_SSL_REQ_INIT(&req); + + if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { + if (php_openssl_generate_private_key(&req)) { + /* pass back a key resource */ + RETVAL_RES(zend_register_resource(req.priv_key, le_key)); + /* make sure the cleanup code doesn't zap it! */ + req.priv_key = NULL; + } + } + PHP_SSL_REQ_DISPOSE(&req); +} +/* }}} */ + +/* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args) + Gets an exportable representation of a key into a file */ +PHP_FUNCTION(openssl_pkey_export_to_file) +{ + struct php_x509_request req; + zval * zpkey, * args = NULL; + char * passphrase = NULL; + size_t passphrase_len = 0; + char * filename = NULL; + size_t filename_len = 0; + zend_resource *key_resource = NULL; + int pem_write = 0; + EVP_PKEY * key; + BIO * bio_out = NULL; + const EVP_CIPHER * cipher; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) { + return; + } + RETVAL_FALSE; + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource); + + if (key == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); + RETURN_FALSE; + } + + if (php_openssl_open_base_dir_chk(filename)) { + RETURN_FALSE; + } + + PHP_SSL_REQ_INIT(&req); + + if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { + bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (bio_out == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + if (passphrase && req.priv_key_encrypt) { + if (req.priv_key_encrypt_cipher) { + cipher = req.priv_key_encrypt_cipher; + } else { + cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + } + } else { + cipher = NULL; + } + + switch (EVP_PKEY_base_id(key)) { +#ifdef HAVE_EVP_PKEY_EC + case EVP_PKEY_EC: + pem_write = PEM_write_bio_ECPrivateKey( + bio_out, EVP_PKEY_get0_EC_KEY(key), cipher, + (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); + break; +#endif + default: + pem_write = PEM_write_bio_PrivateKey( + bio_out, key, cipher, + (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); + break; + } + + if (pem_write) { + /* Success! + * If returning the output as a string, do so now */ + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + } + +clean_exit: + PHP_SSL_REQ_DISPOSE(&req); + + if (key_resource == NULL && key) { + EVP_PKEY_free(key); + } + if (bio_out) { + BIO_free(bio_out); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]]) + Gets an exportable representation of a key into a string or file */ +PHP_FUNCTION(openssl_pkey_export) +{ + struct php_x509_request req; + zval * zpkey, * args = NULL, *out; + char * passphrase = NULL; size_t passphrase_len = 0; + int pem_write = 0; + zend_resource *key_resource = NULL; + EVP_PKEY * key; + BIO * bio_out = NULL; + const EVP_CIPHER * cipher; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) { + return; + } + RETVAL_FALSE; + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource); + + if (key == NULL) { + php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); + RETURN_FALSE; + } + + PHP_SSL_REQ_INIT(&req); + + if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { + bio_out = BIO_new(BIO_s_mem()); + + if (passphrase && req.priv_key_encrypt) { + if (req.priv_key_encrypt_cipher) { + cipher = req.priv_key_encrypt_cipher; + } else { + cipher = (EVP_CIPHER *) EVP_des_ede3_cbc(); + } + } else { + cipher = NULL; + } + + switch (EVP_PKEY_base_id(key)) { +#ifdef HAVE_EVP_PKEY_EC + case EVP_PKEY_EC: + pem_write = PEM_write_bio_ECPrivateKey( + bio_out, EVP_PKEY_get0_EC_KEY(key), cipher, + (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); + break; +#endif + default: + pem_write = PEM_write_bio_PrivateKey( + bio_out, key, cipher, + (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL); + break; + } + + if (pem_write) { + /* Success! + * If returning the output as a string, do so now */ + + char * bio_mem_ptr; + long bio_mem_len; + RETVAL_TRUE; + + bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr); + zval_dtor(out); + ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len); + } else { + php_openssl_store_errors(); + } + } + PHP_SSL_REQ_DISPOSE(&req); + + if (key_resource == NULL && key) { + EVP_PKEY_free(key); + } + if (bio_out) { + BIO_free(bio_out); + } +} +/* }}} */ + +/* {{{ proto int openssl_pkey_get_public(mixed cert) + Gets public key from X.509 certificate */ +PHP_FUNCTION(openssl_pkey_get_public) +{ + zval *cert; + EVP_PKEY *pkey; + zend_resource *res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) { + return; + } + pkey = php_openssl_evp_from_zval(cert, 1, NULL, 0, 1, &res); + if (pkey == NULL) { + RETURN_FALSE; + } + ZVAL_RES(return_value, res); + Z_ADDREF_P(return_value); +} +/* }}} */ + +/* {{{ proto void openssl_pkey_free(int key) + Frees a key */ +PHP_FUNCTION(openssl_pkey_free) +{ + zval *key; + EVP_PKEY *pkey; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) { + return; + } + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { + RETURN_FALSE; + } + zend_list_close(Z_RES_P(key)); +} +/* }}} */ + +/* {{{ proto int openssl_pkey_get_private(string key [, string passphrase]) + Gets private keys */ +PHP_FUNCTION(openssl_pkey_get_private) +{ + zval *cert; + EVP_PKEY *pkey; + char * passphrase = ""; + size_t passphrase_len = sizeof("")-1; + zend_resource *res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) { + return; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + pkey = php_openssl_evp_from_zval(cert, 0, passphrase, passphrase_len, 1, &res); + + if (pkey == NULL) { + RETURN_FALSE; + } + ZVAL_RES(return_value, res); + Z_ADDREF_P(return_value); +} + +/* }}} */ + +/* {{{ proto resource openssl_pkey_get_details(resource key) + returns an array with the key details (bits, pkey, type)*/ +PHP_FUNCTION(openssl_pkey_get_details) +{ + zval *key; + EVP_PKEY *pkey; + BIO *out; + unsigned int pbio_len; + char *pbio; + zend_long ktype; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) { + return; + } + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { + RETURN_FALSE; + } + out = BIO_new(BIO_s_mem()); + if (!PEM_write_bio_PUBKEY(out, pkey)) { + BIO_free(out); + php_openssl_store_errors(); + RETURN_FALSE; + } + pbio_len = BIO_get_mem_data(out, &pbio); + + array_init(return_value); + add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey)); + add_assoc_stringl(return_value, "key", pbio, pbio_len); + /*TODO: Use the real values once the openssl constants are used + * See the enum at the top of this file + */ + switch (EVP_PKEY_base_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + { + RSA *rsa = EVP_PKEY_get0_RSA(pkey); + ktype = OPENSSL_KEYTYPE_RSA; + + if (rsa != NULL) { + zval z_rsa; + const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; + + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + + array_init(&z_rsa); + OPENSSL_PKEY_GET_BN(z_rsa, n); + OPENSSL_PKEY_GET_BN(z_rsa, e); + OPENSSL_PKEY_GET_BN(z_rsa, d); + OPENSSL_PKEY_GET_BN(z_rsa, p); + OPENSSL_PKEY_GET_BN(z_rsa, q); + OPENSSL_PKEY_GET_BN(z_rsa, dmp1); + OPENSSL_PKEY_GET_BN(z_rsa, dmq1); + OPENSSL_PKEY_GET_BN(z_rsa, iqmp); + add_assoc_zval(return_value, "rsa", &z_rsa); + } + } + break; + case EVP_PKEY_DSA: + case EVP_PKEY_DSA2: + case EVP_PKEY_DSA3: + case EVP_PKEY_DSA4: + { + DSA *dsa = EVP_PKEY_get0_DSA(pkey); + ktype = OPENSSL_KEYTYPE_DSA; + + if (dsa != NULL) { + zval z_dsa; + const BIGNUM *p, *q, *g, *priv_key, *pub_key; + + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, &priv_key); + + array_init(&z_dsa); + OPENSSL_PKEY_GET_BN(z_dsa, p); + OPENSSL_PKEY_GET_BN(z_dsa, q); + OPENSSL_PKEY_GET_BN(z_dsa, g); + OPENSSL_PKEY_GET_BN(z_dsa, priv_key); + OPENSSL_PKEY_GET_BN(z_dsa, pub_key); + add_assoc_zval(return_value, "dsa", &z_dsa); + } + } + break; + case EVP_PKEY_DH: + { + DH *dh = EVP_PKEY_get0_DH(pkey); + ktype = OPENSSL_KEYTYPE_DH; + + if (dh != NULL) { + zval z_dh; + const BIGNUM *p, *q, *g, *priv_key, *pub_key; + + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, &priv_key); + + array_init(&z_dh); + OPENSSL_PKEY_GET_BN(z_dh, p); + OPENSSL_PKEY_GET_BN(z_dh, g); + OPENSSL_PKEY_GET_BN(z_dh, priv_key); + OPENSSL_PKEY_GET_BN(z_dh, pub_key); + add_assoc_zval(return_value, "dh", &z_dh); + } + } + break; +#ifdef HAVE_EVP_PKEY_EC + case EVP_PKEY_EC: + ktype = OPENSSL_KEYTYPE_EC; + if (EVP_PKEY_get0_EC_KEY(pkey) != NULL) { + zval ec; + const EC_GROUP *ec_group; + const EC_POINT *pub; + int nid; + char *crv_sn; + ASN1_OBJECT *obj; + // openssl recommends a buffer length of 80 + char oir_buf[80]; + const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey); + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); + const BIGNUM *d; + + ec_group = EC_KEY_get0_group(ec_key); + + // Curve nid (numerical identifier) used for ASN1 mapping + nid = EC_GROUP_get_curve_name(ec_group); + if (nid == NID_undef) { + break; + } + array_init(&ec); + + // Short object name + crv_sn = (char*) OBJ_nid2sn(nid); + if (crv_sn != NULL) { + add_assoc_string(&ec, "curve_name", crv_sn); + } + + obj = OBJ_nid2obj(nid); + if (obj != NULL) { + int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1); + add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len); + ASN1_OBJECT_free(obj); + } + + pub = EC_KEY_get0_public_key(ec_key); + + if (EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x, y, NULL)) { + OPENSSL_GET_BN(ec, x, x); + OPENSSL_GET_BN(ec, y, y); + } else { + php_openssl_store_errors(); + } + + if ((d = EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(pkey))) != NULL) { + OPENSSL_GET_BN(ec, d, d); + } + + add_assoc_zval(return_value, "ec", &ec); + + BN_free(x); + BN_free(y); + } + break; +#endif + default: + ktype = -1; + break; + } + add_assoc_long(return_value, "type", ktype); + + BIO_free(out); +} +/* }}} */ + +/* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key) + Computes shared secret for public value of remote DH key and local DH key */ +PHP_FUNCTION(openssl_dh_compute_key) +{ + zval *key; + char *pub_str; + size_t pub_len; + DH *dh; + EVP_PKEY *pkey; + BIGNUM *pub; + zend_string *data; + int len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sr", &pub_str, &pub_len, &key) == FAILURE) { + return; + } + if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) { + RETURN_FALSE; + } + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { + RETURN_FALSE; + } + dh = EVP_PKEY_get0_DH(pkey); + if (dh == NULL) { + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key); + pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL); + + data = zend_string_alloc(DH_size(dh), 0); + len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh); + + if (len >= 0) { + ZSTR_LEN(data) = len; + ZSTR_VAL(data)[len] = 0; + RETVAL_STR(data); + } else { + php_openssl_store_errors(); + zend_string_release(data); + RETVAL_FALSE; + } + + BN_free(pub); +} +/* }}} */ + +/* }}} */ + +/* {{{ proto string openssl_pbkdf2(string password, string salt, long key_length, long iterations [, string digest_method = "sha1"]) + Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */ +PHP_FUNCTION(openssl_pbkdf2) +{ + zend_long key_length = 0, iterations = 0; + char *password; + size_t password_len; + char *salt; + size_t salt_len; + char *method; + size_t method_len = 0; + zend_string *out_buffer; + + const EVP_MD *digest; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssll|s", + &password, &password_len, + &salt, &salt_len, + &key_length, &iterations, + &method, &method_len) == FAILURE) { + return; + } + + if (key_length <= 0) { + RETURN_FALSE; + } + + if (method_len) { + digest = EVP_get_digestbyname(method); + } else { + digest = EVP_sha1(); + } + + if (!digest) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_LONG_TO_INT(key_length, key); + PHP_OPENSSL_CHECK_LONG_TO_INT(iterations, iterations); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(salt_len, salt); + + out_buffer = zend_string_alloc(key_length, 0); + + if (PKCS5_PBKDF2_HMAC(password, (int)password_len, (unsigned char *)salt, (int)salt_len, (int)iterations, digest, (int)key_length, (unsigned char*)ZSTR_VAL(out_buffer)) == 1) { + ZSTR_VAL(out_buffer)[key_length] = 0; + RETURN_NEW_STR(out_buffer); + } else { + php_openssl_store_errors(); + zend_string_release(out_buffer); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ PKCS7 S/MIME functions */ + +/* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content [, string pk7]]]]]) + Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */ +PHP_FUNCTION(openssl_pkcs7_verify) +{ + X509_STORE * store = NULL; + zval * cainfo = NULL; + STACK_OF(X509) *signers= NULL; + STACK_OF(X509) *others = NULL; + PKCS7 * p7 = NULL; + BIO * in = NULL, * datain = NULL, * dataout = NULL, * p7bout = NULL; + zend_long flags = 0; + char * filename; + size_t filename_len; + char * extracerts = NULL; + size_t extracerts_len = 0; + char * signersfilename = NULL; + size_t signersfilename_len = 0; + char * datafilename = NULL; + size_t datafilename_len = 0; + char * p7bfilename = NULL; + size_t p7bfilename_len = 0; + + RETVAL_LONG(-1); + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|pappp", &filename, &filename_len, + &flags, &signersfilename, &signersfilename_len, &cainfo, + &extracerts, &extracerts_len, &datafilename, &datafilename_len, &p7bfilename, &p7bfilename_len) == FAILURE) { + return; + } + + if (extracerts) { + others = php_openssl_load_all_certs_from_file(extracerts); + if (others == NULL) { + goto clean_exit; + } + } + + flags = flags & ~PKCS7_DETACHED; + + store = php_openssl_setup_verify(cainfo); + + if (!store) { + goto clean_exit; + } + if (php_openssl_open_base_dir_chk(filename)) { + goto clean_exit; + } + + in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(flags)); + if (in == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + p7 = SMIME_read_PKCS7(in, &datain); + if (p7 == NULL) { +#if DEBUG_SMIME + zend_printf("SMIME_read_PKCS7 failed\n"); +#endif + php_openssl_store_errors(); + goto clean_exit; + } + + if (datafilename) { + + if (php_openssl_open_base_dir_chk(datafilename)) { + goto clean_exit; + } + + dataout = BIO_new_file(datafilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (dataout == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + } + + if (p7bfilename) { + + if (php_openssl_open_base_dir_chk(p7bfilename)) { + goto clean_exit; + } + + p7bout = BIO_new_file(p7bfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (p7bout == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + } +#if DEBUG_SMIME + zend_printf("Calling PKCS7 verify\n"); +#endif + + if (PKCS7_verify(p7, others, store, datain, dataout, (int)flags)) { + + RETVAL_TRUE; + + if (signersfilename) { + BIO *certout; + + if (php_openssl_open_base_dir_chk(signersfilename)) { + goto clean_exit; + } + + certout = BIO_new_file(signersfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (certout) { + int i; + signers = PKCS7_get0_signers(p7, NULL, (int)flags); + if (signers != NULL) { + + for (i = 0; i < sk_X509_num(signers); i++) { + if (!PEM_write_bio_X509(certout, sk_X509_value(signers, i))) { + php_openssl_store_errors(); + RETVAL_LONG(-1); + php_error_docref(NULL, E_WARNING, "failed to write signer %d", i); + } + } + + sk_X509_free(signers); + } else { + RETVAL_LONG(-1); + php_openssl_store_errors(); + } + + BIO_free(certout); + } else { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename); + RETVAL_LONG(-1); + } + + if (p7bout) { + PEM_write_bio_PKCS7(p7bout, p7); + } + } + } else { + php_openssl_store_errors(); + RETVAL_FALSE; + } +clean_exit: + if (p7bout) { + BIO_free(p7bout); + } + X509_STORE_free(store); + BIO_free(datain); + BIO_free(in); + BIO_free(dataout); + PKCS7_free(p7); + sk_X509_free(others); +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]]) + Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */ +PHP_FUNCTION(openssl_pkcs7_encrypt) +{ + zval * zrecipcerts, * zheaders = NULL; + STACK_OF(X509) * recipcerts = NULL; + BIO * infile = NULL, * outfile = NULL; + zend_long flags = 0; + PKCS7 * p7 = NULL; + zval * zcertval; + X509 * cert; + const EVP_CIPHER *cipher = NULL; + zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT; + zend_string * strindex; + char * infilename = NULL; + size_t infilename_len; + char * outfilename = NULL; + size_t outfilename_len; + + RETVAL_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len, + &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE) + return; + + + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { + return; + } + + infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags)); + if (infile == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(flags)); + if (outfile == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + recipcerts = sk_X509_new_null(); + + /* get certs */ + if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) { + zend_resource *certresource; + + cert = php_openssl_x509_from_zval(zcertval, 0, &certresource); + if (cert == NULL) { + goto clean_exit; + } + + if (certresource != NULL) { + /* we shouldn't free this particular cert, as it is a resource. + make a copy and push that on the stack instead */ + cert = X509_dup(cert); + if (cert == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + } + sk_X509_push(recipcerts, cert); + } ZEND_HASH_FOREACH_END(); + } else { + /* a single certificate */ + zend_resource *certresource; + + cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource); + if (cert == NULL) { + goto clean_exit; + } + + if (certresource != NULL) { + /* we shouldn't free this particular cert, as it is a resource. + make a copy and push that on the stack instead */ + cert = X509_dup(cert); + if (cert == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + } + sk_X509_push(recipcerts, cert); + } + + /* sanity check the cipher */ + cipher = php_openssl_get_evp_cipher_from_algo(cipherid); + if (cipher == NULL) { + /* shouldn't happen */ + php_error_docref(NULL, E_WARNING, "Failed to get cipher"); + goto clean_exit; + } + + p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (int)flags); + + if (p7 == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + /* tack on extra headers */ + if (zheaders) { + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) { + convert_to_string_ex(zcertval); + + if (strindex) { + BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval)); + } else { + BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval)); + } + } ZEND_HASH_FOREACH_END(); + } + + (void)BIO_reset(infile); + + /* write the encrypted data */ + if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) { + php_openssl_store_errors(); + goto clean_exit; + } + + RETVAL_TRUE; + +clean_exit: + PKCS7_free(p7); + BIO_free(infile); + BIO_free(outfile); + if (recipcerts) { + sk_X509_pop_free(recipcerts, X509_free); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs7_read(string P7B, array &certs) + Exports the PKCS7 file to an array of PEM certificates */ +PHP_FUNCTION(openssl_pkcs7_read) +{ + zval * zout = NULL, zcert; + char *p7b; + size_t p7b_len; + STACK_OF(X509) *certs = NULL; + STACK_OF(X509_CRL) *crls = NULL; + BIO * bio_in = NULL, * bio_out = NULL; + PKCS7 * p7 = NULL; + int i; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/", &p7b, &p7b_len, + &zout) == FAILURE) { + return; + } + + RETVAL_FALSE; + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(p7b_len, p7b); + + bio_in = BIO_new(BIO_s_mem()); + if (bio_in == NULL) { + goto clean_exit; + } + + if (0 >= BIO_write(bio_in, p7b, (int)p7b_len)) { + php_openssl_store_errors(); + goto clean_exit; + } + + p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL); + if (p7 == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_signed: + if (p7->d.sign != NULL) { + certs = p7->d.sign->cert; + crls = p7->d.sign->crl; + } + break; + case NID_pkcs7_signedAndEnveloped: + if (p7->d.signed_and_enveloped != NULL) { + certs = p7->d.signed_and_enveloped->cert; + crls = p7->d.signed_and_enveloped->crl; + } + break; + default: + break; + } + + zval_dtor(zout); + array_init(zout); + + if (certs != NULL) { + for (i = 0; i < sk_X509_num(certs); i++) { + X509* ca = sk_X509_value(certs, i); + + bio_out = BIO_new(BIO_s_mem()); + if (bio_out && PEM_write_bio_X509(bio_out, ca)) { + BUF_MEM *bio_buf; + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); + add_index_zval(zout, i, &zcert); + BIO_free(bio_out); + } + } + } + + if (crls != NULL) { + for (i = 0; i < sk_X509_CRL_num(crls); i++) { + X509_CRL* crl = sk_X509_CRL_value(crls, i); + + bio_out = BIO_new(BIO_s_mem()); + if (bio_out && PEM_write_bio_X509_CRL(bio_out, crl)) { + BUF_MEM *bio_buf; + BIO_get_mem_ptr(bio_out, &bio_buf); + ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); + add_index_zval(zout, i, &zcert); + BIO_free(bio_out); + } + } + } + + RETVAL_TRUE; + +clean_exit: + if (bio_in != NULL) { + BIO_free(bio_in); + } + + if (p7 != NULL) { + PKCS7_free(p7); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]]) + 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 */ + +PHP_FUNCTION(openssl_pkcs7_sign) +{ + zval * zcert, * zprivkey, * zheaders; + zval * hval; + X509 * cert = NULL; + EVP_PKEY * privkey = NULL; + zend_long flags = PKCS7_DETACHED; + PKCS7 * p7 = NULL; + BIO * infile = NULL, * outfile = NULL; + STACK_OF(X509) *others = NULL; + zend_resource *certresource = NULL, *keyresource = NULL; + zend_string * strindex; + char * infilename; + size_t infilename_len; + char * outfilename; + size_t outfilename_len; + char * extracertsfilename = NULL; + size_t extracertsfilename_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|lp!", + &infilename, &infilename_len, &outfilename, &outfilename_len, + &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename, + &extracertsfilename_len) == FAILURE) { + return; + } + + RETVAL_FALSE; + + if (extracertsfilename) { + others = php_openssl_load_all_certs_from_file(extracertsfilename); + if (others == NULL) { + goto clean_exit; + } + } + + privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, 0, &keyresource); + if (privkey == NULL) { + php_error_docref(NULL, E_WARNING, "error getting private key"); + goto clean_exit; + } + + cert = php_openssl_x509_from_zval(zcert, 0, &certresource); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "error getting cert"); + goto clean_exit; + } + + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { + goto clean_exit; + } + + infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags)); + if (infile == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening input file %s!", infilename); + goto clean_exit; + } + + outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (outfile == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error opening output file %s!", outfilename); + goto clean_exit; + } + + p7 = PKCS7_sign(cert, privkey, others, infile, (int)flags); + if (p7 == NULL) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "error creating PKCS7 structure!"); + goto clean_exit; + } + + (void)BIO_reset(infile); + + /* tack on extra headers */ + if (zheaders) { + int ret; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) { + convert_to_string_ex(hval); + + if (strindex) { + ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval)); + } else { + ret = BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval)); + } + if (ret < 0) { + php_openssl_store_errors(); + } + } ZEND_HASH_FOREACH_END(); + } + /* write the signed data */ + if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) { + php_openssl_store_errors(); + goto clean_exit; + } + + RETVAL_TRUE; + +clean_exit: + PKCS7_free(p7); + BIO_free(infile); + BIO_free(outfile); + if (others) { + sk_X509_pop_free(others, X509_free); + } + if (privkey && keyresource == NULL) { + EVP_PKEY_free(privkey); + } + if (cert && certresource == NULL) { + X509_free(cert); + } +} +/* }}} */ + +/* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey]) + 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 */ + +PHP_FUNCTION(openssl_pkcs7_decrypt) +{ + zval * recipcert, * recipkey = NULL; + X509 * cert = NULL; + EVP_PKEY * key = NULL; + zend_resource *certresval, *keyresval; + BIO * in = NULL, * out = NULL, * datain = NULL; + PKCS7 * p7 = NULL; + char * infilename; + size_t infilename_len; + char * outfilename; + size_t outfilename_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|z", &infilename, &infilename_len, + &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) { + return; + } + + RETVAL_FALSE; + + cert = php_openssl_x509_from_zval(recipcert, 0, &certresval); + if (cert == NULL) { + php_error_docref(NULL, E_WARNING, "unable to coerce parameter 3 to x509 cert"); + goto clean_exit; + } + + key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, 0, &keyresval); + if (key == NULL) { + php_error_docref(NULL, E_WARNING, "unable to get private key"); + goto clean_exit; + } + + if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) { + goto clean_exit; + } + + in = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + if (in == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + out = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); + if (out == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + + p7 = SMIME_read_PKCS7(in, &datain); + + if (p7 == NULL) { + php_openssl_store_errors(); + goto clean_exit; + } + if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) { + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } +clean_exit: + PKCS7_free(p7); + BIO_free(datain); + BIO_free(in); + BIO_free(out); + if (cert && certresval == NULL) { + X509_free(cert); + } + if (key && keyresval == NULL) { + EVP_PKEY_free(key); + } +} +/* }}} */ + +/* }}} */ + +/* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding]) + Encrypts data with private key */ +PHP_FUNCTION(openssl_private_encrypt) +{ + zval *key, *crypted; + EVP_PKEY *pkey; + int cryptedlen; + zend_string *cryptedbuf = NULL; + int successful = 0; + zend_resource *keyresource = NULL; + char * data; + size_t data_len; + zend_long padding = RSA_PKCS1_PADDING; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + return; + } + RETVAL_FALSE; + + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); + + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "key param is not a valid private key"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + + cryptedlen = EVP_PKEY_size(pkey); + cryptedbuf = zend_string_alloc(cryptedlen, 0); + + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + successful = (RSA_private_encrypt((int)data_len, + (unsigned char *)data, + (unsigned char *)ZSTR_VAL(cryptedbuf), + EVP_PKEY_get0_RSA(pkey), + (int)padding) == cryptedlen); + break; + default: + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + } + + if (successful) { + zval_dtor(crypted); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); + cryptedbuf = NULL; + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + if (cryptedbuf) { + zend_string_release(cryptedbuf); + } + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } +} +/* }}} */ + +/* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding]) + Decrypts data with private key */ +PHP_FUNCTION(openssl_private_decrypt) +{ + zval *key, *crypted; + EVP_PKEY *pkey; + int cryptedlen; + zend_string *cryptedbuf = NULL; + unsigned char *crypttemp; + int successful = 0; + zend_long padding = RSA_PKCS1_PADDING; + zend_resource *keyresource = NULL; + char * data; + size_t data_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + return; + } + RETVAL_FALSE; + + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + + cryptedlen = EVP_PKEY_size(pkey); + crypttemp = emalloc(cryptedlen + 1); + + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + cryptedlen = RSA_private_decrypt((int)data_len, + (unsigned char *)data, + crypttemp, + EVP_PKEY_get0_RSA(pkey), + (int)padding); + if (cryptedlen != -1) { + cryptedbuf = zend_string_alloc(cryptedlen, 0); + memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen); + successful = 1; + } + break; + default: + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + } + + efree(crypttemp); + + if (successful) { + zval_dtor(crypted); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); + cryptedbuf = NULL; + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } + if (cryptedbuf) { + zend_string_release(cryptedbuf); + } +} +/* }}} */ + +/* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding]) + Encrypts data with public key */ +PHP_FUNCTION(openssl_public_encrypt) +{ + zval *key, *crypted; + EVP_PKEY *pkey; + int cryptedlen; + zend_string *cryptedbuf; + int successful = 0; + zend_resource *keyresource = NULL; + zend_long padding = RSA_PKCS1_PADDING; + char * data; + size_t data_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) + return; + RETVAL_FALSE; + + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + + cryptedlen = EVP_PKEY_size(pkey); + cryptedbuf = zend_string_alloc(cryptedlen, 0); + + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + successful = (RSA_public_encrypt((int)data_len, + (unsigned char *)data, + (unsigned char *)ZSTR_VAL(cryptedbuf), + EVP_PKEY_get0_RSA(pkey), + (int)padding) == cryptedlen); + break; + default: + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + + } + + if (successful) { + zval_dtor(crypted); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); + cryptedbuf = NULL; + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } + if (cryptedbuf) { + zend_string_release(cryptedbuf); + } +} +/* }}} */ + +/* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding]) + Decrypts data with public key */ +PHP_FUNCTION(openssl_public_decrypt) +{ + zval *key, *crypted; + EVP_PKEY *pkey; + int cryptedlen; + zend_string *cryptedbuf = NULL; + unsigned char *crypttemp; + int successful = 0; + zend_resource *keyresource = NULL; + zend_long padding = RSA_PKCS1_PADDING; + char * data; + size_t data_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + return; + } + RETVAL_FALSE; + + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + + cryptedlen = EVP_PKEY_size(pkey); + crypttemp = emalloc(cryptedlen + 1); + + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + cryptedlen = RSA_public_decrypt((int)data_len, + (unsigned char *)data, + crypttemp, + EVP_PKEY_get0_RSA(pkey), + (int)padding); + if (cryptedlen != -1) { + cryptedbuf = zend_string_alloc(cryptedlen, 0); + memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen); + successful = 1; + } + break; + + default: + php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!"); + + } + + efree(crypttemp); + + if (successful) { + zval_dtor(crypted); + ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; + ZVAL_NEW_STR(crypted, cryptedbuf); + cryptedbuf = NULL; + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + } + + if (cryptedbuf) { + zend_string_release(cryptedbuf); + } + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } +} +/* }}} */ + +/* {{{ proto mixed openssl_error_string(void) + Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */ +PHP_FUNCTION(openssl_error_string) +{ + char buf[256]; + unsigned long val; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + php_openssl_store_errors(); + + if (OPENSSL_G(errors) == NULL || OPENSSL_G(errors)->top == OPENSSL_G(errors)->bottom) { + RETURN_FALSE; + } + + OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % ERR_NUM_ERRORS; + val = OPENSSL_G(errors)->buffer[OPENSSL_G(errors)->bottom]; + + if (val) { + ERR_error_string_n(val, buf, 256); + RETURN_STRING(buf); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method]) + Signs data */ +PHP_FUNCTION(openssl_sign) +{ + zval *key, *signature; + EVP_PKEY *pkey; + size_t siglen; + zend_string *sigbuf; + zend_resource *keyresource = NULL; + char * data; + size_t data_len; + EVP_MD_CTX *md_ctx; + EVP_PKEY_CTX *pk_ctx; + zval *method = NULL; + zend_long signature_algo = OPENSSL_ALGO_SHA1; + const EVP_MD *mdtype; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) { + return; + } + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key"); + RETURN_FALSE; + } + + if (method == NULL || Z_TYPE_P(method) == IS_LONG) { + if (method != NULL) { + signature_algo = Z_LVAL_P(method); + } + mdtype = php_openssl_get_evp_md_from_algo(signature_algo); + } else if (Z_TYPE_P(method) == IS_STRING) { + mdtype = EVP_get_digestbyname(Z_STRVAL_P(method)); + } else { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); + RETURN_FALSE; + } + if (!mdtype) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); + RETURN_FALSE; + } + + siglen = EVP_PKEY_size(pkey); + sigbuf = zend_string_alloc(siglen, 0); + + md_ctx = EVP_MD_CTX_create(); + if (md_ctx == NULL) { + php_openssl_store_errors(); + efree(sigbuf); + RETURN_FALSE; + } + + if (!EVP_DigestSignInit(md_ctx, &pk_ctx, mdtype, NULL, pkey)) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + efree(sigbuf); + RETVAL_FALSE; + } + if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) { + if (EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) == NID_sm2p256v1) { + if (EVP_PKEY_CTX_set_ec_scheme(pk_ctx, NID_sm_scheme) <= 0) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + efree(sigbuf); + RETURN_FALSE; + } + } + } + if (!EVP_DigestSignUpdate(md_ctx, data, data_len) || + !EVP_DigestSignFinal(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen)) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + efree(sigbuf); + RETURN_FALSE; + } + + zval_dtor(signature); + ZSTR_VAL(sigbuf)[siglen] = '\0'; + ZSTR_LEN(sigbuf) = siglen; + ZVAL_NEW_STR(signature, sigbuf); + RETVAL_TRUE; + + EVP_MD_CTX_destroy(md_ctx); + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } +} +/* }}} */ + +/* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method]) + Verifys data */ +PHP_FUNCTION(openssl_verify) +{ + zval *key; + EVP_PKEY *pkey; + int err = 0; + EVP_MD_CTX *md_ctx; + EVP_PKEY_CTX *pk_ctx; + const EVP_MD *mdtype; + zend_resource *keyresource = NULL; + char * data; + size_t data_len; + char * signature; + size_t signature_len; + zval *method = NULL; + zend_long signature_algo = OPENSSL_ALGO_SHA1; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) { + return; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature); + + if (method == NULL || Z_TYPE_P(method) == IS_LONG) { + if (method != NULL) { + signature_algo = Z_LVAL_P(method); + } + mdtype = php_openssl_get_evp_md_from_algo(signature_algo); + } else if (Z_TYPE_P(method) == IS_STRING) { + mdtype = EVP_get_digestbyname(Z_STRVAL_P(method)); + } else { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); + RETURN_FALSE; + } + if (!mdtype) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); + RETURN_FALSE; + } + + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); + if (pkey == NULL) { + php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key"); + RETURN_FALSE; + } + + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) { + php_openssl_store_errors(); + RETURN_FALSE; + } + + if (!EVP_DigestVerifyInit(md_ctx, &pk_ctx, mdtype, NULL, pkey)) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + RETURN_FALSE; + } + if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) { + if (EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) == NID_sm2p256v1) { + if (EVP_PKEY_CTX_set_ec_scheme(pk_ctx, NID_sm_scheme) <= 0) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + RETURN_FALSE; + } + } + } + if (!EVP_DigestVerifyUpdate(md_ctx, data, data_len) || + EVP_DigestVerifyFinal(md_ctx, (unsigned char *)signature, (unsigned int)signature_len) != 1) { + php_openssl_store_errors(); + EVP_MD_CTX_free(md_ctx); + RETURN_FALSE; + } + + EVP_MD_CTX_free(md_ctx); + + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } + RETURN_LONG(err); +} +/* }}} */ + +/* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys [, string method [, &string iv]])) + Seals data */ +PHP_FUNCTION(openssl_seal) +{ + zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL; + HashTable *pubkeysht; + EVP_PKEY **pkeys; + zend_resource ** key_resources; /* so we know what to cleanup */ + int i, len1, len2, *eksl, nkeys, iv_len; + unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks; + char * data; + size_t data_len; + char *method =NULL; + size_t method_len = 0; + const EVP_CIPHER *cipher; + EVP_CIPHER_CTX *ctx; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|sz/", &data, &data_len, + &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) { + return; + } + pubkeysht = Z_ARRVAL_P(pubkeys); + nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0; + if (!nkeys) { + php_error_docref(NULL, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + + if (method) { + cipher = EVP_get_cipherbyname(method); + if (!cipher) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm."); + RETURN_FALSE; + } + } else { + cipher = EVP_rc4(); + } + + iv_len = EVP_CIPHER_iv_length(cipher); + if (!iv && iv_len > 0) { + php_error_docref(NULL, E_WARNING, + "Cipher algorithm requires an IV to be supplied as a sixth parameter"); + RETURN_FALSE; + } + + pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0); + eksl = safe_emalloc(nkeys, sizeof(*eksl), 0); + eks = safe_emalloc(nkeys, sizeof(*eks), 0); + memset(eks, 0, sizeof(*eks) * nkeys); + key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0); + memset(key_resources, 0, sizeof(zend_resource*) * nkeys); + memset(pkeys, 0, sizeof(*pkeys) * nkeys); + + /* get the public keys we are using to seal this data */ + i = 0; + ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) { + pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, 0, &key_resources[i]); + if (pkeys[i] == NULL) { + php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1); + RETVAL_FALSE; + goto clean_exit; + } + eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1); + i++; + } ZEND_HASH_FOREACH_END(); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) { + EVP_CIPHER_CTX_free(ctx); + php_openssl_store_errors(); + RETVAL_FALSE; + goto clean_exit; + } + + /* allocate one byte extra to make room for \0 */ + buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(ctx)); + EVP_CIPHER_CTX_cleanup(ctx); + + if (EVP_SealInit(ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) <= 0 || + !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) || + !EVP_SealFinal(ctx, buf + len1, &len2)) { + efree(buf); + EVP_CIPHER_CTX_free(ctx); + php_openssl_store_errors(); + RETVAL_FALSE; + goto clean_exit; + } + + if (len1 + len2 > 0) { + zval_dtor(sealdata); + ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0)); + efree(buf); + + zval_dtor(ekeys); + array_init(ekeys); + for (i=0; i 0) { + if (!iv) { + php_error_docref(NULL, E_WARNING, + "Cipher algorithm requires an IV to be supplied as a sixth parameter"); + RETURN_FALSE; + } + if ((size_t)cipher_iv_len != iv_len) { + php_error_docref(NULL, E_WARNING, "IV length is invalid"); + RETURN_FALSE; + } + iv_buf = (unsigned char *)iv; + } else { + iv_buf = NULL; + } + + buf = emalloc(data_len + 1); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) && + EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) && + EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) { + zval_dtor(opendata); + buf[len1 + len2] = '\0'; + ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0)); + RETVAL_TRUE; + } else { + php_openssl_store_errors(); + RETVAL_FALSE; + } + + efree(buf); + if (keyresource == NULL) { + EVP_PKEY_free(pkey); + } + EVP_CIPHER_CTX_free(ctx); +} +/* }}} */ + +static void php_openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */ +{ + add_next_index_string((zval*)arg, (char*)name->name); +} +/* }}} */ + +static void php_openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */ +{ + if (name->alias == 0) { + add_next_index_string((zval*)arg, (char*)name->name); + } +} +/* }}} */ + +/* {{{ proto array openssl_get_md_methods([bool aliases = false]) + Return array of available digest methods */ +PHP_FUNCTION(openssl_get_md_methods) +{ + zend_bool aliases = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) { + return; + } + array_init(return_value); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, + aliases ? php_openssl_add_method_or_alias: php_openssl_add_method, + return_value); +} +/* }}} */ + +/* {{{ proto array openssl_get_cipher_methods([bool aliases = false]) + Return array of available cipher methods */ +PHP_FUNCTION(openssl_get_cipher_methods) +{ + zend_bool aliases = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) { + return; + } + array_init(return_value); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, + aliases ? php_openssl_add_method_or_alias: php_openssl_add_method, + return_value); +} +/* }}} */ + +/* {{{ proto array openssl_get_curve_names() + Return array of available elliptic curves */ +#ifdef HAVE_EVP_PKEY_EC +PHP_FUNCTION(openssl_get_curve_names) +{ + EC_builtin_curve *curves = NULL; + const char *sname; + size_t i; + size_t len = EC_get_builtin_curves(NULL, 0); + + curves = emalloc(sizeof(EC_builtin_curve) * len); + if (!EC_get_builtin_curves(curves, len)) { + RETURN_FALSE; + } + + array_init(return_value); + for (i = 0; i < len; i++) { + sname = OBJ_nid2sn(curves[i].nid); + if (sname != NULL) { + add_next_index_string(return_value, sname); + } + } + efree(curves); +} +#endif +/* }}} */ + +/* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false]) + Computes digest hash value for given data using given method, returns raw or binhex encoded string */ +PHP_FUNCTION(openssl_digest) +{ + zend_bool raw_output = 0; + char *data, *method; + size_t data_len, method_len; + const EVP_MD *mdtype; + EVP_MD_CTX *md_ctx; + unsigned int siglen; + zend_string *sigbuf; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) { + return; + } + mdtype = EVP_get_digestbyname(method); + if (!mdtype) { + php_error_docref(NULL, E_WARNING, "Unknown signature algorithm"); + RETURN_FALSE; + } + + siglen = EVP_MD_size(mdtype); + sigbuf = zend_string_alloc(siglen, 0); + + md_ctx = EVP_MD_CTX_create(); + if (EVP_DigestInit(md_ctx, mdtype) && + EVP_DigestUpdate(md_ctx, (unsigned char *)data, data_len) && + EVP_DigestFinal (md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) { + if (raw_output) { + ZSTR_VAL(sigbuf)[siglen] = '\0'; + ZSTR_LEN(sigbuf) = siglen; + RETVAL_STR(sigbuf); + } else { + int digest_str_len = siglen * 2; + zend_string *digest_str = zend_string_alloc(digest_str_len, 0); + + make_digest_ex(ZSTR_VAL(digest_str), (unsigned char*)ZSTR_VAL(sigbuf), siglen); + ZSTR_VAL(digest_str)[digest_str_len] = '\0'; + zend_string_release(sigbuf); + RETVAL_STR(digest_str); + } + } else { + php_openssl_store_errors(); + zend_string_release(sigbuf); + RETVAL_FALSE; + } + + EVP_MD_CTX_destroy(md_ctx); +} +/* }}} */ + +/* Cipher mode info */ +struct php_openssl_cipher_mode { + zend_bool is_aead; + zend_bool is_single_run_aead; + int aead_get_tag_flag; + int aead_set_tag_flag; + int aead_ivlen_flag; +}; + +static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */ +{ + switch (EVP_CIPHER_mode(cipher_type)) { +#ifdef EVP_CIPH_GCM_MODE + case EVP_CIPH_GCM_MODE: + mode->is_aead = 1; + mode->is_single_run_aead = 0; + mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG; + mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG; + mode->aead_ivlen_flag = EVP_CTRL_GCM_SET_IVLEN; + break; +#endif +#ifdef EVP_CIPH_CCM_MODE + case EVP_CIPH_CCM_MODE: + mode->is_aead = 1; + mode->is_single_run_aead = 1; + mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG; + mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG; + mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN; + break; +#endif + default: + memset(mode, 0, sizeof(struct php_openssl_cipher_mode)); + } +} +/* }}} */ + +static int php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_required_len, + zend_bool *free_iv, EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode) /* {{{ */ +{ + char *iv_new; + + /* Best case scenario, user behaved */ + if (*piv_len == iv_required_len) { + return SUCCESS; + } + + if (mode->is_aead) { + if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_ivlen_flag, *piv_len, NULL) != 1) { + php_error_docref(NULL, E_WARNING, "Setting of IV length for AEAD mode failed"); + return FAILURE; + } + return SUCCESS; + } + + iv_new = ecalloc(1, iv_required_len + 1); + + if (*piv_len == 0) { + /* BC behavior */ + *piv_len = iv_required_len; + *piv = iv_new; + *free_iv = 1; + return SUCCESS; + + } + + if (*piv_len < iv_required_len) { + php_error_docref(NULL, E_WARNING, + "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0", + *piv_len, iv_required_len); + memcpy(iv_new, *piv, *piv_len); + *piv_len = iv_required_len; + *piv = iv_new; + *free_iv = 1; + return SUCCESS; + } + + php_error_docref(NULL, E_WARNING, + "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating", + *piv_len, iv_required_len); + memcpy(iv_new, *piv, iv_required_len); + *piv_len = iv_required_len; + *piv = iv_new; + *free_iv = 1; + return SUCCESS; + +} +/* }}} */ + +static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type, + EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode, + char **ppassword, size_t *ppassword_len, zend_bool *free_password, + char **piv, size_t *piv_len, zend_bool *free_iv, + char *tag, int tag_len, zend_long options, int enc) /* {{{ */ +{ + unsigned char *key; + int key_len, password_len; + size_t max_iv_len; + + *free_password = 0; + + max_iv_len = EVP_CIPHER_iv_length(cipher_type); + if (enc && *piv_len == 0 && max_iv_len > 0 && !mode->is_aead) { + php_error_docref(NULL, E_WARNING, + "Using an empty Initialization Vector (iv) is potentially insecure and not recommended"); + } + + if (!EVP_CipherInit_ex(cipher_ctx, cipher_type, NULL, NULL, NULL, enc)) { + php_openssl_store_errors(); + return FAILURE; + } + if (php_openssl_validate_iv(piv, piv_len, max_iv_len, free_iv, cipher_ctx, mode) == FAILURE) { + return FAILURE; + } + if (mode->is_single_run_aead && enc) { + EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL); + } else if (!enc && tag && tag_len > 0) { + if (!mode->is_aead) { + php_error_docref(NULL, E_WARNING, "The tag cannot be used because the cipher method does not support AEAD"); + } else if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, (unsigned char *) tag)) { + php_error_docref(NULL, E_WARNING, "Setting tag for AEAD cipher decryption failed"); + return FAILURE; + } + } + /* check and set key */ + password_len = (int) *ppassword_len; + key_len = EVP_CIPHER_key_length(cipher_type); + if (key_len > password_len) { + if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher method"); + return FAILURE; + } + key = emalloc(key_len); + memset(key, 0, key_len); + memcpy(key, *ppassword, password_len); + *ppassword = (char *) key; + *ppassword_len = key_len; + *free_password = 1; + } else { + if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) { + php_openssl_store_errors(); + } + key = (unsigned char*)*ppassword; + } + + if (!EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)*piv, enc)) { + php_openssl_store_errors(); + return FAILURE; + } + if (options & OPENSSL_ZERO_PADDING) { + EVP_CIPHER_CTX_set_padding(cipher_ctx, 0); + } + + return SUCCESS; +} +/* }}} */ + +static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type, + EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode, + zend_string **poutbuf, int *poutlen, char *data, size_t data_len, + char *aad, size_t aad_len, int enc) /* {{{ */ +{ + int i = 0; + + if (mode->is_single_run_aead && !EVP_EncryptUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Setting of data length failed"); + return FAILURE; + } + + if (mode->is_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, (unsigned char *)aad, (int)aad_len)) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Setting of additional application data failed"); + return FAILURE; + } + + *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0); + + if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf), + &i, (unsigned char *)data, (int)data_len)) { + /* we don't show warning when we fail but if we ever do, then it should look like this: + if (mode->is_single_run_aead && !enc) { + php_error_docref(NULL, E_WARNING, "Tag verifycation failed"); + } else { + php_error_docref(NULL, E_WARNING, enc ? "Encryption failed" : "Decryption failed"); + } + */ + php_openssl_store_errors(); + zend_string_release(*poutbuf); + return FAILURE; + } + + *poutlen = i; + + return SUCCESS; +} +/* }}} */ + +/* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv=''[, string &$tag = ''[, string $aad = ''[, long $tag_length = 16]]]]]) + Encrypts given data with given method and key, returns raw or base64 encoded string */ +PHP_FUNCTION(openssl_encrypt) +{ + zend_long options = 0, tag_len = 16; + char *data, *method, *password, *iv = "", *aad = ""; + size_t data_len, method_len, password_len, iv_len = 0, aad_len = 0; + zval *tag = NULL; + const EVP_CIPHER *cipher_type; + EVP_CIPHER_CTX *cipher_ctx; + struct php_openssl_cipher_mode mode; + int i=0, outlen; + zend_string *outbuf; + zend_bool free_iv = 0, free_password = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsz/sl", &data, &data_len, &method, &method_len, + &password, &password_len, &options, &iv, &iv_len, &tag, &aad, &aad_len, &tag_len) == FAILURE) { + return; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad); + PHP_OPENSSL_CHECK_LONG_TO_INT(tag_len, tag_len); + + cipher_type = EVP_get_cipherbyname(method); + if (!cipher_type) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); + RETURN_FALSE; + } + + cipher_ctx = EVP_CIPHER_CTX_new(); + if (!cipher_ctx) { + php_error_docref(NULL, E_WARNING, "Failed to create cipher context"); + RETURN_FALSE; + } + php_openssl_load_cipher_mode(&mode, cipher_type); + + if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode, + &password, &password_len, &free_password, + &iv, &iv_len, &free_iv, NULL, tag_len, options, 1) == FAILURE || + php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen, + data, data_len, aad, aad_len, 1) == FAILURE) { + RETVAL_FALSE; + } else if (EVP_EncryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) { + outlen += i; + if (options & OPENSSL_RAW_DATA) { + ZSTR_VAL(outbuf)[outlen] = '\0'; + ZSTR_LEN(outbuf) = outlen; + RETVAL_STR(outbuf); + } else { + zend_string *base64_str; + + base64_str = php_base64_encode((unsigned char*)ZSTR_VAL(outbuf), outlen); + zend_string_release(outbuf); + outbuf = base64_str; + RETVAL_STR(base64_str); + } + if (mode.is_aead && tag) { + zend_string *tag_str = zend_string_alloc(tag_len, 0); + + if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode.aead_get_tag_flag, tag_len, ZSTR_VAL(tag_str)) == 1) { + zval_dtor(tag); + ZSTR_VAL(tag_str)[tag_len] = '\0'; + ZSTR_LEN(tag_str) = tag_len; + ZVAL_NEW_STR(tag, tag_str); + } else { + php_error_docref(NULL, E_WARNING, "Retrieving verification tag failed"); + zend_string_release(tag_str); + zend_string_release(outbuf); + RETVAL_FALSE; + } + } else if (tag) { + zval_dtor(tag); + ZVAL_NULL(tag); + php_error_docref(NULL, E_WARNING, + "The authenticated tag cannot be provided for cipher that doesn not support AEAD"); + } else if (mode.is_aead) { + php_error_docref(NULL, E_WARNING, "A tag should be provided when using AEAD mode"); + zend_string_release(outbuf); + RETVAL_FALSE; + } + } else { + php_openssl_store_errors(); + zend_string_release(outbuf); + RETVAL_FALSE; + } + + if (free_password) { + efree(password); + } + if (free_iv) { + efree(iv); + } + EVP_CIPHER_CTX_cleanup(cipher_ctx); + EVP_CIPHER_CTX_free(cipher_ctx); +} +/* }}} */ + +/* {{{ proto string openssl_decrypt(string data, string method, string password [, long options=0 [, string $iv = ''[, string $tag = ''[, string $aad = '']]]]) + Takes raw or base64 encoded string and decrypts it using given method and key */ +PHP_FUNCTION(openssl_decrypt) +{ + zend_long options = 0; + char *data, *method, *password, *iv = "", *tag = NULL, *aad = ""; + size_t data_len, method_len, password_len, iv_len = 0, tag_len = 0, aad_len = 0; + const EVP_CIPHER *cipher_type; + EVP_CIPHER_CTX *cipher_ctx; + struct php_openssl_cipher_mode mode; + int i = 0, outlen; + zend_string *outbuf; + zend_string *base64_str = NULL; + zend_bool free_iv = 0, free_password = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsss", &data, &data_len, &method, &method_len, + &password, &password_len, &options, &iv, &iv_len, &tag, &tag_len, &aad, &aad_len) == FAILURE) { + return; + } + + if (!method_len) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); + RETURN_FALSE; + } + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(tag_len, tag); + + cipher_type = EVP_get_cipherbyname(method); + if (!cipher_type) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); + RETURN_FALSE; + } + + cipher_ctx = EVP_CIPHER_CTX_new(); + if (!cipher_ctx) { + php_error_docref(NULL, E_WARNING, "Failed to create cipher context"); + RETURN_FALSE; + } + + php_openssl_load_cipher_mode(&mode, cipher_type); + + if (!(options & OPENSSL_RAW_DATA)) { + base64_str = php_base64_decode((unsigned char*)data, data_len); + if (!base64_str) { + php_error_docref(NULL, E_WARNING, "Failed to base64 decode the input"); + EVP_CIPHER_CTX_free(cipher_ctx); + RETURN_FALSE; + } + data_len = ZSTR_LEN(base64_str); + data = ZSTR_VAL(base64_str); + } + + if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode, + &password, &password_len, &free_password, + &iv, &iv_len, &free_iv, tag, tag_len, options, 0) == FAILURE || + php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen, + data, data_len, aad, aad_len, 0) == FAILURE) { + RETVAL_FALSE; + } else if (mode.is_single_run_aead || + EVP_DecryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) { + outlen += i; + ZSTR_VAL(outbuf)[outlen] = '\0'; + ZSTR_LEN(outbuf) = outlen; + RETVAL_STR(outbuf); + } else { + php_openssl_store_errors(); + zend_string_release(outbuf); + RETVAL_FALSE; + } + + if (free_password) { + efree(password); + } + if (free_iv) { + efree(iv); + } + if (base64_str) { + zend_string_release(base64_str); + } + EVP_CIPHER_CTX_cleanup(cipher_ctx); + EVP_CIPHER_CTX_free(cipher_ctx); +} +/* }}} */ + +/* {{{ proto int openssl_cipher_iv_length(string $method) */ +PHP_FUNCTION(openssl_cipher_iv_length) +{ + char *method; + size_t method_len; + const EVP_CIPHER *cipher_type; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len) == FAILURE) { + return; + } + + if (!method_len) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); + RETURN_FALSE; + } + + cipher_type = EVP_get_cipherbyname(method); + if (!cipher_type) { + php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); + RETURN_FALSE; + } + + RETURN_LONG(EVP_CIPHER_iv_length(cipher_type)); +} +/* }}} */ + + +/* {{{ proto string openssl_random_pseudo_bytes(integer length [, &bool returned_strong_result]) + Returns a string of the length specified filled with random pseudo bytes */ +PHP_FUNCTION(openssl_random_pseudo_bytes) +{ + zend_long buffer_length; + zend_string *buffer = NULL; + zval *zstrong_result_returned = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) { + return; + } + + if (zstrong_result_returned) { + zval_dtor(zstrong_result_returned); + ZVAL_FALSE(zstrong_result_returned); + } + + if (buffer_length <= 0 +#ifndef PHP_WIN32 + || ZEND_LONG_INT_OVFL(buffer_length) +#endif + ) { + RETURN_FALSE; + } + buffer = zend_string_alloc(buffer_length, 0); + +#ifdef PHP_WIN32 + /* random/urandom equivalent on Windows */ + if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){ + zend_string_release(buffer); + if (zstrong_result_returned) { + ZVAL_FALSE(zstrong_result_returned); + } + RETURN_FALSE; + } +#else + + PHP_OPENSSL_CHECK_LONG_TO_INT(buffer_length, length); + PHP_OPENSSL_RAND_ADD_TIME(); + /* FIXME loop if requested size > INT_MAX */ + if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) { + zend_string_release(buffer); + if (zstrong_result_returned) { + ZVAL_FALSE(zstrong_result_returned); + } + RETURN_FALSE; + } else { + php_openssl_store_errors(); + } +#endif + + ZSTR_VAL(buffer)[buffer_length] = 0; + RETVAL_STR(buffer); + + if (zstrong_result_returned) { + ZVAL_BOOL(zstrong_result_returned, 1); + } +} +/* }}} */ + +/* + * Local variables: + * tab-width: 8 + * c-basic-offset: 8 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/php/ext/openssl/php_openssl.h b/php/ext/openssl/php_openssl.h new file mode 100644 index 00000000..271f0ba8 --- /dev/null +++ b/php/ext/openssl/php_openssl.h @@ -0,0 +1,202 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2018 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2018 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Stig Venaas | + | Wez Furlong + +struct php_openssl_errors { + int buffer[ERR_NUM_ERRORS]; + int top; + int bottom; +}; + +ZEND_BEGIN_MODULE_GLOBALS(openssl) + struct php_openssl_errors *errors; +ZEND_END_MODULE_GLOBALS(openssl) + +#define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v) + +#if defined(ZTS) && defined(COMPILE_DL_OPENSSL) +ZEND_TSRMLS_CACHE_EXTERN(); +#endif + +php_stream_transport_factory_func php_openssl_ssl_socket_factory; + +void php_openssl_store_errors(); + +PHP_MINIT_FUNCTION(openssl); +PHP_MSHUTDOWN_FUNCTION(openssl); +PHP_MINFO_FUNCTION(openssl); +PHP_GINIT_FUNCTION(openssl); +PHP_GSHUTDOWN_FUNCTION(openssl); + +PHP_FUNCTION(openssl_pkey_get_private); +PHP_FUNCTION(openssl_pkey_get_public); +PHP_FUNCTION(openssl_pkey_free); +PHP_FUNCTION(openssl_pkey_new); +PHP_FUNCTION(openssl_pkey_export); +PHP_FUNCTION(openssl_pkey_export_to_file); +PHP_FUNCTION(openssl_pkey_get_details); + +PHP_FUNCTION(openssl_sign); +PHP_FUNCTION(openssl_verify); +PHP_FUNCTION(openssl_seal); +PHP_FUNCTION(openssl_open); +PHP_FUNCTION(openssl_private_encrypt); +PHP_FUNCTION(openssl_private_decrypt); +PHP_FUNCTION(openssl_public_encrypt); +PHP_FUNCTION(openssl_public_decrypt); + +PHP_FUNCTION(openssl_pbkdf2); + +PHP_FUNCTION(openssl_pkcs7_verify); +PHP_FUNCTION(openssl_pkcs7_decrypt); +PHP_FUNCTION(openssl_pkcs7_sign); +PHP_FUNCTION(openssl_pkcs7_encrypt); +PHP_FUNCTION(openssl_pkcs7_read); + +PHP_FUNCTION(openssl_error_string); + +PHP_FUNCTION(openssl_x509_read); +PHP_FUNCTION(openssl_x509_free); +PHP_FUNCTION(openssl_x509_parse); +PHP_FUNCTION(openssl_x509_checkpurpose); +PHP_FUNCTION(openssl_x509_export); +PHP_FUNCTION(openssl_x509_fingerprint); +PHP_FUNCTION(openssl_x509_export_to_file); +PHP_FUNCTION(openssl_x509_check_private_key); + +PHP_FUNCTION(openssl_pkcs12_export); +PHP_FUNCTION(openssl_pkcs12_export_to_file); +PHP_FUNCTION(openssl_pkcs12_read); + +PHP_FUNCTION(openssl_csr_new); +PHP_FUNCTION(openssl_csr_export); +PHP_FUNCTION(openssl_csr_export_to_file); +PHP_FUNCTION(openssl_csr_sign); +PHP_FUNCTION(openssl_csr_get_subject); +PHP_FUNCTION(openssl_csr_get_public_key); + +PHP_FUNCTION(openssl_spki_new); +PHP_FUNCTION(openssl_spki_verify); +PHP_FUNCTION(openssl_spki_export); +PHP_FUNCTION(openssl_spki_export_challenge); + +PHP_FUNCTION(openssl_get_cert_locations); + +#ifdef PHP_WIN32 +#define PHP_OPENSSL_BIO_MODE_R(flags) (((flags) & PKCS7_BINARY) ? "rb" : "r") +#define PHP_OPENSSL_BIO_MODE_W(flags) (((flags) & PKCS7_BINARY) ? "wb" : "w") +#else +#define PHP_OPENSSL_BIO_MODE_R(flags) "r" +#define PHP_OPENSSL_BIO_MODE_W(flags) "w" +#endif + +#else + +#define phpext_openssl_ptr NULL + +#endif + + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/php/ext/openssl/tests/001.phpt b/php/ext/openssl/tests/001.phpt new file mode 100644 index 00000000..9bcb3d89 --- /dev/null +++ b/php/ext/openssl/tests/001.phpt @@ -0,0 +1,68 @@ +--TEST-- +OpenSSL private key functions +--SKIPIF-- + +--FILE-- + dirname(__FILE__) . DIRECTORY_SEPARATOR . 'openssl.cnf'); +$privkey = openssl_pkey_new($conf); + +if ($privkey === false) + die("failed to create private key"); + +$passphrase = "banana"; +$key_file_name = tempnam(sys_get_temp_dir(), "ssl"); +if ($key_file_name === false) + die("failed to get a temporary filename!"); + +echo "Export key to file\n"; + +openssl_pkey_export_to_file($privkey, $key_file_name, $passphrase, $conf) or die("failed to export to file $key_file_name"); +var_dump(is_resource($privkey)); + +echo "Load key from file - array syntax\n"; + +$loaded_key = openssl_pkey_get_private(array("file://$key_file_name", $passphrase)); + +if ($loaded_key === false) + die("failed to load key using array syntax"); + +openssl_pkey_free($loaded_key); + +echo "Load key using direct syntax\n"; + +$loaded_key = openssl_pkey_get_private("file://$key_file_name", $passphrase); + +if ($loaded_key === false) + die("failed to load key using direct syntax"); + +openssl_pkey_free($loaded_key); + +echo "Load key manually and use string syntax\n"; + +$key_content = file_get_contents($key_file_name); +$loaded_key = openssl_pkey_get_private($key_content, $passphrase); + +if ($loaded_key === false) + die("failed to load key using string syntax"); + +openssl_pkey_free($loaded_key); + +echo "OK!\n"; + +@unlink($key_file_name); + +?> +--EXPECT-- +Creating private key +Export key to file +bool(true) +Load key from file - array syntax +Load key using direct syntax +Load key manually and use string syntax +OK! diff --git a/php/ext/openssl/tests/74651.pem b/php/ext/openssl/tests/74651.pem new file mode 100644 index 00000000..4ed5905e --- /dev/null +++ b/php/ext/openssl/tests/74651.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEoDCCBAmgAwIBAgIBJzANBgkqhkiG9w0BAQQFADCBkDELMAkGA1UEFhMCUk8x +EDAOBgNVBAgTB1JvbWFuaWExEDAOBgNVBAcTB0NyYWlvdmExDzANBgNVBAoTBlNl +cmdpdTETMBEGA1UECxMKU2VyZ2l1IFNSTDESMBAGA1UEAxMJU2VyZ2l1IENBMSMw +IQYJKoZIhvcNAQkBFhRuX3NlcmdpdUBob3RtYWlsLmNvbTAeFw0wNDA1MTQxMzM0 +NTZaFw0wNTA1MTQxMzM0NTZaMIGaMQswCQYDVQQGEwJSTzEQMA4GA1UECBMHUm9t +YW5pYTEQMA4GA1UEBxMHQ3JhaW92YTETMBEGA1UEChMKU2VyZ2l1IFNSTDETMBEG +A1UECxMKU2VyZ2l1IFNSTDEYMBYGA1UEAxMPU2VyZ2l1IHBlcnNvbmFsMSMwIQYJ +KoZIhvcNAQkBFhRuX3NlcmdpdUBob3RtYWlsLmNvbTCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEApNj7XXz8T8FcLIWpBniPYom3QcT6T7u0xRPHqtqzj5oboBYp +DJe5d354/y0gJTpiLt8+fTrPgWXnbHm3pOHgXzTcX6Arani0GDU0/xDi4VkCRGcS +YqX2sJpcDzAbmK9UDMt3xf/O1B8AJan3RfO0Bm3ozTEPziLMkmsiYr5b/L4CAwEA +AaOCAfwwggH4MAkGA1UdEwQCMAAwNQYJYIZIAYb4QgENBCgWJkZvciBHcmlkIHVz +ZSBvbmx5OyByZXF1ZXN0IHRhZyB1c2VyVGFnMBEGCWCGSAGG+EIBAQQEAwIF4DA/ +BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vbW9iaWxlLmJsdWUtc29mdHdhcmUucm86 +OTAvY2EvY3JsLnNodG1sMDUGCWCGSAGG+EIBCAQoFiZodHRwOi8vbW9iaWxlLmJs +dWUtc29mdHdhcmUucm86OTAvcHViLzAhBgNVHREEGjAYgRZzZXJnaXVAYmx1ZXNv +ZnR3YXJlLnJvMB0GA1UdDgQWBBSwp//5QRXeIzm93TEPl6CyonTg/DCBpwYDVR0j +BIGfMIGcoYGWpIGTMIGQMQswCQYDVQQGEwJSTzEQMA4GA1UECBMHUm9tYW5pYTEQ +MA4GA1UEBxMHQ3JhaW92YTEPMA0GA1UEChMGU2VyZ2l1MRMwEQYDVQQLEwpTZXJn +aXUgU1JMMRIwEAYDVQQDEwlTZXJnaXUgQ0ExIzAhBgkqhkiG9w0BCQEWFG5fc2Vy +Z2l1QGhvdG1haWwuY29tggEAMAsGA1UdDwQEAwIE8DAjBglghkgBhvhCAQIEFhYU +aHR0cDovLzYyLjIzMS45OC41Mi8wCwYDKgMEBAQ+52I0MA0GCSqGSIb3DQEBBAUA +A4GBAIBIOJ+iiLyQfNJEY+IMefayQea0nmuXYY+F+L1DFjSC7xChytgYoPNnKkhh +3dWPtxbswiqKYUnGi6y3Hi4UhDsOaDW29t2S305hSc2qgjOiNtRYQIVYQ8EHG1k7 +Fl63S7uCOhnVJt+4MnUK1N6/pwgsp+Z2GvEsDG1qCKnvNpf6 +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/ServerClientTestCase.inc b/php/ext/openssl/tests/ServerClientTestCase.inc new file mode 100644 index 00000000..fe463003 --- /dev/null +++ b/php/ext/openssl/tests/ServerClientTestCase.inc @@ -0,0 +1,113 @@ +notify(); +} + +function phpt_wait() +{ + ServerClientTestCase::getInstance()->wait(); +} + +/** + * This is a singleton to let the wait/notify functions work + * I know it's horrible, but it's a means to an end + */ +class ServerClientTestCase +{ + private $isWorker = false; + + private $workerHandle; + + private $workerStdIn; + + private $workerStdOut; + + private static $instance; + + public static function getInstance($isWorker = false) + { + if (!isset(self::$instance)) { + self::$instance = new self($isWorker); + } + + return self::$instance; + } + + public function __construct($isWorker = false) + { + if (!isset(self::$instance)) { + self::$instance = $this; + } + + $this->isWorker = $isWorker; + } + + private function spawnWorkerProcess($code) + { + if (defined("PHP_WINDOWS_VERSION_MAJOR")) { + $ini = php_ini_loaded_file(); + $cmd = sprintf('%s %s "%s" %s', PHP_BINARY, $ini ? "-n -c $ini" : "", __FILE__, WORKER_ARGV_VALUE); + } else { + $cmd = sprintf('%s "%s" %s', PHP_BINARY, __FILE__, WORKER_ARGV_VALUE); + } + $this->workerHandle = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], STDERR], $pipes); + $this->workerStdIn = $pipes[0]; + $this->workerStdOut = $pipes[1]; + + fwrite($this->workerStdIn, $code . "\n---\n"); + } + + private function cleanupWorkerProcess() + { + fclose($this->workerStdIn); + fclose($this->workerStdOut); + proc_close($this->workerHandle); + } + + private function stripPhpTagsFromCode($code) + { + return preg_replace('/^\s*<\?(?:php)?|\?>\s*$/i', '', $code); + } + + public function runWorker() + { + $code = ''; + + while (1) { + $line = fgets(STDIN); + + if (trim($line) === "---") { + break; + } + + $code .= $line; + } + + eval($code); + } + + public function run($proc1Code, $proc2Code) + { + $this->spawnWorkerProcess($this->stripPhpTagsFromCode($proc2Code)); + eval($this->stripPhpTagsFromCode($proc1Code)); + $this->cleanupWorkerProcess(); + } + + public function wait() + { + fgets($this->isWorker ? STDIN : $this->workerStdOut); + } + + public function notify() + { + fwrite($this->isWorker ? STDOUT : $this->workerStdIn, "\n"); + } +} + +if (isset($argv[1]) && $argv[1] === WORKER_ARGV_VALUE) { + ServerClientTestCase::getInstance(true)->runWorker(); +} diff --git a/php/ext/openssl/tests/bug25614.phpt b/php/ext/openssl/tests/bug25614.phpt new file mode 100644 index 00000000..a4313070 --- /dev/null +++ b/php/ext/openssl/tests/bug25614.phpt @@ -0,0 +1,14 @@ +--TEST-- +openssl: get public key from generated private key +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_pkey_get_public(): Don't know how to get public key from this private key %s diff --git a/php/ext/openssl/tests/bug28382.phpt b/php/ext/openssl/tests/bug28382.phpt new file mode 100644 index 00000000..2bedeb2d --- /dev/null +++ b/php/ext/openssl/tests/bug28382.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #28382 (openssl_x509_parse extensions support) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +array(11) { + ["basicConstraints"]=> + string(8) "CA:FALSE" + ["nsComment"]=> + string(38) "For Grid use only; request tag userTag" + ["nsCertType"]=> + string(30) "SSL Client, SSL Server, S/MIME" + ["crlDistributionPoints"]=> + string(%d) "%AURI:http://mobile.blue-software.ro:90/ca/crl.shtml +" + ["nsCaPolicyUrl"]=> + string(38) "http://mobile.blue-software.ro:90/pub/" + ["subjectAltName"]=> + string(28) "email:sergiu@bluesoftware.ro" + ["subjectKeyIdentifier"]=> + string(59) "B0:A7:FF:F9:41:15:DE:23:39:BD:DD:31:0F:97:A0:B2:A2:74:E0:FC" + ["authorityKeyIdentifier"]=> + string(115) "DirName:/C=RO/ST=Romania/L=Craiova/O=Sergiu/OU=Sergiu SRL/CN=Sergiu CA/emailAddress=n_sergiu@hotmail.com +serial:00 +" + ["keyUsage"]=> + string(71) "Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment" + ["nsBaseUrl"]=> + string(20) "http://62.231.98.52/" + ["1.2.3.4"]=> + string(4) "%s" +} diff --git a/php/ext/openssl/tests/bug28382cert.txt b/php/ext/openssl/tests/bug28382cert.txt new file mode 100644 index 00000000..cce8d422 --- /dev/null +++ b/php/ext/openssl/tests/bug28382cert.txt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEoDCCBAmgAwIBAgIBJzANBgkqhkiG9w0BAQQFADCBkDELMAkGA1UEBhMCUk8x +EDAOBgNVBAgTB1JvbWFuaWExEDAOBgNVBAcTB0NyYWlvdmExDzANBgNVBAoTBlNl +cmdpdTETMBEGA1UECxMKU2VyZ2l1IFNSTDESMBAGA1UEAxMJU2VyZ2l1IENBMSMw +IQYJKoZIhvcNAQkBFhRuX3NlcmdpdUBob3RtYWlsLmNvbTAeFw0wNDA1MTQxMzM0 +NTZaFw0wNTA1MTQxMzM0NTZaMIGaMQswCQYDVQQGEwJSTzEQMA4GA1UECBMHUm9t +YW5pYTEQMA4GA1UEBxMHQ3JhaW92YTETMBEGA1UEChMKU2VyZ2l1IFNSTDETMBEG +A1UECxMKU2VyZ2l1IFNSTDEYMBYGA1UEAxMPU2VyZ2l1IHBlcnNvbmFsMSMwIQYJ +KoZIhvcNAQkBFhRuX3NlcmdpdUBob3RtYWlsLmNvbTCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEApNj7XXz8T8FcLIWpBniPYom3QcT6T7u0xRPHqtqzj5oboBYp +DJe5d354/y0gJTpiLt8+fTrPgWXnbHm3pOHgXzTcX6Arani0GDU0/xDi4VkCRGcS +YqX2sJpcDzAbmK9UDMt3xf/O1B8AJan3RfO0Bm3ozTEPziLMkmsiYr5b/L8CAwEA +AaOCAfwwggH4MAkGA1UdEwQCMAAwNQYJYIZIAYb4QgENBCgWJkZvciBHcmlkIHVz +ZSBvbmx5OyByZXF1ZXN0IHRhZyB1c2VyVGFnMBEGCWCGSAGG+EIBAQQEAwIF4DA/ +BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vbW9iaWxlLmJsdWUtc29mdHdhcmUucm86 +OTAvY2EvY3JsLnNodG1sMDUGCWCGSAGG+EIBCAQoFiZodHRwOi8vbW9iaWxlLmJs +dWUtc29mdHdhcmUucm86OTAvcHViLzAhBgNVHREEGjAYgRZzZXJnaXVAYmx1ZXNv +ZnR3YXJlLnJvMB0GA1UdDgQWBBSwp//5QRXeIzm93TEPl6CyonTg/DCBpwYDVR0j +BIGfMIGcoYGWpIGTMIGQMQswCQYDVQQGEwJSTzEQMA4GA1UECBMHUm9tYW5pYTEQ +MA4GA1UEBxMHQ3JhaW92YTEPMA0GA1UEChMGU2VyZ2l1MRMwEQYDVQQLEwpTZXJn +aXUgU1JMMRIwEAYDVQQDEwlTZXJnaXUgQ0ExIzAhBgkqhkiG9w0BCQEWFG5fc2Vy +Z2l1QGhvdG1haWwuY29tggEAMAsGA1UdDwQEAwIE8DAjBglghkgBhvhCAQIEFhYU +aHR0cDovLzYyLjIzMS45OC41Mi8wCwYDKgMEBAQ+52I0MA0GCSqGSIb3DQEBBAUA +A4GBAIBIOJ+iiLyQfNJEY+IMefayQea0nmuXYY+F+L1DFjSC7xChytgYoPNnKkhh +3dWPtxbswiqKYUnGi6y3Hi4UhDsOaDW29t2S305hSc2qgjOiNtRYQIVYQ8EHG1k7 +Fl63S7uCOhnVJt+4MnUK1N6/pwgsp+Z2GvEsDG1qCKnvNpf6 +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug36732.phpt b/php/ext/openssl/tests/bug36732.phpt new file mode 100644 index 00000000..87fad984 --- /dev/null +++ b/php/ext/openssl/tests/bug36732.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #36732 (add support for req_extensions in openss_csr_new and sign) +--SKIPIF-- + +--FILE-- + "v3_req", + "x509_extensions" => "usr_cert", + "config" => __DIR__. DIRECTORY_SEPARATOR . "openssl.cnf", +); + +$dn = array( + "countryName" => "GB", + "stateOrProvinceName" => "Berkshire", + "localityName" => "Newbury", + "organizationName" => "My Company Ltd", + "commonName" => "Demo Cert" +); + +$key = openssl_pkey_new(); +$csr = openssl_csr_new($dn, $key, $configargs); +$crt = openssl_csr_sign($csr, NULL, $key, 365, $configargs); + +$str = ''; +openssl_csr_export($csr, $str, false); + +if (strpos($str, 'Requested Extensions:')) { + echo "Ok\n"; +} +openssl_x509_export($crt, $str, false); +if (strpos($str, 'X509v3 extensions:')) { + echo "Ok\n"; +} +?> +--EXPECTF-- +Ok +Ok diff --git a/php/ext/openssl/tests/bug37820.phpt b/php/ext/openssl/tests/bug37820.phpt new file mode 100644 index 00000000..2eef8c5b --- /dev/null +++ b/php/ext/openssl/tests/bug37820.phpt @@ -0,0 +1,36 @@ +--TEST-- +openssl_sign/verify: accept different algos +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Ok diff --git a/php/ext/openssl/tests/bug37820cert.pem b/php/ext/openssl/tests/bug37820cert.pem new file mode 100644 index 00000000..9d7ac238 --- /dev/null +++ b/php/ext/openssl/tests/bug37820cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD +VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv +bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy +dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X +DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw +EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l +dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT +EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw +L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN +BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX +9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug37820key.pem b/php/ext/openssl/tests/bug37820key.pem new file mode 100644 index 00000000..239ad66f --- /dev/null +++ b/php/ext/openssl/tests/bug37820key.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNwL4lYKbpzzlmC5beaQXeQ +2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAAQJBALjkK+jc2+iihI98riEF +oudmkNziSRTYjnwjx8mCoAjPWviB3c742eO3FG4/soi1jD9A5alihEOXfUzloenr +8IECIQD3B5+0l+68BA/6d76iUNqAAV8djGTzvxnCxycnxPQydQIhAMXt4trUI3nc +a+U8YL2HPFA3gmhBsSICbq2OptOCnM7hAiEA6Xi3JIQECob8YwkRj29DU3/4WYD7 +WLPgsQpwo1GuSpECICGsnWH5oaeD9t9jbFoSfhJvv0IZmxdcLpRcpslpeWBBAiEA +6/5B8J0GHdJq89FHwEG/H2eVVUYu5y/aD6sgcm+0Avg= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/bug38255.phpt b/php/ext/openssl/tests/bug38255.phpt new file mode 100644 index 00000000..48726055 --- /dev/null +++ b/php/ext/openssl/tests/bug38255.phpt @@ -0,0 +1,55 @@ +--TEST-- +openssl key from zval leaks +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_verify(): supplied key param cannot be coerced into a public key in %s on line %d + +Warning: openssl_verify(): supplied key param cannot be coerced into a public key in %s on line %d +bool(false) + +Warning: openssl_verify(): supplied key param cannot be coerced into a public key in %s on line %d +bool(false) + +Warning: openssl_verify() expects parameter 2 to be string, object given in %s on line %d +NULL + +Warning: openssl_verify() expects parameter 2 to be string, object given in %s on line %d +NULL + +Warning: openssl_verify() expects parameter 2 to be string, array given in %s on line %d +NULL + +Warning: openssl_verify() expects at least 3 parameters, 0 given in %s on line %d +NULL + +Warning: openssl_verify() expects parameter 1 to be string, object given in %s on line %d +NULL +Done diff --git a/php/ext/openssl/tests/bug38261.phpt b/php/ext/openssl/tests/bug38261.phpt new file mode 100644 index 00000000..66de8b87 --- /dev/null +++ b/php/ext/openssl/tests/bug38261.phpt @@ -0,0 +1,34 @@ +--TEST-- +openssl key from zval leaks +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(false) +bool(false) +bool(false) + +Warning: openssl_x509_parse() expects at least 1 parameter, 0 given in %sbug38261.php on line %d +NULL +bool(false) + +Recoverable fatal error: Object of class stdClass could not be converted to string in %sbug38261.php on line %d diff --git a/php/ext/openssl/tests/bug39217.phpt b/php/ext/openssl/tests/bug39217.phpt new file mode 100644 index 00000000..7895e2f3 --- /dev/null +++ b/php/ext/openssl/tests/bug39217.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #39217 (Large serial number return -1) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +163040343498260435477161879008842183802 +15 diff --git a/php/ext/openssl/tests/bug39217cert1.txt b/php/ext/openssl/tests/bug39217cert1.txt new file mode 100644 index 00000000..c3ddfb4a --- /dev/null +++ b/php/ext/openssl/tests/bug39217cert1.txt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICvzCCAiigAwIBAgIBDzANBgkqhkiG9w0BAQUFADBbMRkwFwYDVQQKExBET0Ug +U2NpZW5jZSBHcmlkMSAwHgYDVQQLExdDZXJ0aWZpY2F0ZSBBdXRob3JpdGllczEc +MBoGA1UEAxMTQ2VydGlmaWNhdGUgTWFuYWdlcjAeFw0wMDA4MjkyMjI4MDJaFw0w +MTA4MjkyMjI4MDJaMHgxDTALBgNVBAoTBEdyaWQxLjAsBgNVBAoTJUxhd3JlbmNl +IEJlcmtlbGV5IE5hdGlvbmFsIExhYm9yYXRvcnkxIDAeBgNVBAsTF0NlcnRpZmlj +YXRlIEF1dGhvcml0aWVzMRUwEwYDVQQDEwxMQk5MLUdyaWQtQ0EwgZ8wDQYJKoZI +hvcNAQEBBQADgY0AMIGJAoGBAL2t4aX933WXYlofuY+L+16Tdl/KxpAammyfcW8u +kHHT6RYDjaQdfV1FpNEqfSrRjKNwGGGkrG4XHZWiUO0Di0AlBN04lsRY6jB68l6B +5byujfZv+8EeCI2c1ObBLYZYi4lToJf0sm0Hpn3GD7PZBv6BVHLOuwEFDl9z9Dnc +DFDdAgMBAAGjdjB0MBEGCWCGSAGG+EIBAQQEAwIAhzAOBgNVHQ8BAf8EBAMCAcYw +HQYDVR0OBBYEFIn+csPVyp+iprpYUIu1SziMQiDxMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAUm85P8ry9WHAx1fIyDn6eveJRFOcwDQYJKoZIhvcNAQEFBQAD +gYEAHindWQ4P4VUmJVt5sUGA05hSAZriDJDDnkvkm/9AR7xgGxtsy21QruhUVe2E +eVFBws85zbwRqMpfUQyE/xHhUcka2GQTaKlBlcEjZTMnsh27Si2PMYU/UPr/PIpq +kBkoxVV1bMWRK57mG2tzzTy9j0wkct4G5IjEsrYNDzW6U3E= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug39217cert2.txt b/php/ext/openssl/tests/bug39217cert2.txt new file mode 100644 index 00000000..399618ca --- /dev/null +++ b/php/ext/openssl/tests/bug39217cert2.txt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC3DCCAkWgAwIBAgIQeqhtj1pzHCrTTq2AldV0ejANBgkqhkiG9w0BAQQFADAy +MRcwFQYDVQQKEw5FLUFDSEFUIE1JTkRFRjEXMBUGA1UEAxMORS1BQ0hBVCBNSU5E +RUYwHhcNMDQwMTA1MDAwMDAwWhcNMDYwMTA0MjM1OTU5WjCB5DEOMAwGA1UEBxQF +UEFSSVMxCzAJBgNVBAYTAkZSMRcwFQYDVQQKFA5FLUFDSEFUIE1JTkRFRjEtMCsG +A1UECxQkRW50LiAtIENhcCBHZW1pbmkgRXJuc3QgWW91bmcgRnJhbmNlMR8wHQYD +VQQLFBZTSVJFTiAtIDMyODc4MTc4NjAwMDUzMTQwMgYDVQQDEytDR0VZIEZyYW5j +ZSAtIENhcCBHZW1pbmkgRXJuc3QgWW91bmcgRnJhbmNlMSYwJAYJKoZIhvcNAQkB +FhdkZ2FlbWEtbWNvQGNhcGdlbWluaS5mcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEApFgcuVTuUe0z+iGTaPw7yVxhZsPq6aIqGHsCvU9fqUcymbmg9l4oTfAk +gR5bvDo+JTQb1/OPlQCKqyVa7wn6lPs97dMOZMobjCRcvw7z0jVphortA1NS8FRH +6LsWELZ13uC57IIakpW726Vz3tST9qHHbQoWbX/n8NjHcwL4zUECAwEAAaNAMD4w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMBEGCmCG +SAGG+EUBBgkEAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAWdmEu8TkFdgqA/xN6llo9 +zZR3EUH0X5HstxJRYgofcQyfumJHhgvaNB8vkDhZ3iJORVVxcJ27W36TAJ6b4jcr +yWjO/nc42XdgknS8r9NIV7VKzmjY7Ip2+9N6JOAWFkjGrnF1G69nrerIJavJTzrb +PYlQnzJO6SHAoi5j6WsKPw== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug41033.pem b/php/ext/openssl/tests/bug41033.pem new file mode 100644 index 00000000..4ae74b9a --- /dev/null +++ b/php/ext/openssl/tests/bug41033.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCrQ/By/Y5OQRmmc/e+W+eFVoeR5y8WPOkykwS2hc21aSNY5X3q +8ZHdV467thFd/QCoR55hHTRGRbYmfOkXSiscotU08ISlxIH39EEhFSzwqzkxFfak +cgHEu41AUOIfJ2Dz+vcmuasME159pDP0d0gt55pKRPcXoh916p2VS/FBiQIVAMnQ +C6W+K1brelHqpUqwQ1cdNJklAoGAN858gG/UIF+U3CYTcgl5/OUAqOzvitMV2ue+ +AkDEkGNEZs3KUAjpqHduf1E3znl7hJJIRr+33sul9USxn0vczDBkEJPralQjNX2C +dnYKDDhJ+UKlAFG2JZint4CBKPFiZC0tVo04iDQQUUfDC4c8K3cS5uzypebJyoLo +e5b8rScCgYBedJg6vklhMWv2wZD10hbQaXEX5r8T6EQujbfO0RcKpuaJziPPrXO8 +QwPtLt0f40yjTmPxN3LcpgMymiun9UCSTZ3MhVKekCmSNzs5+lQpCm1VlDrCg+jn +djw0VCX8Cm0lOPIyQ4eCNAB6nQLtBnXFWaqYuUS8iVDE7wmT0iwnkAIVAMKogWVA +ZOKwjTj9Yztv3lGj7VTa +-----END DSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/bug41033.phpt b/php/ext/openssl/tests/bug41033.phpt new file mode 100644 index 00000000..4e9bea3e --- /dev/null +++ b/php/ext/openssl/tests/bug41033.phpt @@ -0,0 +1,27 @@ +--TEST-- +#41033, enable signing with DSA keys +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Signature: %s +Signature validity: 1 diff --git a/php/ext/openssl/tests/bug41033pub.pem b/php/ext/openssl/tests/bug41033pub.pem new file mode 100644 index 00000000..0d4ab27f --- /dev/null +++ b/php/ext/openssl/tests/bug41033pub.pem @@ -0,0 +1,12 @@ +-----BEGIN PUBLIC KEY----- +MIIBtjCCASsGByqGSM44BAEwggEeAoGBAKtD8HL9jk5BGaZz975b54VWh5HnLxY8 +6TKTBLaFzbVpI1jlferxkd1Xjru2EV39AKhHnmEdNEZFtiZ86RdKKxyi1TTwhKXE +gff0QSEVLPCrOTEV9qRyAcS7jUBQ4h8nYPP69ya5qwwTXn2kM/R3SC3nmkpE9xei +H3XqnZVL8UGJAhUAydALpb4rVut6UeqlSrBDVx00mSUCgYA3znyAb9QgX5TcJhNy +CXn85QCo7O+K0xXa574CQMSQY0RmzcpQCOmod25/UTfOeXuEkkhGv7fey6X1RLGf +S9zMMGQQk+tqVCM1fYJ2dgoMOEn5QqUAUbYlmKe3gIEo8WJkLS1WjTiINBBRR8ML +hzwrdxLm7PKl5snKguh7lvytJwOBhAACgYBedJg6vklhMWv2wZD10hbQaXEX5r8T +6EQujbfO0RcKpuaJziPPrXO8QwPtLt0f40yjTmPxN3LcpgMymiun9UCSTZ3MhVKe +kCmSNzs5+lQpCm1VlDrCg+jndjw0VCX8Cm0lOPIyQ4eCNAB6nQLtBnXFWaqYuUS8 +iVDE7wmT0iwnkA== +-----END PUBLIC KEY----- diff --git a/php/ext/openssl/tests/bug41353.phpt b/php/ext/openssl/tests/bug41353.phpt new file mode 100644 index 00000000..47fda89f --- /dev/null +++ b/php/ext/openssl/tests/bug41353.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #41353 (openssl_pkcs12_read() does not verify the type of the first arg) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Done diff --git a/php/ext/openssl/tests/bug46127.pem b/php/ext/openssl/tests/bug46127.pem new file mode 100644 index 00000000..9d754d46 --- /dev/null +++ b/php/ext/openssl/tests/bug46127.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIC5jCCAk+gAwIBAgIBADANBgkqhkiG9w0BAQQFADBcMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKUXVlZW5zbGFuZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQx +HDAaBgNVBAMTE1Rlc3QgUENBICgxMDI0IGJpdCkwHhcNOTkxMjAyMjEzNTQ4WhcN +MDUwNzExMjEzNTQ4WjBcMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFu +ZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxHDAaBgNVBAMTE1Rlc3QgUENB +ICgxMDI0IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ2haT/f5Zwy +V+MiuSDjSR62adBoSiBB7Usty44lXqsp9RICw+DCCxpsn/CfxPEDXLLd4olsWXc6 +JRcxGynbYmnzk+Z6aIPPJQhK3CTvaqGnWKZsA1m+WaUIUqJCuNTK4N+7hMAGaf6S +S3e9HVgEQ4a34gXJ7VQFVIBNV1EnZRWHAgMBAAGjgbcwgbQwHQYDVR0OBBYEFE0R +aEcrj18q1dw+G6nJbsTWR213MIGEBgNVHSMEfTB7gBRNEWhHK49fKtXcPhupyW7E +1kdtd6FgpF4wXDELMAkGA1UEBhMCQVUxEzARBgNVBAgTClF1ZWVuc2xhbmQxGjAY +BgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRwwGgYDVQQDExNUZXN0IFBDQSAoMTAy +NCBiaXQpggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAUa8B3pho ++Mvxeq9HsEzJxHIFQla05S5J/e/V+DQTYoKiRFchKPrDAdrzYSEvP3h4QJEtsNqQ +JfOxg5M42uLFq7aPGWkF6ZZqZsYS+zA9IVT14g7gNA6Ne+5QtJqQtH9HA24st0T0 +Tga/lZ9M2ovImovaxSL/kRHbpCWcqWVxpOw= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCdoWk/3+WcMlfjIrkg40ketmnQaEogQe1LLcuOJV6rKfUSAsPg +wgsabJ/wn8TxA1yy3eKJbFl3OiUXMRsp22Jp85PmemiDzyUIStwk72qhp1imbANZ +vlmlCFKiQrjUyuDfu4TABmn+kkt3vR1YBEOGt+IFye1UBVSATVdRJ2UVhwIDAQAB +AoGAba4fTtuap5l7/8ZsbE7Z1O32KJY4ZcOZukLOLUUhXxXduT+FTgGWujc0/rgc +z9qYCLlNZHOouMYTgtSfYvuMuLZ11VIt0GYH+nRioLShE59Yy+zCRyC+gPigS1kz +xvo14AsOIPYV14Tk/SsHyq6E0eTk7VzaIE197giiINUERPECQQDSKmtPTh/lRKw7 +HSZSM0I1mFWn/1zqrAbontRQY5w98QWIOe5qmzYyFbPXYT3d9BzlsMyhgiRNoBbD +yvohSHXJAkEAwAHx6ezAZeWWzD5yXD36nyjpkVCw7Tk7TSmOceLJMWt1QcrCfqlS +xA5jjpQ6Z8suU5DdtWAryM2sAir1WisYzwJAd6Zcx56jvAQ3xcPXsE6scBTVFzrj +7FqZ6E+cclPzfLQ+QQsyOBE7bpI6e/FJppY26XGZXo3YGzV8IGXrt40oOQJALETG +h86EFXo3qGOFbmsDy4pdP5nBERCu8X1xUCSfintiD4c2DInxgS5oGclnJeMcjTvL +QjQoJCX3UJCi/OUO1QJBAKgcDHWjMvt+l1pjJBsSEZ0HX9AAIIVx0RQmbFGS+F2Q +hhu5l77WnnZOQ9vvhV5u7NPCUF9nhU3jh60qWWO8mkc= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/bug46127.phpt b/php/ext/openssl/tests/bug46127.phpt new file mode 100644 index 00000000..5410d2f8 --- /dev/null +++ b/php/ext/openssl/tests/bug46127.phpt @@ -0,0 +1,42 @@ +--TEST-- +#46127, openssl_sign/verify: accept different algos +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug46127.pem', + ]]); + + $sock = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $link = stream_socket_accept($sock); + fwrite($link, "Sending bug 46127\n"); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false + ]]); + + phpt_wait(); + $sock = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); + + echo fgets($sock); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECT-- +Sending bug 46127 diff --git a/php/ext/openssl/tests/bug47828.phpt b/php/ext/openssl/tests/bug47828.phpt new file mode 100644 index 00000000..6f7ee395 --- /dev/null +++ b/php/ext/openssl/tests/bug47828.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #47828 (segfaults when a UTF-8 conversion fails openssl_x509_parse()) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(8) "%s" +Done diff --git a/php/ext/openssl/tests/bug48182.phpt b/php/ext/openssl/tests/bug48182.phpt new file mode 100644 index 00000000..5211c23d --- /dev/null +++ b/php/ext/openssl/tests/bug48182.phpt @@ -0,0 +1,50 @@ +--TEST-- +Bug #48182: ssl handshake fails during asynchronous socket connection +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $client = @stream_socket_accept($server, 1); + + $data = "Sending bug48182\n" . fread($client, 8192); + fwrite($client, $data); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local' + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 10, $clientFlags, $clientCtx); + + $data = "Sending data over to SSL server in async mode with contents like Hello World\n"; + + fwrite($client, $data); + echo fread($client, 1024); +CODE; + +echo "Running bug48182\n"; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Running bug48182 +Sending bug48182 +Sending data over to SSL server in async mode with contents like Hello World diff --git a/php/ext/openssl/tests/bug54060.phpt b/php/ext/openssl/tests/bug54060.phpt new file mode 100644 index 00000000..88f1f944 --- /dev/null +++ b/php/ext/openssl/tests/bug54060.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #54060 (Memory leak in openssl_encrypt) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Done diff --git a/php/ext/openssl/tests/bug54061.phpt b/php/ext/openssl/tests/bug54061.phpt new file mode 100644 index 00000000..f1d2e24a --- /dev/null +++ b/php/ext/openssl/tests/bug54061.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #54061 (Memory leak in openssl_decrypt) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Done diff --git a/php/ext/openssl/tests/bug54992-ca.pem b/php/ext/openssl/tests/bug54992-ca.pem new file mode 100644 index 00000000..0fdbb2f9 --- /dev/null +++ b/php/ext/openssl/tests/bug54992-ca.pem @@ -0,0 +1,42 @@ +-----BEGIN CERTIFICATE----- +MIIHZzCCBU+gAwIBAgIBATANBgkqhkiG9w0BAQQFADCByzEpMCcGA1UEAxMgQ2F0 +YXBocmFjdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxCzAJBgNVBAYTAlBUMQ8wDQYD +VQQHEwZMaXNib2ExETAPBgNVBAgTCFBvcnR1Z2FsMSkwJwYDVQQKEyBDYXRhcGhy +YWN0IENlcnRpZmljYXRlIEF1dGhvcml0eTEcMBoGA1UECxMTQ2VydGlmaWNhdGUg +U2lnbmluZzEkMCIGCSqGSIb3DQEJARYVQ2F0YXBocmFjdEBuZXRjYWJvLnB0MB4X +DTAzMTIwNTAwMTExOVoXDTE4MTIwMTAwMTExOVowgcsxKTAnBgNVBAMTIENhdGFw +aHJhY3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQswCQYDVQQGEwJQVDEPMA0GA1UE +BxMGTGlzYm9hMREwDwYDVQQIEwhQb3J0dWdhbDEpMCcGA1UEChMgQ2F0YXBocmFj +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHDAaBgNVBAsTE0NlcnRpZmljYXRlIFNp +Z25pbmcxJDAiBgkqhkiG9w0BCQEWFUNhdGFwaHJhY3RAbmV0Y2Fiby5wdDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANg+noZuxtWdxmZjxanJGEpzmDYu +Uko9OHdmhVr3UU+z04a9JFT7aH5wuwrnpadNy1u9CqrSHVWFEtSmOMOH8QYzIy4C +qCjFPSJR5UQjxpxTZeXaTvfhKI9n0LMSqc7I68HkP5MF64N3Z2cRdYvM4U6R5ERD +Xw2LiRpii/+J2cezgi/Nw3vS4hZlWDWMkttfBd0HKSwxxN7OlPcjyzoTVhQgSISV +Zvd3kwENTWD7s3EnnPRtMiW8Vzcjd8eSTCSjuGBG/8NnI44amLo7gSWocCJ2os69 +CJgiqMpp0tLT8cJm0mQUBk0o9gBS7l1GPpgq5fwWG+DmoLIHrKjxpuI5v2DW23gx +yimXSyiD1GX0JLlTqZ+klM7Mv7ptnigRXA8F5f4GbVzBlGM1L1EERd8orsSmzPEA +S6puHdlNzjcx00glp1UoAs6+tV39eW/fjiP493biPcar0pNO8QWfRSqPsgy6/qKN +m7x2DoSdTbRgCalBMp57xYCUHIETZvlewGKnQD1Tj9FlbzvOnH6r52gj5U/5r3pn +E4DshILn/qtdRwd/2Dwx/KSyBJznU7Yu0vEeMwQioZ6YFH1FnC4229lHYCN6ByVw +UE7OMH7n0A8SUN8flxr2X7MmWpQsMrgVfrAjufmFwUaeIRq9X3wihDYw0MYP0brU +x5ONmY+VA93gLdStAgMBAAGjggFSMIIBTjASBgNVHRMBAf8ECDAGAQH/AgEBMB0G +A1UdDgQWBBQj+82/Y4YWpR8kIi0obJULkqmBwTCB+AYDVR0jBIHwMIHtgBQj+82/ +Y4YWpR8kIi0obJULkqmBwaGB0aSBzjCByzEpMCcGA1UEAxMgQ2F0YXBocmFjdCBD +ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxCzAJBgNVBAYTAlBUMQ8wDQYDVQQHEwZMaXNi +b2ExETAPBgNVBAgTCFBvcnR1Z2FsMSkwJwYDVQQKEyBDYXRhcGhyYWN0IENlcnRp +ZmljYXRlIEF1dGhvcml0eTEcMBoGA1UECxMTQ2VydGlmaWNhdGUgU2lnbmluZzEk +MCIGCSqGSIb3DQEJARYVQ2F0YXBocmFjdEBuZXRjYWJvLnB0ggEBMAsGA1UdDwQE +AwIBBjARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEEBQADggIBAKN6pRY1 +8GwQx378ukmw4pzvODlee5IKSPRT92hfLKNGNUAMu2LFo+bjItpilhSvR4aklRvh +5RBoVE8ejEdZXsz0HobMUUcL9IemaRwBCWHPii7Y3zX2J1FUiS/KmWhrYvw5hb1P +P83f/kxdWhxD+MbwuGc2I/6WgfsRyzevQsxdJgElQvNGkOXsC56pEXm2ChVoLbZL +sZX0zPa5ZzXByQGwXl9eqOkV7fdNKulJPcLPOs/y1cAfcxXrDYHpqBGf9nb14p3C +NaWXFhvq9Khk/QiWKSO4QarPlYS4H0Sl6tp7zBaE+dZHAjci2mSTraUf7q61kqoJ +g/ZA3qupd1rR67NzN+6x/TJmIq0G3GUxnDNNqNAHvS4YJx8g4Ji0F3Qoz3CgKnc4 +HsneYQ/LCLq2pDjsffnLI88MBGbfHZDjdj2nowwX76W/6PPutD5IR/kOmHEaX1TJ +/Ff99bVV4HwNF3GPwmKPmHpw3hB9A/xG9aiQRcYs0reXoYeQ+8nyCGmu41LweFyV +1WVwWJ/MHgdtzJZHdPjeXKMWQzOx3AS3TCc31oi4IEo4NgNigcuvl0qgUcwDRXBI +HZm4f7npm7xiES8BSoq5PIVCj8EXJd4b7Gk6dHGJGO+APaw3kYKqfqg5+AN1e4a5 +x3onNvWhjcwDGgcs/xAfVJIUucEqpC5h0pZq +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug54992.pem b/php/ext/openssl/tests/bug54992.pem new file mode 100644 index 00000000..0675450a --- /dev/null +++ b/php/ext/openssl/tests/bug54992.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIFizCCA3OgAwIBAgIBGTANBgkqhkiG9w0BAQUFADCByzEpMCcGA1UEAxMgQ2F0 +YXBocmFjdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxCzAJBgNVBAYTAlBUMQ8wDQYD +VQQHEwZMaXNib2ExETAPBgNVBAgTCFBvcnR1Z2FsMSkwJwYDVQQKEyBDYXRhcGhy +YWN0IENlcnRpZmljYXRlIEF1dGhvcml0eTEcMBoGA1UECxMTQ2VydGlmaWNhdGUg +U2lnbmluZzEkMCIGCSqGSIb3DQEJARYVQ2F0YXBocmFjdEBuZXRjYWJvLnB0MB4X +DTExMDYwNzIzNTIwM1oXDTE4MTIwMTAwMTExOVowWjEXMBUGA1UEAxMOYnVnNTQ5 +OTIubG9jYWwxCzAJBgNVBAYTAlBUMQ8wDQYDVQQHEwZMaXNib2ExDzANBgNVBAgT +Bkxpc2JvYTEQMA4GA1UEChMHcGhwLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAtUAVQKTgpUPgtFOJ3w3kDJETS45tWeT96kUg1NeYLKW+jNbFhxPoPJv7 +XhfemCaqh2tbq1cdYW906Wp1L+eNQvdTYA2IQG4EQBUlmfyIakOIMsN/RizVkF09 +vlNQwTpaMpqTv7wB8vvwbxb9jbC2ZhQUBEg6PIn18dSstbM9FZ0CAwEAAaOCAWww +ggFoMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCysG9r7vXtfHa38AUZeCM6tgH9c +MIH4BgNVHSMEgfAwge2AFCP7zb9jhhalHyQiLShslQuSqYHBoYHRpIHOMIHLMSkw +JwYDVQQDEyBDYXRhcGhyYWN0IENlcnRpZmljYXRlIEF1dGhvcml0eTELMAkGA1UE +BhMCUFQxDzANBgNVBAcTBkxpc2JvYTERMA8GA1UECBMIUG9ydHVnYWwxKTAnBgNV +BAoTIENhdGFwaHJhY3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRwwGgYDVQQLExND +ZXJ0aWZpY2F0ZSBTaWduaW5nMSQwIgYJKoZIhvcNAQkBFhVDYXRhcGhyYWN0QG5l +dGNhYm8ucHSCAQEwCwYDVR0PBAQDAgXgMBEGCWCGSAGG+EIBAQQEAwIGQDAeBglg +hkgBhvhCAQ0EERYPeGNhIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4ICAQAT +M7Id7nBSvaDXuStLunfeV0WPAh3DkKWCxw9YK0MjK7E/K5xEiYaWWbz9zuHEcKrN +MuflSdYVPXTqvD6mHLFNptOgzG6YMOO+rAAEYB5HZ/PYTO6UWAdSLlS96DpA4SS3 +Qwmrc0eXe1p4U8noEN+N3+rAbetjOuvnLG/cpoQGcA8Mws84B/elzjRne5C8N1rF +Tvdb3bqIqvP1thuPfyh/uIKSQb5ZusHvj7ZBkEs+zQLBRnCcDK4ETXFM0TcKSPar +d11tve/91BqqemwlA+ntVrVTgi/pnw4wuWxa3GOVmeEeWgtv3063wZ3lGv/72PCh +gSjxoCoVLaLPTbC/iG2a5+ca2HcF0TjfJqYNCgosgRGlm5IunvuIv+g5jLcZcDSO +hMw+HzyF8GlDF166YRRb9nUL6AtBisdEw6uQW1vQFRRQS4SGMoArSBw2EBqd7Kvf +ruCMcrkudC8vbWQHMETEvhAXdAjgsIxLeGCPh0/8mtES1Lnr0TWIrM9evPJkKACj +f6CyIASkIDZKFf5JwuUh02qvuNLr/QRELfI1NnA1aTYMQQWWOVCBffu4ce+NPdtl +Uh1vRwWAWI0Zjszw3kUk2vHLbSXeD3bU7gP3IFa1X8XsXBW2SH+BfpNWHUilHj1I +bX+zqjfaRWDJuZqB9y6iTCu8DfBtbMiTUGcI/Rs9wQ== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQC1QBVApOClQ+C0U4nfDeQMkRNLjm1Z5P3qRSDU15gspb6M1sWH +E+g8m/teF96YJqqHa1urVx1hb3TpanUv541C91NgDYhAbgRAFSWZ/IhqQ4gyw39G +LNWQXT2+U1DBOloympO/vAHy+/BvFv2NsLZmFBQESDo8ifXx1Ky1sz0VnQIDAQAB +AoGBALUEnHUkdgv4P7o5WJACAomedqPWSlYmgoVvpvuLmrq0ihuFAGAIvL+TlTgD +JNfWfiejTDlSVtCSDTR1kzZVztitfXDxRkWEjGtFjMhk/DJkql3w10SUtcqCiWqw +/XknyPHZ7A+w7Fu5KRO2LoSIze2ZLKvCfP/M/pLR2fTKGTHtAkEA2NreT1GUnvzj +u1lb2J0nTZbSQHvEkfpEej9akl0Bc5UkskenEsiXE3cJYA1TbEGSqYCmt23x3Rd2 +FYxm6MwV6wJBANX34ZuUOllsS0FJPbkEAps3M4s59daQSFiEkQc5XjPgVB0xVV7s +OEBlGkM3eqcCUOMnMI8L9wfBk49sELZCeJcCQQC/y/TL2q/EXo9c6I/faj+U1Exp +VA5rvhpKtTX6NeBOxh6Kv+z5JAja4nGcTqz2FpkM6giKO+erUFDUhjWOuNK5AkEA +xkmHnCRLxp8jRodXWeQrfigz7ixydLsVMGL5+9XgRPb5PGyBjwwePR70raH2Wls9 +FqU0zPvrnBZ6Zwlgm2cSVQJAPLYA51Z9piajbTuggpioQ5qbUEDkJjmYHbm8eJnK +h5NW/EtCk4SBxAc+8ElPrvJjtZyOPWfm4vZF5sDKtC3Fkg== +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/bug54992.phpt b/php/ext/openssl/tests/bug54992.phpt new file mode 100644 index 00000000..878cb4a8 --- /dev/null +++ b/php/ext/openssl/tests/bug54992.phpt @@ -0,0 +1,47 @@ +--TEST-- +Bug #54992: Stream not closed and error not returned when SSL CN_match fails +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'buga_buga', + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); + + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): Peer certificate CN=`bug54992.local' did not match expected CN=`buga_buga' in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) + + diff --git a/php/ext/openssl/tests/bug55259.phpt b/php/ext/openssl/tests/bug55259.phpt new file mode 100644 index 00000000..b58d28ad --- /dev/null +++ b/php/ext/openssl/tests/bug55259.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #55259 (openssl extension does not get the DH parameters from DH key resource) +--SKIPIF-- + +--FILE-- + $phex, 'g' => '2' ); +$dh = openssl_pkey_new(array( 'dh'=> array( 'p' => $phex, 'g' => '2' ))); +var_dump($dh); +$dh = openssl_pkey_new(array( 'dh'=> array( 'p' => hex2bin($phex), 'g' => '2' ))); +$details = openssl_pkey_get_details($dh); +var_dump(bin2hex($details['dh']['p'])); +var_dump($details['dh']['g']); +var_dump(strlen($details['dh']['pub_key']) > 0); +var_dump(strlen($details['dh']['priv_key']) > 0); +echo "Done"; +?> +--EXPECT-- +bool(false) +string(256) "dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61ef75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d2683705577d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e3826634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab" +string(1) "2" +bool(true) +bool(true) +Done diff --git a/php/ext/openssl/tests/bug55646.phpt b/php/ext/openssl/tests/bug55646.phpt new file mode 100644 index 00000000..6c504588 --- /dev/null +++ b/php/ext/openssl/tests/bug55646.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #55646: textual input in openssl_csr_new() is not expected in UTF-8 +--SKIPIF-- + "sha1","x509_extensions" => "v3_ca","req_extensions" => "v3_req","private_key_bits" => 2048,"private_key_type" => OPENSSL_KEYTYPE_RSA,"encrypt_key" => false,); +$csr_info = array( + "countryName" => "US", + "stateOrProvinceName" => "Utah", + "localityName" => "Lindon", + "organizationName" => "Chinese", + "organizationalUnitName" => "IT \xe4\xba\x92", + "commonName" => "www.example.com",); +$private = openssl_pkey_new($config); +while (openssl_error_string()) {} +$csr_res = openssl_csr_new($csr_info, $private, + ['config' => __DIR__. DIRECTORY_SEPARATOR . "openssl.cnf"]); +if (!$csr_res) { + while ($e = openssl_error_string()) { $err = $e; } + die("Failed; last error: $err"); +} +openssl_csr_export($csr_res, $csr); +$output = openssl_csr_get_subject($csr); + +echo "A: ".$csr_info["organizationalUnitName"]."\n"; +echo "B: ".stringAsHex($csr_info["organizationalUnitName"])."\n"; +echo "C: ".$output['OU']."\n"; +echo "D: ".stringAsHex($output['OU'])."\n"; +--EXPECT-- +A: IT 互 +B: 49 54 20 e4 ba 92 +C: IT 互 +D: 49 54 20 e4 ba 92 diff --git a/php/ext/openssl/tests/bug60632.phpt b/php/ext/openssl/tests/bug60632.phpt new file mode 100644 index 00000000..eb51276f --- /dev/null +++ b/php/ext/openssl/tests/bug60632.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #60632: openssl_seal fails with AES +--SKIPIF-- + +--FILE-- + 'sha256', + 'private_key_bits' => 1024, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + 'encrypt_key' => false, + 'config' => __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf', +)); +$details = openssl_pkey_get_details($pkey); +$test_pubkey = $details['key']; +$pubkey = openssl_pkey_get_public($test_pubkey); +$encrypted = null; +$ekeys = array(); +$result = openssl_seal('test phrase', $encrypted, $ekeys, array($pubkey), 'AES-256-CBC'); +echo "Done"; +?> +--EXPECTF-- +Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d +Done diff --git a/php/ext/openssl/tests/bug61124.phpt b/php/ext/openssl/tests/bug61124.phpt new file mode 100644 index 00000000..4b6194bd --- /dev/null +++ b/php/ext/openssl/tests/bug61124.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #61124: Segmentation fault with openssl_decrypt +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (OpenSSL key) +int(1) + diff --git a/php/ext/openssl/tests/bug64802.pem b/php/ext/openssl/tests/bug64802.pem new file mode 100644 index 00000000..187cda31 --- /dev/null +++ b/php/ext/openssl/tests/bug64802.pem @@ -0,0 +1,37 @@ +-----BEGIN CERTIFICATE----- +MIIGfzCCBWegAwIBAgIQSVCinGH6MkvjJZjRyjK9nTANBgkqhkiG9w0BAQUFADCB +jjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNDAyBgNV +BAMTK0NPTU9ETyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Ew +HhcNMTIwMjI5MDAwMDAwWhcNMTQwMjI4MjM1OTU5WjCCAW8xEjAQBgNVBAMTCXd3 +dy5yZC5pbzERMA8GA1UEAxMIcmRpby5jb20xDjAMBgNVBAMTBXJkLmlvMRUwEwYD +VQQDEwxhcGkucmRpby5jb20xEjAQBgNVBAMTCWFwaS5yZC5pbzEQMA4GA1UEBRMH +NDU4NjAwNzETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgECEwhE +ZWxhd2FyZTEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xCzAJBgNVBAYT +AlVTMQ4wDAYDVQQREwU5NDEwMzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBG +cmFuY2lzY28xFzAVBgNVBAkTDjE1NTAgQnJ5YW50IHN0MRMwEQYDVQQKEwpSZGlv +LCBJbmMuMSMwIQYDVQQLExpDT01PRE8gRVYgTXVsdGktRG9tYWluIFNTTDEVMBMG +A1UEAxMMd3d3LnJkaW8uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt0AgYOe8EBJNVBAuSJFLKHRKZn0/ObCLBFG4xVH/5fb1rfYHBT1XSjjOqR3t +iGC/A3esF8YC7TuHQcTLVephx0DtJv1ASxRg3zPM8ebBRsuul18N0W+sY1aNXpkd +36quxvjg5UdBrAweuekJ7OTSZcCe2Ry/SKBeZSWWtkWsI4krCLv7JaKUwxw2h+Hn +TAZSBLVxz/mixF0WYdepYwnq2Hm7XvvVEIQ7wxOQ9bA7iCevLojZOnb39BT2QII7 +cy8AB47RZdfYg7UwaO3bST2rauA4MKar7/Ozqc0aemNFpLatJfgv07cydiuj9fsd +5aE/c8is8C9M9+7MmSMkcNEgGwIDAQABo4IB8zCCAe8wHwYDVR0jBBgwFoAUiERR +/1AqaV4tiPQhutkM8s7L6nwwHQYDVR0OBBYEFCrYw8bfrYJ61NS2yYx6/CnhjzT4 +MA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUF +BwMBBggrBgEFBQcDAjBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEFATArMCkGCCsG +AQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzBTBgNVHR8ETDBK +MEigRqBEhkJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FeHRlbmRlZFZh +bGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcmwwgYQGCCsGAQUFBwEBBHgwdjBOBggr +BgEFBQcwAoZCaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPRXh0ZW5kZWRW +YWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC5jb21vZG9jYS5jb20wTAYDVR0RBEUwQ4IMd3d3LnJkaW8uY29tgglhcGku +cmQuaW+CDGFwaS5yZGlvLmNvbYIFcmQuaW+CCHJkaW8uY29tggl3d3cucmQuaW8w +DQYJKoZIhvcNAQEFBQADggEBAKFd4bPVFRyrlqIKPtrtMuqGqid6685ohxf0cv52 +sjdRYwLVTjnZOrmkDdNaF3R2A1ZlVMRN+67rK+qfY5sTeijFcudV3/i0PDtOFRwP +6yYVD2uZmYkxfPiW309HPmDF+EzhxpVjWlTQEOwkfFLTmJmwl3Qu2Kffp8F1ENXW +OTVNvj5VtMghvzu68PpzKl1VjlOR4Ej9NCwh1dUjNKEoTPzvpehXsIZ7jHSpX/T1 +wSSt9ckiechDdpgZXTzHgbxHNibK0Uhh+QhkBgYMj5F8qj5BlBhWAWqQa/VnEdmr +Pfo7U+QmadoqQd7qt06hE2hG1nfZ0vPJDbWV3oVSwG2Yt7I= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug64802.phpt b/php/ext/openssl/tests/bug64802.phpt new file mode 100644 index 00000000..3b273998 --- /dev/null +++ b/php/ext/openssl/tests/bug64802.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #64802: openssl_x509_parse fails to parse subject properly in some cases +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +array(6) { + [0]=> + string(9) "www.rd.io" + [1]=> + string(8) "rdio.com" + [2]=> + string(5) "rd.io" + [3]=> + string(12) "api.rdio.com" + [4]=> + string(9) "api.rd.io" + [5]=> + string(12) "www.rdio.com" +} diff --git a/php/ext/openssl/tests/bug65538.phar b/php/ext/openssl/tests/bug65538.phar new file mode 100644 index 00000000..ae0bd29c Binary files /dev/null and b/php/ext/openssl/tests/bug65538.phar differ diff --git a/php/ext/openssl/tests/bug65538_001.phpt b/php/ext/openssl/tests/bug65538_001.phpt new file mode 100644 index 00000000..e666859d --- /dev/null +++ b/php/ext/openssl/tests/bug65538_001.phpt @@ -0,0 +1,52 @@ +--TEST-- +Bug #65538: SSL context "cafile" supports stream wrappers +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $client = @stream_socket_accept($server); + if ($client) { + $in = ''; + while (!preg_match('/\r?\n\r?\n/', $in)) { + $in .= fread($client, 2048); + } + $response = "HTTP/1.0 200 OK\r\n" + . "Content-Type: text/plain\r\n" + . "Content-Length: 12\r\n" + . "Connection: close\r\n" + . "\r\n" + . "Hello World!"; + fwrite($client, $response); + fclose($client); + } +CODE; + +$clientCode = <<<'CODE' + $serverUri = "https://127.0.0.1:64321/"; + $clientCtx = stream_context_create(['ssl' => [ + 'cafile' => 'file://' . __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + $html = file_get_contents($serverUri, false, $clientCtx); + + var_dump($html); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECT-- +string(12) "Hello World!" diff --git a/php/ext/openssl/tests/bug65538_002.phpt b/php/ext/openssl/tests/bug65538_002.phpt new file mode 100644 index 00000000..21a23a26 --- /dev/null +++ b/php/ext/openssl/tests/bug65538_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #65538: SSL context "cafile" disallows URL stream wrappers +--SKIPIF-- + +--FILE-- + [ + // We don't get any ca list from php.net but it does not matter as we + // care about the fact that the external stream is not allowed. + // We can't use http://curl.haxx.se/ca/cacert.pem for this test + // as it is redirected to https which means the test would depend + // on system cafile when opening stream. + 'cafile' => 'http://www.php.net', +]]); +file_get_contents('https://github.com', false, $clientCtx); +?> +--EXPECTF-- +Warning: remote cafile streams are disabled for security purposes in %s on line %d + +Warning: file_get_contents(): Failed to enable crypto in %s on line %d + +Warning: file_get_contents(%s): failed to open stream: operation failed in %s on line %d diff --git a/php/ext/openssl/tests/bug65538_003.phpt b/php/ext/openssl/tests/bug65538_003.phpt new file mode 100644 index 00000000..da997791 --- /dev/null +++ b/php/ext/openssl/tests/bug65538_003.phpt @@ -0,0 +1,53 @@ +--TEST-- +Bug #65538: SSL context "cafile" supports phar wrapper +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $client = @stream_socket_accept($server); + if ($client) { + $in = ''; + while (!preg_match('/\r?\n\r?\n/', $in)) { + $in .= fread($client, 2048); + } + $response = "HTTP/1.0 200 OK\r\n" + . "Content-Type: text/plain\r\n" + . "Content-Length: 12\r\n" + . "Connection: close\r\n" + . "\r\n" + . "Hello World!"; + fwrite($client, $response); + fclose($client); + } +CODE; + +$clientCode = <<<'CODE' + $serverUri = "https://127.0.0.1:64321/"; + $clientCtx = stream_context_create(['ssl' => [ + 'cafile' => 'phar://' . __DIR__ . '/bug65538.phar/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + $html = file_get_contents($serverUri, false, $clientCtx); + + var_dump($html); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(12) "Hello World!" diff --git a/php/ext/openssl/tests/bug65698.crt b/php/ext/openssl/tests/bug65698.crt new file mode 100644 index 00000000..c4a02611 --- /dev/null +++ b/php/ext/openssl/tests/bug65698.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEsTCCA5mgAwIBAgIQdwrGwrpRpBwdXS+ZsmsMGjANBgkqhkiG9w0BAQUFADA+ +MQswCQYDVQQGEwJQTDEbMBkGA1UEChMSVW5pemV0byBTcC4geiBvLm8uMRIwEAYD +VQQDEwlDZXJ0dW0gQ0EwIhgPMjAwOTAzMDMxMjUzMThaGA8yMDI0MDMwMzEyNTMx +OFowdzELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVz +IFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEb +MBkGA1UEAxMSQ2VydHVtIExldmVsIElJIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4LE0Ixw8h5Lper9tHVtZkWIujxYsPVgUZABeZZgQsKTdJjaG +VP64B/oiEV5Hd3AxRqaZ7dRRsf4Pg/PSS/2mHRQQ/SH3XACbrDHmucDvYgtU/WoZ +yp9d6PXVPY4j7J5t/52s+EbZD5swSuQLGjZ9iwg9sXX3JdJ9Ty+B3z80oiajpK0B +wqAxrcX3DekEOknj7LkAOK6iuQKI85REj4IVb9kD7KKIWdISGbfL4Ezh/TP51e0L +/WhTJ7lHbHbRzFfPU/oi3Qyt5tEexrPKe+6N+Jrejdb5Ya7Ne3tKujDU7KlbO+dn +pzFH7VHkBPJcQJ7QUrprPaqVsVg3JJ1PXTqVnwIDAQABo4IBbDCCAWgwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUgGIR3sBrpxDhCPBVtDCDv/qPCGAwUgYDVR0j +BEswSaFCpEAwPjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHog +by5vLjESMBAGA1UEAxMJQ2VydHVtIENBggMBACAwDgYDVR0PAQH/BAQDAgEGMCwG +A1UdHwQlMCMwIaAfoB2GG2h0dHA6Ly9jcmwuY2VydHVtLnBsL2NhLmNybDBoBggr +BgEFBQcBAQRcMFowKAYIKwYBBQUHMAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1 +bS5jb20wLgYIKwYBBQUHMAKGImh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9j +YS5jZXIwOgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8v +d3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEFBQADggEBAI/jSDAW/w9qLzF6 +4oQiIRB7dGKp2Nlj27xZFYDBRINn4DKyZExkpanASF2of9eEzvrS+qoDY29mhXCi +MkiGr0vCsVhn0ReUpjg4Z5SsiQhZ2BGSjXiOJgaDI7Dw1MH7Ru6jdfSbLyd97EFj +ER0ERGdrcA2kLw7KfQm78IkClXEEKjKnAUTn1d/5Y4UuBWDCEL0FLgO9AqNXEzIy +rlXVGIs73kdefAK+Z1T6dm83vUrDMyzemWNRBI2tVBujkN6zkaF6uPjE4hfoIkEQ +Z4317byFkG4mxjATU+tQLG1Bs88HUAOrxtJOo/WoeCNsFJaxbYPt4oQGxIVYdz29 +OUX9CQA= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug65698.phpt b/php/ext/openssl/tests/bug65698.phpt new file mode 100644 index 00000000..5b693421 --- /dev/null +++ b/php/ext/openssl/tests/bug65698.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #65689 (GeneralizedTime format parsing) +--SKIPIF-- + +--FILE-- + +Done +--EXPECTF-- +string(15) "20090303125318Z" +int(12360%d) +string(15) "20240303125318Z" +int(17094%d) +Done diff --git a/php/ext/openssl/tests/bug65729.pem b/php/ext/openssl/tests/bug65729.pem new file mode 100644 index 00000000..91844571 --- /dev/null +++ b/php/ext/openssl/tests/bug65729.pem @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDU8RgB8O2uR3ApjlxEX5rpCI+gIaZ3h0RBAF9rNA/s0pPTtX/e +NGJgDyuT/TF6mcv0I/0/s2WSmIE50NW6tgWZ7RoBdVw/MiByPt6vK1aDrggbycN/ +C6RrxrEsdZe3E9CDZCFM1br8/8tnV19Ju80g8zY2MgDjAjSkeXN5yp3kgQIDAQAB +AoGBANFKKRt3TlRVmHLvndYB1YKmzGtJx5CBXV85247FO8W67lpNcGDYQbxCDMXG +PARQ9vl9CeK7EuDzjUdi7z40uujUOJtsLbMP6ikwKFi/tA2cW1yoLionZ3JkfyEr +4Uu8kkkIut0VLX8uuVz/Y03lt8Uzc+GvD2DPhkSQn80f10SFAkEA94EcjwFcwuVi +QofgOPbf7qfOoWDsXYhlMU9g1CaPJiMcMcvgoLK3V514oMDxlkvuLujlYeG9NvRS +tREluGsbywJBANxARX5MSzAkFRNZNZKDUvifdC0BA2Dqzd2iOJRcTdcebGENd7+e +oub/9lVLGrX7T4U2en8IXwJV4UHxwoQLz2MCQQCI1Bj8ui0VFgj/bOy5sUnVP3IN +Z27kuo3u98o5HuQOmmRw5xxU2thfGJBilqg4hdu0lU6SkWCwq9u5fDRVQumHAkAM +mJBg3LQgGLAr3xo1OtVv6o6WVEyBKmyDlFdwBKde+hpwoniKuOPQGitYTWdFqQ2v +LKJsyWnFlGvBfbYGHzbJAkEA17SgCf7Wx7NxuLCSMj/rd25ul0jlIrjx6+/HfyLb ++T2SXXU4g2DBiPngrfJ9jX8QGoLpZiBGcwX3QxssX5FgJQ== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICvDCCAiWgAwIBAgIJANOyJnvPEioVMA0GCSqGSIb3DQEBBQUAMEkxCzAJBgNV +BAYTAlNHMRIwEAYDVQQIEwlUZXN0dmlsbGUxETAPBgNVBAoTCGRhdGliYmF3MRMw +EQYDVQQDFAoqLnRlc3QuY29tMB4XDTE0MTAxNTEzMDg1OFoXDTM0MTAxMDEzMDg1 +OFowSTELMAkGA1UEBhMCU0cxEjAQBgNVBAgTCVRlc3R2aWxsZTERMA8GA1UEChMI +ZGF0aWJiYXcxEzARBgNVBAMUCioudGVzdC5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBANTxGAHw7a5HcCmOXERfmukIj6AhpneHREEAX2s0D+zSk9O1f940 +YmAPK5P9MXqZy/Qj/T+zZZKYgTnQ1bq2BZntGgF1XD8yIHI+3q8rVoOuCBvJw38L +pGvGsSx1l7cT0INkIUzVuvz/y2dXX0m7zSDzNjYyAOMCNKR5c3nKneSBAgMBAAGj +gaswgagwHQYDVR0OBBYEFErHO0eHLp9YvBWVvvhty/jGie5wMHkGA1UdIwRyMHCA +FErHO0eHLp9YvBWVvvhty/jGie5woU2kSzBJMQswCQYDVQQGEwJTRzESMBAGA1UE +CBMJVGVzdHZpbGxlMREwDwYDVQQKEwhkYXRpYmJhdzETMBEGA1UEAxQKKi50ZXN0 +LmNvbYIJANOyJnvPEioVMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA +gMv2HUUp0FMTYQ6tL9YgNUNARukxJzGDWweo4/YuNSgI+Ljpye4Nf1MpyDWfhZGc +QbUhfm5CdEvcBzZBtI0lLXs61yGdLnDH/6QHViXP2rlH0yeAABw8+wSdxuiZN1yR +ed4pNXU+tczgW2Ri2+T0ScOZd0XommKHrQnu2T9mMBY= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug65729.phpt b/php/ext/openssl/tests/bug65729.phpt new file mode 100644 index 00000000..347dc55e --- /dev/null +++ b/php/ext/openssl/tests/bug65729.phpt @@ -0,0 +1,60 @@ +--TEST-- +Bug #65729: CN_match gives false positive when wildcard is used +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug65729.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $expected_names = ['foo.test.com.sg', 'foo.test.com', 'FOO.TEST.COM', 'foo.bar.test.com']; + foreach ($expected_names as $name) { + @stream_socket_accept($server, 1); + } +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + + phpt_wait(); + + $expected_names = ['foo.test.com.sg', 'foo.test.com', 'FOO.TEST.COM', 'foo.bar.test.com']; + foreach ($expected_names as $expected_name) { + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'allow_self_signed' => true, + 'peer_name' => $expected_name, + ]]); + + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + } +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): Peer certificate CN=`*.test.com' did not match expected CN=`foo.test.com.sg' in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) + +Warning: stream_socket_client(): Peer certificate CN=`*.test.com' did not match expected CN=`foo.bar.test.com' in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/bug66501.phpt b/php/ext/openssl/tests/bug66501.phpt new file mode 100644 index 00000000..fa450318 --- /dev/null +++ b/php/ext/openssl/tests/bug66501.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #66501: EC private key support in openssl_sign +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug68265.pem', + 'passphrase' => 'elephpant', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + stream_socket_accept($server, 30); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => true, + 'peer_name' => 'debs.ak-online.net', + ]]); + + phpt_wait(); + + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) + diff --git a/php/ext/openssl/tests/bug68879.pem b/php/ext/openssl/tests/bug68879.pem new file mode 100644 index 00000000..15c6f039 --- /dev/null +++ b/php/ext/openssl/tests/bug68879.pem @@ -0,0 +1,33 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIuw/AFD7RWcMCAggA +MBQGCCqGSIb3DQMHBAh98F6GmaGn1ASCAoBpzaFxyttEhyh4dhMjarJIqTz24DjO +yZnp1K5qthejSYx2P28uUsh+gQOh6F2jbVAq++eAWkTBGuc4pWhhoT7nY8vhf0Y0 +6yTlVrTxuI/8MNo/lfa0xE/+ZD4B5zp0hQxfij4GTd8l6V/kpXMgiYD1JmIXArm7 +sucn+9XV3RucsTBpeIJ1nLEDfpbyEWqNfhoyskQ+S3I6HkMgELI9JpsO6OR9fh1Q +ttdoYxBU+YjoDYcSWRGkTGrJFeGGhTQzz+L2ijgoqNWDSfrLBoQR1bqNVUuw6gcE +9PpA/vpRlxcHbUNNkOWft+4e0tV3I2EqscEcsYeNbd2Ta4yu7f6pk4/Kxn40wrQ8 +6Ss9GZylghaFth2xppL/vpmGaCC7FqpZRh+NKqjlcBobIkwyRcsQrPHB0CYLPHA4 +yak/dNTY8L5K8Rtd5XG3+E41CoDF6ssNY0Kw7l9kAn/neDVh+WnQkWIiWPmq210a +p4L/uiXRK7aYi+UqKJ5+svayNw2w1dkqpbeejwLq2F1+ek/447JFPVJcvP8Nm7sr +04Mcg+ZHusZdjiWEv4W6CBq8o6eF2JdhfpSDgPkHwiZ/EarHfx0vcYIMJhlEQBmk +a/XsZPk2wnamKSPfJautO3MIus0M6SniWF6eDA4/AZzSjXV8Vc0unb6lc+Nc8tJa +6MU1soTsmki/YraCmQswqpL+kXFZVeHuLowOC5oH+CimQoscmiZ9tBvpnYo6XwEZ +S9jZRIBQ77oMku+rlMPfz2FURgVXZpEfrGmxKvA5Vt3ojrYfTwwD2YqZHVcm39zy +iKqA1qVt7A2A90ILMAzYnN0VRE4SO3yIDN1ZBp5OOY61AduPrhpaHl81 +-----END ENCRYPTED PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICkTCCAfqgAwIBAgIJAPbIVRT31Al1MA0GCSqGSIb3DQEBCwUAMFgxCzAJBgNV +BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg +Q29tcGFueSBMdGQxFDASBgNVBAMMC3BocCB0ZXN0IGNhMB4XDTE1MDMwNTA0NTQx +NVoXDTI1MDMwMjA0NTQxNVowUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlNDMRUw +EwYDVQQHDAxNeXJ0bGUgQmVhY2gxDDAKBgNVBAsMA1BIUDERMA8GA1UEAwwIdGVz +dC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKp5gxUbKvY5eFwZJti0 +6d6YBo400Or6M+bLfIMnz5C1WQ7dMfiQpeFLpSIlOIaFqyrqkeeR9k5dsx1K9FOu +PAJ4+lmWA4R93RpdJFz8kmQoNu3P59JMATXi8wvNBIrN/Vc08NT0wBRImeyQSVHd +UcFIXBEbBM0dQsPKQ1k8n5WDAgMBAAGjaTBnMAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgXgME0GA1UdEQRGMESCCHRlc3QuY29tggx3d3cudGVzdC5jb22CEnN1YmRvbWFp +bi50ZXN0LmNvbYcQAAAAAAAAAAAAAP//CgIAAYcECgIAATANBgkqhkiG9w0BAQsF +AAOBgQBZ4TptNXV85gNj3wcB5feWFcwKO8cN4hwnhrbqiHN280r9O/g1CQiLmB4K +2txrJt06UNCnvWse7CdvsN14wu6rRGRk/+7M36NBw5ERkAzp5HXgZUWVdMl3YltB +PpqbLhGGrkVn7/jW2FdAxfax7qaGDYgC3qcQNfiK6K92SPxV7Q== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug68879.phpt b/php/ext/openssl/tests/bug68879.phpt new file mode 100644 index 00000000..2982d00c --- /dev/null +++ b/php/ext/openssl/tests/bug68879.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #68879: Match IP address fields in subjectAltName checks +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug68879.pem', + 'passphrase' => 'elephpant', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + stream_socket_accept($server, 30); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => true, + 'peer_name' => '10.2.0.1', + ]]); + + phpt_wait(); + + var_dump(stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) + diff --git a/php/ext/openssl/tests/bug68912.phpt b/php/ext/openssl/tests/bug68912.phpt new file mode 100644 index 00000000..c18291a6 --- /dev/null +++ b/php/ext/openssl/tests/bug68912.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #68912 (Segmentation fault at openssl_spki_new) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_spki_new(): supplied resource is not a valid OpenSSL X.509/key resource in %sbug68912.php on line %d + +Warning: openssl_spki_new(): Unable to use supplied private key in %sbug68912.php on line %d diff --git a/php/ext/openssl/tests/bug68920.phpt b/php/ext/openssl/tests/bug68920.phpt new file mode 100644 index 00000000..52a103f6 --- /dev/null +++ b/php/ext/openssl/tests/bug68920.phpt @@ -0,0 +1,81 @@ +--TEST-- +Bug #68920: peer_fingerprint input checks should be strict +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/san-cert.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + stream_socket_accept($server, 30); + stream_socket_accept($server, 30); + stream_socket_accept($server, 30); + stream_socket_accept($server, 30); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + + phpt_wait(); + + $ctx = stream_context_create(['ssl' => ['verify_peer'=> false, 'peer_fingerprint' => true]]); + $sock = stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $ctx); + var_dump($sock); + + $ctx = stream_context_create(['ssl' => ['verify_peer'=> false, 'peer_fingerprint' => null]]); + $sock = stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $ctx); + var_dump($sock); + + $ctx = stream_context_create(['ssl' => ['verify_peer'=> false, 'peer_fingerprint' => []]]); + $sock = stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $ctx); + var_dump($sock); + + $ctx = stream_context_create(['ssl' => ['verify_peer'=> false, 'peer_fingerprint' => ['foo']]]); + $sock = stream_socket_client($serverUri, $errno, $errstr, 30, $clientFlags, $ctx); + var_dump($sock); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): Expected peer fingerprint must be a string or an array in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to %s (Unknown error) in %s on line %d +bool(false) + +Warning: stream_socket_client(): Expected peer fingerprint must be a string or an array in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to %s (Unknown error) in %s on line %d +bool(false) + +Warning: stream_socket_client(): Invalid peer_fingerprint array; [algo => fingerprint] form required in %s on line %d + +Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to %s (Unknown error) in %s on line %d +bool(false) + +Warning: stream_socket_client(): Invalid peer_fingerprint array; [algo => fingerprint] form required in %s on line %d + +Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to %s (Unknown error) in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/bug69215-ca.pem b/php/ext/openssl/tests/bug69215-ca.pem new file mode 100644 index 00000000..bf1be072 --- /dev/null +++ b/php/ext/openssl/tests/bug69215-ca.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICfjCCAeegAwIBAgIJAMO7Amv3ZHJBMA0GCSqGSIb3DQEBCwUAMFgxCzAJBgNV +BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg +Q29tcGFueSBMdGQxFDASBgNVBAMMC3BocCB0ZXN0IGNhMB4XDTE1MDMwMzE3NTQz +OVoXDTI1MDIyODE3NTQzOVowWDELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1 +bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEUMBIGA1UEAwwL +cGhwIHRlc3QgY2EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKac+r8AzEEk +Cdnue7nx3gxmsXTYzwnywjjGJSknoWCdNEE+LqtT8RU0J+V76w4ehWRnhLVtu//v +3InsrpcniGfTcov60NelHQOfn5XCCV5zqVi628WddwwdVw4AI58K3YrNk450VCBu +dMy6m2Tm+dQwgVbtR+nIwzfm47CMWW2DAgMBAAGjUDBOMB0GA1UdDgQWBBTtMxRr +plep4RW3PjhosYsIdIoMojAfBgNVHSMEGDAWgBTtMxRrplep4RW3PjhosYsIdIoM +ojAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBADMF2pL8jCF6PFPhMuFN +zxoLSuy6uLAkjkujo5e33kSUW5MI4jT/aoL2hnBPA4uJPC/TZXoBHKBpnPES2GkJ +r7tOR51Jsk7HRTdvOMkcdD9Fe+M+Q5rOMUlCtyX/SRhc1uFnC2//Y/rx4Tc8djGl +RqrH/Oi38u1083krmNRQNw/Z +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug69215-client.pem b/php/ext/openssl/tests/bug69215-client.pem new file mode 100644 index 00000000..271732fa --- /dev/null +++ b/php/ext/openssl/tests/bug69215-client.pem @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,CE3DEB59F7DF7AF4 + +9REujZuwDkwoN949Gw77c3aJiQvwoPiUXJ+cDirn4ii56OsHBSCWfCe4Mqn976GK +9IAPwHJ5yRewPpFvb+xRqtMtnm8S7HIfVtZqW4FkG+g/paEg6rwqVpW78Jco/gww +6XFGrmU1bwKWrB05YV1BWnbB4L7Q+/U0ZcNvdNISOBW//2HuHeKVWe1DKoaRtoVz +v4BFQxr7F3A9tm3vz9Jn2JreVrihdWQVlVTVOsfiQk/yPVA7twxiT2Hfimp/gFSX +l28rA+jB7xd6IhpA/EXAYnCbxSp9kSXYtba26dO3rQHlgRv1a38AwvCD/3igQzF/ +XjetX2a75ITi5c7bUT4ZpVX8ZPU8oVBqSo6MXisFWBT0Svx+KhWyyn2V0z66APdR +X1V6dZiAcqN7giRg3Yj/lMDo0nV4Ph+Ce7p3Mv/p4qU0mxf7O8sPhp7DloHQFEF0 +HyooNp26YT4V47NDxwIlkoj9YZ5nkO/svQ1qxiTKWNUdfWw5r3lFiAw5xTyDDiBs +Sz776DaFo3Ss3JSUr5RLe4rEEc02iVqYB9OPXoUaUwS+//1KKgzF3xq/yxsJM5dR +ljphraCViZzJPw4z69Lmao9CPRfDxKChVOSLkKgmFIOeronLdTypieanc3/o002c +2ecb/x9f7G2XAn0iwcfylMkSZHirxqaos8LodsPxg8GdNJT89C66n+EJerrFwi6i +qT0EvNfkbxYd3zj82+j1weNFLsQuB0O1UJBWEdyj74gIX+4HkZpSYLQ2O8MTz3yE +52JcRRyl9ECdNJw15jkDQIusUreYMHb7YW+u+3+ci21H94Iay5XSYw== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICKDCCAZECCQD2yFUU99QJdzANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJY +WDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh +bnkgTHRkMRQwEgYDVQQDDAtwaHAgdGVzdCBjYTAeFw0xNTAzMTAyMzM0MDNaFw0y +NTAzMDcyMzM0MDNaMFkxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJTQzEVMBMGA1UE +BwwMTXlydGxlIEJlYWNoMQwwCgYDVQQLDANQSFAxGDAWBgNVBAMMD2J1ZzY5MjE1 +LWNsaWVudDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyLTbIGryqx0wGDD+ +xdrJsrcwXFyTYpCOHUaxl1wt/6j6u7yW5m4TJFEDUtIGnqBGYiPE9iynkLkOwUF/ +IpheONJENIjXkdSJPUEy/Ggz9WOa0qO6dQZU44NpGO7LFW97HglBIsbhioOsdcf/ +INAgidoMJNizkuTBNRGW7iKp0lsCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBKkZLQ +aU12/cPvW5e9AXArnE9jxMhnzuCKy81eHj30CC/nHpId9i5YZytHcZEZyEOWE6DQ +IsqmsP5ZheXq26mUtHOcEdEgcqcXTRotKXFwIxTZxP5jkCRn0xGbeHh7H9pg6TP0 +QekWTkWCh5qcf3NXvJtk4TCfLC6FSjehHkq9yQ== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug69215-server.pem b/php/ext/openssl/tests/bug69215-server.pem new file mode 100644 index 00000000..677afebd --- /dev/null +++ b/php/ext/openssl/tests/bug69215-server.pem @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,4C7155D678EDABFA + +NdOGB8UpC5xrnCFIOzxV6s4y4PZlxgX8s+iL/JeGVmS7a8pDSTzbb6wjauYy3n/2 +KCywHsFdAjifi8SGHJOJBVep3GS7dWw979vWdiKjQEAlJpoouv6P58Xpn4jDf1uX +ZrpmSTXI0iH7HYE2pzrkxPbg0Cz5GV2d2VlL7U5d4+UxXh8fSBndgHligmoc8mCU +1AG7ZmvPhMDTewhR333qKBYi9TBZuw75Crpy5CjPO30vBMfZpseOvtEnmI0JYGwe +75Q3e6sgY0o9b7Q42+g9v+FpGBTHhmldwYD7k1TtOC/PT4eO68E3mDawR2v+X9r8 +4jL22d3tB4Q4qAfBwbR37umTaQHLIxtjzc2OjXb/Ju35LW9d0hEuaAQK3oY8yeEi +gctYWrCN4K+cxZQwq1+ulpkHXULGs9QxXT9KJYfV1+HWkauWUSycFhA74jWW0mL5 +InlGaFf6oiRrP4lgRVXD3rtTLCwkCD2JcvTbF+re9+vCpui7zPW2peGwcE/W7TiK +wHFJhQQyYGcAWsal7ekXshTLoz4jeaPgak7dg50ZjjwcWr0bJuJ3RRaocMhYZ6Bd +DiF30nCijVSJfrLhugN2RJmSysT4WNXn5qaDGEOhVgkXZscZ3ClFGsMnxAz9sqbJ +J+ZMbqxkwSIf/+dPfhnjOWm3HPpP3T9wioYZT7KuI98pfGnHMZmX5CaJ6d/uBO5G +8jMvQLWOx+1WoDfWDkn7SfNDyTg4/dEo5IJFXv2S9zSPynCnQcBkYUevIfJ7vDo/ +7pXCkcY+C1zssW8R1J+WNbHI1syzVbvSg6hlgyEPXuDbErCRqiFm1g== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICKDCCAZECCQD2yFUU99QJeDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJY +WDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh +bnkgTHRkMRQwEgYDVQQDDAtwaHAgdGVzdCBjYTAeFw0xNTAzMTAyMzM1MjFaFw0y +NTAzMDcyMzM1MjFaMFkxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJTQzEVMBMGA1UE +BwwMTXlydGxlIEJlYWNoMQwwCgYDVQQLDANQSFAxGDAWBgNVBAMMD2J1ZzY5MjE1 +LXNlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAup0kaIwQufxQWXmE +QWbd7yxMQ69UHRhbb2stAo7qxmYMeH3bWCaR/oAPOswjtkXZQgyj0slLAWJDXKDg +zCnEKsU2yWLnvQy/h1rq/kBIybMoLKMIkRZQtrGcApKJtyrq8OtTz6odKQ7k9hym +DtPF+2lcVhSAd+qjngF3txrVKjsCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCfXuL4 +TODLV54uKKVdVGwr8U3EQ3JdYOqN3Hr9kpmxe6StIcLxQ1e+mSDgKcixzw6CXN3P +f++8NugAt4Ja2SDqqw1gzrX+9u6KZpnMKpEDIK0Z3Ss51ZwqilAXmFVybNTyYeVo +HweM1IY/zrBpSTQv/aKs1R2Pyb0Heindnp0PUQ== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/bug69215.phpt b/php/ext/openssl/tests/bug69215.phpt new file mode 100644 index 00000000..2e2fe922 --- /dev/null +++ b/php/ext/openssl/tests/bug69215.phpt @@ -0,0 +1,48 @@ +--TEST-- +Bug #69215: Crypto servers should send client CA list +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug69215-server.pem', + 'passphrase' => 'elephpant', + 'cafile' => __DIR__ . '/bug69215-ca.pem', + 'verify_peer' => true, + 'verify_peer_name' => true, + 'peer_name' => 'bug69215-client', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + stream_socket_accept($server, 30); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'local_cert' => __DIR__ . '/bug69215-client.pem', + 'passphrase' => 'elephpant', + 'cafile' => __DIR__ . '/bug69215-ca.pem', + 'verify_peer' => true, + 'verify_peer_name' => true, + 'peer_name' => 'bug69215-server', + ]]); + + phpt_wait(); + + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) + diff --git a/php/ext/openssl/tests/bug70395.phpt b/php/ext/openssl/tests/bug70395.phpt new file mode 100644 index 00000000..bfa881a0 --- /dev/null +++ b/php/ext/openssl/tests/bug70395.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #70395 (Missing ARG_INFO for openssl_seal()) +--SKIPIF-- + +--FILE-- +getParameters()[4]; +var_dump($param); +var_dump($param->isOptional()); +?> +--EXPECTF-- +object(ReflectionParameter)#%d (1) { + ["name"]=> + string(6) "method" +} +bool(true) diff --git a/php/ext/openssl/tests/bug70438.phpt b/php/ext/openssl/tests/bug70438.phpt new file mode 100644 index 00000000..937e9f3b --- /dev/null +++ b/php/ext/openssl/tests/bug70438.phpt @@ -0,0 +1,29 @@ +--TEST-- +Request #70438: Add IV parameter for openssl_seal and openssl_open +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_seal(): Cipher algorithm requires an IV to be supplied as a sixth parameter in %s on line %d + +Warning: openssl_seal(): Unknown signature algorithm. in %s on line %d +openssl_seal() test diff --git a/php/ext/openssl/tests/bug71475.phpt b/php/ext/openssl/tests/bug71475.phpt new file mode 100644 index 00000000..e959371c --- /dev/null +++ b/php/ext/openssl/tests/bug71475.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #71475: openssl_seal() uninitialized memory usage +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- + +Warning: openssl_seal(): not a public key (1th member of pubkeys) in %s%ebug71475.php on line %d +DONE diff --git a/php/ext/openssl/tests/bug71917.phpt b/php/ext/openssl/tests/bug71917.phpt new file mode 100644 index 00000000..d4415b3e --- /dev/null +++ b/php/ext/openssl/tests/bug71917.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #71917: openssl_open() returns junk on envelope < 16 bytes +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/php/ext/openssl/tests/bug72165.phpt b/php/ext/openssl/tests/bug72165.phpt new file mode 100644 index 00000000..93b3c3d4 --- /dev/null +++ b/php/ext/openssl/tests/bug72165.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72165 Null pointer dereference - openssl_csr_new +--SKIPIF-- + +--FILE-- + "hello", 1 => "world"); +$var2 = openssl_csr_new(array(0),$var0,null,array(0)); +?> +==DONE== +--EXPECTF-- +Warning: openssl_csr_new(): dn: numeric fild names are not supported in %sbug72165.php on line %d + +Warning: openssl_csr_new(): add1_attr_by_txt challengePassword_min -> 4 (failed; check error queue and value of string_mask OpenSSL option if illegal characters are reported) in %sbug72165.php on line %d +==DONE== diff --git a/php/ext/openssl/tests/bug72333.phpt b/php/ext/openssl/tests/bug72333.phpt new file mode 100644 index 00000000..a7b1c93b --- /dev/null +++ b/php/ext/openssl/tests/bug72333.phpt @@ -0,0 +1,68 @@ +--TEST-- +Bug #72333: fwrite() on non-blocking SSL sockets doesn't work +--SKIPIF-- + +--FILE-- + ['local_cert' => __DIR__ . '/bug54992.pem']]); + + $flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN; + $fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context); + phpt_notify(); + $conn = stream_socket_accept($fp); + $total = 100000; + $result = fread($conn, $total); + stream_set_blocking($conn, false); + usleep(50000); + $read = [$conn]; + while (stream_select($read, $write, $except, 1)) { + $result = fread($conn, 100000); + if (!$result) { + break; + } + $total += strlen($result); + if ($total >= 4000000) { + break; + } + } + phpt_wait(); +CODE; + +$clientCode = <<<'CODE' + $context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => 'bug54992.local']]); + + phpt_wait(); + $fp = stream_socket_client("ssl://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context); + stream_set_blocking($fp, false); + + function blocking_fwrite($fp, $buf) { + $write = [$fp]; + $total = 0; + while (stream_select($read, $write, $except, 1)) { + $result = fwrite($fp, $buf); + if (!$result) { + break; + } + $total += $result; + if ($total >= strlen($buf)) { + return $total; + } + $buf = substr($buf, $total); + } + } + $str1 = str_repeat("a", 4000000); + blocking_fwrite($fp, $str1); + phpt_notify(); + echo "done"; +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECT-- +done + diff --git a/php/ext/openssl/tests/bug72336.phpt b/php/ext/openssl/tests/bug72336.phpt new file mode 100644 index 00000000..893b5183 --- /dev/null +++ b/php/ext/openssl/tests/bug72336.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #72336 (openssl_pkey_new does not fail for invalid DSA params) +--SKIPIF-- + +--FILE-- + array('p' => $p, 'q' => $q, 'g' => $g)))); +?> +--EXPECT-- +bool(false) diff --git a/php/ext/openssl/tests/bug72362.phpt b/php/ext/openssl/tests/bug72362.phpt new file mode 100644 index 00000000..40acdbed --- /dev/null +++ b/php/ext/openssl/tests/bug72362.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #72362: OpenSSL Blowfish encryption is incorrect for short keys +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3" +string(48) "e3214d1b16e574828c8a3e222202dde81afd1ad2cb165ab3" diff --git a/php/ext/openssl/tests/bug73072.phpt b/php/ext/openssl/tests/bug73072.phpt new file mode 100644 index 00000000..cc352233 --- /dev/null +++ b/php/ext/openssl/tests/bug73072.phpt @@ -0,0 +1,45 @@ +--TEST-- +Bug #73072: Invalid path SNI_server_certs causes segfault +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => __DIR__ . '/domain1.pem', + 'SNI_server_certs' => [ + "domain1.com" => __DIR__ . "/sni_server_domain1.pem", + "domain2.com" => __DIR__ . "/not_existing.pem", + ] + ]]); + + $server = stream_socket_server('tls://127.0.0.1:64322', $errno, $errstr, $flags, $ctx); + + phpt_notify(); + @stream_socket_accept($server, 3); + // if there is a segfault, this won't be called + fwrite(STDERR, "done\n"); +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctxArr = [ + 'cafile' => __DIR__ . '/sni_server_ca.pem', + 'capture_peer_cert' => true + ]; + + phpt_wait(); + + $ctxArr['peer_name'] = 'domain1.com'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + @stream_socket_client("tls://127.0.0.1:64322", $errno, $errstr, 1, $flags, $ctx); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECT-- +done diff --git a/php/ext/openssl/tests/bug73478.phpt b/php/ext/openssl/tests/bug73478.phpt new file mode 100644 index 00000000..1dfc5841 --- /dev/null +++ b/php/ext/openssl/tests/bug73478.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #73478: openssl_pkey_new() generates wrong pub/priv keys with Diffie Hellman +--SKIPIF-- + +--FILE-- + base64_decode('3Pk6C4g5cuwOGZiaxaLOMQ4dN3F+jZVxu3Yjcxhm5h73Wi4niYsFf5iRwuJ6Y5w/KbYIFFgc07LKOYbSaDcFV31FwuflLcgcehcYduXOp0sUSL/frxiCjv0lGfFOReOCZjSvGUnltTXMgppIO4p2Ij5dSQolfwW9/xby+yLFg6s='), + 'g' => base64_decode('Ag=='), + 'priv_key' => base64_decode('jUdcV++P/m7oUodWiqKqKXZVenHRuj92Ig6Fmzs7QlqVdUc5mNBxmEWjug+ObffanPpOeab/LyXwjNMzevtBz3tW4oROau++9EIMJVVQr8fW9zdYBJcYieC5l4t8nRj5/Uu/Z0G2rWVLBleSi28mqqNEvnUs7uxYxrar69lwQYs=') +]; + +$opensslKeyResource = openssl_pkey_new(['dh' => $details]); +$data = openssl_pkey_get_details($opensslKeyResource); + +printf("Private key:\n%s\n", base64_encode($data['dh']['priv_key'])); +printf("Public key:\n%s\n", base64_encode($data['dh']['pub_key'])); +?> +--EXPECT-- +Private key: +jUdcV++P/m7oUodWiqKqKXZVenHRuj92Ig6Fmzs7QlqVdUc5mNBxmEWjug+ObffanPpOeab/LyXwjNMzevtBz3tW4oROau++9EIMJVVQr8fW9zdYBJcYieC5l4t8nRj5/Uu/Z0G2rWVLBleSi28mqqNEvnUs7uxYxrar69lwQYs= +Public key: +0DmJUe9dr02pAtVoGyLHdC+rfBU3mDCelKGPXRDFHofx6mFfN2gcZCmp/ab4ezDXfpIBOatpVdbn2fTNUGo64DtKE2WGTsZCl90RgrGUv8XW/4WDPXeE7g5u7KWHBG/LCE5+XsilE5P5/GIyqr9gsiudTmk+H/hiYZl9Smar9k0= diff --git a/php/ext/openssl/tests/bug73711.cnf b/php/ext/openssl/tests/bug73711.cnf new file mode 100644 index 00000000..0d27d910 --- /dev/null +++ b/php/ext/openssl/tests/bug73711.cnf @@ -0,0 +1,3 @@ +[ req ] +default_bits = 384 + diff --git a/php/ext/openssl/tests/bug73711.phpt b/php/ext/openssl/tests/bug73711.phpt new file mode 100644 index 00000000..791eec99 --- /dev/null +++ b/php/ext/openssl/tests/bug73711.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #73711: Segfault in openssl_pkey_new when generating DSA or DH key +--SKIPIF-- + +--FILE-- + OPENSSL_KEYTYPE_DSA, 'config' => $cnf])); +var_dump(openssl_pkey_new(["private_key_type" => OPENSSL_KEYTYPE_DH, 'config' => $cnf])); +echo "DONE"; +?> +--EXPECTF-- +resource(%d) of type (OpenSSL key) +resource(%d) of type (OpenSSL key) +DONE diff --git a/php/ext/openssl/tests/bug73833.phpt b/php/ext/openssl/tests/bug73833.phpt new file mode 100644 index 00000000..2ea5f9e4 --- /dev/null +++ b/php/ext/openssl/tests/bug73833.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #73833: null character not allowed in openssl_pkey_get_private +--SKIPIF-- + +--FILE-- + __DIR__ . DIRECTORY_SEPARATOR . 'openssl.cnf']; + +foreach($passwords as $password) { + $key = openssl_pkey_new($conf); + + if (openssl_pkey_export($key, $privatePEM, $password, $conf) === false) { + echo "Failed to encrypt.\n"; + } else { + echo "Encrypted!\n"; + } + if (openssl_pkey_get_private($privatePEM, $password) === false) { + echo "Failed to decrypt.\n"; + } else { + echo "Decrypted!\n"; + } +} +?> +--EXPECT-- +Encrypted! +Decrypted! +Encrypted! +Decrypted! diff --git a/php/ext/openssl/tests/bug74022.pfx b/php/ext/openssl/tests/bug74022.pfx new file mode 100644 index 00000000..851dd990 Binary files /dev/null and b/php/ext/openssl/tests/bug74022.pfx differ diff --git a/php/ext/openssl/tests/bug74022.phpt b/php/ext/openssl/tests/bug74022.phpt new file mode 100644 index 00000000..0ab321c7 --- /dev/null +++ b/php/ext/openssl/tests/bug74022.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #74022 PHP Fast CGI crashes when reading from a pfx file with valid password +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECTF-- +bool(true) +bool(false) +===DONE=== diff --git a/php/ext/openssl/tests/bug74022_2.phpt b/php/ext/openssl/tests/bug74022_2.phpt new file mode 100644 index 00000000..65d09776 --- /dev/null +++ b/php/ext/openssl/tests/bug74022_2.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #74022 PHP Fast CGI crashes when reading from a pfx file with valid password, multiple extra certs +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECTF-- +int(2) +===DONE=== diff --git a/php/ext/openssl/tests/bug74099.phpt b/php/ext/openssl/tests/bug74099.phpt new file mode 100644 index 00000000..c0e02ba0 --- /dev/null +++ b/php/ext/openssl/tests/bug74099.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #74099 Memory leak with openssl_encrypt() +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(0) "" diff --git a/php/ext/openssl/tests/bug74159.phpt b/php/ext/openssl/tests/bug74159.phpt new file mode 100644 index 00000000..c031ea2f --- /dev/null +++ b/php/ext/openssl/tests/bug74159.phpt @@ -0,0 +1,112 @@ +--TEST-- +Bug #74159: Writing a large buffer to non-blocking encrypted streams fails +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $client = stream_socket_accept($server, 1); + + if (!$client) { + exit(); + } + + $data = ''; + while (strlen($data) < 0xfffff) { + $buffer = fread($client, 8192); + if (empty($buffer)) { + exit(); + } + $data .= $buffer; + usleep(100); + } + + fclose($client); +CODE; + +$clientCode = <<<'CODE' + function streamRead($stream) : int { + return strlen(fread($stream, 8192)); + } + + function streamWrite($stream, $data) : int { + return fwrite($stream, $data); + } + + function waitForWrite(...$streams) : bool { + $read = null; + $except = null; + while($streams && !($n = stream_select($read, $streams, $except, 1))); + return $n > 0; + } + + function waitForRead(...$streams) : bool { + $write = null; + $except = null; + while ($streams && !($n = stream_select($streams, $write, $except, 1))); + return $n > 0; + } + + set_error_handler(function ($errno, $errstr) { + exit("$errstr\n"); + }); + + $serverUri = "tcp://127.0.0.1:10012"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + $fp = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + + stream_set_blocking($fp, false); + while (0 === ($n = stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT))); + + $data = str_repeat("a", 0xfffff); + $written = 0; + $total = $written; + while(!empty($data)) { + $written = streamWrite($fp, $data); + $total += $written; + $data = substr($data, $written); + waitForWrite($fp); + } + printf("Written %d bytes\n", $total); + + while(waitForRead($fp)) { + streamRead($fp); + if (feof($fp)) { + break; + } + } + + exit("DONE\n"); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--EXPECTF-- +Written 1048575 bytes +DONE diff --git a/php/ext/openssl/tests/bug74341.phpt b/php/ext/openssl/tests/bug74341.phpt new file mode 100644 index 00000000..a3c78cfa --- /dev/null +++ b/php/ext/openssl/tests/bug74341.phpt @@ -0,0 +1,52 @@ +--TEST-- +Bug #74341 (openssl_x509_parse fails to parse ASN.1 UTCTime without seconds) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +int(1389052800) +int(1459494000) diff --git a/php/ext/openssl/tests/bug74402.phpt b/php/ext/openssl/tests/bug74402.phpt new file mode 100644 index 00000000..8cd98362 --- /dev/null +++ b/php/ext/openssl/tests/bug74402.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #74402 (segfault on random_bytes, bin3hex, openssl_seal) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +int(64) +int(80) diff --git a/php/ext/openssl/tests/bug74651.phpt b/php/ext/openssl/tests/bug74651.phpt new file mode 100644 index 00000000..f86394bd --- /dev/null +++ b/php/ext/openssl/tests/bug74651.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #74651: negative-size-param (-1) in memcpy in zif_openssl_seal() +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (OpenSSL key) +bool(false) \ No newline at end of file diff --git a/php/ext/openssl/tests/bug74720_0.phpt b/php/ext/openssl/tests/bug74720_0.phpt new file mode 100644 index 00000000..d84dc47d --- /dev/null +++ b/php/ext/openssl/tests/bug74720_0.phpt @@ -0,0 +1,93 @@ +--TEST-- +Bug #74720 pkcs7_en/decrypt does not work if \x1a is used in content, variant 0 +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECTF-- +bool(true) +bool(true) +int(39) +int(39) +int(39) +==DONE== + diff --git a/php/ext/openssl/tests/bug74720_1.phpt b/php/ext/openssl/tests/bug74720_1.phpt new file mode 100644 index 00000000..9a8099a3 --- /dev/null +++ b/php/ext/openssl/tests/bug74720_1.phpt @@ -0,0 +1,88 @@ +--TEST-- +Bug #74720 pkcs7_en/decrypt does not work if \x1a is used in content, variant 1 +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECTF-- +bool(true) +==DONE== + diff --git a/php/ext/openssl/tests/bug74798.phpt b/php/ext/openssl/tests/bug74798.phpt new file mode 100644 index 00000000..5b41af3e --- /dev/null +++ b/php/ext/openssl/tests/bug74798.phpt @@ -0,0 +1,96 @@ +--TEST-- +Bug #74798 pkcs7_en/decrypt does not work if \x0a is used in content +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECTF-- +bool(true) +bool(true) +int(40) +int(40) +int(40) +string(80) "537472696e672077697468200a2077696c6c20656e6420696e206f6e652062797465206d6f72652e" +string(80) "537472696e672077697468200a2077696c6c20656e6420696e206f6e652062797465206d6f72652e" +===DONE=== diff --git a/php/ext/openssl/tests/bug74903.phpt b/php/ext/openssl/tests/bug74903.phpt new file mode 100644 index 00000000..2dc06cc0 --- /dev/null +++ b/php/ext/openssl/tests/bug74903.phpt @@ -0,0 +1,83 @@ +--TEST-- +Bug #74903 openssl_pkcs7_encrypt() uses different EOL than before +--SKIPIF-- + +--FILE-- + +==DONE== +--EXPECT-- +bool(true) +bool(true) +==DONE== + diff --git a/php/ext/openssl/tests/bug75307.phpt b/php/ext/openssl/tests/bug75307.phpt new file mode 100644 index 00000000..606f7a52 --- /dev/null +++ b/php/ext/openssl/tests/bug75307.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #75307 Wrong reflection for openssl_open function +--SKIPIF-- + +--FILE-- +getNumberOfParameters()); +var_dump($rf->getNumberOfRequiredParameters()); +?> +===DONE=== +--EXPECT-- +int(6) +int(4) +===DONE=== diff --git a/php/ext/openssl/tests/capture_peer_cert_001.phpt b/php/ext/openssl/tests/capture_peer_cert_001.phpt new file mode 100644 index 00000000..0396cace --- /dev/null +++ b/php/ext/openssl/tests/capture_peer_cert_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +capture_peer_cert context captures on verify failure +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'capture_peer_cert' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem' + ]]); + + phpt_wait(); + $client = @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + $cert = stream_context_get_options($clientCtx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(%d) "bug54992.local" diff --git a/php/ext/openssl/tests/cert.crt b/php/ext/openssl/tests/cert.crt new file mode 100644 index 00000000..2e779051 --- /dev/null +++ b/php/ext/openssl/tests/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD +VQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBv +cnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJ +KoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4 +MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRl +IGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1 +ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTz +e4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+ +iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aR +S1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLo +Ymhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGE +MIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTAT +BgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5n +ZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zS +UW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LW +PVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn +4vh8xF/9+eVEj+hM+0OflA== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/cert.csr b/php/ext/openssl/tests/cert.csr new file mode 100644 index 00000000..39084bce --- /dev/null +++ b/php/ext/openssl/tests/cert.csr @@ -0,0 +1,22 @@ +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIDYzCCAswCAQAwgYcxCzAJBgNVBAYTAk5MMRYwFAYDVQQIEw1Ob29yZCBCcmFi +YW50MQ0wCwYDVQQHEwRVZGVuMRMwEQYDVQQKEwpUcmljb25uZWN0MRMwEQYDVQQL +EwpUcmljb25uZWN0MScwJQYDVQQDHh4AKgAuAHQAcgBpAGMAbwBuAG4AZQBjAHQA +LgBuAGwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANjE/qKAKgo93162HhtX +OZdvunF5eG/PFK2yn6uAUDWgZciPoKBslgL6a6sK+RdcS7LjWdjWEOOANGzZY1Kk +FelzxrIjIGSGJHC9eubebdu2LWFFM5cEMDiH0QSD9Rdiy7svSLWvngUDYj0wwd+m +iV2duzUFHnusj9iVPpD9s47RAgMBAAGgggGZMBoGCisGAQQBgjcNAgMxDBYKNS4y +LjM3OTAuMjB7BgorBgEEAYI3AgEOMW0wazAOBgNVHQ8BAf8EBAMCBPAwRAYJKoZI +hvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCAMAcGBSsO +AwIHMAoGCCqGSIb3DQMHMBMGA1UdJQQMMAoGCCsGAQUFBwMBMIH9BgorBgEEAYI3 +DQICMYHuMIHrAgEBHloATQBpAGMAcgBvAHMAbwBmAHQAIABSAFMAQQAgAFMAQwBo +AGEAbgBuAGUAbAAgAEMAcgB5AHAAdABvAGcAcgBhAHAAaABpAGMAIABQAHIAbwB2 +AGkAZABlAHIDgYkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAADANBgkqhkiG9w0BAQUFAAOBgQA4agiUkIblhF+n0wth4vQY+PwMadyaBpA4 +epr4TKL0QEkA0bQBbIERw5dDE3WQi6aVFJe6y870QymBwmKIvfBBfOyyA0IlQq/n +uybhzQNQbSMKF1T82hpfh1w2RwVGaGrw7f6qH+CLyP1ydvBPvmD88HwiibNBBB3c +R23mEEGYUQ== +-----END NEW CERTIFICATE REQUEST----- + diff --git a/php/ext/openssl/tests/cert.p7b b/php/ext/openssl/tests/cert.p7b new file mode 100644 index 00000000..87d3160a --- /dev/null +++ b/php/ext/openssl/tests/cert.p7b @@ -0,0 +1,22 @@ +-----BEGIN PKCS7----- +MIIDnQYJKoZIhvcNAQcCoIIDjjCCA4oCAQExADALBgkqhkiG9w0BBwGgggNwMIID +bDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYDVQQG +EwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRv +IEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZI +hvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4MDcz +MDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRlIGRv +IFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1ZSBk +byBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTze4SZ +Lwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+iiiI +tHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aRS1d+ +KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLoYmhq +tz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGEMIGB +MQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNV +BAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxv +MR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIwDAYD +VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zSUW8K +utKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LWPVKP +hYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn4vh8 +xF/9+eVEj+hM+0OflKEAMQA= +-----END PKCS7----- diff --git a/php/ext/openssl/tests/check_default_conf_path.phpt b/php/ext/openssl/tests/check_default_conf_path.phpt new file mode 100644 index 00000000..16aaa4bc --- /dev/null +++ b/php/ext/openssl/tests/check_default_conf_path.phpt @@ -0,0 +1,24 @@ +--TEST-- +Check for default OpenSSL config path on Windows +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(28) "c:\usr\local\ssl\openssl.cnf" diff --git a/php/ext/openssl/tests/cipher_tests.inc b/php/ext/openssl/tests/cipher_tests.inc new file mode 100644 index 00000000..b9e84af8 --- /dev/null +++ b/php/ext/openssl/tests/cipher_tests.inc @@ -0,0 +1,111 @@ + array( + array( + 'key' => '1bde3251d41a8b5ea013c195ae128b21' . + '8b3e0306376357077ef1c1c78548b92e', + 'iv' => '5b8e40746f6b98e00f1d13ff41', + 'aad' => 'c17a32514eb6103f3249e076d4c871dc' . + '97e04b286699e54491dc18f6d734d4c0', + 'tag' => '2024931d73bca480c24a24ece6b6c2bf', + 'pt' => '53bd72a97089e312422bf72e242377b3' . + 'c6ee3e2075389b999c4ef7f28bd2b80a', + 'ct' => '9a5fcccdb4cf04e7293d2775cc76a488' . + 'f042382d949b43b7d6bb2b9864786726', + ), + ), + 'aes-128-gcm' => array( + array( + 'key' => '00000000000000000000000000000000', + 'iv' => '000000000000000000000000', + 'tag' => '58e2fccefa7e3061367f1d57a4e7455a', + 'pt' => '', + 'ct' => '', + ), + array( + 'key' => '00000000000000000000000000000000', + 'iv' => '000000000000000000000000', + 'tag' => 'ab6e47d42cec13bdf53a67b21257bddf', + 'pt' => '00000000000000000000000000000000', + 'ct' => '0388dace60b6a392f328c2b971b2fe78', + ), + array( + 'key' => 'feffe9928665731c6d6a8f9467308308', + 'iv' => 'cafebabefacedbaddecaf888', + 'tag' => '4d5c2af327cd64a62cf35abd2ba6fab4', + 'pt' => 'd9313225f88406e5a55909c5aff5269a' . + '86a7a9531534f7da2e4c303d8a318a72' . + '1c3c0c95956809532fcf0e2449a6b525' . + 'b16aedf5aa0de657ba637b391aafd255', + 'ct' => '42831ec2217774244b7221b784d0d49c' . + 'e3aa212f2c02a4e035c17e2329aca12e' . + '21d514b25466931c7d8f6a5aac84aa05' . + '1ba30b396a0aac973d58e091473f5985', + ), + array( + 'key' => 'feffe9928665731c6d6a8f9467308308', + 'iv' => 'cafebabefacedbaddecaf888', + 'aad' => 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'tag' => '5bc94fbc3221a5db94fae95ae7121a47', + 'pt' => 'd9313225f88406e5a55909c5aff5269a' . + '86a7a9531534f7da2e4c303d8a318a72' . + '1c3c0c95956809532fcf0e2449a6b525' . + 'b16aedf5aa0de657ba637b39', + 'ct' => '42831ec2217774244b7221b784d0d49c' . + 'e3aa212f2c02a4e035c17e2329aca12e' . + '21d514b25466931c7d8f6a5aac84aa05' . + '1ba30b396a0aac973d58e091', + ), + array( + 'key' => 'feffe9928665731c6d6a8f9467308308', + 'iv' => 'cafebabefacedbad', + 'aad' => 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'tag' => '3612d2e79e3b0785561be14aaca2fccb', + 'pt' => 'd9313225f88406e5a55909c5aff5269a' . + '86a7a9531534f7da2e4c303d8a318a72' . + '1c3c0c95956809532fcf0e2449a6b525' . + 'b16aedf5aa0de657ba637b39', + 'ct' => '61353b4c2806934a777ff51fa22a4755' . + '699b2a714fcdc6f83766e5f97b6c7423' . + '73806900e49f24b22b097544d4896b42' . + '4989b5e1ebac0f07c23f4598' + ), + array( + 'key' => 'feffe9928665731c6d6a8f9467308308', + 'iv' => '9313225df88406e555909c5aff5269aa' . + '6a7a9538534f7da1e4c303d2a318a728' . + 'c3c0c95156809539fcf0e2429a6b5254' . + '16aedbf5a0de6a57a637b39b', + 'aad' => 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'tag' => '619cc5aefffe0bfa462af43c1699d050', + 'pt' => 'd9313225f88406e5a55909c5aff5269a' . + '86a7a9531534f7da2e4c303d8a318a72' . + '1c3c0c95956809532fcf0e2449a6b525' . + 'b16aedf5aa0de657ba637b39', + 'ct' => '8ce24998625615b603a033aca13fb894' . + 'be9112a5c3a211a8ba262a3cca7e2ca7' . + '01e4a9a4fba43c90ccdcb281d48c7c6f' . + 'd62875d2aca417034c34aee5', + ), + ) +); + +function openssl_get_cipher_tests($method) +{ + global $php_openssl_cipher_tests; + + $tests = array(); + + foreach ($php_openssl_cipher_tests[$method] as $instance) { + $test = array(); + foreach ($instance as $field_name => $field_value) { + $test[$field_name] = pack("H*", $field_value); + } + if (!isset($test['aad'])) { + $test['aad'] = ""; + } + $tests[] = $test; + } + + return $tests; +} diff --git a/php/ext/openssl/tests/cve-2013-6420.crt b/php/ext/openssl/tests/cve-2013-6420.crt new file mode 100644 index 00000000..45433146 --- /dev/null +++ b/php/ext/openssl/tests/cve-2013-6420.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCA4ygAwIBAgIJAJzu8r6u6eBcMA0GCSqGSIb3DQEBBQUAMIHDMQswCQYD +VQQGEwJERTEcMBoGA1UECAwTTm9yZHJoZWluLVdlc3RmYWxlbjEQMA4GA1UEBwwH +S8ODwrZsbjEUMBIGA1UECgwLU2VrdGlvbkVpbnMxHzAdBgNVBAsMFk1hbGljaW91 +cyBDZXJ0IFNlY3Rpb24xITAfBgNVBAMMGG1hbGljaW91cy5zZWt0aW9uZWlucy5k +ZTEqMCgGCSqGSIb3DQEJARYbc3RlZmFuLmVzc2VyQHNla3Rpb25laW5zLmRlMHUY +ZDE5NzAwMTAxMDAwMDAwWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAXDTE0MTEyODExMzkzNVowgcMxCzAJBgNVBAYTAkRFMRwwGgYDVQQIDBNO +b3JkcmhlaW4tV2VzdGZhbGVuMRAwDgYDVQQHDAdLw4PCtmxuMRQwEgYDVQQKDAtT +ZWt0aW9uRWluczEfMB0GA1UECwwWTWFsaWNpb3VzIENlcnQgU2VjdGlvbjEhMB8G +A1UEAwwYbWFsaWNpb3VzLnNla3Rpb25laW5zLmRlMSowKAYJKoZIhvcNAQkBFhtz +dGVmYW4uZXNzZXJAc2VrdGlvbmVpbnMuZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDDAf3hl7JY0XcFniyEJpSSDqn0OqBr6QP65usJPRt/8PaDoqBu +wEYT/Na+6fsgPjC0uK9DZgWg2tHWWoanSblAMoz5PH6Z+S4SHRZ7e2dDIjPjdhjh +0mLg2UMO5yp0V797Ggs9lNt6JRfH81MN2obXWs4NtztLMuD6egqpr8dDbr34aOs8 +pkdui5UawTZksy5pLPHq5cMhFGm06v65CLo0V2Pd9+KAokPrPcN5KLKebz7mLpk6 +SMeEXOKP4idEqxyQ7O7fBuHMedsQhu+prY3si3BUyKfQtP5CZnX2bp0wKHxX12DX +1nfFIt9DbGvHTcyOuN+nZLPBm3vWxntyIIvVAgMBAAGjQjBAMAkGA1UdEwQCMAAw +EQYJYIZIAYb4QgEBBAQDAgeAMAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEF +BQcDAjANBgkqhkiG9w0BAQUFAAOCAQEAG0fZYYCTbdj1XYc+1SnoaPR+vI8C8CaD +8+0UYhdnyU4gga0BAcDrY9e94eEAu6ZqycF6FjLqXXdAboppWocr6T6GD1x33Ckl +VArzG/KxQohGD2JeqkhIMlDomxHO7ka39+Oa8i2vWLVyjU8AZvWMAruHa4EENyG7 +lW2AagaFKFCr9TnXTfrdxGVEbv7KVQ6bdhg5p5SjpWH1+Mq03uR3ZXPBYdyV8319 +o0lVj1KFI2DCL/liWisJRoof+1cR35Ctd0wYBcpB6TZslMcOPl76dwKwJgeJo2Qg +Zsfmc2vC1/qOlNuNq/0TzzkVGv8ETT3CgaU+UXe4XOVvkccebJn2dg== +-----END CERTIFICATE----- + + diff --git a/php/ext/openssl/tests/cve-2013-6420.phpt b/php/ext/openssl/tests/cve-2013-6420.phpt new file mode 100644 index 00000000..ccead0aa --- /dev/null +++ b/php/ext/openssl/tests/cve-2013-6420.phpt @@ -0,0 +1,18 @@ +--TEST-- +CVE-2013-6420 +--SKIPIF-- + +--FILE-- + +Done +--EXPECTF-- +%s openssl_x509_parse(): illegal length in timestamp in %s%ecve-2013-6420.php on line 3 +string(27) "stefan.esser@sektioneins.de" +int(-1) +Done diff --git a/php/ext/openssl/tests/cve2013_4073.pem b/php/ext/openssl/tests/cve2013_4073.pem new file mode 100644 index 00000000..7ebb9949 --- /dev/null +++ b/php/ext/openssl/tests/cve2013_4073.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE2DCCA8CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBxTELMAkGA1UEBhMCVVMx +DzANBgNVBAgMBk9yZWdvbjESMBAGA1UEBwwJQmVhdmVydG9uMSMwIQYDVQQKDBpQ +eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEgMB4GA1UECwwXUHl0aG9uIENvcmUg +RGV2ZWxvcG1lbnQxJDAiBgNVBAMMG251bGwucHl0aG9uLm9yZwBleGFtcGxlLm9y +ZzEkMCIGCSqGSIb3DQEJARYVcHl0aG9uLWRldkBweXRob24ub3JnMB4XDTEzMDgw +NzEzMTE1MloXDTEzMDgwNzEzMTI1MlowgcUxCzAJBgNVBAYTAlVTMQ8wDQYDVQQI +DAZPcmVnb24xEjAQBgNVBAcMCUJlYXZlcnRvbjEjMCEGA1UECgwaUHl0aG9uIFNv +ZnR3YXJlIEZvdW5kYXRpb24xIDAeBgNVBAsMF1B5dGhvbiBDb3JlIERldmVsb3Bt +ZW50MSQwIgYDVQQDDBtudWxsLnB5dGhvbi5vcmcAZXhhbXBsZS5vcmcxJDAiBgkq +hkiG9w0BCQEWFXB5dGhvbi1kZXZAcHl0aG9uLm9yZzCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALXq7cn7Rn1vO3aA3TrzA5QLp6bb7B3f/yN0CJ2XFj+j +pHs+Gw6WWSUDpybiiKnPec33BFawq3kyblnBMjBU61ioy5HwQqVkJ8vUVjGIUq3P +vX/wBmQfzCe4o4uM89gpHyUL9UYGG8oCRa17dgqcv7u5rg0Wq2B1rgY+nHwx3JIv +KRrgSwyRkGzpN8WQ1yrXlxWjgI9de0mPVDDUlywcWze1q2kwaEPTM3hLAmD1PESA +oY/n8A/RXoeeRs9i/Pm/DGUS8ZPINXk/yOzsR/XvvkTVroIeLZqfmFpnZeF0cHzL +08LODkVJJ9zjLdT7SA4vnne4FEbAxDbKAq5qkYzaL4UCAwEAAaOB0DCBzTAMBgNV +HRMBAf8EAjAAMB0GA1UdDgQWBBSIWlXAUv9hzVKjNQ/qWpwkOCL3XDALBgNVHQ8E +BAMCBeAwgZAGA1UdEQSBiDCBhYIeYWx0bnVsbC5weXRob24ub3JnAGV4YW1wbGUu +Y29tgSBudWxsQHB5dGhvbi5vcmcAdXNlckBleGFtcGxlLm9yZ4YpaHR0cDovL251 +bGwucHl0aG9uLm9yZwBodHRwOi8vZXhhbXBsZS5vcmeHBMAAAgGHECABDbgAAAAA +AAAAAAAAAAEwDQYJKoZIhvcNAQEFBQADggEBAKxPRe99SaghcI6IWT7UNkJw9aO9 +i9eo0Fj2MUqxpKbdb9noRDy2CnHWf7EIYZ1gznXPdwzSN4YCjV5d+Q9xtBaowT0j +HPERs1ZuytCNNJTmhyqZ8q6uzMLoht4IqH/FBfpvgaeC5tBTnTT0rD5A/olXeimk +kX4LxlEx5RAvpGB2zZVRGr6LobD9rVK91xuHYNIxxxfEGE8tCCWjp0+3ksri9SXx +VHWBnbM9YaL32u3hxm8sYB/Yb8WSBavJCWJJqRStVRHM1koZlJmXNx2BX4vPo6iW +RFEIPQsFZRLrtnCAiEhyT8bC2s/Njlu6ly9gtJZWSV46Q3ZjBL4q9sHKqZQ= +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/cve2013_4073.phpt b/php/ext/openssl/tests/cve2013_4073.phpt new file mode 100644 index 00000000..e676ddfb --- /dev/null +++ b/php/ext/openssl/tests/cve2013_4073.phpt @@ -0,0 +1,19 @@ +--TEST-- +CVE 2013-4073: Null-byte certificate handling +--SKIPIF-- + 'CA:FALSE', + 'subjectKeyIdentifier' => '88:5A:55:C0:52:FF:61:CD:52:A3:35:0F:EA:5A:9C:24:38:22:F7:5C', + 'keyUsage' => 'Digital Signature, Non Repudiation, Key Encipherment', + 'subjectAltName' => 'DNS:altnull.python.org' . "\0" . 'example.com, email:null@python.org' . "\0" . 'user@example.org, URI:http://null.python.org' . "\0" . 'http://example.org, IP Address:192.0.2.1, IP Address:2001:DB8:0:0:0:0:0:1 +', +) diff --git a/php/ext/openssl/tests/ecc.phpt b/php/ext/openssl/tests/ecc.phpt new file mode 100644 index 00000000..e4c1d208 --- /dev/null +++ b/php/ext/openssl/tests/ecc.phpt @@ -0,0 +1,110 @@ +--TEST-- +openssl_*() with OPENSSL_KEYTYPE_EC +--SKIPIF-- + +--FILE-- + "secp384r1", + "private_key_type" => OPENSSL_KEYTYPE_EC, +); +echo "Testing openssl_pkey_new\n"; +$key1 = openssl_pkey_new($args); +var_dump($key1); + +$argsFailed = array( + "curve_name" => "invalid_cuve_name", + "private_key_type" => OPENSSL_KEYTYPE_EC, +); + +$keyFailed = openssl_pkey_new($argsFailed); +var_dump($keyFailed); + +$d1 = openssl_pkey_get_details($key1); +var_dump($d1["bits"]); +var_dump(strlen($d1["key"])); +var_dump($d1["ec"]["curve_name"]); +var_dump($d1["type"] == OPENSSL_KEYTYPE_EC); + +$key2 = openssl_pkey_new($d1); +var_dump($key2); + +$d2 = openssl_pkey_get_details($key2); +// Compare array +var_dump($d1 === $d2); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" +); + +// openssl_csr_new creates a new public key pair if the key argument is null +echo "Testing openssl_csr_new with key generation\n"; +$keyGenerate = null; +var_dump($keyGenerate); +$csr = openssl_csr_new($dn, $keyGenerate, $args); + +var_dump($keyGenerate); + +$args["digest_alg"] = "sha1"; +echo "Testing openssl_csr_new with existing ecc key\n"; +$csr = openssl_csr_new($dn, $key1, $args); +var_dump($csr); + +$pubkey1 = openssl_pkey_get_details(openssl_csr_get_public_key($csr)); +var_dump(isset($pubkey1["ec"]["priv_key"])); +unset($d1["ec"]["priv_key"]); +var_dump(array_diff($d1["ec"], $pubkey1["ec"])); + +$x509 = openssl_csr_sign($csr, null, $key1, 365, $args); +var_dump($x509); + +echo "Testing openssl_x509_check_private_key\n"; +var_dump(openssl_x509_check_private_key($x509, $key1)); + +$key3 = openssl_pkey_new($args); +var_dump(openssl_x509_check_private_key($x509, $key3)); + +echo "Testing openssl_get_curve_names\n"; +$curve_names = openssl_get_curve_names(); + +var_dump(is_array($curve_names)); + +foreach ($curve_names as $curve_name) { + if ("secp384r1" === $curve_name) { + echo "Found secp384r1 in curve names\n"; + } +} +?> +--EXPECTF-- +Testing openssl_pkey_new +resource(%d) of type (OpenSSL key) + +Warning: openssl_pkey_new(): Unknown elliptic curve (short) name invalid_cuve_name in %s on line %d +bool(false) +int(384) +int(215) +string(9) "secp384r1" +bool(true) +resource(%d) of type (OpenSSL key) +bool(true) +Testing openssl_csr_new with key generation +NULL +resource(%d) of type (OpenSSL key) +Testing openssl_csr_new with existing ecc key +resource(%d) of type (OpenSSL X.509 CSR) +bool(false) +array(1) { + ["d"]=> + string(%d) "%a" +} +resource(%d) of type (OpenSSL X.509) +Testing openssl_x509_check_private_key +bool(true) +bool(false) +Testing openssl_get_curve_names +bool(true) +Found secp384r1 in curve names diff --git a/php/ext/openssl/tests/openssl.cnf b/php/ext/openssl/tests/openssl.cnf new file mode 100644 index 00000000..f3025aeb --- /dev/null +++ b/php/ext/openssl/tests/openssl.cnf @@ -0,0 +1,50 @@ +oid_section = new_oids + +[ new_oids ] +# Example policies to test their +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 + +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert +string_mask = MASK:4294967295 + + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +localityName = Locality Name (eg, city) +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd +organizationalUnitName = Organizational Unit Name (eg, section) +commonName = Common Name (eg, YOUR name) +commonName_max = 64 +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 +unstructuredName = An optional company name + +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints = CA:true + +[ usr_cert ] +basicConstraints=CA:FALSE + diff --git a/php/ext/openssl/tests/openssl_csr_export_bacis.phpt b/php/ext/openssl/tests/openssl_csr_export_bacis.phpt new file mode 100644 index 00000000..d3f8842e --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_export_bacis.phpt @@ -0,0 +1,48 @@ +--TEST-- +openssl_csr_export() tests +--SKIPIF-- + +--FILE-- + $config); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" +); + +$args = array( + "digest_alg" => "sha1", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_DSA, + "encrypt_key" => true, + "config" => $config, +); + +$privkey = openssl_pkey_new($config_arg); +$csr = openssl_csr_new($dn, $privkey, $args); +var_dump(openssl_csr_export($csr, $output)); +var_dump(openssl_csr_export($wrong, $output)); +var_dump(openssl_csr_export($privkey, $output)); +var_dump(openssl_csr_export(array(), $output)); +var_dump(openssl_csr_export($csr, $output, false)); +?> +--EXPECTF-- +bool(true) + +Warning: openssl_csr_export() expects parameter 1 to be resource, string given in %s on line %d +NULL + +Warning: openssl_csr_export(): supplied resource is not a valid OpenSSL X.509 CSR resource in %s on line %d + +Warning: openssl_csr_export(): cannot get CSR from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_csr_export() expects parameter 1 to be resource, array given in %s on line %d +NULL +bool(true) diff --git a/php/ext/openssl/tests/openssl_csr_export_to_file_basic.phpt b/php/ext/openssl/tests/openssl_csr_export_to_file_basic.phpt new file mode 100644 index 00000000..1576302a --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_export_to_file_basic.phpt @@ -0,0 +1,83 @@ +--TEST-- +openssl_csr_export_to_file() tests +--SKIPIF-- + +--FILE-- + $phex, 'g' => '2'); +$dh = openssl_pkey_new(array( + 'dh'=> array('p' => hex2bin($phex), 'g' => '2')) +); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" +); + +$args = array( + "digest_alg" => "sha1", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_DSA, + "encrypt_key" => true, + "config" => $config, +); + +$privkey_file = 'file://' . dirname(__FILE__) . '/private_rsa_2048.key'; +$csr = openssl_csr_new($dn, $privkey_file, $args); +var_dump(openssl_csr_export_to_file($csr, $csrfile)); +var_dump(file_get_contents($csrfile)); +var_dump(openssl_csr_export_to_file($wrong, $csrfile)); +var_dump(openssl_csr_export_to_file($dh, $csrfile)); +var_dump(openssl_csr_export_to_file(array(), $csrfile)); +var_dump(openssl_csr_export_to_file($csr, $csrfile, false)); +?> +--CLEAN-- + +--EXPECTF-- +bool(true) +string(1086) "-----BEGIN CERTIFICATE REQUEST----- +MIIC6jCCAdICAQAwgaQxCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRl +IGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1 +ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQx +ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAK21JlVtWPqyc2UQtw2AdJHSIL5OzAHWsu/Mmxjz +w4VZWwG+Ao1m2j7OJ8lAkxLfSlRtB+6Vx8Q21krAtve+M3b6pT9C9qKdfzNkrXk3 +BggTncBh9ozkVQGS/P1m0zn/SKSgDO+6DdeLHLMjpUASaoYfsay4PJLAdnTqLOeM +g6qNE6u0ebZXVfmpSmV1pSZ6kQnxbsb6rX1iOZxkwHnVWYb40Hy0EILo31x6BVqB +m159m7s38ChiRHqlj20DmRfxXjiT5YDgYYQ29wQBTVQrTN5O9UW5Y+eKTXd8r6te +dsbIBXdKN7NeX7ksGYHq1I3hLsP8EyvZO78qfjKyEB0Jj3UCAwEAAaAAMA0GCSqG +SIb3DQEBBQUAA4IBAQCamzVmIbElkiDQKzQpkfU5tHjrWPrHDSB186NI0sQ8i6GQ +1YT6yPAXBPTQ1aER/6uAZJL5HfWEX8V1rKbe8GkPAPCHHQzmHyWlaO2EHS57zJhk +sRrhqkhhkSNiDg4OrsguhRtbB2VMGeDbqHGI89uGqqGHUiZc/Bh8N7WFXZkUU/A0 +sfBgVeqg0P4SWez5fHXqBNcjMdMI5f0bikcDZSIfTHS8FX+PMurLBC8UPB0YNIOl +1r2Lvo+6YUHOziG1OwQd3K0xxu/JzzOE+lMB73ynz4V6DY5Qv3qVno1GpupvgmQA +JViHkCA9x6m8RJXAFvqmgLlWlUzbDv/cRrDfjWjR +-----END CERTIFICATE REQUEST----- +" + +Warning: openssl_csr_export_to_file() expects parameter 1 to be resource, string given in %s on line %d +NULL + +Warning: openssl_csr_export_to_file(): supplied resource is not a valid OpenSSL X.509 CSR resource in %s on line %d + +Warning: openssl_csr_export_to_file(): cannot get CSR from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_csr_export_to_file() expects parameter 1 to be resource, array given in %s on line %d +NULL +bool(true) diff --git a/php/ext/openssl/tests/openssl_csr_get_public_key_basic.phpt b/php/ext/openssl/tests/openssl_csr_get_public_key_basic.phpt new file mode 100644 index 00000000..e8a9b7a0 --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_get_public_key_basic.phpt @@ -0,0 +1,44 @@ +--TEST-- +openssl_csr_get_public_key() tests +--SKIPIF-- + +--FILE-- + $phex, 'g' => '2'); +$dh = openssl_pkey_new(array( + 'dh'=> array('p' => hex2bin($phex), 'g' => '2')) +); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" +); + +$args = array( + "digest_alg" => "sha1", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_DSA, + "encrypt_key" => true, + "config" => $config, +); + +$privkey_file = 'file://' . dirname(__FILE__) . '/private_rsa_2048.key'; +$csr = openssl_csr_new($dn, $privkey_file, $args); +$csr_file = file_get_contents(dirname(__FILE__) . '/cert.csr'); + +var_dump(openssl_csr_get_public_key($csr)); +var_dump(openssl_csr_get_public_key($csr_file)); +?> +--EXPECTF-- +resource(%d) of type (OpenSSL key) +resource(%d) of type (OpenSSL key) diff --git a/php/ext/openssl/tests/openssl_csr_get_subject_basic.phpt b/php/ext/openssl/tests/openssl_csr_get_subject_basic.phpt new file mode 100644 index 00000000..6fe41f80 --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_get_subject_basic.phpt @@ -0,0 +1,70 @@ +--TEST-- +openssl_csr_get_subject() tests +--SKIPIF-- + +--FILE-- + $phex, 'g' => '2'); +$dh = openssl_pkey_new(array( + 'dh'=> array('p' => hex2bin($phex), 'g' => '2')) +); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" +); + +$args = array( + "digest_alg" => "sha1", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_DSA, + "encrypt_key" => true, + "config" => $config, +); + +$privkey_file = 'file://' . dirname(__FILE__) . '/private_rsa_2048.key'; +$csr = openssl_csr_new($dn, $privkey_file, $args); +$csr_file = file_get_contents(dirname(__FILE__) . '/cert.csr'); + +var_dump(openssl_csr_get_subject($csr_file)); +var_dump(openssl_csr_get_subject($csr, false)); +?> +--EXPECTF-- +array(6) { + ["C"]=> + string(2) "NL" + ["ST"]=> + string(13) "Noord Brabant" + ["L"]=> + string(4) "Uden" + ["O"]=> + string(10) "Triconnect" + ["OU"]=> + string(10) "Triconnect" + ["CN"]=> + string(15) "*.triconnect.nl" +} +array(6) { + ["countryName"]=> + string(2) "BR" + ["stateOrProvinceName"]=> + string(17) "Rio Grande do Sul" + ["localityName"]=> + string(12) "Porto Alegre" + ["commonName"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + ["organizationName"]=> + string(24) "Internet Widgits Pty Ltd" +} diff --git a/php/ext/openssl/tests/openssl_csr_new_basic.phpt b/php/ext/openssl/tests/openssl_csr_new_basic.phpt new file mode 100644 index 00000000..e0f52d73 --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_new_basic.phpt @@ -0,0 +1,41 @@ +--TEST-- +openssl_csr_new() tests +--SKIPIF-- + +--FILE-- + dirname(__FILE__) . DIRECTORY_SEPARATOR . 'openssl.cnf'); +var_dump(openssl_csr_new(array(), $a, $conf, array())); + +// this leaks +$a = array(1,2); +$b = array(1,2); +var_dump(openssl_csr_new($a, $b, $conf)); + +// options type check +$x = openssl_pkey_new($conf); +var_dump(openssl_csr_new(["countryName" => "DE"], $x, $conf + ["x509_extensions" => 0xDEADBEEF])); + + +echo "Done\n"; +?> +--EXPECTF-- +Warning: openssl_csr_new() expects parameter 1 to be array, integer given in %s on line %d +NULL + +Warning: openssl_csr_new() expects parameter 1 to be array, integer given in %s on line %d +NULL + +Warning: openssl_csr_new(): key array must be of the form array(0 => key, 1 => phrase) in %s on line %d + +Warning: openssl_csr_new(): add1_attr_by_txt challengePassword_min -> 4 (failed; check error queue and value of string_mask OpenSSL option if illegal characters are reported) in %s on line %d +bool(false) +resource(%d) of type (OpenSSL X.509 CSR) +resource(%d) of type (OpenSSL X.509 CSR) +Done diff --git a/php/ext/openssl/tests/openssl_csr_sign_basic.phpt b/php/ext/openssl/tests/openssl_csr_sign_basic.phpt new file mode 100644 index 00000000..572bb366 --- /dev/null +++ b/php/ext/openssl/tests/openssl_csr_sign_basic.phpt @@ -0,0 +1,82 @@ +--TEST-- +openssl_csr_sign() tests +--SKIPIF-- + +--FILE-- + $config); + +$dn = array( + "countryName" => "BR", + "stateOrProvinceName" => "Rio Grande do Sul", + "localityName" => "Porto Alegre", + "commonName" => "Henrique do N. Angelo", + "emailAddress" => "hnangelo@php.net" + ); + +$args = array( + "digest_alg" => "sha1", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_DSA, + "encrypt_key" => true, + "config" => $config + ); + +$privkey = openssl_pkey_new($config_arg); +$csr = openssl_csr_new($dn, $privkey, $args); +var_dump(openssl_csr_sign($csr, null, $privkey, 365, $args)); +var_dump(openssl_csr_sign($csr, null, $privkey, 365, $config_arg)); +var_dump(openssl_csr_sign($csr, $cert, $priv, 365, $config_arg)); +var_dump(openssl_csr_sign($csr, openssl_x509_read($cert), $priv, 365, $config_arg)); +var_dump(openssl_csr_sign($csr, $wrong, $privkey, 365)); +var_dump(openssl_csr_sign($csr, null, $wrong, 365)); +var_dump(openssl_csr_sign($csr, null, $privkey, $wrong)); +var_dump(openssl_csr_sign($csr, null, $privkey, 365, $wrong)); +var_dump(openssl_csr_sign($wrong, null, $privkey, 365)); +var_dump(openssl_csr_sign(array(), null, $privkey, 365)); +var_dump(openssl_csr_sign($csr, array(), $privkey, 365)); +var_dump(openssl_csr_sign($csr, null, array(), 365)); +var_dump(openssl_csr_sign($csr, null, $privkey, array())); +var_dump(openssl_csr_sign($csr, null, $privkey, 365, $config_arg)); +?> +--EXPECTF-- +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (OpenSSL X.509) + +Warning: openssl_csr_sign(): cannot get cert from parameter 2 in %s on line %d +bool(false) + +Warning: openssl_csr_sign(): cannot get private key from parameter 3 in %s on line %d +bool(false) + +Warning: openssl_csr_sign() expects parameter 4 to be integer, string given in %s on line %d +NULL + +Warning: openssl_csr_sign() expects parameter 5 to be array, string given in %s on line %d +NULL + +Warning: openssl_csr_sign(): cannot get CSR from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_csr_sign(): cannot get CSR from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_csr_sign(): cannot get cert from parameter 2 in %s on line %d +bool(false) + +Warning: openssl_csr_sign(): key array must be of the form array(0 => key, 1 => phrase) in %s on line %d + +Warning: openssl_csr_sign(): cannot get private key from parameter 3 in %s on line %d +bool(false) + +Warning: openssl_csr_sign() expects parameter 4 to be integer, array given in %s on line %d +NULL +resource(%d) of type (OpenSSL X.509) + diff --git a/php/ext/openssl/tests/openssl_decrypt_basic.phpt b/php/ext/openssl/tests/openssl_decrypt_basic.phpt new file mode 100644 index 00000000..37d17150 --- /dev/null +++ b/php/ext/openssl/tests/openssl_decrypt_basic.phpt @@ -0,0 +1,36 @@ +--TEST-- +openssl_decrypt() tests dependent on openssl_encrypt +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(45) "openssl_encrypt() and openssl_decrypt() tests" +string(45) "openssl_encrypt() and openssl_decrypt() tests" +string(45) "openssl_encrypt() and openssl_decrypt() tests" +string(45) "openssl_encrypt() and openssl_decrypt() tests" diff --git a/php/ext/openssl/tests/openssl_decrypt_ccm.phpt b/php/ext/openssl/tests/openssl_decrypt_ccm.phpt new file mode 100644 index 00000000..83278e09 --- /dev/null +++ b/php/ext/openssl/tests/openssl_decrypt_ccm.phpt @@ -0,0 +1,41 @@ +--TEST-- +openssl_decrypt() with CCM cipher algorithm tests +--SKIPIF-- + +--FILE-- + $test) { + echo "TEST $idx\n"; + $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], $test['aad']); + var_dump($test['pt'] === $pt); +} + +// no IV +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + NULL, $test['tag'], $test['aad'])); +// failed because no AAD +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'])); +// failed because wrong tag +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], str_repeat('x', 10), $test['aad'])); + +?> +--EXPECTF-- +TEST 0 +bool(true) + +Warning: openssl_decrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) +bool(false) +bool(false) diff --git a/php/ext/openssl/tests/openssl_decrypt_error.phpt b/php/ext/openssl/tests/openssl_decrypt_error.phpt new file mode 100644 index 00000000..b34397a6 --- /dev/null +++ b/php/ext/openssl/tests/openssl_decrypt_error.phpt @@ -0,0 +1,59 @@ +--TEST-- +openssl_decrypt() error tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- + +Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in %s on line %d +string(44) "yof6cPPH4mLee6TOc0YQSrh4dvywMqxGUyjp0lV6+aM=" +string(44) "yof6cPPH4mLee6TOc0YQSrh4dvywMqxGUyjp0lV6+aM=" +bool(false) + +Warning: openssl_decrypt(): Unknown cipher algorithm in %s on line %d +bool(false) +bool(false) + +Warning: openssl_decrypt(): Unknown cipher algorithm in %s on line %d +bool(false) + +Warning: openssl_decrypt(): Unknown cipher algorithm in %s on line %d +bool(false) + +Warning: openssl_decrypt(): Unknown cipher algorithm in %s on line %d +bool(false) + +Warning: openssl_decrypt() expects parameter 1 to be string, array given in %s on line %d +NULL + +Warning: openssl_decrypt() expects parameter 2 to be string, array given in %s on line %d +NULL + +Warning: openssl_decrypt() expects parameter 3 to be string, array given in %s on line %d +NULL + +Warning: openssl_encrypt(): The authenticated tag cannot be provided for cipher that doesn not support AEAD in %s on line %d +string(44) "yof6cPPH4mLee6TOc0YQSrh4dvywMqxGUyjp0lV6+aM=" diff --git a/php/ext/openssl/tests/openssl_decrypt_gcm.phpt b/php/ext/openssl/tests/openssl_decrypt_gcm.phpt new file mode 100644 index 00000000..f7002ed5 --- /dev/null +++ b/php/ext/openssl/tests/openssl_decrypt_gcm.phpt @@ -0,0 +1,51 @@ +--TEST-- +openssl_decrypt() with GCM cipher algorithm tests +--SKIPIF-- + +--FILE-- + $test) { + echo "TEST $idx\n"; + $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], $test['aad']); + var_dump($test['pt'] === $pt); +} + +// no IV +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + NULL, $test['tag'], $test['aad'])); +// failed because no AAD +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'])); +// failed because wrong tag +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], str_repeat('x', 16), $test['aad'])); + +?> +--EXPECTF-- +TEST 0 +bool(true) +TEST 1 +bool(true) +TEST 2 +bool(true) +TEST 3 +bool(true) +TEST 4 +bool(true) +TEST 5 +bool(true) + +Warning: openssl_decrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) +bool(false) +bool(false) diff --git a/php/ext/openssl/tests/openssl_digest_basic.phpt b/php/ext/openssl/tests/openssl_digest_basic.phpt new file mode 100644 index 00000000..a924c068 --- /dev/null +++ b/php/ext/openssl/tests/openssl_digest_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +openssl_digest() basic test +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(32) "f0045b6c41d9ec835cb8948c7fec4955" +string(40) "aa6e750fef05c2414c18860ad31f2c35e79bf3dc" diff --git a/php/ext/openssl/tests/openssl_encrypt_ccm.phpt b/php/ext/openssl/tests/openssl_encrypt_ccm.phpt new file mode 100644 index 00000000..945e81df --- /dev/null +++ b/php/ext/openssl/tests/openssl_encrypt_ccm.phpt @@ -0,0 +1,39 @@ +--TEST-- +openssl_encrypt() with CCM cipher algorithm tests +--SKIPIF-- + +--FILE-- + $test) { + echo "TEST $idx\n"; + $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $tag, $test['aad'], strlen($test['tag'])); + var_dump($test['ct'] === $ct); + var_dump($test['tag'] === $tag); +} + +// Empty IV error +var_dump(openssl_encrypt('data', $method, 'password', 0, NULL, $tag, '')); + +// Test setting different IV length and unlimeted tag +var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 10), $tag, '', 1024)); +var_dump(strlen($tag)); +?> +--EXPECTF-- +TEST 0 +bool(true) +bool(true) + +Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) +string(8) "p/lvgA==" +int(1024) diff --git a/php/ext/openssl/tests/openssl_encrypt_crash.phpt b/php/ext/openssl/tests/openssl_encrypt_crash.phpt new file mode 100644 index 00000000..b88782b0 --- /dev/null +++ b/php/ext/openssl/tests/openssl_encrypt_crash.phpt @@ -0,0 +1,13 @@ +--TEST-- +openssl_encrypt() crash with old OpenSSL +--SKIPIF-- + +--FILE-- + +--EXPECTF-- + +Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in %s on line %d +string(4) "done" \ No newline at end of file diff --git a/php/ext/openssl/tests/openssl_encrypt_error.phpt b/php/ext/openssl/tests/openssl_encrypt_error.phpt new file mode 100644 index 00000000..ea69ad9e --- /dev/null +++ b/php/ext/openssl/tests/openssl_encrypt_error.phpt @@ -0,0 +1,56 @@ +--TEST-- +openssl_encrypt() error tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_encrypt(): Unknown cipher algorithm in %s on line %d +bool(false) + +Warning: openssl_encrypt() expects parameter 1 to be string, object given in %s on line %d +NULL + +Warning: openssl_encrypt() expects parameter 2 to be string, object given in %s on line %d +NULL + +Warning: openssl_encrypt() expects parameter 3 to be string, object given in %s on line %d +NULL + +Warning: openssl_encrypt() expects parameter 1 to be string, array given in %s on line %d +NULL + +Warning: openssl_encrypt() expects parameter 2 to be string, array given in %s on line %d +NULL + +Warning: openssl_encrypt() expects parameter 3 to be string, array given in %s on line %d +NULL + +Warning: openssl_encrypt(): The authenticated tag cannot be provided for cipher that doesn not support AEAD in %s on line %d +string(44) "iPR4HulskuaP5Z6me5uImk6BqVyJG73+63tkPauVZYk=" + +Warning: openssl_encrypt(): Key length cannot be set for the cipher method in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/openssl_encrypt_gcm.phpt b/php/ext/openssl/tests/openssl_encrypt_gcm.phpt new file mode 100644 index 00000000..60b48cd0 --- /dev/null +++ b/php/ext/openssl/tests/openssl_encrypt_gcm.phpt @@ -0,0 +1,60 @@ +--TEST-- +openssl_encrypt() with GCM cipher algorithm tests +--SKIPIF-- + +--FILE-- + $test) { + echo "TEST $idx\n"; + $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $tag, $test['aad'], strlen($test['tag'])); + var_dump($test['ct'] === $ct); + var_dump($test['tag'] === $tag); +} + +// Empty IV error +var_dump(openssl_encrypt('data', $method, 'password', 0, NULL, $tag, '')); + +// Failing to retrieve tag (max is 16 bytes) +var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 32), $tag, '', 20)); + +// Failing when no tag supplied +var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 32))); +?> +--EXPECTF-- +TEST 0 +bool(true) +bool(true) +TEST 1 +bool(true) +bool(true) +TEST 2 +bool(true) +bool(true) +TEST 3 +bool(true) +bool(true) +TEST 4 +bool(true) +bool(true) +TEST 5 +bool(true) +bool(true) + +Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) + +Warning: openssl_encrypt(): Retrieving verification tag failed in %s on line %d +bool(false) + +Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/openssl_error_string_basic.phpt b/php/ext/openssl/tests/openssl_error_string_basic.phpt new file mode 100644 index 00000000..04cc5508 --- /dev/null +++ b/php/ext/openssl/tests/openssl_error_string_basic.phpt @@ -0,0 +1,167 @@ +--TEST-- +openssl_error_string() tests +--SKIPIF-- + +--FILE-- + 14) { + $error_code = substr($error_string, 6, 8); + if (isset($expected_errors[$error_code])) { + $expected_errors[$error_code] = true; + } + } + } + + $fail = false; + foreach ($expected_errors as $error_code => $error_code_found) { + if (!$error_code_found) { + $fail = true; + echo "$name: no error code $error_code\n"; + } + } + + if (!$fail) { + echo "$name: ok\n"; + } +} + +// helper for debugging errors +function dump_openssl_errors($name) { + echo "\n$name\n"; + while (($error_string = openssl_error_string()) !== false) { + var_dump($error_string); + } +} + +// common output file +$output_file = __DIR__ . "/openssl_error_string_basic_output.tmp"; +// invalid file for read is something that does not exist in current directory +$invalid_file_for_read = __DIR__ . "/invalid_file_for_read_operation.txt"; +// invalid file for is the test dir as writting file to existing dir should alway fail +$invalid_file_for_write = __DIR__; +// crt file +$crt_file = "file://" . __DIR__ . "/cert.crt"; +// csr file +$csr_file = "file://" . __DIR__ . "/cert.csr"; +// public key file +$public_key_file = "file://" .__DIR__ . "/public.key"; +// private key file +$private_key_file = "file://" .__DIR__ . "/private_rsa_1024.key"; +// private key file with password (password is 'php') +$private_key_file_with_pass = "file://" .__DIR__ . "/private_rsa_2048_pass_php.key"; + +// ENCRYPTION +$data = "test"; +$method = "AES-128-ECB"; +$enc_key = str_repeat('x', 40); +// error because password is longer then key length and +// EVP_CIPHER_CTX_set_key_length fails for AES +openssl_encrypt($data, $method, $enc_key); +$enc_error = openssl_error_string(); +var_dump($enc_error); +// make sure that error is cleared now +var_dump(openssl_error_string()); +// internally OpenSSL ERR won't save more than 15 (16 - 1) errors so lets test it +for ($i = 0; $i < 20; $i++) { + openssl_encrypt($data, $method, $enc_key); +} +$error_queue_size = 0; +while (($enc_error_new = openssl_error_string()) !== false) { + if ($enc_error_new !== $enc_error) { + echo "The new encoding error doesn't match the expected one\n"; + } + ++$error_queue_size; +} +var_dump($error_queue_size); +echo "\n"; + +// PKEY +echo "PKEY errors\n"; +// file for pkey (file:///) fails when opennig (BIO_new_file) +@openssl_pkey_export_to_file("file://" . $invalid_file_for_read, $output_file); +expect_openssl_errors('openssl_pkey_export_to_file opening', ['02001002', '2006D080']); +// file or private pkey is not correct PEM - failing PEM_read_bio_PrivateKey +@openssl_pkey_export_to_file($csr_file, $output_file); +expect_openssl_errors('openssl_pkey_export_to_file pem', ['0906D06C']); +// file to export cannot be written +@openssl_pkey_export_to_file($private_key_file, $invalid_file_for_write); +expect_openssl_errors('openssl_pkey_export_to_file write', ['2006D002']); +// succesful export +@openssl_pkey_export($private_key_file_with_pass, $out, 'wrong pwd'); +expect_openssl_errors('openssl_pkey_export', ['06065064', '0906A065']); +// invalid x509 for getting public key +@openssl_pkey_get_public($private_key_file); +expect_openssl_errors('openssl_pkey_get_public', ['0906D06C']); +// private encrypt with unknown padding +@openssl_private_encrypt("data", $crypted, $private_key_file, 1000); +expect_openssl_errors('openssl_private_encrypt', ['04066076']); +// private decrypt with failed padding check +@openssl_private_decrypt("data", $crypted, $private_key_file); +expect_openssl_errors('openssl_private_decrypt', ['04065072']); +// public encrypt and decrypt with failed padding check and padding +@openssl_public_encrypt("data", $crypted, $public_key_file, 1000); +@openssl_public_decrypt("data", $crypted, $public_key_file); +expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0906D06C', '04068076', '04067072']); + +// X509 +echo "X509 errors\n"; +// file for x509 (file:///) fails when opennig (BIO_new_file) +@openssl_x509_export_to_file("file://" . $invalid_file_for_read, $output_file); +expect_openssl_errors('openssl_x509_export_to_file open', ['02001002']); +// file or str cert is not correct PEM - failing PEM_read_bio_X509 or PEM_ASN1_read_bio +@openssl_x509_export_to_file($csr_file, $output_file); +expect_openssl_errors('openssl_x509_export_to_file pem', ['0906D06C']); +// file to export cannot be written +@openssl_x509_export_to_file($crt_file, $invalid_file_for_write); +expect_openssl_errors('openssl_x509_export_to_file write', ['2006D002']); +// checking purpose fails because there is no such purpose 1000 +@openssl_x509_checkpurpose($crt_file, 1000); +expect_openssl_errors('openssl_x509_checkpurpose purpose', ['0B086079']); + +// CSR +echo "CSR errors\n"; +// file for csr (file:///) fails when opennig (BIO_new_file) +@openssl_csr_get_subject("file://" . $invalid_file_for_read); +expect_openssl_errors('openssl_csr_get_subject open', ['02001002', '2006D080']); +// file or str csr is not correct PEM - failing PEM_read_bio_X509_REQ +@openssl_csr_get_subject($crt_file); +expect_openssl_errors('openssl_csr_get_subjec pem', ['0906D06C']); + +// other possible cuases that are difficult to catch: +// - ASN1_STRING_to_UTF8 fails in add_assoc_name_entry +// - invalid php_x509_request field (NULL) would cause error with CONF_get_string + +?> +--CLEAN-- + +--EXPECT-- +string(89) "error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length" +bool(false) +int(15) + +PKEY errors +openssl_pkey_export_to_file opening: ok +openssl_pkey_export_to_file pem: ok +openssl_pkey_export_to_file write: ok +openssl_pkey_export: ok +openssl_pkey_get_public: ok +openssl_private_encrypt: ok +openssl_private_decrypt: ok +openssl_private_(en|de)crypt padding: ok +X509 errors +openssl_x509_export_to_file open: ok +openssl_x509_export_to_file pem: ok +openssl_x509_export_to_file write: ok +openssl_x509_checkpurpose purpose: ok +CSR errors +openssl_csr_get_subject open: ok +openssl_csr_get_subjec pem: ok diff --git a/php/ext/openssl/tests/openssl_free_key.phpt b/php/ext/openssl/tests/openssl_free_key.phpt new file mode 100644 index 00000000..ea79ce70 --- /dev/null +++ b/php/ext/openssl/tests/openssl_free_key.phpt @@ -0,0 +1,78 @@ +--TEST-- +void openssl_free_key ( resource $key_identifier ); +--CREDITS-- +marcosptf - - @phpsp - sao paulo - br +--SKIPIF-- + +--FILE-- + dirname(__FILE__) . DIRECTORY_SEPARATOR . 'openssl.cnf'); +$privkey = openssl_pkey_new($conf); + +if ($privkey === false) + die("failed to create private key"); + +$passphrase = "banana"; +$key_file_name = tempnam(sys_get_temp_dir(), "ssl"); +if ($key_file_name === false) + die("failed to get a temporary filename!"); + +echo "Export key to file\n"; + +openssl_pkey_export_to_file($privkey, $key_file_name, $passphrase, $conf) or die("failed to export to file $key_file_name"); + +echo "Load key from file - array syntax\n"; + +$loaded_key = openssl_pkey_get_private(array("file://$key_file_name", $passphrase)); + +if ($loaded_key === false) + die("failed to load key using array syntax"); + +openssl_free_key($loaded_key); + +echo "Load key using direct syntax\n"; + +$loaded_key = openssl_pkey_get_private("file://$key_file_name", $passphrase); + +if ($loaded_key === false) + die("failed to load key using direct syntax"); + +openssl_free_key($loaded_key); + +echo "Load key manually and use string syntax\n"; + +$key_content = file_get_contents($key_file_name); +$loaded_key = openssl_pkey_get_private($key_content, $passphrase); + +if ($loaded_key === false) + die("failed to load key using string syntax"); + +openssl_free_key($loaded_key); + +echo "OK!\n"; + +@unlink($key_file_name); +?> +--EXPECT-- +Creating private key +Export key to file +Load key from file - array syntax +Load key using direct syntax +Load key manually and use string syntax +OK! diff --git a/php/ext/openssl/tests/openssl_get_cipher_methods.phpt b/php/ext/openssl/tests/openssl_get_cipher_methods.phpt new file mode 100644 index 00000000..cae223f4 --- /dev/null +++ b/php/ext/openssl/tests/openssl_get_cipher_methods.phpt @@ -0,0 +1,16 @@ +--TEST-- +openssl_get_cipher_methods basic test +--CREDITS-- +marcosptf - +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/php/ext/openssl/tests/openssl_get_md_methods.phpt b/php/ext/openssl/tests/openssl_get_md_methods.phpt new file mode 100644 index 00000000..b35e55d6 --- /dev/null +++ b/php/ext/openssl/tests/openssl_get_md_methods.phpt @@ -0,0 +1,16 @@ +--TEST-- +openssl_get_md_methods basic test +--CREDITS-- +marcosptf - +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/php/ext/openssl/tests/openssl_open_basic.phpt b/php/ext/openssl/tests/openssl_open_basic.phpt new file mode 100644 index 00000000..55bb9eb0 --- /dev/null +++ b/php/ext/openssl/tests/openssl_open_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +openssl_open() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(19) "openssl_open() test" + +Warning: openssl_open(): unable to coerce parameter 4 into a private key in %s on line %d +NULL +string(19) "openssl_open() test" +NULL diff --git a/php/ext/openssl/tests/openssl_pbkdf2_basic.phpt b/php/ext/openssl/tests/openssl_pbkdf2_basic.phpt new file mode 100644 index 00000000..3ec4dce2 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pbkdf2_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +openssl_pbkdf2() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(40) "0c60c80f961f0e71f3a9b524af6012062fe037a6" +string(40) "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957" +string(40) "4b007901b765489abead49d926f721d065a429c1" +string(50) "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038" +string(32) "56fa6aa75548099dcc37d7f03425e0c3" diff --git a/php/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt b/php/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt new file mode 100644 index 00000000..74323357 --- /dev/null +++ b/php/ext/openssl/tests/openssl_peer_fingerprint_basic.phpt @@ -0,0 +1,54 @@ +--TEST-- +Testing peer fingerprint on connection +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'capture_peer_cert' => true, + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + // should be: 81cafc260aa8d82956ebc6212a362ecc + stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', '81cafc260aa8d82956ebc6212a362ece'); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'peer_fingerprint', [ + 'sha256' => '78ea579f2c3b439359dec5dac9d445108772927427c4780037e87df3799a0aa0', + ]); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): peer_fingerprint match failure in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/openssl_pkcs12_export_basic.phpt b/php/ext/openssl/tests/openssl_pkcs12_export_basic.phpt new file mode 100644 index 00000000..65692cfe --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs12_export_basic.phpt @@ -0,0 +1,56 @@ +--TEST-- +openssl_pkcs12_export() tests +--SKIPIF-- + +--FILE-- + $cert))); // extra optional cert +var_dump(openssl_pkcs12_read($output, $opts, $pass)); +var_dump(count($opts)); // should be 3 certificates, priv, pub, extra optional cert + + +var_dump(openssl_pkcs12_export($invalid, $output, $invalid, $pass)); +var_dump(openssl_pkcs12_export($invalid_path, $output, $invalid_path, $pass)); +var_dump(openssl_pkcs12_export($priv_res, $output, $cert_res, $pass)); +//var_dump(openssl_pkcs12_export($cert, $output, $priv, $pass, array("foo"))); +?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +int(3) + +Warning: openssl_pkcs12_export(): cannot get cert from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_pkcs12_export(): cannot get cert from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_pkcs12_export(): supplied resource is not a valid OpenSSL X.509 resource in %s on line %d + +Warning: openssl_pkcs12_export(): cannot get cert from parameter 1 in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/openssl_pkcs12_export_to_file_basic.phpt b/php/ext/openssl/tests/openssl_pkcs12_export_to_file_basic.phpt new file mode 100644 index 00000000..a360591b --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs12_export_to_file_basic.phpt @@ -0,0 +1,61 @@ +--TEST-- +openssl_pkcs12_export_to_file() tests +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: openssl_pkcs12_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_pkcs12_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) + +Warning: openssl_pkcs12_export_to_file(): supplied resource is not a valid OpenSSL X.509 resource in %s on line %d + +Warning: openssl_pkcs12_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/openssl_pkcs12_read_basic.phpt b/php/ext/openssl/tests/openssl_pkcs12_read_basic.phpt new file mode 100644 index 00000000..ece9dd2e --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs12_read_basic.phpt @@ -0,0 +1,97 @@ +--TEST-- +openssl_pkcs12_read() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(false) +bool(false) +bool(true) +array(3) { + ["cert"]=> + string(1111) "-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQCS/had1ITjDjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJQ +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE1MDYxMDEyMTI0N1oXDTE2MDYwOTEyMTI0N1owRTELMAkG +A1UEBhMCUEwxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANHezJRoGMbtDzSwK7WPjj6+Yhj7R9LJyR7TjvxH01ZVA+sHUrcXs3tDXukIQcH1 +rsnf4WbBjGbQT3jlLicsll6gMOh8oaCdi6863cvw1XRUmlezpAs2V5MZOEgqkWvU +8OKHqjt8o9F07T3n1zYeeBjiUsr6UWqX4+Znwa25UF0Fid1R4BxmX7GpDoq0Weuv +WQafbM9qs3Qrd7Ea3Lqz9pGkWx1BmOv49XorAhQadxCT32GbUdhmhxgrDgyW5M7m +ECz4DngZLhZvLC8Juf/Q6R5SjhN5/f/TBq//QpKaCjBAamhZDJtWMv80IDKJO7Ir +fQMnPEq4vCnHdKvG7N6ZjsECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHGAiEN0o +tOV2tbK0Qm/mWlyuRKtxqnP3y/2Q5SFMmRpkOS54hFf9YBNgT7nWK3Z5fPKor17t +rGthXPSZU8hxY5iHFhELurp23qGmJftdcYL2mF7IyoGOiZ1Q6Vt9LnRTDtgrHh/f +ZziI+gaPpmAfEAh48xQrlviHqaR9F63d0UN1jz9cF1kIj1H21PAGC0tmAIxxb4ee +hjipL+JLH0iRoBQE83cF2BOQCfRzRekotnDYon6v7mTjYu7kwl8paRIEMNrBckby +IL3CJOZFesaFO7suK7oP7r6BIATpVcg2m0V25mVMVFRm4F/JOvSkB381Pte/Ccuv +dxPWHER13ptIVg== +-----END CERTIFICATE----- +" + ["pkey"]=> + string(1704) "-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR3syUaBjG7Q80 +sCu1j44+vmIY+0fSycke0478R9NWVQPrB1K3F7N7Q17pCEHB9a7J3+FmwYxm0E94 +5S4nLJZeoDDofKGgnYuvOt3L8NV0VJpXs6QLNleTGThIKpFr1PDih6o7fKPRdO09 +59c2HngY4lLK+lFql+PmZ8GtuVBdBYndUeAcZl+xqQ6KtFnrr1kGn2zParN0K3ex +Gty6s/aRpFsdQZjr+PV6KwIUGncQk99hm1HYZocYKw4MluTO5hAs+A54GS4Wbywv +Cbn/0OkeUo4Tef3/0wav/0KSmgowQGpoWQybVjL/NCAyiTuyK30DJzxKuLwpx3Sr +xuzemY7BAgMBAAECggEAbdYX5ZexV/LbYWzOA2CVRnsnJgHkrgnTS2HXVGtWzLkD +qu6TOKWb1mgE9RrQJ22oQ5j7A2dKTsi4vwHarL/mFrHpxtLrV/78CwJY8BIj9JUO +jdXDheaz4JVzYjl9EB1K0JPF4QozRjzWqO58MKOzoPpZ8EcfcxT5Pi2RLJVu3K9F +DR3cUNa9h66j84sDJARzvxMfgR6VysHVmgN1aR78Mye0dFVYeL7wCXFJmJXa2AYw +TQR5FcFRa0h8t40EOJdXcoWu63TUd7rvDgebHXJeKax8W2pGREHZfeEw5wWpFQn8 +j+znHSISe7eM9wmW6ombab7zcJsCwXDYgtY/6OqRAQKBgQD6EXKfXThfnrN/od/Y +jF8mfKdJ67HOc8WVPlB9vHDsduFyX914ahJHeCVQPkV1a2nx+bv3PviWbrKreEKl +b7aAAAkbxy/FakcxE9b0wC5JsSW9vByXQiRn0iDqDNl9iwzX/LLW6wE7SruCPp+z +mzCHArp6mvJmRFooR8e3IXiA0QKBgQDW2T9xXFBpumSOBRpn7Zc9SGiQ9qZTSKKb +boVSDd2cod8O1aow3gnQNid/cNnt54Yh5Z3KlYfFWkmrV+0/yQZ/SThZ1uHAaZVy +OnWKVELykpYLnKGlHoQpOYTCfdYan5xOfkw55em3TTeQq5tETYWMdhS/9VVxeLKZ +k2xr+CYq8QKBgQCzHpJK4nwByexq7KkpNIrnR3yQb1oiNjz9xO/k0HjWd+TOhypd +GSVUuhOIIcKg87qkj6x60kk/f7VNK0wZsiY4E05y7j8imhi6Z6qeD5ZYRKJzAG4+ +TitDjnjzDRcwXMxrXV9AoH52WPZsuays+ulMm8C1F42vgSBPH/NHEpt9MQKBgAIw +nLDvG/K376Zy7t34Uf5R6p7vpKpcpyumaL15XrTmAXwJOX7eBIOWybhG0jHWlktq +J72U4JlmXjHc55Iq3mIVwPlJc2uep+NOLTyHt1b5n4Xmxs8EDJzO9Ud2OOR0lAdI +ykYczdEMfHCBD0gW8jGIUpXSTlilvkxKcGR5VwpBAoGBANdAWL3lw+/P43x6Rxth +GJN8QzWe5vRFJYS5mkeaa/6jrFrsvk176WudopropFGtRc/44E1IDOZULJM80Xgb +JTeUFyb+ZjYLrHUp1yir+oZIm5DBZDZjYclanrPPHg9YwVxcHtunPeCFy3iC+W+F +MK80GEnRQIkB7uZVk+r0HusK +-----END PRIVATE KEY----- +" + ["extracerts"]=> + array(1) { + [0]=> + string(1111) "-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQDaL5/+UVeXuTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE1MDYxMDEyNDAwNVoXDTE2MDYwOTEyNDAwNVowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AL/IF7bW0vpEg5A054SDqTi5pkSeie6nyIT77qCAVI5PMlhNjxuqDIlLpCWonvKb +LMRtp7t24BsQBRgQgps8mtfRr0gV1qq9HMfDj2bZdGcTShZN/M/BFATwxaNRTHl9 +ey8zxGcLd4aFFBlVhXHYdBXg/PG/oxJMAFuMwa+KxSP6Mqp1FlOZtvUUieQcToMf +Mh8Lbr4g/yHFj5lgWIJ2fmJjHJZ4wf9QBeGUrVqqxzSDEL9f0PGy+grqSHoIzLr3 ++uhvhoI85nCyZs9+lrELuQKqbiZ8Q6Vmj6JGt3miNBFVTbBpP9GK8sVuVQwgqd8p +C3e8hHqv7vwF+s0zjiZ+rCcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAdpTtiyDJ +0wLB18iunXCMUJpjc/HVYEp5P9vl2E/bcZfGns/8KxNHoe9mgJycr3mwjCjMjVx2 +L/9q/8XoT02aBncwAx4oZ2H0qfjZppaUSnSc1Uv+dsldDC2mZvJgwXN7jtQmU5P3 +cspFHuJoYK8AqYJqlO6E4L9uRF7dLEliUnrBpF4BxziwskTquRX+zgD+fmk0L5O8 +qqvm8btWCxfng+qD7UHFWbUQ2IegZ3VrBWJ2XsxOvokMM4HoHVb0BZgq8Dvu0XJ9 +EriEQkcydtrRKtlcWHLKcJuNUnkw2qfj+F8mmdaZib8Apa1UCkt0ZlpyYO3V2ejY +WIjafwJYrv6f5g== +-----END CERTIFICATE----- +" + } +} diff --git a/php/ext/openssl/tests/openssl_pkcs7_decrypt_basic.phpt b/php/ext/openssl/tests/openssl_pkcs7_decrypt_basic.phpt new file mode 100644 index 00000000..cf6c0df8 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_decrypt_basic.phpt @@ -0,0 +1,66 @@ +--TEST-- +openssl_pkcs7_decrypt() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +bool(true) + +Warning: openssl_pkcs7_decrypt(): unable to get private key in %s on line %d +bool(false) + +Warning: openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert in %s on line %d +bool(false) + +Warning: openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) + +Warning: openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert in %s on line %d +bool(false) + +Warning: openssl_pkcs7_decrypt(): unable to get private key in %s on line %d +bool(false) +true +true diff --git a/php/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt b/php/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt new file mode 100644 index 00000000..e8ba2645 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_decrypt_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +openssl_pkcs7_decrypt() and invalid parameters +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(57) "Object of class stdClass could not be converted to string" +string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" +bool(false) +object(stdClass)#1 (0) { +} +string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" +bool(false) +string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" +bool(false) +string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" +bool(false) +string(66) "openssl_pkcs7_decrypt(): unable to coerce parameter 3 to x509 cert" +bool(false) +Done diff --git a/php/ext/openssl/tests/openssl_pkcs7_encrypt_basic.phpt b/php/ext/openssl/tests/openssl_pkcs7_encrypt_basic.phpt new file mode 100644 index 00000000..210e5de9 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_encrypt_basic.phpt @@ -0,0 +1,68 @@ +--TEST-- +openssl_pkcs7_encrypt() tests +--SKIPIF-- + +--FILE-- + "test@test", "Subject" => "testing openssl_pkcs7_encrypt()"); +$headers = array("test@test", "testing openssl_pkcs7_encrypt()"); +$empty_headers = array(); +$wrong = "wrong"; +$empty = ""; + +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $single_cert, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, openssl_x509_read($single_cert), $headers)); +var_dump(openssl_pkcs7_decrypt($outfile, $outfile2, $single_cert, $privkey)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $single_cert, $assoc_headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $single_cert, $empty_headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $single_cert, $wrong)); +var_dump(openssl_pkcs7_encrypt($wrong, $outfile, $single_cert, $headers)); +var_dump(openssl_pkcs7_encrypt($empty, $outfile, $single_cert, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $empty, $single_cert, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $wrong, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $empty, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $single_cert, $empty)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, $multi_certs, $headers)); +var_dump(openssl_pkcs7_encrypt($infile, $outfile, array_map('openssl_x509_read', $multi_certs) , $headers)); + +if (file_exists($outfile)) { + echo "true\n"; + unlink($outfile); +} +if (file_exists($outfile2)) { + echo "true\n"; + unlink($outfile2); +} +?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: openssl_pkcs7_encrypt() expects parameter 4 to be array, string given in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) + +Warning: openssl_pkcs7_encrypt() expects parameter 4 to be array, string given in %s on line %d +bool(false) +bool(true) +bool(true) +true +true diff --git a/php/ext/openssl/tests/openssl_pkcs7_read_basic.phpt b/php/ext/openssl/tests/openssl_pkcs7_read_basic.phpt new file mode 100644 index 00000000..052779dc --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_read_basic.phpt @@ -0,0 +1,52 @@ +--TEST-- +openssl_pkcs7_read() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- + +Warning: openssl_pkcs7_read() expects exactly 2 parameters, 0 given in %s on line %d +NULL + +Warning: openssl_pkcs7_read() expects exactly 2 parameters, 1 given in %s on line %d +NULL +bool(false) +bool(false) +bool(true) +array(1) { + [0]=> + string(1249) "-----BEGIN CERTIFICATE----- +MIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD +VQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBv +cnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJ +KoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4 +MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRl +IGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1 +ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTz +e4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+ +iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aR +S1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLo +Ymhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGE +MIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTAT +BgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5n +ZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zS +UW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LW +PVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn +4vh8xF/9+eVEj+hM+0OflA== +-----END CERTIFICATE----- +" +} diff --git a/php/ext/openssl/tests/openssl_pkcs7_sign_basic.phpt b/php/ext/openssl/tests/openssl_pkcs7_sign_basic.phpt new file mode 100644 index 00000000..d6ce7998 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_sign_basic.phpt @@ -0,0 +1,68 @@ +--TEST-- +openssl_pkcs7_sign() tests +--SKIPIF-- + +--FILE-- + "test@test", "Subject" => "testing openssl_pkcs7_sign()"); +$headers = array("test@test", "testing openssl_pkcs7_sign()"); +$empty_headers = array(); +$wrong = "wrong"; +$empty = ""; + +var_dump(openssl_pkcs7_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $privkey, $assoc_headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $privkey, $empty_headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $privkey, $wrong)); +var_dump(openssl_pkcs7_sign($wrong, $outfile, $single_cert, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($empty, $outfile, $single_cert, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $empty, $single_cert, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $wrong, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $empty, $privkey, $headers)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $privkey, $empty)); +var_dump(openssl_pkcs7_sign($infile, $outfile, $single_cert, $wrong, $headers)); + +if (file_exists($outfile)) { + echo "true\n"; + unlink($outfile); +} +?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: openssl_pkcs7_sign() expects parameter 5 to be array, string given in %s on line %d +NULL + +Warning: openssl_pkcs7_sign(): error opening input file %s in %s on line %d +bool(false) + +Warning: openssl_pkcs7_sign(): error opening input file %s in %s on line %d +bool(false) + +Warning: openssl_pkcs7_sign(): error opening output file %s in %s on line %d +bool(false) + +Warning: openssl_pkcs7_sign(): error getting cert in %s on line %d +bool(false) + +Warning: openssl_pkcs7_sign(): error getting cert in %s on line %d +bool(false) + +Warning: openssl_pkcs7_sign() expects parameter 5 to be array, string given in %s on line %d +NULL + +Warning: openssl_pkcs7_sign(): error getting private key in %s on line %d +bool(false) +true diff --git a/php/ext/openssl/tests/openssl_pkcs7_verify_basic.phpt b/php/ext/openssl/tests/openssl_pkcs7_verify_basic.phpt new file mode 100644 index 00000000..bd3169ac --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkcs7_verify_basic.phpt @@ -0,0 +1,94 @@ +--TEST-- +openssl_pkcs7_verify() tests +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +int(-1) +int(-1) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +string(20%d) "-----BEGIN PKCS7----- +MIIFzQYJKoZIhvcNAQcCoIIFvjCCBboCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggNwMIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEB +BQUAMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwx +FTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4g +QW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYz +MDEwMjg0M1oXDTA4MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQI +ExFSaW8gR3JhbmRlIGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYD +VQQDExVIZW5yaXF1ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5n +ZWxvQHBocC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ul +X4/WDAVBYfoTPRTze4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4 +I2bkWR6/PTqrvnv+iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkx +Q/ksqL9O/F6zk+aRS1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+ +QHK9XDWF7CkpgRLoYmhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLo +Ymhqtz99oYGHpIGEMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5k +ZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlx +dWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0 +ggkArsVWzHI3UKIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUn +StC0TBqngr3Kx+zSUW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQ +S3X2+Y0VvIpW72LWPVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r +8s+KhNAqI4PbClvn4vh8xF/9+eVEj+hM+0OflDGCAiEwggIdAgEBMIGPMIGBMQsw +CQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcT +DFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8w +HQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0AgkArsVWzHI3UKIwDQYJYIZI +AWUDBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B +CQUxDxcNMTcwNTIyMTAxMDU1WjAvBgkqhkiG9w0BCQQxIgQg37MSoxw91phVhwUO +MeurwtXAXK1ADEeYYl/7Bfmz4CsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQME +ASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG +9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgw +DQYJKoZIhvcNAQEBBQAEgYAw4XcsQ4BIhEuRNspG8RqPE9ODCrTWwXPSQ4B9fzks +KUAsqcefO8AfifY+uuq3/k6Prhl23U5ILth/0fUAIGFLTcIZziaGTwbpgcmRSmNi +jBxatHyKVaGJNGqij5KRk8vhEpy5mwOzmkUzYa0r4teXjyfnKhI/h1vUrO3kKybC +5Q== +-----END PKCS7----- +" +true +true diff --git a/php/ext/openssl/tests/openssl_pkey_export_basic.phpt b/php/ext/openssl/tests/openssl_pkey_export_basic.phpt new file mode 100644 index 00000000..4346b5a6 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkey_export_basic.phpt @@ -0,0 +1,59 @@ +--TEST-- +openssl_pkey_export() with EC key +--SKIPIF-- + +--FILE-- + __DIR__ . DIRECTORY_SEPARATOR . "openssl.cnf"); + +var_dump(openssl_pkey_export($key, $output, NULL, $config_arg)); +echo $output; + +// Load the private key from the exported pem string +$details = openssl_pkey_get_details(openssl_pkey_get_private($output)); +var_dump(OPENSSL_KEYTYPE_EC === $details['type']); + +// Export key with passphrase +openssl_pkey_export($key, $output, 'passphrase', $config_arg); + +$details = openssl_pkey_get_details(openssl_pkey_get_private($output, 'passphrase')); +var_dump(OPENSSL_KEYTYPE_EC === $details['type']); + +// Read public key +$pKey = openssl_pkey_get_public('file://' . dirname(__FILE__) . '/public_ec.key'); +var_dump($pKey); +// The details are the same for a public or private key, expect the private key parameter 'd +$detailsPKey = openssl_pkey_get_details($pKey); +var_dump(array_diff_assoc($details['ec'], $detailsPKey['ec'])); + +// Export to file +$tempname = tempnam(sys_get_temp_dir(), 'openssl_ec'); +var_dump(openssl_pkey_export_to_file($key, $tempname, NULL, $config_arg)); +$details = openssl_pkey_get_details(openssl_pkey_get_private('file://' . $tempname)); +var_dump(OPENSSL_KEYTYPE_EC === $details['type']); +var_dump(is_resource($key)); +// Clean the temporary file +@unlink($tempname); +?> +--EXPECTF-- +resource(%d) of type (OpenSSL key) +bool(true) +-----BEGIN EC PRIVATE KEY-----%a-----END EC PRIVATE KEY----- +bool(true) +bool(true) +resource(%d) of type (OpenSSL key) +array(1) { + ["d"]=> + string(32) "%a" +} +bool(true) +bool(true) +bool(true) diff --git a/php/ext/openssl/tests/openssl_pkey_get_details_basic.phpt b/php/ext/openssl/tests/openssl_pkey_get_details_basic.phpt new file mode 100644 index 00000000..3c239af2 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkey_get_details_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +openssl_pkey_get_details() with EC key +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Array +( + [bits] => 256 + [key] => -----BEGIN PUBLIC KEY-----%a +-----END PUBLIC KEY----- + + [ec] => Array + ( + [curve_name] => prime256v1 + [curve_oid] => 1.2.840.10045.3.1.7 + [x] => %a + [y] => %a + [d] => %a + ) + + [type] => 3 +) diff --git a/php/ext/openssl/tests/openssl_pkey_new_basic.phpt b/php/ext/openssl/tests/openssl_pkey_new_basic.phpt new file mode 100644 index 00000000..b73b1f58 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkey_new_basic.phpt @@ -0,0 +1,106 @@ +--TEST-- +openssl_pkey_new() basic usage tests +--SKIPIF-- + +--FILE-- + array( + 'n' => hex2bin($nhex), + 'e' => hex2bin($ehex), + 'd' => hex2bin($dhex), + 'p' => hex2bin($phex), + 'q' => hex2bin($qhex), + ) +)); +$details = openssl_pkey_get_details($rsa); +$rsa_details = $details['rsa']; +openssl_pkey_test_cmp($nhex, $rsa_details['n']); +openssl_pkey_test_cmp($ehex, $rsa_details['e']); +openssl_pkey_test_cmp($dhex, $rsa_details['d']); +openssl_pkey_test_cmp($phex, $rsa_details['p']); +openssl_pkey_test_cmp($qhex, $rsa_details['q']); + +// DSA +$phex = '00f8000ae45b2dacb47dd977d58b719d097bdf07cb2c17660ad898518c08' . + '1a61659a16daadfaa406a0a994c743df5eda07e36bd0adcad921b77432ff' . + '24ccc31e782d647e66768122b578857e9293df78387dc8b44af2a4a3f305' . + '1f236b1000a3e31da489c6681b0031f7ec37c2e1091bdb698e7660f135b6' . + '996def90090303b7ad'; + +$qhex = '009b3734fc9f7a4a9d6437ec314e0a78c2889af64b'; + +$ghex = '00b320300a0bc55b8f0ec6edc218e2185250f38fbb8291db8a89227f6e41' . + '00d47d6ccb9c7d42fc43280ecc2ed386e81ff65bc5d6a2ae78db7372f5dc' . + 'f780f4558e7ed3dd0c96a1b40727ac56c5165aed700a3b63997893a1fb21' . + '4e882221f0dd9604820dc34e2725dd6901c93e0ca56f6d76d495c332edc5' . + 'b81747c4c447a941f3'; +$dsa = openssl_pkey_new(array( + 'dsa' => array( + 'p' => hex2bin($phex), + 'q' => hex2bin($qhex), + 'g' => hex2bin($ghex) + ) +)); +$details = openssl_pkey_get_details($dsa); +$dsa_details = $details['dsa']; +openssl_pkey_test_cmp($phex, $dsa_details['p']); +openssl_pkey_test_cmp($qhex, $dsa_details['q']); +openssl_pkey_test_cmp($ghex, $dsa_details['g']); +var_dump(strlen($dsa_details['priv_key'])); +var_dump(strlen($dsa_details['pub_key'])); + +// DH +$phex = 'dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61e' . + 'f75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d268370557' . + '7d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e382' . + '6634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab'; + +$dh_details = array('p' => $phex, 'g' => '2'); +$dh = openssl_pkey_new(array( + 'dh'=> array('p' => hex2bin($phex), 'g' => '2')) +); +$details = openssl_pkey_get_details($dh); +$dh_details = $details['dh']; +openssl_pkey_test_cmp($phex, $dh_details['p']); +var_dump($dh_details['g']); +var_dump(strlen($dh_details['pub_key'])); +var_dump(strlen($dh_details['priv_key'])); +?> +--EXPECTF-- +int(0) +int(0) +int(0) +int(0) +int(0) +int(0) +int(0) +int(0) +int(%d) +int(%d) +int(0) +string(1) "2" +int(%d) +int(%d) diff --git a/php/ext/openssl/tests/openssl_pkey_new_error.phpt b/php/ext/openssl/tests/openssl_pkey_new_error.phpt new file mode 100644 index 00000000..c5993411 --- /dev/null +++ b/php/ext/openssl/tests/openssl_pkey_new_error.phpt @@ -0,0 +1,25 @@ +--TEST-- +openssl_pkey_new() error tests +--SKIPIF-- + +--FILE-- + array()); +$dsa = array("dsa" => array()); +$dh = array("dh" => array()); + +openssl_pkey_get_details(openssl_pkey_new($rsa)); +openssl_pkey_get_details(openssl_pkey_new($dsa)); +openssl_pkey_get_details(openssl_pkey_new($dh)); +?> +--EXPECTF-- + +Warning: openssl_pkey_get_details() expects parameter 1 to be resource, boolean given in %s on line %d + +Warning: openssl_pkey_get_details() expects parameter 1 to be resource, boolean given in %s on line %d + +Warning: openssl_pkey_get_details() expects parameter 1 to be resource, boolean given in %s on line %d + diff --git a/php/ext/openssl/tests/openssl_private_decrypt_basic.phpt b/php/ext/openssl/tests/openssl_private_decrypt_basic.phpt new file mode 100644 index 00000000..76a08b8d --- /dev/null +++ b/php/ext/openssl/tests/openssl_private_decrypt_basic.phpt @@ -0,0 +1,40 @@ +--TEST-- +openssl_private_decrypt() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +string(32) "Testing openssl_public_decrypt()" + +Warning: openssl_private_decrypt(): key parameter is not a valid private key in %s on line %d +bool(false) +NULL +bool(false) +NULL + +Warning: openssl_private_decrypt(): key array must be of the form array(0 => key, 1 => phrase) in %s on line %d + +Warning: openssl_private_decrypt(): key parameter is not a valid private key in %s on line %d +bool(false) +NULL +bool(true) +string(32) "Testing openssl_public_decrypt()" diff --git a/php/ext/openssl/tests/openssl_private_encrypt_basic.phpt b/php/ext/openssl/tests/openssl_private_encrypt_basic.phpt new file mode 100644 index 00000000..a2a51521 --- /dev/null +++ b/php/ext/openssl/tests/openssl_private_encrypt_basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +openssl_private_encrypt() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) + +Warning: openssl_private_encrypt(): key param is not a valid private key in %s on line %d +bool(false) + +Warning: openssl_private_encrypt(): key param is not a valid private key in %s on line %d +bool(false) + +Warning: openssl_private_encrypt(): key param is not a valid private key in %s on line %d +bool(false) +bool(true) +string(4) "test" diff --git a/php/ext/openssl/tests/openssl_public_decrypt_basic.phpt b/php/ext/openssl/tests/openssl_public_decrypt_basic.phpt new file mode 100644 index 00000000..42d72b9c --- /dev/null +++ b/php/ext/openssl/tests/openssl_public_decrypt_basic.phpt @@ -0,0 +1,48 @@ +--TEST-- +openssl_public_decrypt() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +string(32) "Testing openssl_public_decrypt()" + +Warning: openssl_public_decrypt(): key parameter is not a valid public key in %s on line %d +bool(false) +NULL +bool(false) +NULL + +Warning: openssl_public_decrypt(): key array must be of the form array(0 => key, 1 => phrase) in %s on line %d + +Warning: openssl_public_decrypt(): key parameter is not a valid public key in %s on line %d +bool(false) +NULL + +Warning: openssl_public_decrypt(): key array must be of the form array(0 => key, 1 => phrase) in %s on line %d + +Warning: openssl_public_decrypt(): key parameter is not a valid public key in %s on line %d +bool(false) +NULL +bool(true) +string(32) "Testing openssl_public_decrypt()" diff --git a/php/ext/openssl/tests/openssl_public_encrypt_basic.phpt b/php/ext/openssl/tests/openssl_public_encrypt_basic.phpt new file mode 100644 index 00000000..a3c4c575 --- /dev/null +++ b/php/ext/openssl/tests/openssl_public_encrypt_basic.phpt @@ -0,0 +1,40 @@ +--TEST-- +openssl_public_encrypt() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) + +Warning: openssl_public_encrypt(): key parameter is not a valid public key in %s on line %d +bool(false) + +Warning: openssl_public_encrypt(): key parameter is not a valid public key in %s on line %d +bool(false) + +Warning: openssl_public_encrypt(): key parameter is not a valid public key in %s on line %d +bool(false) +bool(true) +string(4) "test" + diff --git a/php/ext/openssl/tests/openssl_random_pseudo_bytes_basic.phpt b/php/ext/openssl/tests/openssl_random_pseudo_bytes_basic.phpt new file mode 100644 index 00000000..ac5a3079 --- /dev/null +++ b/php/ext/openssl/tests/openssl_random_pseudo_bytes_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +openssl_random_pseudo_bytes() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(0) "" +string(2) "%s" +string(4) "%s" +string(6) "%s" +string(8) "%s" +string(10) "%s" +string(12) "%s" +string(14) "%s" +string(16) "%s" +string(18) "%s" \ No newline at end of file diff --git a/php/ext/openssl/tests/openssl_seal_basic.phpt b/php/ext/openssl/tests/openssl_seal_basic.phpt new file mode 100644 index 00000000..4f1958a3 --- /dev/null +++ b/php/ext/openssl/tests/openssl_seal_basic.phpt @@ -0,0 +1,58 @@ +--TEST-- +openssl_seal() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: openssl_seal(): not a public key (1th member of pubkeys) in %s on line %d +bool(false) + +Warning: openssl_seal(): Fourth argument to openssl_seal() must be a non-empty array in %s on line %d +bool(false) + +Warning: openssl_seal() expects parameter 1 to be string, array given in %s on line %d +NULL + +Warning: openssl_seal() expects parameter 1 to be string, array given in %s on line %d +NULL +int(19) +int(19) + +Warning: openssl_seal(): not a public key (2th member of pubkeys) in %s on line %d +bool(false) + +Warning: openssl_seal() expects parameter 4 to be array, string given in %s on line %d +NULL + +Warning: openssl_seal(): Fourth argument to openssl_seal() must be a non-empty array in %s on line %d +bool(false) + +Warning: openssl_seal(): not a public key (1th member of pubkeys) in %s on line %d +bool(false) +Done diff --git a/php/ext/openssl/tests/openssl_sign_basic.phpt b/php/ext/openssl/tests/openssl_sign_basic.phpt new file mode 100644 index 00000000..3d41ee1d --- /dev/null +++ b/php/ext/openssl/tests/openssl_sign_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +openssl_sign() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) + +Warning: openssl_sign(): supplied key param cannot be coerced into a private key in %s on line %d +bool(false) + +Warning: openssl_sign() expects parameter 1 to be string, array given in %s on line %d +NULL diff --git a/php/ext/openssl/tests/openssl_spki_export_basic.phpt b/php/ext/openssl/tests/openssl_spki_export_basic.phpt new file mode 100644 index 00000000..1e3bd1fd --- /dev/null +++ b/php/ext/openssl/tests/openssl_spki_export_basic.phpt @@ -0,0 +1,60 @@ +--TEST-- +openssl_spki_export() tests for exporting public key +--SKIPIF-- + +--FILE-- + +--EXPECTREGEX-- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- diff --git a/php/ext/openssl/tests/openssl_spki_export_challenge_basic.phpt b/php/ext/openssl/tests/openssl_spki_export_challenge_basic.phpt new file mode 100644 index 00000000..07a69d3b --- /dev/null +++ b/php/ext/openssl/tests/openssl_spki_export_challenge_basic.phpt @@ -0,0 +1,103 @@ +--TEST-- +openssl_spki_export_challenge() tests for exporting challenge +--INI-- +error_reporting=0 +--SKIPIF-- + +--FILE-- + +--EXPECTREGEX-- +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) diff --git a/php/ext/openssl/tests/openssl_spki_new_basic.phpt b/php/ext/openssl/tests/openssl_spki_new_basic.phpt new file mode 100644 index 00000000..b31d6f91 --- /dev/null +++ b/php/ext/openssl/tests/openssl_spki_new_basic.phpt @@ -0,0 +1,73 @@ +--TEST-- +openssl_spki_new() test for creating SPKI string +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(474) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(826) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1506) "%s" diff --git a/php/ext/openssl/tests/openssl_spki_verify_basic.phpt b/php/ext/openssl/tests/openssl_spki_verify_basic.phpt new file mode 100644 index 00000000..7b56a37e --- /dev/null +++ b/php/ext/openssl/tests/openssl_spki_verify_basic.phpt @@ -0,0 +1,88 @@ +--TEST-- +openssl_spki_verify() tests for valid signature +--INI-- +error_reporting=0 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) diff --git a/php/ext/openssl/tests/openssl_verify_basic.phpt b/php/ext/openssl/tests/openssl_verify_basic.phpt new file mode 100644 index 00000000..a21dfedb --- /dev/null +++ b/php/ext/openssl/tests/openssl_verify_basic.phpt @@ -0,0 +1,28 @@ +--TEST-- +openssl_verify() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +int(1) + +Warning: openssl_verify(): supplied key param cannot be coerced into a public key in %s on line %d +bool(false) + +Warning: openssl_verify(): supplied key param cannot be coerced into a public key in %s on line %d +bool(false) +int(0) +int(0) diff --git a/php/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt b/php/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt new file mode 100644 index 00000000..ca6eac94 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_check_private_key_basic.phpt @@ -0,0 +1,29 @@ +--TEST-- +openssl_x509_check_private_key() tests +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +bool(false) +bool(false) +bool(false) +bool(true) diff --git a/php/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt b/php/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt new file mode 100644 index 00000000..677f4d89 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt @@ -0,0 +1,150 @@ +--TEST-- +int openssl_x509_checkpurpose ( mixed $x509cert , int $purpose [, array $cainfo = array() [, string $untrustedfile ]] ) function +--CREDITS-- +marcosptf - +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +int(-1) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/php/ext/openssl/tests/openssl_x509_export_basic.phpt b/php/ext/openssl/tests/openssl_x509_export_basic.phpt new file mode 100644 index 00000000..4177bd77 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_export_basic.phpt @@ -0,0 +1,45 @@ +--TEST-- +openssl_x509_export() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +bool(true) + +Warning: openssl_x509_export(): cannot get cert from parameter 1 in %s on line %d +bool(false) +bool(true) + +Warning: openssl_x509_export(): cannot get cert from parameter 1 in %s on line %d +bool(false) +int(0) +int(0) +int(%d) +int(0) +int(%d) diff --git a/php/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt b/php/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt new file mode 100644 index 00000000..68ba9323 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_export_to_file_basic.phpt @@ -0,0 +1,42 @@ +--TEST-- +openssl_x509_export_to_file() tests +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(true) +bool(true) + +Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) +bool(true) + +Warning: openssl_x509_export_to_file(): cannot get cert from parameter 1 in %s on line %d +bool(false) +--- +bool(true) diff --git a/php/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt b/php/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt new file mode 100644 index 00000000..add65cb3 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_fingerprint_basic.phpt @@ -0,0 +1,54 @@ +--TEST-- +openssl_x509_fingerprint() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +** Testing with no parameters ** + +Warning: openssl_x509_fingerprint() expects at least 1 parameter, 0 given in %s on line %d +NULL +** Testing default functionality ** +string(40) "6e6fd1ea10a5a23071d61c728ee9b40df6dbc33c" +** Testing hash method md5 ** +string(32) "ac77008e172897e06c0b065294487a67" +**Testing raw output md5 ** +string(32) "ac77008e172897e06c0b065294487a67" +** Testing hash method sha1 with resource ** +string(40) "6e6fd1ea10a5a23071d61c728ee9b40df6dbc33c" +** Testing bad certification ** + +Warning: openssl_x509_fingerprint(): cannot get cert from parameter 1 in %s on line %d +bool(false) +** Testing bad hash method ** + +Warning: openssl_x509_fingerprint(): Unknown signature algorithm in %s on line %d +bool(false) + diff --git a/php/ext/openssl/tests/openssl_x509_free_basic.phpt b/php/ext/openssl/tests/openssl_x509_free_basic.phpt new file mode 100644 index 00000000..d8b586e8 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_free_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +openssl_x509_free() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (Unknown) + +Warning: openssl_x509_free() expects parameter 1 to be resource, boolean given in %s on line %d diff --git a/php/ext/openssl/tests/openssl_x509_parse_basic.phpt b/php/ext/openssl/tests/openssl_x509_parse_basic.phpt new file mode 100644 index 00000000..65cc062e --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_parse_basic.phpt @@ -0,0 +1,313 @@ +--TEST-- +openssl_x509_parse() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +array(16) { + ["name"]=> + string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + ["subject"]=> + array(5) { + ["C"]=> + string(2) "BR" + ["ST"]=> + string(17) "Rio Grande do Sul" + ["L"]=> + string(12) "Porto Alegre" + ["CN"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["hash"]=> + string(8) "%s" + ["issuer"]=> + array(5) { + ["C"]=> + string(2) "BR" + ["ST"]=> + string(17) "Rio Grande do Sul" + ["L"]=> + string(12) "Porto Alegre" + ["CN"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["version"]=> + int(2) + ["serialNumber"]=> + string(20) "12593567369101004962" + ["serialNumberHex"]=> + string(16) "AEC556CC723750A2" + ["validFrom"]=> + string(13) "080630102843Z" + ["validTo"]=> + string(13) "080730102843Z" + ["validFrom_time_t"]=> + int(1214821723) + ["validTo_time_t"]=> + int(1217413723) + ["signatureTypeSN"]=> + string(8) "RSA-SHA1" + ["signatureTypeLN"]=> + string(21) "sha1WithRSAEncryption" + ["signatureTypeNID"]=> + int(65) + ["purposes"]=> + array(9) { + [1]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "sslclient" + } + [2]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "sslserver" + } + [3]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "nssslserver" + } + [4]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(9) "smimesign" + } + [5]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(12) "smimeencrypt" + } + [6]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(7) "crlsign" + } + [7]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(3) "any" + } + [8]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "ocsphelper" + } + [9]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(13) "timestampsign" + } + } + ["extensions"]=> + array(3) { + ["subjectKeyIdentifier"]=> + string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" + ["authorityKeyIdentifier"]=> + string(202) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D +DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net +serial:AE:C5:56:CC:72:37:50:A2 +" + ["basicConstraints"]=> + string(7) "CA:TRUE" + } +} +array(16) { + ["name"]=> + string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + ["subject"]=> + array(5) { + ["countryName"]=> + string(2) "BR" + ["stateOrProvinceName"]=> + string(17) "Rio Grande do Sul" + ["localityName"]=> + string(12) "Porto Alegre" + ["commonName"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["hash"]=> + string(8) "%s" + ["issuer"]=> + array(5) { + ["countryName"]=> + string(2) "BR" + ["stateOrProvinceName"]=> + string(17) "Rio Grande do Sul" + ["localityName"]=> + string(12) "Porto Alegre" + ["commonName"]=> + string(21) "Henrique do N. Angelo" + ["emailAddress"]=> + string(16) "hnangelo@php.net" + } + ["version"]=> + int(2) + ["serialNumber"]=> + string(20) "12593567369101004962" + ["serialNumberHex"]=> + string(16) "AEC556CC723750A2" + ["validFrom"]=> + string(13) "080630102843Z" + ["validTo"]=> + string(13) "080730102843Z" + ["validFrom_time_t"]=> + int(1214821723) + ["validTo_time_t"]=> + int(1217413723) + ["signatureTypeSN"]=> + string(8) "RSA-SHA1" + ["signatureTypeLN"]=> + string(21) "sha1WithRSAEncryption" + ["signatureTypeNID"]=> + int(65) + ["purposes"]=> + array(9) { + [1]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "SSL client" + } + [2]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(10) "SSL server" + } + [3]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(19) "Netscape SSL server" + } + [4]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(14) "S/MIME signing" + } + [5]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(17) "S/MIME encryption" + } + [6]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "CRL signing" + } + [7]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "Any Purpose" + } + [8]=> + array(3) { + [0]=> + bool(true) + [1]=> + bool(true) + [2]=> + string(11) "OCSP helper" + } + [9]=> + array(3) { + [0]=> + bool(false) + [1]=> + bool(true) + [2]=> + string(18) "Time Stamp signing" + } + } + ["extensions"]=> + array(3) { + ["subjectKeyIdentifier"]=> + string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" + ["authorityKeyIdentifier"]=> + string(202) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D +DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net +serial:AE:C5:56:CC:72:37:50:A2 +" + ["basicConstraints"]=> + string(7) "CA:TRUE" + } +} diff --git a/php/ext/openssl/tests/openssl_x509_read_basic.phpt b/php/ext/openssl/tests/openssl_x509_read_basic.phpt new file mode 100644 index 00000000..5f530534 --- /dev/null +++ b/php/ext/openssl/tests/openssl_x509_read_basic.phpt @@ -0,0 +1,37 @@ +--TEST-- +openssl_x509_read() tests +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (OpenSSL X.509) +resource(%d) of type (OpenSSL X.509) + +Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d +bool(false) +resource(%d) of type (OpenSSL X.509) + +Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d +bool(false) + +Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! in %s on line %d +bool(false) + diff --git a/php/ext/openssl/tests/p12_with_extra_certs.p12 b/php/ext/openssl/tests/p12_with_extra_certs.p12 new file mode 100644 index 00000000..b3ba2230 Binary files /dev/null and b/php/ext/openssl/tests/p12_with_extra_certs.p12 differ diff --git a/php/ext/openssl/tests/peer_verification.phpt b/php/ext/openssl/tests/peer_verification.phpt new file mode 100644 index 00000000..6aff34dd --- /dev/null +++ b/php/ext/openssl/tests/peer_verification.phpt @@ -0,0 +1,61 @@ +--TEST-- +Peer verification enabled for client streams +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + for ($i = 0; $i < 5; $i++) { + @stream_socket_accept($server, 1); + } +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $caFile = __DIR__ . '/bug54992-ca.pem'; + + phpt_wait(); + + // Expected to fail -- untrusted server cert and no CA File present + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags)); + + // Expected to fail -- untrusted server cert and no CA File present + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + ]]); + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + // Should succeed with peer verification disabled in context + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + // Should succeed with CA file specified in context + $clientCtx = stream_context_create(['ssl' => [ + 'cafile' => $caFile, + 'peer_name' => 'bug54992.local', + ]]); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +bool(false) +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/private.crt b/php/ext/openssl/tests/private.crt new file mode 100644 index 00000000..3a6b1049 --- /dev/null +++ b/php/ext/openssl/tests/private.crt @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR3syUaBjG7Q80 +sCu1j44+vmIY+0fSycke0478R9NWVQPrB1K3F7N7Q17pCEHB9a7J3+FmwYxm0E94 +5S4nLJZeoDDofKGgnYuvOt3L8NV0VJpXs6QLNleTGThIKpFr1PDih6o7fKPRdO09 +59c2HngY4lLK+lFql+PmZ8GtuVBdBYndUeAcZl+xqQ6KtFnrr1kGn2zParN0K3ex +Gty6s/aRpFsdQZjr+PV6KwIUGncQk99hm1HYZocYKw4MluTO5hAs+A54GS4Wbywv +Cbn/0OkeUo4Tef3/0wav/0KSmgowQGpoWQybVjL/NCAyiTuyK30DJzxKuLwpx3Sr +xuzemY7BAgMBAAECggEAbdYX5ZexV/LbYWzOA2CVRnsnJgHkrgnTS2HXVGtWzLkD +qu6TOKWb1mgE9RrQJ22oQ5j7A2dKTsi4vwHarL/mFrHpxtLrV/78CwJY8BIj9JUO +jdXDheaz4JVzYjl9EB1K0JPF4QozRjzWqO58MKOzoPpZ8EcfcxT5Pi2RLJVu3K9F +DR3cUNa9h66j84sDJARzvxMfgR6VysHVmgN1aR78Mye0dFVYeL7wCXFJmJXa2AYw +TQR5FcFRa0h8t40EOJdXcoWu63TUd7rvDgebHXJeKax8W2pGREHZfeEw5wWpFQn8 +j+znHSISe7eM9wmW6ombab7zcJsCwXDYgtY/6OqRAQKBgQD6EXKfXThfnrN/od/Y +jF8mfKdJ67HOc8WVPlB9vHDsduFyX914ahJHeCVQPkV1a2nx+bv3PviWbrKreEKl +b7aAAAkbxy/FakcxE9b0wC5JsSW9vByXQiRn0iDqDNl9iwzX/LLW6wE7SruCPp+z +mzCHArp6mvJmRFooR8e3IXiA0QKBgQDW2T9xXFBpumSOBRpn7Zc9SGiQ9qZTSKKb +boVSDd2cod8O1aow3gnQNid/cNnt54Yh5Z3KlYfFWkmrV+0/yQZ/SThZ1uHAaZVy +OnWKVELykpYLnKGlHoQpOYTCfdYan5xOfkw55em3TTeQq5tETYWMdhS/9VVxeLKZ +k2xr+CYq8QKBgQCzHpJK4nwByexq7KkpNIrnR3yQb1oiNjz9xO/k0HjWd+TOhypd +GSVUuhOIIcKg87qkj6x60kk/f7VNK0wZsiY4E05y7j8imhi6Z6qeD5ZYRKJzAG4+ +TitDjnjzDRcwXMxrXV9AoH52WPZsuays+ulMm8C1F42vgSBPH/NHEpt9MQKBgAIw +nLDvG/K376Zy7t34Uf5R6p7vpKpcpyumaL15XrTmAXwJOX7eBIOWybhG0jHWlktq +J72U4JlmXjHc55Iq3mIVwPlJc2uep+NOLTyHt1b5n4Xmxs8EDJzO9Ud2OOR0lAdI +ykYczdEMfHCBD0gW8jGIUpXSTlilvkxKcGR5VwpBAoGBANdAWL3lw+/P43x6Rxth +GJN8QzWe5vRFJYS5mkeaa/6jrFrsvk176WudopropFGtRc/44E1IDOZULJM80Xgb +JTeUFyb+ZjYLrHUp1yir+oZIm5DBZDZjYclanrPPHg9YwVxcHtunPeCFy3iC+W+F +MK80GEnRQIkB7uZVk+r0HusK +-----END PRIVATE KEY----- diff --git a/php/ext/openssl/tests/private_ec.key b/php/ext/openssl/tests/private_ec.key new file mode 100644 index 00000000..51cdcb72 --- /dev/null +++ b/php/ext/openssl/tests/private_ec.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEILPkqoeyM7XgwYkuSj3077lrsrfWJK5LqMolv+m2oOjZoAoGCCqGSM49 +AwEHoUQDQgAEPq4hbIWHvB51rdWr8ejrjWo4qVNWVugYFtPg/xLQw0mHkIPZ4DvK +sqOTOnMoezkbSmVVMuwz9flvnqHGmQvmug== +-----END EC PRIVATE KEY----- diff --git a/php/ext/openssl/tests/private_rsa_1024.key b/php/ext/openssl/tests/private_rsa_1024.key new file mode 100644 index 00000000..bce512e0 --- /dev/null +++ b/php/ext/openssl/tests/private_rsa_1024.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDLXp6PkCtbpV+P1gwFQWH6Ez0U83uEmS8IGnpeI8Fk8rY/vHOZ +zZZaxRCw+loyc342qCDIQheMOCNm5Fkevz06q757/oooiLR3yryYGKiKG1IZIipl +mtsC95oKrzUSKk60wuI1mbgpMUP5LKi/Tvxes5PmkUtXfimz2qgkeUcPpQIDAQAB +AoGBAMcP/dp+fsI9FFYBaVC3mASlUjOwxKWdH3kqGb8N9p4uKRAoEWtp3hNJM7ZX +x3P8sn0jgrsiXlRFGvn65/T9shp8hj+CdJKg2jKCs7S58v60TLfSvOQSIYsw9Qm9 +Bsx4hKfz+d52ptuJRbv8tDxsYP3D/KjQfpX1OysiP/WBfeg9AkEA+AGT0goqjWOM +YgFtZGrefIegF31XSCQTaLIml6/2JwF+oBKjJUQFar2Rwn6qUwrsGtSPMM0Iz8ry +9uvUbs8PPwJBANHsuTVWzLf8TJNGc+xIlhvzKFkF0nJIWx4ozhlMNDQMMF/3FRSo +zvHIgUnpG9Vwa2GtjTDnD8jHtzTauAZmjBsCQCGDVQ5VAVsJ0LaNqtKe/mGlkiSa +c2j0Nws2x7BHvuOWeB35ZsJqZrD93OyDYVDHcRBPGOpnSoGJ0zs6swImSNECQHSH +0BgH4wSPDYMDrP4RHSLOzCr+zF+cQthvFll8r83kpkXfRth9DMOy5fI9cLH/Adzr +FmF7Iov2MYEpmNYUvtkCQHfW0ntkVY9xS2/VTs57F5tUkfNG2hG74pJM6vSfTNWn +R/oI5m2sDtRWQ88LCYJMEmIZhN00Ys4xOSoTs+SUakY= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/private_rsa_2048.key b/php/ext/openssl/tests/private_rsa_2048.key new file mode 100644 index 00000000..d83e1b85 --- /dev/null +++ b/php/ext/openssl/tests/private_rsa_2048.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEArbUmVW1Y+rJzZRC3DYB0kdIgvk7MAday78ybGPPDhVlbAb4C +jWbaPs4nyUCTEt9KVG0H7pXHxDbWSsC2974zdvqlP0L2op1/M2SteTcGCBOdwGH2 +jORVAZL8/WbTOf9IpKAM77oN14scsyOlQBJqhh+xrLg8ksB2dOos54yDqo0Tq7R5 +tldV+alKZXWlJnqRCfFuxvqtfWI5nGTAedVZhvjQfLQQgujfXHoFWoGbXn2buzfw +KGJEeqWPbQOZF/FeOJPlgOBhhDb3BAFNVCtM3k71Rblj54pNd3yvq152xsgFd0o3 +s15fuSwZgerUjeEuw/wTK9k7vyp+MrIQHQmPdQIDAQABAoIBABPDKDlP12+uHbLB +1BGVK63rWg5MqKkM5A6kGIEeOoBRSilIlMHBkdLTYXNkBVeAT9SLEvvxzmhkVLzs +b+R/nxtKKMKpu6WEhZQzQAkqWWVR1gCtJH+i+ojTUDUEHcPbZ0hTbSVY5XpAOWOo +CoTfk37u3CfqTfnkK5XhjnpJYjFk60fLeTKKG90xb4WmPGCOxBZGeI9yk+gEgMVx +4qYBQEgcaJEBXebvM0q8BCDh/rlYxwQ/q0RJ6W1D84SOeyYv/9LesFZSbnUN16tA +/YezkhYVkVIrQFzh1al7NKvWEUZ3Yx3AEuggKtijlZyO9zOAOigSiFQjtqOl7S6e +jbVfLYECgYEA51E5TNvN6IW6p58wOXTmINnsW3sDYS1CyPh3TkSvWU2OqMXJxQSA +bASpXtqicAY32wkBOiazyY/+L7x1ReG/8z3tTm53AsYwkLKrgUfjdrOFhXWk8QI3 +0WS/1hS7qZ4Ycxi5B2X+rPPLnc2+mUvaEX6/B2Fjbqp4nIt+ZAE8SvcCgYEAwD47 +anMk8z68wdgzxY4J10sgCKfgHCe7J8ikpzloznX1HnbZTWf74FLlA/8ctfFJCVAy +4dG1s0D+JSpxxMSkk4hvi10Ha6t5U+BreD9VPAQRspGSKhn8JfwvLfKPH65uazBP +yvBtVIdagBf/msLfF33vkrQSjAEJM1njl6XMEfMCgYB1BddqNa0G3Figol0gRC6E +Iht78FC2YdJun5yj4QWgtSbd5Sn9XRinDPiufwc8izjIu9Z+F8ROzWT3u2zMzLdy +FDswuZvFsIQzP+CaB8dgbtO2v9yQ/OFGMqUGZfjGh6+w0qoQvx3HW5MAI20wWnpY +7Xkw/6jw/JcGA2AOsb1R4wKBgQCFfnF54Q1GkEk4/m4tAA4bX4KWICUCyCAxZyXX +LYl23PhiuDr7gnqockevt8ZzHWMPQY6juyFGoZoZqtinv7lc7YAvsWEGxmMQ+KUI +Mkp4y4aSjn2GGNc8dVs5t9blNBZe/oRaMwxohzkz+/Y1vJ54TK5BHCRI7is6anAd +jTchOwKBgQDP9yOdQTfUwJRUMERWmzXWU2oDXeEMdpbGPLGJ4/e/hu1CW7bdQRoc +jBSEpn3hOodmdwdmoXtbJReMCE8qS6yVHNn4orpJf+uOBr5fVnHwttFfN8HID9js +Lml8jAAQItMFw1CEPR75NVdFb7ksNKlxE9376tG63JhrTttRGwO3CA== +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/private_rsa_2048_pass_php.key b/php/ext/openssl/tests/private_rsa_2048_pass_php.key new file mode 100644 index 00000000..242b1868 --- /dev/null +++ b/php/ext/openssl/tests/private_rsa_2048_pass_php.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,D839E12F98A22F4FA90401E31A896A03 + +gVJ/972mKRrZ2+55rofbFXuLY03Umb7+m7OotGHkYa3dJpNuOLta+LDpSMRdgKcT +7s+vZ7CERJsWolbdCSphwWs74FV4fJheuzrnEthmVazmIcDwWu1FiiD5XEmRQMFH +AvwUKTN5PIyN67eCusbrV5/FJsVdxvRwLUM70UE+nhBW8rg6AhszDtSHhGG1KN9T +TwT2m8xYOgzzPPseQN/VcKNJ+LZcUVN/8+12duy1Ej/HoFaE7wp5GH0mueeShf0R +xFZ6mizZ3x+Ef4+PbTDnSXRheF9uvSdwmff4rUS4Szpk0aYpSrluJJjzI9Unjvqi +129ZQsNUfLebJlaauTYYNsHHh64hRXelqKz5mNmcF/OV+pbCjYljgDsyndmrZ5jB +xjfjp/1VGQAU26VnF0X9zv5q9Gz3/bkl3VFnS7gNyMCanyTuaXNNFNcbkY59Iq1l +rWjGGMeujWttFhYsChtCb6Clsq4aCiXJ9lqFNTU+eqVD9F5C4v5ATM6VHqjxwvj3 +RB4P98pQsGLkHUKgAZrYqxhLjN6O7FvZuuSRSZl+Q6suYcie+hR4p2TRopRTttc2 +d/gdJCBEbboJH3XOFlHz08mhxgVobi5ACzAoSpCVT4NIahG+Gt7h8Rk6+A9/uiwj +Jy6+MRiylhAOXAfOps7+FvBFi4nKByFXtWOHRL6DGpYWy20vCk0gsuICRpwL33A4 +e6YAJiuygQSWTExyGfeRk5VQRkZrWL1s3nTnA0MLqx1VdIbDeNPtIZ+dQHCN5vYt +pP7zFSuF6fse8mSobzA9x4hKXUKWQ/V985arHYzYpJXfIRMyZDqKjRW5xKGYR0eH +adhpbOCWx73+vVa8tABbvNIPjp/7KPaGPSp7uV9Afvvt5qjM/nho/VstyWscivM0 +c+oylG4cNBaJCVyb6nsiBYK2XE/Llfjsj/l2+SRfIZOwmvhL+CG7z7okPEiNp7EB +DcefH7/N/Fg4R4PzWskHfb6ZU+nnPKV9JJdBitw/EQFAN8qO7b6O1HRsXUJziBsH +cgQBDT0wOue49lDFratmWBx1K10paRuAl1DmO5WtstC/cthGYvKVGDWclLbIVRpv +/DyXZMsXdt9IaP31vHs+W0Yj/1Pcj3iKFX/oh0e7Kb2MQziquQcMzJM2n3BVa2PQ +dZ3FGKSoDtdT3RhEWGAY5zh7nwPUDqR2frCTGdRAASJbHmC/dn3Fs/m7kQHCUTw8 +EpDCCFZhp23DODk96Q0vtgtPU16qONMzVlzSH8REjS23GrbZ4wn/SW8Qm5QZiScH +WbJ3Aj5iemcFnL5aDN81BNX9GtUvJFK2jvmmPcv1x5+x51RweMQYErgahI9YVFtM +0cEN2cm27hZjktHxduJefc+WVu6vCyzSA0q/CbT58eIWBPyvyIM8AB65h4TFxX9N +4g0/0Kh8gqe3EVg1x62LEAC6AaRZEm/GBeux41DlNDYbCik6VdLRHVozmf7PYm+X +6miR4EfGE+kM7/V+shMQZni/Q64gzIn+/vpMiNV5JQsr1E2tqUp2/P6N0puUwWv2 +ORVWWk6gy8wnJ//LsDNEhSKfCrffuv2u2oVQWMcBwyqbR6ru/V3i9+9ngWd2D4E0 +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/private_rsa_4096.key b/php/ext/openssl/tests/private_rsa_4096.key new file mode 100644 index 00000000..8338c86c --- /dev/null +++ b/php/ext/openssl/tests/private_rsa_4096.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAtlmPieG4yL/HQ1j98U+VqlAzO55+aSHKXOV9q5+uTevtzXVV +s+rOPUAlPkUi7kcp3Yrum+Y0rNCnTNpSmpFB2f/Y1rHb6Rxn8SXzWSq8BM0BhbCm +yE+PY3DyIBizX6isb13vJyvU7f8Ayv4xAQ/ve8ytFAnBXUdIhtQNygraxvr8aoZw +81cBRQ8NhBkk/qDZWVkOiePC9voZ05sENhL4aUZw3Xew2JtZyw+lRxheczkYYc71 +OQuOKoU06j3ZpLhdhtdjpOVC6csIk9qyq8ki8t9m66a2BdiPaz1cWGZGqQg4SDrJ +0XKG6/wdSWgdUKMp0wB2Kwph2SWwLm7BQEpdtMtXnNGB2dT+lffjtqRvyT4HKO03 +R9b7ZxUVA34Tzi+kX04g3e4qI4eD0bsHYwioUlkKf/q7E1+WjwaQ2LLbOUnWeKqb +wGBsZYMWeWGTc/FO4oyDJBG9gnsqmSHasAsxsW6ojsGnz9IXywpwInlz+R4pB+ua +dXHiUZEuT8lCdBUWKAtCIb/F9cNEJg/Vq0iVoWFaOYd5D4PHXV5aXjEx18ez7GvN +98XPYNXQmVBmsIlOHQpytz0RdrlstksxBqWhaBUT3ZJU6czchNgYeFsEuYKkUNK+ +fwQLhA9aeT6RBdet2efhyaf4y3vQFb5kxx4JcljXjIYVR3yB9iZnD0WGQxkCAwEA +AQKCAgBHrhkQmFxs/YY04SyhySkKFBCvpPQIG7JSphuqdVCtbMrD8xXHbcu4pBh/ +y+mZRPweDFkTi4C1VigNu9ywydza9wmkC7JohjQNxV9Nc9EJChVJGlHVeADjlCh5 +mXwZZFK0THaQLVi8XXtQUG+u/TaksaZvtA4Avt6xsXXiMDYj9dF3hnWsEk17ehlU +DhZOyafmyW0/ovqm31V7qvoSz446w+fmBwDLhPXdLr9HnTqzjIQbHqGi1PoDmO1e +DwYZDCgns0+GKGEPSjKK/HMzuBM26b6pb5Up4yEthKdiUIICPCrzqbhfzudeqHJS +wsyTQDBWs13AOYqRM5F4Dy2EOjdvCgt2zElO0c3r/pOTplk3/v7VrsqiNN33xGfc +4zGw3d0xLjQRhA9vhG5Kdtqqs1GqZDf3mNmPxv8gHJDdB6Twkk9iNlUnV5neew6R +0KKklZvMApE+KMVrRKmez0+ab/ktpoAe9Xox9ChBfLaZQgJlDwNDktjRu8RT1da8 +L6SMy5+mP+aSKxWxgNGoM0BQiv3DBriyTuyhcu+2SIr4c0LrWqedZRI1eRREZjhG +VLBpftvQH7AMTZuIHXYjtF8XcZneaa2/fI7SNH6RpPc7WJmLCF3ufjv6HVp3qA8B +ahRCgsr4sBZDJqwMkbNJQfuF/zNOAGmO5VRBodb/P9UQeEVeAQKCAQEA6TkahKZq +374hUnElMH3mmYPVxOKfqx4EMrS+MP8cjXXmiw7bWjQlufcmbMhxHaXkGiU9+/TB +VdFPtLZvo7Aa+m2sHCySJ1pG2T4kkmV9cNVExKPllraH3/QvDK3o34aA2DxgOXAT +33wxlxvmmaMmrjjP6BZduvS/W/vwL6+aA1erZbsBuA1CoeyiyE95zdcD43+TlZWi +fwCqCZ27wrKHCPFcEN/ecpjKQTQQdogDNWdJJzaTH7y3iWNOsLdTNeLRYrvu94dS +J9n7cCoLCEFzdylaXx/jGCNrnaNtqDj46JHW6XSQ6e3D0UpV2hx5V2+0q1gbEhWe +wtBrhGsHj/jj+QKCAQEAyCiOlcE6a1tjIdMihAO1hqdUiFcIKzoiDQKNBEaY9ELz +oWkuZj2fUnhjeAKhkQ4ZheH6+fk2Tt0+kU1Jl+Iym/ciE/m/N8RUyqq2FOnmwktz +yGqD9fQeLix2b2txp+0dyi1niQ+S8ZKAJBbxKTb3CBefowrkz5JK7+jWqaUDNQ5h +8KoGCcAB8kSkXGgqVOapXyGb31YdyM3X1mJGv95jO4A+OmFI2faPAOtZrg9EicSI +7U84bfFMhfhrpxZuU7Bbyz6Kg9hleAv0q/3tBFSJvMTOiuM7OFtlUAByL+pWwZ9Y +haQ4ojojsPaQ6pMmf0JNXwnp8Rhz2+QNDyFzRm/gIQKCAQEA3dmA/S/kuAL/ZZHV +g4QvyFYdEdVVdwvtiGJgDPGPsoy1ig/O3sZ+IKEWPyKIX2B/U9ObW8Hd6wlZXZix +J68Maq3Kq15GhQKeJGa1mUDLi3qDmN4jNjNZmtKHsvL3czFZ/Nep3NldPhjAf3J9 +8CW/VLkcJDSqYn4QTaqhNms/APDzTKkQIIkUmj0kN5FKV2CyBUVFGWSml1MFbHJL +ug/i3cHiBvc9fhsTQeUJyAbnrnQapR+H4ge9OwZpQzaQA9FHxjjpPzLNFrWHNZH4 +vpisAm0m1xfZCQwggWqFlCDlvS2FlrtYYf3XaI3ijsDJOEA9R0RfM9u3Eq/5ppO9 +NNnX2QKCAQAJ63ilk14B1BWlp4EeadClS8W0vBt7iPYHDwlOHPGXqXnJlhzmlEdB +HxZO7FJ1je1V5U069k7quaxQJzRugpdfg2/87XO8n85T/QHpJ254UqT6Wc0Qc3jL +cQitnPWVDPtc+cMX193AezI+l6R8Fm1HyWPwAKo2X1m3aiK5ZaQzDPNtqf+CnDF8 +gEplCgSPEJ90R4YiG3J+cTUxOs2m1K62VDTBT/D8XGvZ79ASAE+1RDhFCpgRWtQg +D5/GOCZfn23tNLxIrIDa4jzOCVelz0rEQDy8RWa59E2hGWSPW13RWsRYWzszTw5V +xuKHvaM6y15qR2OAv2V+kF7VUSMVapYBAoIBAEyZDn9H+IMQBkRyZgxPLsE5cgd3 +DeR2Txn2RxQBpop9+lgniuq/NVHiUIRscynsJ01/bFifmFNkgD2cRORy7SU+wsNr +zsWlLPO1e/axdfMsT0OIBOQ84jZ6FDGi5JnqnC8zVVPU7g2iNoDEtA7ltlXknUUX +uigFoR1CXoNz8KdW+18MtYDjBLR1crfGa+zqPOpxfjoXBhehtCKG9ZxtrBSWq6mz +lR9N5Tv9USiJW1r6+85aLsC5E9ARjAxMLhTKvD+NXbQDwZJgfM/vs1eZ6eIYMYE9 +lB7kMFfHKqsagNXdyhRFzfEfx+FkKTHaqC6V5rOp6q0t8AO41ZvZO/tKdi8= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/public.crt b/php/ext/openssl/tests/public.crt new file mode 100644 index 00000000..62dd1e13 --- /dev/null +++ b/php/ext/openssl/tests/public.crt @@ -0,0 +1,23 @@ +Bag Attributes + localKeyID: E1 BC BF 63 1E 2A A4 F6 4C 71 6B E7 CE E2 6D 4A 95 CD 26 5B +subject=/C=PL/ST=Some-State/O=Internet Widgits Pty Ltd +issuer=/C=PL/ST=Some-State/O=Internet Widgits Pty Ltd +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQCS/had1ITjDjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJQ +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE1MDYxMDEyMTI0N1oXDTE2MDYwOTEyMTI0N1owRTELMAkG +A1UEBhMCUEwxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANHezJRoGMbtDzSwK7WPjj6+Yhj7R9LJyR7TjvxH01ZVA+sHUrcXs3tDXukIQcH1 +rsnf4WbBjGbQT3jlLicsll6gMOh8oaCdi6863cvw1XRUmlezpAs2V5MZOEgqkWvU +8OKHqjt8o9F07T3n1zYeeBjiUsr6UWqX4+Znwa25UF0Fid1R4BxmX7GpDoq0Weuv +WQafbM9qs3Qrd7Ea3Lqz9pGkWx1BmOv49XorAhQadxCT32GbUdhmhxgrDgyW5M7m +ECz4DngZLhZvLC8Juf/Q6R5SjhN5/f/TBq//QpKaCjBAamhZDJtWMv80IDKJO7Ir +fQMnPEq4vCnHdKvG7N6ZjsECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAHGAiEN0o +tOV2tbK0Qm/mWlyuRKtxqnP3y/2Q5SFMmRpkOS54hFf9YBNgT7nWK3Z5fPKor17t +rGthXPSZU8hxY5iHFhELurp23qGmJftdcYL2mF7IyoGOiZ1Q6Vt9LnRTDtgrHh/f +ZziI+gaPpmAfEAh48xQrlviHqaR9F63d0UN1jz9cF1kIj1H21PAGC0tmAIxxb4ee +hjipL+JLH0iRoBQE83cF2BOQCfRzRekotnDYon6v7mTjYu7kwl8paRIEMNrBckby +IL3CJOZFesaFO7suK7oP7r6BIATpVcg2m0V25mVMVFRm4F/JOvSkB381Pte/Ccuv +dxPWHER13ptIVg== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/public.key b/php/ext/openssl/tests/public.key new file mode 100644 index 00000000..92021c10 --- /dev/null +++ b/php/ext/openssl/tests/public.key @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLXp6PkCtbpV+P1gwFQWH6Ez0U +83uEmS8IGnpeI8Fk8rY/vHOZzZZaxRCw+loyc342qCDIQheMOCNm5Fkevz06q757 +/oooiLR3yryYGKiKG1IZIiplmtsC95oKrzUSKk60wuI1mbgpMUP5LKi/Tvxes5Pm +kUtXfimz2qgkeUcPpQIDAQAB +-----END PUBLIC KEY----- diff --git a/php/ext/openssl/tests/public_ec.key b/php/ext/openssl/tests/public_ec.key new file mode 100644 index 00000000..a93b2c8a --- /dev/null +++ b/php/ext/openssl/tests/public_ec.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPq4hbIWHvB51rdWr8ejrjWo4qVNW +VugYFtPg/xLQw0mHkIPZ4DvKsqOTOnMoezkbSmVVMuwz9flvnqHGmQvmug== +-----END PUBLIC KEY----- diff --git a/php/ext/openssl/tests/san-ca.pem b/php/ext/openssl/tests/san-ca.pem new file mode 100644 index 00000000..88682ba2 --- /dev/null +++ b/php/ext/openssl/tests/san-ca.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICYTCCAcqgAwIBAgIJAIaqxtY5dwjtMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UEBxMLTWlubmVhcG9saXMxITAfBgNV +BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDAeFw0xMzA5MjQwODA1NTFaFw0y +MTEyMTEwODA1NTFaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UE +BxMLTWlubmVhcG9saXMxITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRl +ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsFGqfbU/8D+KjroQl4XMyt9m +dcSP7iZtqphOu9nVZxYAAqfaqj8FnC/pwYV3TU6ZHndLTQAllwYT3sQBQPPGmZQ9 +clSIMEL003t3pi4ZVXkttG6Vvr+Z9PBcHhlKLQ7WMHnn4qctllWXTSoyTQpkETF3 +Fc3mrG5G37BhoUno7NECAwEAAaM9MDswOQYDVR0RBDIwMIILZXhhbXBsZS5vcmeC +D3d3dy5leGFtcGxlLm9yZ4IQdGVzdC5leGFtcGxlLm9yZzANBgkqhkiG9w0BAQUF +AAOBgQBf/FZhzheIcQJ+dyTk8xQ/nJLvpmBhbd1LNtfwk/MsC9UHsz4QXs9sBw1k +rH0FjoqgM6avj7zKHJFTj6q7Rd+OX5V4HynYPhX67sWbN3KWEHffL98nGGd/bo3X +pSjNk5vnyKYiwdUUe11Ac9csh0HcSBbhOYjy0T/i9AlQcKbuCg== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/san-cert.pem b/php/ext/openssl/tests/san-cert.pem new file mode 100644 index 00000000..923d490e --- /dev/null +++ b/php/ext/openssl/tests/san-cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIICYTCCAcqgAwIBAgIJAIaqxtY5dwjtMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UEBxMLTWlubmVhcG9saXMxITAfBgNV +BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDAeFw0xMzA5MjQwODA1NTFaFw0y +MTEyMTEwODA1NTFaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UE +BxMLTWlubmVhcG9saXMxITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRl +ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsFGqfbU/8D+KjroQl4XMyt9m +dcSP7iZtqphOu9nVZxYAAqfaqj8FnC/pwYV3TU6ZHndLTQAllwYT3sQBQPPGmZQ9 +clSIMEL003t3pi4ZVXkttG6Vvr+Z9PBcHhlKLQ7WMHnn4qctllWXTSoyTQpkETF3 +Fc3mrG5G37BhoUno7NECAwEAAaM9MDswOQYDVR0RBDIwMIILZXhhbXBsZS5vcmeC +D3d3dy5leGFtcGxlLm9yZ4IQdGVzdC5leGFtcGxlLm9yZzANBgkqhkiG9w0BAQUF +AAOBgQBf/FZhzheIcQJ+dyTk8xQ/nJLvpmBhbd1LNtfwk/MsC9UHsz4QXs9sBw1k +rH0FjoqgM6avj7zKHJFTj6q7Rd+OX5V4HynYPhX67sWbN3KWEHffL98nGGd/bo3X +pSjNk5vnyKYiwdUUe11Ac9csh0HcSBbhOYjy0T/i9AlQcKbuCg== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALBRqn21P/A/io66 +EJeFzMrfZnXEj+4mbaqYTrvZ1WcWAAKn2qo/BZwv6cGFd01OmR53S00AJZcGE97E +AUDzxpmUPXJUiDBC9NN7d6YuGVV5LbRulb6/mfTwXB4ZSi0O1jB55+KnLZZVl00q +Mk0KZBExdxXN5qxuRt+wYaFJ6OzRAgMBAAECgYB11e5iWvqjPmQEZRdnnJU0VD8u +n7ItT+Nk6qtb4gY8Abj6DWIW+01th5vqqJ8FvGyartFVYa69kuM+srG/zevAZWeu +fGZtwiwZR4DRSyRcPp4rnNiksK3dkAZA6UewmRDPv8uyHJlXc5i+Ft1ILJ5Q5jgn +UkC4z3EJP5Se9KZywQJBAOO4lRq42wLsYr2SDrQDSs4leie3FKc2bgvjF7Djosh1 +ZYbf55F5b9w1zgnccmni2HkqOnyFu4SKarmXyCsYxrkCQQDGNvnUh7/zZswrdWZ/ +PMp9zVDTh/5Oc2B4ByNLw1ERDwYhjchKgPRlQvn4cp3Pwf3UYPQ/8XGXzzEJey3A +r0rZAkBf/tDEOgcBPXsGZQrTscuYCU5sbY5ESvqrAilbhSp7DJom+D5bIfEYyIm5 +uHd20Yzlzvpmwc1huyPwZt6X5FLpAkATDReoGMAXSesXxjnqwtIHk2NQYYLM0YQV +JUJ8NrKk/Bevw+vbVVeoH+7ctU97t36JGiR/vNoZKD3jVmaIXZDJAkEA4wJbwzIo +L32mu9VmZa7wjmfkraQEmXTPaA5D9lNC0AwRTgkj+x2Qe1vawNblNK9PPLBDdplQ +L//53ADq/wv5rA== +-----END PRIVATE KEY----- diff --git a/php/ext/openssl/tests/san_peer_matching.phpt b/php/ext/openssl/tests/san_peer_matching.phpt new file mode 100644 index 00000000..0e1f30cb --- /dev/null +++ b/php/ext/openssl/tests/san_peer_matching.phpt @@ -0,0 +1,50 @@ +--TEST-- +Peer verification matches SAN names +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/san-cert.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'cafile' => __DIR__ . '/san-ca.pem', + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'peer_name', 'example.org'); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'peer_name', 'moar.example.org'); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) + +Warning: stream_socket_client(): Unable to locate peer certificate CN in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/session_meta_capture.phpt b/php/ext/openssl/tests/session_meta_capture.phpt new file mode 100644 index 00000000..a09d7e87 --- /dev/null +++ b/php/ext/openssl/tests/session_meta_capture.phpt @@ -0,0 +1,59 @@ +--TEST-- +Capture SSL session meta array in stream context +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + 'capture_session_meta' => true, + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); + @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; + var_dump($meta['protocol']); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT); + @stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; + var_dump($meta['protocol']); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); + @stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); + $meta = stream_context_get_options($clientCtx)['ssl']['session_meta']; + var_dump($meta['protocol']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(5) "TLSv1" +string(7) "TLSv1.1" +string(7) "TLSv1.2" diff --git a/php/ext/openssl/tests/signed.eml b/php/ext/openssl/tests/signed.eml new file mode 100644 index 00000000..557f1750 --- /dev/null +++ b/php/ext/openssl/tests/signed.eml @@ -0,0 +1,68 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----68AEC934FD4DA77FB8B713FA8054A638" + +This is an S/MIME signed message + +------68AEC934FD4DA77FB8B713FA8054A638 +-----BEGIN CERTIFICATE----- +MIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD +VQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBv +cnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJ +KoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4 +MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRl +IGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1 +ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQw +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTz +e4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+ +iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aR +S1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLo +Ymhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGE +MIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTAT +BgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5n +ZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zS +UW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LW +PVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn +4vh8xF/9+eVEj+hM+0OflA== +-----END CERTIFICATE----- + +------68AEC934FD4DA77FB8B713FA8054A638 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIFzQYJKoZIhvcNAQcCoIIFvjCCBboCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggNwMIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEB +BQUAMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwx +FTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4g +QW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYz +MDEwMjg0M1oXDTA4MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQI +ExFSaW8gR3JhbmRlIGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYD +VQQDExVIZW5yaXF1ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5n +ZWxvQHBocC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ul +X4/WDAVBYfoTPRTze4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4 +I2bkWR6/PTqrvnv+iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkx +Q/ksqL9O/F6zk+aRS1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+ +QHK9XDWF7CkpgRLoYmhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLo +Ymhqtz99oYGHpIGEMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5k +ZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlx +dWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0 +ggkArsVWzHI3UKIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUn +StC0TBqngr3Kx+zSUW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQ +S3X2+Y0VvIpW72LWPVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r +8s+KhNAqI4PbClvn4vh8xF/9+eVEj+hM+0OflDGCAiEwggIdAgEBMIGPMIGBMQsw +CQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcT +DFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8w +HQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0AgkArsVWzHI3UKIwDQYJYIZI +AWUDBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B +CQUxDxcNMTcwNTIyMTAxMDU1WjAvBgkqhkiG9w0BCQQxIgQg37MSoxw91phVhwUO +MeurwtXAXK1ADEeYYl/7Bfmz4CsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQME +ASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG +9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgw +DQYJKoZIhvcNAQEBBQAEgYAw4XcsQ4BIhEuRNspG8RqPE9ODCrTWwXPSQ4B9fzks +KUAsqcefO8AfifY+uuq3/k6Prhl23U5ILth/0fUAIGFLTcIZziaGTwbpgcmRSmNi +jBxatHyKVaGJNGqij5KRk8vhEpy5mwOzmkUzYa0r4teXjyfnKhI/h1vUrO3kKybC +5Q== + +------68AEC934FD4DA77FB8B713FA8054A638-- + diff --git a/php/ext/openssl/tests/sni_server.phpt b/php/ext/openssl/tests/sni_server.phpt new file mode 100644 index 00000000..d55c5d69 --- /dev/null +++ b/php/ext/openssl/tests/sni_server.phpt @@ -0,0 +1,60 @@ +--TEST-- +sni_server +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/domain1.pem', + 'SNI_server_certs' => [ + "cs.php.net" => __DIR__ . "/sni_server_cs.pem", + "uk.php.net" => __DIR__ . "/sni_server_uk.pem", + "us.php.net" => __DIR__ . "/sni_server_us.pem" + ] + ]]); + + $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctxArr = [ + 'cafile' => __DIR__ . '/sni_server_ca.pem', + 'capture_peer_cert' => true + ]; + + phpt_wait(); + + $ctxArr['peer_name'] = 'cs.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); + + $ctxArr['peer_name'] = 'uk.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); + + $ctxArr['peer_name'] = 'us.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(%d) "cs.php.net" +string(%d) "uk.php.net" +string(%d) "us.php.net" diff --git a/php/ext/openssl/tests/sni_server_ca.pem b/php/ext/openssl/tests/sni_server_ca.pem new file mode 100644 index 00000000..b2522884 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_ca.pem @@ -0,0 +1,63 @@ +-----BEGIN CERTIFICATE----- +MIIFejCCA2KgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAMMB3Bo +cC5uZXQwHhcNMTcxMTIyMTQyODIzWhcNMjcxMTIwMTQyODIzWjBVMQswCQYDVQQG +EwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwHUEhQLm5ldDEQMA4GA1UE +CwwHb3BlbnNzbDEQMA4GA1UEAwwHcGhwLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMeENPus84HfIaypUVybbn5ZZyu1gXSYZAnDYYHhOlHu5kFh +26ohnHnoheapXVRbUtDZgUW5BztA+vDhKkM5G3U4p+YsqcSA/IkF2JQBkJH1jrxs +XMDtXIA4/MzYAVtyySqoMsrbkSCDzvI8imsbZI9O1x02VgaqoaQ9JZvglt1nhTIY +YpTbTKGCzMmrnFGHITeBsVose1ACFIAtqKqvUaA6TxcCtVcrENY3T3N/vEmoHHBg +O7j9+UvYN/WRPNcv0aIOlro83O9xQuJdRCygPmcv/jkqWRKm2Pu0lEkvbMCvOJr/ +Fz/kQg/6EVmIMsR/dgOMIjWjmpeTx24UJaNHUdNCeUbxIyTIyl9ISLWLM0Ipoq3L +95ygH6FSESAOpc8rVE2A5YZCtKlwvogMx3C/tMH1gWwMlfxn0CopP4Jx6lngw3yn +IpP0hnuCauQikBkyhsGu4J0Lbx5BsyDWQLwjiq4s8EcEy0vTdAvhDMRUGvpnjWaa +zBDVVrzHaRFvp6ueh35xf+dYieGL5UTICyrrQX9wwSafHV90a87y6XU+RwA25Dmc +V/kTn8/xkFv/4CbZp+0yArKpwXjqBMsQFbkFjT+Ky9MN+nedoFUMl7slgjpBs6RI +T08Hoa7/kMZGtLCiGcRXlwiIhB00gDz2avUvFTxwik9ssjDqBJGzNbBvZGb/AgMB +AAGjZjBkMB0GA1UdDgQWBBTjyuOBGnHnb+x20diIHG3sPuJFGjAfBgNVHSMEGDAW +gBQ0s99BNsV4Dszph6PArogA8HP4TDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAFrQMmCoSe8uJbJLqPGMPW4ZE +0U81WWboc9FrSfezBYkTKuCjMTjQFv8oLp4pnuWZw22mHrOiz9izjNnXcR/rdVbG +Cip/JSHlTzHd3gnxSSd2diXvVrSb4zuLyN6WIficlsj3QdIP4Cdfv1pdHBTsRPbW +vuHpwYqqjxPBjqvoVZyZRyRM1pqpxLCvxOt4S3z4uZXyIH2UI7yWxI6MvdHBZg5m +TwiVi1gEQuRnYRy4sK9qJlBo5jERvzDr46W1e9Yz5sNMPfwWb64Hkkys3GqJt5am +OKxvgF3lvIK90vBjenGDfYEENP+0qdmdpHQkxGM2cl9iPqW8iyRGBVjdbzTIeRgB +u+CEbffSKWCpbm1Zcszv3FHMlsU4Px2pUTdLwEMgBQUPW/ngBMdRgVZE01GI7D1k +AM3hO347eehQTWoyuHgsnB2uaANEeR/XFBGDFmbs5ggAzxxRsH1FxoHXrv3iDIPW +9lKnSow+OZGcPKgaY5Nsregt4jO+pQqhzxlMa2QMfrMoGkEvrKNcDqeEI6KQa1SI +Zbq7sjf2w+VL0oQcse+gtg4q771dKy9V/XcfnPbiBAXfQqGj/v0LmZRn3ZRrkgzl +CaZocqVRJZbqu7/iu/p9pDRMR03vhBWPn7iM8VqzkhKjAlD0rolnQqvOAXyPpd/O +qYuYP+6Ymt/rUWXGVh0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIJAJcrLHeFQrGEMA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNV +BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMRAwDgYDVQQKDAdQSFAubmV0MRAwDgYD +VQQDDAdwaHAubmV0MB4XDTE3MTExNTE5MTEwMVoXDTM4MDUyOTE5MTEwMVowQzEL +MAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQx +EDAOBgNVBAMMB3BocC5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQC4bIXbh+e+OCbLum2FYB8i6ZnOShp1teWNEE/8A4ot20wkPxLeXFSU1Egn+3BG +fxHKrWxV/FOiL7bims/SfwptFkgNZkwE52HVk49zgQevG38smsnIGuBMXMKebLPT +wlsIWRqCmZqEmh1wNcC9+qwoHoYjvJvMYfFvofiSc7qkTFsjoBVe+ho90vjYMznr +Bs9DlD88iXO0kKN0Bsu2igz68JWkUsoNeD6UKSir16SmQZxdFPCM0O0gxmOyz4NZ +w8pJ5XGDJyS82fVp13tYCOBFhK0QBvvzaz/gN6De5arefm6cer9TX0HE+VvGhx4T +2lqydFLfAVKTTNoZHOQk2mFVUm7dlMzLvsgNKdEZH6wAa12eBImCea+CyJNkbGLC +nrN6a93iGqTft75sbDyvzRk/BdnxadkAPlOxgK1qGrOgeS0+7chPMh24MRoKj5bU +lYGdcp7Y9qIW1hZXFfgPJO0yMOug/7J14jybp+YhymBIBTZYi1zbGqGNXdLPyp77 +9KTfyJE9KkbGegBvwqJmZTW8QoUDllopDjr1zaIqHWJqfAK7vGivu0iLVJHBRbRs +w9c48RCjfIh7AkvFKsdIDt9SMdZOdm9D8SXosYPM1zMFQsFFRPh/nKyl9QnhWbwd +Vs1tIFDrb10Z2sn0pF/V0F0gubR5rvYs+3h/dLciLVFobQIDAQABo2MwYTAdBgNV +HQ4EFgQUNLPfQTbFeA7M6YejwK6IAPBz+EwwHwYDVR0jBBgwFoAUNLPfQTbFeA7M +6YejwK6IAPBz+EwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQELBQADggIBAIkctDRCNcNVs2qP/O3zZsVZ1cqlqYNjcHIVHqNZRvVb +bPtInZ/i/6BbwA5QM/giKpl2aMwetUnezjHVD+7/m24Mfs1FWyPD3joCMIANj7hR +MNbmX1LQBMt/bD3E5trq9S9rZ++/ny4gn/z2jH3x+lzDMBDiam/wXbvSmyIUPUX6 +V8FFpkTBNERpurUvX1NEFLuiilWKrI7/u1qS11PGBcX3pNQNfhKNMtuFz74hAE7C +RE8756CGu2bZzydYCarUXSNTXqNm5ly2J0UN6Al4myFwj/6XnLnDhXDAI8CaqDMD +MwmxUzJvzuphNS085ZIntrSgPJESGozevEsf9bGD8GyoBQN/cSqOJCFfnJqxtKHb +wNa2F78SXYsiWkRb5EzoyCeon+0tygG6gLBouVY8ouCerExkH9qzRLLzFInxmCm2 +ill7c8Xmml4H2BxJE33dz/Qh7PM3eF2A2VriioLDj4+HOiWq/1BjdW6/Xiwx5iP2 +nC6Cex+lBt6HkP9WIiJbGxVeamF5jxNWWvLoUkrjFhpukjb5BPR9zFt7mAty9J/T +iQt26yylP4ucmL9KB6lv4ISW4Ri8mhMcYh6nF3tIYWZMCSQKqkyvymhKdLMZa20A +IME2oxnfZcmsfMpM6BYsN4XDfGBeYctqqt2AFRNLkI4wFkFFdPTMcTi1q0iRH2Xk +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_cs.pem b/php/ext/openssl/tests/sni_server_cs.pem new file mode 100644 index 00000000..9f5a201b --- /dev/null +++ b/php/ext/openssl/tests/sni_server_cs.pem @@ -0,0 +1,57 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvy5NhzktzEdsHTbGB6vqYANms5rn1zXFmTJrGlWCwoIsNmTf +ahvZkrC1cCXTZ7fbPB8XQbpAtz2ZSU7OcwBW9B8okYUPo9zi/ptwcrgsQsN0hrcD +8MBRUccevwime5fLvg8E9RJ/68y9y3BnRcVWYO2sAK9juTfidNjETU3Bb05oXv8D +SD/6onXQu4uXDgsQ3cRXeld9UB0xazmQXyyiIqXc/cpTAnaEVYzn28aj7NlUbzNq +511UXMXY44x9EcXWpPVZ7heNcJNzY5DCNzmtXKrt9yiMpWQcPXEzsESVxAMqib9u +TFOlvVX17LIPxBG656PjTD9J1h6kBbMCUxzs7wIDAQABAoIBAQC85lBeY0X4ST3v +I7bJz7kWQ2YP4uhfAdeLhoDDFWjNLffniwYhfwEc6xNri0R2f/jUT9gX7qORKwEx +qPdeNCC2t67LElGg1FlJv2Z9Q7MgCKYzkdQH5s6y4e9kTHTLO/JpiceZKz1QTQ3f +XOH9032E6nIAf0wmr6xHTgOwajrN8VI5BuPEMVmEwIw3AtYeqVuPCNKyGR4HUVkC +2bAydnGngbRJRnNzmKcWJancxpHDGBSFqPyuXMFC7Jgo3ZmyCbGp99vuXVk/sW9x +5aj94M9nRE0guk05ivH2/JZao2uLYkIgjFWlhNxKdWgWRk8DEuN4djC8mKS9YH1q +crYRToMhAoGBAOspUTtKP54mpZmyhxuDqj02JaJRzNTskPHsiF1UhtXuw7uT+ryV +ekUFLNXoFmn9mbx1WVaUvGH4qjilvQOxz7u++lz0ApqJEfyM3jc/cC40Y5zcuGSu +Etbg+SyDoytlgMCIydJyrS7NNALSo5p5oG6XY2f8yd/DCAmo8LzypaHRAoGBANAf +R1SlBMc/bOsi6GrJxcBVSCFMiKYiO5woL5aUKa9yM+UQuQ/6xbQ7Q+sOlt0FH3xo +AJ2L60qTdjyXVtjOdtXs5ZC4l+C6AfnCx6yLr+fNc4SOYXEfqS4LZylgwKd9KyVB +asspIW9Idbgebmi6vPyt9LDkIp0h1VuFGjkvQJK/AoGBAI4pbS0dprXyARyYW6sb +fpgAmuG099IkrT9DUfCx/81myTclr2fAKal+BmvOIXaz0/OlMXvw8K19iVIzh7+r +B70lJ+93p/dKM/BsLI5TsHqOO0YB/QsIXOVAHgJ2FfdPJnW+e9vYba+kZ/Po6PSi +4ITaykJ8BIJcQgis89QWEGFxAoGBAJhQO+jzuDKF9ZWEf6ofrw0anOZZ16wWY5/e +PS2rk3JmVxpuibHrKqPDt+ogTELHDAsFJmYmz3VNxHuFmrajK49Wh4/JuMVr/CQo +6+8YcA1qa/94IFIlBLDBAafjujsZvOjQHnM+z8xcsGKmStF00Pjv6qNG4xoyd646 +FD4DmfOLAoGAWXehpopZKXE9gRAni881ucK6WqxPPBoofbozi09D0MmfarIVaSkv +jNVVHBfLWd7IEXTjiipPBeUqq6Jc3pscN1Vp4rrl8jTmVTdazEv0LuzpdUFqmNo2 +M+xw17uz9D9Q32/aW1Lar0PdIaL/wGEDEyzEBFwrGppcENLilPz8gzU= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjEyWhcNMjYwNDAy +MTgzNjEyWjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKY3MucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAL8uTYc5LcxHbB02xger6mADZrOa59c1xZkyaxpVgsKC +LDZk32ob2ZKwtXAl02e32zwfF0G6QLc9mUlOznMAVvQfKJGFD6Pc4v6bcHK4LELD +dIa3A/DAUVHHHr8IpnuXy74PBPUSf+vMvctwZ0XFVmDtrACvY7k34nTYxE1NwW9O +aF7/A0g/+qJ10LuLlw4LEN3EV3pXfVAdMWs5kF8soiKl3P3KUwJ2hFWM59vGo+zZ +VG8zauddVFzF2OOMfRHF1qT1We4XjXCTc2OQwjc5rVyq7fcojKVkHD1xM7BElcQD +Kom/bkxTpb1V9eyyD8QRuuej40w/SdYepAWzAlMc7O8CAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFHPfd8dK +Lz1R0Ck4WV1B9AWXd5DSMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQB6WSIHEyDXLZxH +hZjqSNQOA7Wc9Z2FCAiD29xYkGTL8WuPVGGP1mu4B92ytj+PMWwqSReDa7eTGLE7 +O7ozw9l+c+gNmHFNikSsGjlV2E8CToQOFMny+jAQYMSXf8UbTp9xDfgG02t/71hv +SLWqdeHMLcR0xi0nBQH0vDOkwUbuWYqFa3jejHieGhykHM6CkIk6lqnyOEO+ooIF +ZsLprrg1ss/mXCPI6niP0hze55ERKdxI7Rk8sZ4pVkf2SUWqZrUS0aJ+Ymmwi6Xd +2V7izq5N30PkJS8MtqII4FAjRBIkwPh0sy8PmW/DzkYU+lYQnDfYLKDFKcj8xJK/ +o8oZUBsQltrSj0KlM9QuqxCTCBCy1nXZ9WHOhq+jdLiTc1Oi60uEHcUMrLK8aYc4 +HqIvZS6C2iwMI0d1OP3VxmAbMQ9yqRi+FbLYavJ3H40jrU9SYqdxa0BrTaz8MJNE +6AEwgQDPChczSghvHME+Fs4mtGCY3TesbNZKVahQRjaFIhMZIZ4RP4CRc0bJOBG+ +8Me4+KHNsD2ki5b03wAN6C1P2QrMzI+gH9fXLZYp761ciDAsX6YIzrhHHYLxYpJH +BkQKKs8dCQWE5IzgVrdlvC3Z1/l9om66wHqqx7nKnPfYs/Sfnwe9MpCD6xJrXiTm +WS7NM6fbQpO9APNr7o0ZOjbbWFzlNw== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_cs_cert.pem b/php/ext/openssl/tests/sni_server_cs_cert.pem new file mode 100644 index 00000000..b77c7b83 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_cs_cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjEyWhcNMjYwNDAy +MTgzNjEyWjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKY3MucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAL8uTYc5LcxHbB02xger6mADZrOa59c1xZkyaxpVgsKC +LDZk32ob2ZKwtXAl02e32zwfF0G6QLc9mUlOznMAVvQfKJGFD6Pc4v6bcHK4LELD +dIa3A/DAUVHHHr8IpnuXy74PBPUSf+vMvctwZ0XFVmDtrACvY7k34nTYxE1NwW9O +aF7/A0g/+qJ10LuLlw4LEN3EV3pXfVAdMWs5kF8soiKl3P3KUwJ2hFWM59vGo+zZ +VG8zauddVFzF2OOMfRHF1qT1We4XjXCTc2OQwjc5rVyq7fcojKVkHD1xM7BElcQD +Kom/bkxTpb1V9eyyD8QRuuej40w/SdYepAWzAlMc7O8CAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFHPfd8dK +Lz1R0Ck4WV1B9AWXd5DSMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQB6WSIHEyDXLZxH +hZjqSNQOA7Wc9Z2FCAiD29xYkGTL8WuPVGGP1mu4B92ytj+PMWwqSReDa7eTGLE7 +O7ozw9l+c+gNmHFNikSsGjlV2E8CToQOFMny+jAQYMSXf8UbTp9xDfgG02t/71hv +SLWqdeHMLcR0xi0nBQH0vDOkwUbuWYqFa3jejHieGhykHM6CkIk6lqnyOEO+ooIF +ZsLprrg1ss/mXCPI6niP0hze55ERKdxI7Rk8sZ4pVkf2SUWqZrUS0aJ+Ymmwi6Xd +2V7izq5N30PkJS8MtqII4FAjRBIkwPh0sy8PmW/DzkYU+lYQnDfYLKDFKcj8xJK/ +o8oZUBsQltrSj0KlM9QuqxCTCBCy1nXZ9WHOhq+jdLiTc1Oi60uEHcUMrLK8aYc4 +HqIvZS6C2iwMI0d1OP3VxmAbMQ9yqRi+FbLYavJ3H40jrU9SYqdxa0BrTaz8MJNE +6AEwgQDPChczSghvHME+Fs4mtGCY3TesbNZKVahQRjaFIhMZIZ4RP4CRc0bJOBG+ +8Me4+KHNsD2ki5b03wAN6C1P2QrMzI+gH9fXLZYp761ciDAsX6YIzrhHHYLxYpJH +BkQKKs8dCQWE5IzgVrdlvC3Z1/l9om66wHqqx7nKnPfYs/Sfnwe9MpCD6xJrXiTm +WS7NM6fbQpO9APNr7o0ZOjbbWFzlNw== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_cs_key.pem b/php/ext/openssl/tests/sni_server_cs_key.pem new file mode 100644 index 00000000..bf1e9f25 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_cs_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvy5NhzktzEdsHTbGB6vqYANms5rn1zXFmTJrGlWCwoIsNmTf +ahvZkrC1cCXTZ7fbPB8XQbpAtz2ZSU7OcwBW9B8okYUPo9zi/ptwcrgsQsN0hrcD +8MBRUccevwime5fLvg8E9RJ/68y9y3BnRcVWYO2sAK9juTfidNjETU3Bb05oXv8D +SD/6onXQu4uXDgsQ3cRXeld9UB0xazmQXyyiIqXc/cpTAnaEVYzn28aj7NlUbzNq +511UXMXY44x9EcXWpPVZ7heNcJNzY5DCNzmtXKrt9yiMpWQcPXEzsESVxAMqib9u +TFOlvVX17LIPxBG656PjTD9J1h6kBbMCUxzs7wIDAQABAoIBAQC85lBeY0X4ST3v +I7bJz7kWQ2YP4uhfAdeLhoDDFWjNLffniwYhfwEc6xNri0R2f/jUT9gX7qORKwEx +qPdeNCC2t67LElGg1FlJv2Z9Q7MgCKYzkdQH5s6y4e9kTHTLO/JpiceZKz1QTQ3f +XOH9032E6nIAf0wmr6xHTgOwajrN8VI5BuPEMVmEwIw3AtYeqVuPCNKyGR4HUVkC +2bAydnGngbRJRnNzmKcWJancxpHDGBSFqPyuXMFC7Jgo3ZmyCbGp99vuXVk/sW9x +5aj94M9nRE0guk05ivH2/JZao2uLYkIgjFWlhNxKdWgWRk8DEuN4djC8mKS9YH1q +crYRToMhAoGBAOspUTtKP54mpZmyhxuDqj02JaJRzNTskPHsiF1UhtXuw7uT+ryV +ekUFLNXoFmn9mbx1WVaUvGH4qjilvQOxz7u++lz0ApqJEfyM3jc/cC40Y5zcuGSu +Etbg+SyDoytlgMCIydJyrS7NNALSo5p5oG6XY2f8yd/DCAmo8LzypaHRAoGBANAf +R1SlBMc/bOsi6GrJxcBVSCFMiKYiO5woL5aUKa9yM+UQuQ/6xbQ7Q+sOlt0FH3xo +AJ2L60qTdjyXVtjOdtXs5ZC4l+C6AfnCx6yLr+fNc4SOYXEfqS4LZylgwKd9KyVB +asspIW9Idbgebmi6vPyt9LDkIp0h1VuFGjkvQJK/AoGBAI4pbS0dprXyARyYW6sb +fpgAmuG099IkrT9DUfCx/81myTclr2fAKal+BmvOIXaz0/OlMXvw8K19iVIzh7+r +B70lJ+93p/dKM/BsLI5TsHqOO0YB/QsIXOVAHgJ2FfdPJnW+e9vYba+kZ/Po6PSi +4ITaykJ8BIJcQgis89QWEGFxAoGBAJhQO+jzuDKF9ZWEf6ofrw0anOZZ16wWY5/e +PS2rk3JmVxpuibHrKqPDt+ogTELHDAsFJmYmz3VNxHuFmrajK49Wh4/JuMVr/CQo +6+8YcA1qa/94IFIlBLDBAafjujsZvOjQHnM+z8xcsGKmStF00Pjv6qNG4xoyd646 +FD4DmfOLAoGAWXehpopZKXE9gRAni881ucK6WqxPPBoofbozi09D0MmfarIVaSkv +jNVVHBfLWd7IEXTjiipPBeUqq6Jc3pscN1Vp4rrl8jTmVTdazEv0LuzpdUFqmNo2 +M+xw17uz9D9Q32/aW1Lar0PdIaL/wGEDEyzEBFwrGppcENLilPz8gzU= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/sni_server_key_cert.phpt b/php/ext/openssl/tests/sni_server_key_cert.phpt new file mode 100644 index 00000000..cd52ddfe --- /dev/null +++ b/php/ext/openssl/tests/sni_server_key_cert.phpt @@ -0,0 +1,69 @@ +--TEST-- +sni_server with separate pk and cert +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/domain1.pem', + 'SNI_server_certs' => [ + "cs.php.net" => [ + 'local_cert' => __DIR__ . "/sni_server_cs_cert.pem", + 'local_pk' => __DIR__ . "/sni_server_cs_key.pem" + ], + "uk.php.net" => [ + 'local_cert' => __DIR__ . "/sni_server_uk_cert.pem", + 'local_pk' => __DIR__ . "/sni_server_uk_key.pem" + ], + "us.php.net" => [ + 'local_cert' => __DIR__ . "/sni_server_us_cert.pem", + 'local_pk' => __DIR__ . "/sni_server_us_key.pem" + ], + ] + ]]); + + $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctxArr = [ + 'cafile' => __DIR__ . '/sni_server_ca.pem', + 'capture_peer_cert' => true + ]; + + phpt_wait(); + + $ctxArr['peer_name'] = 'cs.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); + + $ctxArr['peer_name'] = 'uk.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); + + $ctxArr['peer_name'] = 'us.php.net'; + $ctx = stream_context_create(['ssl' => $ctxArr]); + $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 1, $flags, $ctx); + $cert = stream_context_get_options($ctx)['ssl']['peer_certificate']; + var_dump(openssl_x509_parse($cert)['subject']['CN']); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +string(%d) "cs.php.net" +string(%d) "uk.php.net" +string(%d) "us.php.net" diff --git a/php/ext/openssl/tests/sni_server_uk.pem b/php/ext/openssl/tests/sni_server_uk.pem new file mode 100644 index 00000000..f929b698 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_uk.pem @@ -0,0 +1,57 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArMpFePSNUHNHCiUWfsSPQxHaQTpDfogEISIMuGq5JhEuHWyl +HRe51JWZGi39a/PY9rAClfg/qqPnuxwFDoovhQsq9Kd0JnsXW11CMSqiBimf8vyg +GE/V2DIOiex7Ab8+5zEL7cCrNyXfDk+DuoT7Np3jaSE/u31OMUAzFz4/EL7Zqzlk +IMkHB/GSwLIJB8VbHt4Hunf28bLreTcjO/5QpNkSFtJ1PvbWRv3WheR5ykQQWGKF +9VgwYwS0Lu7YktLF2RGFZhIypUK8jazJiwsBRQ0faSCpAXTSPYh12GDegwAiKqGk +L+fayUdWGnnpYTVOysYL8mCoi9Ar0BPgtHEVvwIDAQABAoIBAGpg7XyWMxpAno/k +XYEWSo0kRJa75CnWW5R6fhJbwjlpglajONQ8czAqGeRARDFeI0lc+3qRJ8FKv7Q2 +f/Z/pNnoEj4liiDWz350X/gdIztgDRVv6rCNFj7QMps/eEuPDo8PZySs5bxCGJ2a +3qLKlE7/za4/xhkMAEPaHppEvFb15dpomqP2Fjqei9afp8tD+xJv9BGtkFIy9acw +94AWQi974kgW7ZzfEf8RqHM0ExKiESCc26knbcBu0tQ892YHggMccUMk/UrVgR5d +vuGOBurlYGLBstSDSKCCe6la4N/FX3FiC3WhVNescnuTZPXcX3zebh7roGjgrTdd +6UJYBIECgYEA09XYihdwW66G9Y09OatzlzBh1Rvzjv2Vl5NmWHHb6vh38H4PcOof +S1pT0JvRzpt8uEs4i+Eda5PyQyp4iGtD+DQ07Dxh2jiixsE3PRFRG2wg2QCgDHnS +6vgV1VOqA/A4on4nhxLZXxhX4YvHaJYlm1bZ+amG+j5XiI/NtHJm9k8CgYEA0NB9 +bAoaZnc06+T8rMaO45boX5SvYsCZbtY3VRl75SrbMal0IKfnXHELVHuei12LmlMs +LuFgG8jGO3+ncxUqMytoGvrmk/cM9tCNbDKVHtFbqz0qt9lkDAwLsBougKnVsNDW +Aae/tz/wYXJct86unfLh0xtvkx5Iz1we4cS1fZECgYA8YR+vfK7R8xUUuIVTAsOX +vHqmO6lYgH87DRCG9S0x9FB7g/LyxEjXOY/aTg+nTDpobUhY1nmESE8tRdXFTI27 +GWZcT3m0sZ/z9u6/wUfVAST7tWnpJHAx+TR/8bDsHnSGHF836O98Y3vpFeZosSNW ++5J1zxRiD5LzocmIPXOLkQKBgEgHApxXx898YwbTj8zRGMysay89DFpV8RboUWHL +To83/y/cMbBp+kZKwAu+MGwGMndjJSRunUY4NRik6c+qh0nrORfFX+++Efy4529g +60scEDC7Apc0J2x4Yze1cED1VD6PaqJbiKffKD2UwyKr6lOVSgwVtKDcm2Tbc9OQ +lMHhAoGBAIPwYVxzWM6I6pr8x2TucpBZZReLytz7uzybMNvbKCrwlETbNNXubnfp +nPuPKzpeRI0y26pIIAbijzFW0MXq+kIu3H7we8TaImsJ1AaQCTYeoLWBVcr6RISk +3d4i7iT35aWCuhPVve0FNIv/u3jrqX2H2C2MXMiLOsw1GFxPvpi4 +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjMyWhcNMjYwNDAy +MTgzNjMyWjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKdWsucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKzKRXj0jVBzRwolFn7Ej0MR2kE6Q36IBCEiDLhquSYR +Lh1spR0XudSVmRot/Wvz2PawApX4P6qj57scBQ6KL4ULKvSndCZ7F1tdQjEqogYp +n/L8oBhP1dgyDonsewG/PucxC+3Aqzcl3w5Pg7qE+zad42khP7t9TjFAMxc+PxC+ +2as5ZCDJBwfxksCyCQfFWx7eB7p39vGy63k3Izv+UKTZEhbSdT721kb91oXkecpE +EFhihfVYMGMEtC7u2JLSxdkRhWYSMqVCvI2syYsLAUUNH2kgqQF00j2Iddhg3oMA +IiqhpC/n2slHVhp56WE1TsrGC/JgqIvQK9AT4LRxFb8CAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFJK58uJe +Lv8WDOR8TTLUcSxO1zCyMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQDHayU795hFnQNj +fuYV21sEmkSjgtp6X4rV9JfoCp8U2gieL4mizoCPx9Q8HYaAf98hPYTofGUaCSd+ +Xlzd8lhLt9GCU+BsCxGtJocrjOQDhyhkioN8iirQRTtJpRVC6a4RCBGpenOD7Z7C +Z32uGXohzFuigP/J8/SXBdHrlpNSa03iEkkisPR46mbGj06lFVOFHJDNKA3CnQwM +3VfqvZt0ksZi/gAOol8dtrAd3k5JBfJ2BtqsPbycEGAhsGrTK/MeqiFcO8QZiXpN +qf0wZzOMFZJ4HqTiHs4TMMQaDK8c4qfR0l1OE224ijcB5NlqMjGAZabMfHgNZcl7 +fYPX+POsOMaqubv98uoC0PCK8NCTyfB4V/el72EEoVfwKYOxm3eYXBEE2ZNyIci6 +YKYhNa9e2k+cFueYMztV06HTGgkcHcSJATP+3ISTRx3tj1BPmc4O4WAMEMx1E0gg +PaVrBVAylGzt8kaMaOQMBImpsALSfutq6+KtQiu0OTGS3yVUGamV4AyRjuwF1/ZA +kZbjmNEGsf9d2rzS89ckds24QUx0zrfJ56p7lRvyVK/pML7iadv8dUH3fKDDDerD +oocLjOjNxFGN9Woz+kfidA8Siu0zsfQ6CLPlaQrVAVQH4iMuCZraqMc3TqAiUKRj +iHKp6FFrRZmY8W8HEKHv98uGofn+3g== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_uk_cert.pem b/php/ext/openssl/tests/sni_server_uk_cert.pem new file mode 100644 index 00000000..57663855 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_uk_cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjMyWhcNMjYwNDAy +MTgzNjMyWjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKdWsucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKzKRXj0jVBzRwolFn7Ej0MR2kE6Q36IBCEiDLhquSYR +Lh1spR0XudSVmRot/Wvz2PawApX4P6qj57scBQ6KL4ULKvSndCZ7F1tdQjEqogYp +n/L8oBhP1dgyDonsewG/PucxC+3Aqzcl3w5Pg7qE+zad42khP7t9TjFAMxc+PxC+ +2as5ZCDJBwfxksCyCQfFWx7eB7p39vGy63k3Izv+UKTZEhbSdT721kb91oXkecpE +EFhihfVYMGMEtC7u2JLSxdkRhWYSMqVCvI2syYsLAUUNH2kgqQF00j2Iddhg3oMA +IiqhpC/n2slHVhp56WE1TsrGC/JgqIvQK9AT4LRxFb8CAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFJK58uJe +Lv8WDOR8TTLUcSxO1zCyMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQDHayU795hFnQNj +fuYV21sEmkSjgtp6X4rV9JfoCp8U2gieL4mizoCPx9Q8HYaAf98hPYTofGUaCSd+ +Xlzd8lhLt9GCU+BsCxGtJocrjOQDhyhkioN8iirQRTtJpRVC6a4RCBGpenOD7Z7C +Z32uGXohzFuigP/J8/SXBdHrlpNSa03iEkkisPR46mbGj06lFVOFHJDNKA3CnQwM +3VfqvZt0ksZi/gAOol8dtrAd3k5JBfJ2BtqsPbycEGAhsGrTK/MeqiFcO8QZiXpN +qf0wZzOMFZJ4HqTiHs4TMMQaDK8c4qfR0l1OE224ijcB5NlqMjGAZabMfHgNZcl7 +fYPX+POsOMaqubv98uoC0PCK8NCTyfB4V/el72EEoVfwKYOxm3eYXBEE2ZNyIci6 +YKYhNa9e2k+cFueYMztV06HTGgkcHcSJATP+3ISTRx3tj1BPmc4O4WAMEMx1E0gg +PaVrBVAylGzt8kaMaOQMBImpsALSfutq6+KtQiu0OTGS3yVUGamV4AyRjuwF1/ZA +kZbjmNEGsf9d2rzS89ckds24QUx0zrfJ56p7lRvyVK/pML7iadv8dUH3fKDDDerD +oocLjOjNxFGN9Woz+kfidA8Siu0zsfQ6CLPlaQrVAVQH4iMuCZraqMc3TqAiUKRj +iHKp6FFrRZmY8W8HEKHv98uGofn+3g== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_uk_key.pem b/php/ext/openssl/tests/sni_server_uk_key.pem new file mode 100644 index 00000000..3baa6efd --- /dev/null +++ b/php/ext/openssl/tests/sni_server_uk_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArMpFePSNUHNHCiUWfsSPQxHaQTpDfogEISIMuGq5JhEuHWyl +HRe51JWZGi39a/PY9rAClfg/qqPnuxwFDoovhQsq9Kd0JnsXW11CMSqiBimf8vyg +GE/V2DIOiex7Ab8+5zEL7cCrNyXfDk+DuoT7Np3jaSE/u31OMUAzFz4/EL7Zqzlk +IMkHB/GSwLIJB8VbHt4Hunf28bLreTcjO/5QpNkSFtJ1PvbWRv3WheR5ykQQWGKF +9VgwYwS0Lu7YktLF2RGFZhIypUK8jazJiwsBRQ0faSCpAXTSPYh12GDegwAiKqGk +L+fayUdWGnnpYTVOysYL8mCoi9Ar0BPgtHEVvwIDAQABAoIBAGpg7XyWMxpAno/k +XYEWSo0kRJa75CnWW5R6fhJbwjlpglajONQ8czAqGeRARDFeI0lc+3qRJ8FKv7Q2 +f/Z/pNnoEj4liiDWz350X/gdIztgDRVv6rCNFj7QMps/eEuPDo8PZySs5bxCGJ2a +3qLKlE7/za4/xhkMAEPaHppEvFb15dpomqP2Fjqei9afp8tD+xJv9BGtkFIy9acw +94AWQi974kgW7ZzfEf8RqHM0ExKiESCc26knbcBu0tQ892YHggMccUMk/UrVgR5d +vuGOBurlYGLBstSDSKCCe6la4N/FX3FiC3WhVNescnuTZPXcX3zebh7roGjgrTdd +6UJYBIECgYEA09XYihdwW66G9Y09OatzlzBh1Rvzjv2Vl5NmWHHb6vh38H4PcOof +S1pT0JvRzpt8uEs4i+Eda5PyQyp4iGtD+DQ07Dxh2jiixsE3PRFRG2wg2QCgDHnS +6vgV1VOqA/A4on4nhxLZXxhX4YvHaJYlm1bZ+amG+j5XiI/NtHJm9k8CgYEA0NB9 +bAoaZnc06+T8rMaO45boX5SvYsCZbtY3VRl75SrbMal0IKfnXHELVHuei12LmlMs +LuFgG8jGO3+ncxUqMytoGvrmk/cM9tCNbDKVHtFbqz0qt9lkDAwLsBougKnVsNDW +Aae/tz/wYXJct86unfLh0xtvkx5Iz1we4cS1fZECgYA8YR+vfK7R8xUUuIVTAsOX +vHqmO6lYgH87DRCG9S0x9FB7g/LyxEjXOY/aTg+nTDpobUhY1nmESE8tRdXFTI27 +GWZcT3m0sZ/z9u6/wUfVAST7tWnpJHAx+TR/8bDsHnSGHF836O98Y3vpFeZosSNW ++5J1zxRiD5LzocmIPXOLkQKBgEgHApxXx898YwbTj8zRGMysay89DFpV8RboUWHL +To83/y/cMbBp+kZKwAu+MGwGMndjJSRunUY4NRik6c+qh0nrORfFX+++Efy4529g +60scEDC7Apc0J2x4Yze1cED1VD6PaqJbiKffKD2UwyKr6lOVSgwVtKDcm2Tbc9OQ +lMHhAoGBAIPwYVxzWM6I6pr8x2TucpBZZReLytz7uzybMNvbKCrwlETbNNXubnfp +nPuPKzpeRI0y26pIIAbijzFW0MXq+kIu3H7we8TaImsJ1AaQCTYeoLWBVcr6RISk +3d4i7iT35aWCuhPVve0FNIv/u3jrqX2H2C2MXMiLOsw1GFxPvpi4 +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/sni_server_us.pem b/php/ext/openssl/tests/sni_server_us.pem new file mode 100644 index 00000000..170a8a96 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_us.pem @@ -0,0 +1,57 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA1QkC3tiNYDY+ZxMmPbagYUbMpzuXo9mVBvYh86bYZaeB7bts +QCBK+6VD4D2LjR3RszpzmOzhJXjm8j0t+GeRS3OMIM75/BKAnixXicRSIb8zdIPz +JP992vvMq8p46/XftAfBhAMOaCqcD85zpyX4PhfC9733nOyN4yqx58O4UhVTKih6 +W9/ldp3uwSYAW+HyoINnHls/bFO8vv60K5VIhkxK30LHnC5PvByGfuHOgrscEThs +jW0ESqO0+9l88KhGdmLgzvbBlGxNziCMfn0LcFH6p2ITc3foD4LSzGEFtJ92OZi3 +buCOfbFsN7vWHTsEi89fRcCnWGtMwLUx0TCluQIDAQABAoIBAQCnsUQ1Lrl6trhA +Yu6DPbLZX+XQ7jPbonaQ2Ea5iOhmfIjmHdaEU+cyV1EqvseO+Z4MO0KraiuAV79T +h50cIEpa3kW7vbFCHz5nQ/hUVdlg/yT93rASu5rSOctOnz64Xv8Ms948kDtS+9eF +Cbo4JMdX+VRbt4mmWP8HhqAsFACPexEoWxJcIxwFcI24GTGzySjemNjQzbmcVhzM +a4k6n8DolCL1cRS54C5Aaf5g4+IFDgyydcgZXp1lnX3MnqivSNkejnPnY55NcmrH +X3ZWPlAi9GHOJE33uy8bGWnip7Tn4iTt6tJvjz/yP82TGACDg1B8XsKrqsuQLsoU +cNBVGcQBAoGBAPteCgNmuNOpo4SRA1UVRw1WgnE8YtnNA6vYyVcTLSpqabq33UaD +03L9CQsbHtj88U+E8OH24Iqj3U9x7QJfH8DVmWuBrlwez80JsKGnLdViHydjKcAz +H2Cbv+SiWeaWXkFCkN4Jf7k3q0Ew4SG2LOq5PVUy/NB4bilbJD2ExKpZAoGBANj2 +Hpwo35IQ4XfSSsGaCdn+8ajMcNUMMGZ6YkZqmVO4kogqobyrPL/2KE9ol/hlacw6 +U/6Digox5/wqruYfqyM8lqGOq2/0Xf7c4XfiOTS9Na4JN3OGzlyqPvcn2zdqhYFY +iHPu2RqpA+LhCHW9Zs8C1Bp/KAEPdRP6OabqVaphAoGACLrHVj7nBFLL3vq6RuYq +RYhPl2cld7LrAbjRpTiBRQvVCCsCgERrv36SJdSXSanfJ4fSZcaRHb97HBs0w/RR +wfypC1bBm2lmhhRkEfkgWlzCADgtZwNff5dpHqOUw7FNLK8HIO7rhJ8uT2FHMEiH +Xs94FdFjfknwaXdE1u4ZdmECgYEAgxfbkQHFbO2UPqErGGXp0/WOsS6ucpyF1jXW +kbOxZ3vb1jjkNyrEbzzeSHTrdmRYk9UekWeLjfNvt9dWjKfP8V+XqJCbF+9wqCFw +fs6LQEmfWMQq5DwtDqKznwVPGOHdPzVuZZaJSemb9oeAZBwINccAv+3bDyD23hZQ +pYFsN6ECgYEA33QYDNG/spki4D8rlxyxZ+1MdB/efnrGBhO8FsJpG5+AtmYhWgD9 +sl29+3aiRkmDznoy36z+hoeZePILEAKMcbHyXOymixOHPuaZJ95hbvq6sqd6WMAe +w5tHnxlfEuu11zatolk6WiAmTmG3sZpN5Tqloq0Ye4dvlhVKNV3Bn3E= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjQ0WhcNMjYwNDAy +MTgzNjQ0WjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKdXMucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANUJAt7YjWA2PmcTJj22oGFGzKc7l6PZlQb2IfOm2GWn +ge27bEAgSvulQ+A9i40d0bM6c5js4SV45vI9LfhnkUtzjCDO+fwSgJ4sV4nEUiG/ +M3SD8yT/fdr7zKvKeOv137QHwYQDDmgqnA/Oc6cl+D4Xwve995zsjeMqsefDuFIV +Uyooelvf5Xad7sEmAFvh8qCDZx5bP2xTvL7+tCuVSIZMSt9Cx5wuT7wchn7hzoK7 +HBE4bI1tBEqjtPvZfPCoRnZi4M72wZRsTc4gjH59C3BR+qdiE3N36A+C0sxhBbSf +djmYt27gjn2xbDe71h07BIvPX0XAp1hrTMC1MdEwpbkCAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOXnUeNs +grKQb+EvG36DXjjDDmsFMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQBDLwuLbx75ACSU +5cF2L/D17JEnhlna62MgKNdpNLJSpaofK2Lk2BqsmnQf5JdkrXWMUN/DsmXZc9pq +25XmprfABUP9Cx18KPVqLQ43Z9o+R9xI1Ospt5mrpxGp6l2BHSs/4G69nuPFpcIJ +iabnLYdUk2Z+64lPe4EMBrZH+pj4xn3JA59BACJYNYn0nLaw45DIAyzyLJ0vVSwc +0JtjsztXQov4UqdWXxLRFfe2nEGoK8ZkTJ8ELcCYu6sNSBjw9Ech78uXN1BQOBTK +lhAgN3FKqOp3hqf0umqf35gDvmWwLB/eptUYZ96gBYT0tbPA0P+YsW+iZmamxXma +Odgg8iRcPxKl9bVPt57NLaDy/RQhOxTGXQs1Q2jp7UhzqoZDClwVSDxd6DEppAFA +OZAY+Rsrm7VoCwVQ/1KbcJHmJ/79tArvaWJk3KHLGMpdZq4KwrC3hM8/QxYtyX/6 +cfnXvShBYCdfTGgNlj3t/mNAgp1ZB3s9ClGqRBR/P0Db+ryv5DuxYM6nzEB3Od0y +kT5tHbXDQY+1HCExjOMi7Al0cmC2r3+oxDA4UjGv+npgcfeoxQhXmm/SQRiPdKlb +vT0D594sLoB23jqA9bMehpxEyI7eGjfFUmXwMeu0tJhipvpJI3ogJoM+SCFTyLkc +12cPiz/sR/ALhvhUJXTeUH8wxPjzbA== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_us_cert.pem b/php/ext/openssl/tests/sni_server_us_cert.pem new file mode 100644 index 00000000..4452e3c6 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_us_cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjQ0WhcNMjYwNDAy +MTgzNjQ0WjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKdXMucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANUJAt7YjWA2PmcTJj22oGFGzKc7l6PZlQb2IfOm2GWn +ge27bEAgSvulQ+A9i40d0bM6c5js4SV45vI9LfhnkUtzjCDO+fwSgJ4sV4nEUiG/ +M3SD8yT/fdr7zKvKeOv137QHwYQDDmgqnA/Oc6cl+D4Xwve995zsjeMqsefDuFIV +Uyooelvf5Xad7sEmAFvh8qCDZx5bP2xTvL7+tCuVSIZMSt9Cx5wuT7wchn7hzoK7 +HBE4bI1tBEqjtPvZfPCoRnZi4M72wZRsTc4gjH59C3BR+qdiE3N36A+C0sxhBbSf +djmYt27gjn2xbDe71h07BIvPX0XAp1hrTMC1MdEwpbkCAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOXnUeNs +grKQb+EvG36DXjjDDmsFMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQBDLwuLbx75ACSU +5cF2L/D17JEnhlna62MgKNdpNLJSpaofK2Lk2BqsmnQf5JdkrXWMUN/DsmXZc9pq +25XmprfABUP9Cx18KPVqLQ43Z9o+R9xI1Ospt5mrpxGp6l2BHSs/4G69nuPFpcIJ +iabnLYdUk2Z+64lPe4EMBrZH+pj4xn3JA59BACJYNYn0nLaw45DIAyzyLJ0vVSwc +0JtjsztXQov4UqdWXxLRFfe2nEGoK8ZkTJ8ELcCYu6sNSBjw9Ech78uXN1BQOBTK +lhAgN3FKqOp3hqf0umqf35gDvmWwLB/eptUYZ96gBYT0tbPA0P+YsW+iZmamxXma +Odgg8iRcPxKl9bVPt57NLaDy/RQhOxTGXQs1Q2jp7UhzqoZDClwVSDxd6DEppAFA +OZAY+Rsrm7VoCwVQ/1KbcJHmJ/79tArvaWJk3KHLGMpdZq4KwrC3hM8/QxYtyX/6 +cfnXvShBYCdfTGgNlj3t/mNAgp1ZB3s9ClGqRBR/P0Db+ryv5DuxYM6nzEB3Od0y +kT5tHbXDQY+1HCExjOMi7Al0cmC2r3+oxDA4UjGv+npgcfeoxQhXmm/SQRiPdKlb +vT0D594sLoB23jqA9bMehpxEyI7eGjfFUmXwMeu0tJhipvpJI3ogJoM+SCFTyLkc +12cPiz/sR/ALhvhUJXTeUH8wxPjzbA== +-----END CERTIFICATE----- diff --git a/php/ext/openssl/tests/sni_server_us_key.pem b/php/ext/openssl/tests/sni_server_us_key.pem new file mode 100644 index 00000000..8b0d73d7 --- /dev/null +++ b/php/ext/openssl/tests/sni_server_us_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA1QkC3tiNYDY+ZxMmPbagYUbMpzuXo9mVBvYh86bYZaeB7bts +QCBK+6VD4D2LjR3RszpzmOzhJXjm8j0t+GeRS3OMIM75/BKAnixXicRSIb8zdIPz +JP992vvMq8p46/XftAfBhAMOaCqcD85zpyX4PhfC9733nOyN4yqx58O4UhVTKih6 +W9/ldp3uwSYAW+HyoINnHls/bFO8vv60K5VIhkxK30LHnC5PvByGfuHOgrscEThs +jW0ESqO0+9l88KhGdmLgzvbBlGxNziCMfn0LcFH6p2ITc3foD4LSzGEFtJ92OZi3 +buCOfbFsN7vWHTsEi89fRcCnWGtMwLUx0TCluQIDAQABAoIBAQCnsUQ1Lrl6trhA +Yu6DPbLZX+XQ7jPbonaQ2Ea5iOhmfIjmHdaEU+cyV1EqvseO+Z4MO0KraiuAV79T +h50cIEpa3kW7vbFCHz5nQ/hUVdlg/yT93rASu5rSOctOnz64Xv8Ms948kDtS+9eF +Cbo4JMdX+VRbt4mmWP8HhqAsFACPexEoWxJcIxwFcI24GTGzySjemNjQzbmcVhzM +a4k6n8DolCL1cRS54C5Aaf5g4+IFDgyydcgZXp1lnX3MnqivSNkejnPnY55NcmrH +X3ZWPlAi9GHOJE33uy8bGWnip7Tn4iTt6tJvjz/yP82TGACDg1B8XsKrqsuQLsoU +cNBVGcQBAoGBAPteCgNmuNOpo4SRA1UVRw1WgnE8YtnNA6vYyVcTLSpqabq33UaD +03L9CQsbHtj88U+E8OH24Iqj3U9x7QJfH8DVmWuBrlwez80JsKGnLdViHydjKcAz +H2Cbv+SiWeaWXkFCkN4Jf7k3q0Ew4SG2LOq5PVUy/NB4bilbJD2ExKpZAoGBANj2 +Hpwo35IQ4XfSSsGaCdn+8ajMcNUMMGZ6YkZqmVO4kogqobyrPL/2KE9ol/hlacw6 +U/6Digox5/wqruYfqyM8lqGOq2/0Xf7c4XfiOTS9Na4JN3OGzlyqPvcn2zdqhYFY +iHPu2RqpA+LhCHW9Zs8C1Bp/KAEPdRP6OabqVaphAoGACLrHVj7nBFLL3vq6RuYq +RYhPl2cld7LrAbjRpTiBRQvVCCsCgERrv36SJdSXSanfJ4fSZcaRHb97HBs0w/RR +wfypC1bBm2lmhhRkEfkgWlzCADgtZwNff5dpHqOUw7FNLK8HIO7rhJ8uT2FHMEiH +Xs94FdFjfknwaXdE1u4ZdmECgYEAgxfbkQHFbO2UPqErGGXp0/WOsS6ucpyF1jXW +kbOxZ3vb1jjkNyrEbzzeSHTrdmRYk9UekWeLjfNvt9dWjKfP8V+XqJCbF+9wqCFw +fs6LQEmfWMQq5DwtDqKznwVPGOHdPzVuZZaJSemb9oeAZBwINccAv+3bDyD23hZQ +pYFsN6ECgYEA33QYDNG/spki4D8rlxyxZ+1MdB/efnrGBhO8FsJpG5+AtmYhWgD9 +sl29+3aiRkmDznoy36z+hoeZePILEAKMcbHyXOymixOHPuaZJ95hbvq6sqd6WMAe +w5tHnxlfEuu11zatolk6WiAmTmG3sZpN5Tqloq0Ye4dvlhVKNV3Bn3E= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/stream_crypto_flags_001.phpt b/php/ext/openssl/tests/stream_crypto_flags_001.phpt new file mode 100644 index 00000000..1ba93093 --- /dev/null +++ b/php/ext/openssl/tests/stream_crypto_flags_001.phpt @@ -0,0 +1,46 @@ +--TEST-- +Basic bitwise stream crypto context flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLS_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/stream_crypto_flags_002.phpt b/php/ext/openssl/tests/stream_crypto_flags_002.phpt new file mode 100644 index 00000000..e57f2b70 --- /dev/null +++ b/php/ext/openssl/tests/stream_crypto_flags_002.phpt @@ -0,0 +1,57 @@ +--TEST-- +TLSv1.1 and TLSv1.2 bitwise stream crypto flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLS_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) + diff --git a/php/ext/openssl/tests/stream_crypto_flags_003.phpt b/php/ext/openssl/tests/stream_crypto_flags_003.phpt new file mode 100644 index 00000000..28cb640c --- /dev/null +++ b/php/ext/openssl/tests/stream_crypto_flags_003.phpt @@ -0,0 +1,56 @@ +--TEST-- +Server bitwise stream crypto flag assignment +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + + // Only accept TLSv1.2 connections + 'crypto_method' => STREAM_CRYPTO_METHOD_SSLv3_SERVER | STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT); + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) + diff --git a/php/ext/openssl/tests/stream_crypto_flags_004.phpt b/php/ext/openssl/tests/stream_crypto_flags_004.phpt new file mode 100644 index 00000000..e51a2bab --- /dev/null +++ b/php/ext/openssl/tests/stream_crypto_flags_004.phpt @@ -0,0 +1,60 @@ +--TEST-- +Specific protocol method specification +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_SERVER, + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'peer_name' => 'bug54992.local', + ]]); + + phpt_wait(); + + // Should succeed because the SSLv23 handshake here is compatible with the + // TLSv1 hello method employed in the server + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + // Should fail because the TLSv1.1 hello method is not supported + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT); + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + // Should fail because the TLSv1.2 hello method is not supported + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); + var_dump(@stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); + + // Should succeed because we use the same TLSv1 hello + stream_context_set_option($clientCtx, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT); + var_dump(stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx)); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/stream_security_level.phpt b/php/ext/openssl/tests/stream_security_level.phpt new file mode 100644 index 00000000..fb1d36a5 --- /dev/null +++ b/php/ext/openssl/tests/stream_security_level.phpt @@ -0,0 +1,48 @@ +--TEST-- +security_level setting to prohibit cert +--SKIPIF-- += v1.1.0 required"); +if (!function_exists("proc_open")) die("skip no proc_open"); +--FILE-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64322"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'security_level' => 3, + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'verify_peer_name' => false + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: +error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed in %s : eval()'d code on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s : eval()'d code on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64322 (Unknown error) in %s : eval()'d code on line %d +bool(false) diff --git a/php/ext/openssl/tests/stream_server_reneg_limit.phpt b/php/ext/openssl/tests/stream_server_reneg_limit.phpt new file mode 100644 index 00000000..d355505e --- /dev/null +++ b/php/ext/openssl/tests/stream_server_reneg_limit.phpt @@ -0,0 +1,89 @@ +--TEST-- +TLS server rate-limits client-initiated renegotiation +--SKIPIF-- + 0) die("skip couldn't locate openssl binary"); +if(substr(PHP_OS, 0, 3) == 'WIN') { + die('skip not suitable for Windows'); +} +?> +--FILE-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem', + 'reneg_limit' => 0, + 'reneg_window' => 30, + 'reneg_limit_callback' => function($stream) { + var_dump($stream); + } + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $clients = []; + while (1) { + $r = array_merge([$server], $clients); + $w = $e = []; + + stream_select($r, $w, $e, $timeout=42); + + foreach ($r as $sock) { + if ($sock === $server && ($client = stream_socket_accept($server, $timeout = 42))) { + $clientId = (int) $client; + $clients[$clientId] = $client; + } elseif ($sock !== $server) { + $clientId = (int) $sock; + $buffer = fread($sock, 1024); + if (strlen($buffer)) { + continue; + } elseif (!is_resource($sock) || feof($sock)) { + unset($clients[$clientId]); + break 2; + } + } + } + } +CODE; + +$clientCode = <<<'CODE' + $cmd = 'openssl s_client -connect 127.0.0.1:64321'; + $descriptorSpec = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]]; + $process = proc_open($cmd, $descriptorSpec, $pipes); + + list($stdin, $stdout, $stderr) = $pipes; + + // Trigger renegotiation twice + // Server settings only allow one per second (should result in disconnection) + fwrite($stdin, "R\nR\nR\nR\n"); + + $lines = []; + while(!feof($stderr)) { + fgets($stderr); + } + + fclose($stdin); + fclose($stdout); + fclose($stderr); + proc_terminate($process); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($serverCode, $clientCode); +--EXPECTF-- +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/stream_verify_peer_name_001.phpt b/php/ext/openssl/tests/stream_verify_peer_name_001.phpt new file mode 100644 index 00000000..4aecf8c7 --- /dev/null +++ b/php/ext/openssl/tests/stream_verify_peer_name_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +Verify host name by default in client transfers +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'peer_name' => 'bug54992.local' + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/stream_verify_peer_name_002.phpt b/php/ext/openssl/tests/stream_verify_peer_name_002.phpt new file mode 100644 index 00000000..cfee8b1c --- /dev/null +++ b/php/ext/openssl/tests/stream_verify_peer_name_002.phpt @@ -0,0 +1,40 @@ +--TEST-- +Allow host name mismatch when "verify_host" disabled +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem', + 'verify_peer_name' => false + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 2, $clientFlags, $clientCtx); + + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/stream_verify_peer_name_003.phpt b/php/ext/openssl/tests/stream_verify_peer_name_003.phpt new file mode 100644 index 00000000..e4e083f7 --- /dev/null +++ b/php/ext/openssl/tests/stream_verify_peer_name_003.phpt @@ -0,0 +1,44 @@ +--TEST-- +Host name mismatch triggers error +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/bug54992.pem' + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + @stream_socket_accept($server, 1); +CODE; + +$clientCode = <<<'CODE' + $serverUri = "ssl://127.0.0.1:64321"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => true, + 'cafile' => __DIR__ . '/bug54992-ca.pem' + ]]); + + phpt_wait(); + $client = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx); + + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Warning: stream_socket_client(): Peer certificate CN=`bug54992.local' did not match expected CN=`127.0.0.1' in %s on line %d + +Warning: stream_socket_client(): Failed to enable crypto in %s on line %d + +Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Unknown error) in %s on line %d +bool(false) diff --git a/php/ext/openssl/tests/streams_crypto_method.pem b/php/ext/openssl/tests/streams_crypto_method.pem new file mode 100644 index 00000000..9d754d46 --- /dev/null +++ b/php/ext/openssl/tests/streams_crypto_method.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIC5jCCAk+gAwIBAgIBADANBgkqhkiG9w0BAQQFADBcMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKUXVlZW5zbGFuZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQx +HDAaBgNVBAMTE1Rlc3QgUENBICgxMDI0IGJpdCkwHhcNOTkxMjAyMjEzNTQ4WhcN +MDUwNzExMjEzNTQ4WjBcMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFu +ZDEaMBgGA1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxHDAaBgNVBAMTE1Rlc3QgUENB +ICgxMDI0IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ2haT/f5Zwy +V+MiuSDjSR62adBoSiBB7Usty44lXqsp9RICw+DCCxpsn/CfxPEDXLLd4olsWXc6 +JRcxGynbYmnzk+Z6aIPPJQhK3CTvaqGnWKZsA1m+WaUIUqJCuNTK4N+7hMAGaf6S +S3e9HVgEQ4a34gXJ7VQFVIBNV1EnZRWHAgMBAAGjgbcwgbQwHQYDVR0OBBYEFE0R +aEcrj18q1dw+G6nJbsTWR213MIGEBgNVHSMEfTB7gBRNEWhHK49fKtXcPhupyW7E +1kdtd6FgpF4wXDELMAkGA1UEBhMCQVUxEzARBgNVBAgTClF1ZWVuc2xhbmQxGjAY +BgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRwwGgYDVQQDExNUZXN0IFBDQSAoMTAy +NCBiaXQpggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAUa8B3pho ++Mvxeq9HsEzJxHIFQla05S5J/e/V+DQTYoKiRFchKPrDAdrzYSEvP3h4QJEtsNqQ +JfOxg5M42uLFq7aPGWkF6ZZqZsYS+zA9IVT14g7gNA6Ne+5QtJqQtH9HA24st0T0 +Tga/lZ9M2ovImovaxSL/kRHbpCWcqWVxpOw= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCdoWk/3+WcMlfjIrkg40ketmnQaEogQe1LLcuOJV6rKfUSAsPg +wgsabJ/wn8TxA1yy3eKJbFl3OiUXMRsp22Jp85PmemiDzyUIStwk72qhp1imbANZ +vlmlCFKiQrjUyuDfu4TABmn+kkt3vR1YBEOGt+IFye1UBVSATVdRJ2UVhwIDAQAB +AoGAba4fTtuap5l7/8ZsbE7Z1O32KJY4ZcOZukLOLUUhXxXduT+FTgGWujc0/rgc +z9qYCLlNZHOouMYTgtSfYvuMuLZ11VIt0GYH+nRioLShE59Yy+zCRyC+gPigS1kz +xvo14AsOIPYV14Tk/SsHyq6E0eTk7VzaIE197giiINUERPECQQDSKmtPTh/lRKw7 +HSZSM0I1mFWn/1zqrAbontRQY5w98QWIOe5qmzYyFbPXYT3d9BzlsMyhgiRNoBbD +yvohSHXJAkEAwAHx6ezAZeWWzD5yXD36nyjpkVCw7Tk7TSmOceLJMWt1QcrCfqlS +xA5jjpQ6Z8suU5DdtWAryM2sAir1WisYzwJAd6Zcx56jvAQ3xcPXsE6scBTVFzrj +7FqZ6E+cclPzfLQ+QQsyOBE7bpI6e/FJppY26XGZXo3YGzV8IGXrt40oOQJALETG +h86EFXo3qGOFbmsDy4pdP5nBERCu8X1xUCSfintiD4c2DInxgS5oGclnJeMcjTvL +QjQoJCX3UJCi/OUO1QJBAKgcDHWjMvt+l1pjJBsSEZ0HX9AAIIVx0RQmbFGS+F2Q +hhu5l77WnnZOQ9vvhV5u7NPCUF9nhU3jh60qWWO8mkc= +-----END RSA PRIVATE KEY----- diff --git a/php/ext/openssl/tests/streams_crypto_method.phpt b/php/ext/openssl/tests/streams_crypto_method.phpt new file mode 100644 index 00000000..f8ec8649 --- /dev/null +++ b/php/ext/openssl/tests/streams_crypto_method.phpt @@ -0,0 +1,53 @@ +--TEST-- +Specific crypto method for ssl:// transports. +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx); + phpt_notify(); + + $client = @stream_socket_accept($server); + if ($client) { + $in = ''; + while (!preg_match('/\r?\n\r?\n/', $in)) { + $in .= fread($client, 2048); + } + $response = "HTTP/1.0 200 OK\r\n" + . "Content-Type: text/plain\r\n" + . "Content-Length: 12\r\n" + . "Connection: close\r\n" + . "\r\n" + . "Hello World!"; + fwrite($client, $response); + fclose($client); + } +CODE; + +$clientCode = <<<'CODE' + $serverUri = "https://127.0.0.1:64321/"; + $clientFlags = STREAM_CLIENT_CONNECT; + $clientCtx = stream_context_create(['ssl' => [ + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, + 'verify_peer' => false, + 'verify_peer_name' => false + ]]); + + phpt_wait(); + echo file_get_contents($serverUri, false, $clientCtx); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +Hello World! diff --git a/php/ext/openssl/tests/tls_wrapper.phpt b/php/ext/openssl/tests/tls_wrapper.phpt new file mode 100644 index 00000000..91352338 --- /dev/null +++ b/php/ext/openssl/tests/tls_wrapper.phpt @@ -0,0 +1,59 @@ +--TEST-- +tls stream wrapper +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server('tls://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 6; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + + phpt_wait(); + + $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("ssl://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tls://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) diff --git a/php/ext/openssl/tests/tlsv1.0_wrapper.phpt b/php/ext/openssl/tests/tlsv1.0_wrapper.phpt new file mode 100644 index 00000000..c0477dfe --- /dev/null +++ b/php/ext/openssl/tests/tlsv1.0_wrapper.phpt @@ -0,0 +1,47 @@ +--TEST-- +tlsv1.0 stream wrapper +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server('tlsv1.0://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + + phpt_wait(); + + $client = stream_socket_client("tlsv1.0://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/php/ext/openssl/tests/tlsv1.1_wrapper.phpt b/php/ext/openssl/tests/tlsv1.1_wrapper.phpt new file mode 100644 index 00000000..a5dba299 --- /dev/null +++ b/php/ext/openssl/tests/tlsv1.1_wrapper.phpt @@ -0,0 +1,48 @@ +--TEST-- +tlsv1.1 stream wrapper +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server('tlsv1.1://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + + phpt_wait(); + + $client = stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/php/ext/openssl/tests/tlsv1.2_wrapper.phpt b/php/ext/openssl/tests/tlsv1.2_wrapper.phpt new file mode 100644 index 00000000..42980cf6 --- /dev/null +++ b/php/ext/openssl/tests/tlsv1.2_wrapper.phpt @@ -0,0 +1,48 @@ +--TEST-- +tlsv1.2 stream wrapper +--SKIPIF-- + [ + 'local_cert' => __DIR__ . '/streams_crypto_method.pem', + ]]); + + $server = stream_socket_server('tlsv1.2://127.0.0.1:64321', $errno, $errstr, $flags, $ctx); + phpt_notify(); + + for ($i=0; $i < 3; $i++) { + @stream_socket_accept($server, 3); + } +CODE; + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + $ctx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + + phpt_wait(); + + $client = stream_socket_client("tlsv1.2://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("sslv3://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); + + $client = @stream_socket_client("tlsv1.1://127.0.0.1:64321", $errno, $errstr, 3, $flags, $ctx); + var_dump($client); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +--EXPECTF-- +resource(%d) of type (stream) +bool(false) +bool(false) diff --git a/php/ext/openssl/xp_ssl.c b/php/ext/openssl/xp_ssl.c new file mode 100644 index 00000000..79f165f3 --- /dev/null +++ b/php/ext/openssl/xp_ssl.c @@ -0,0 +1,2751 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2018 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2018 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Wez Furlong | + | Daniel Lowrey | + | Chris Wright | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "ext/standard/file.h" +#include "ext/standard/url.h" +#include "streams/php_streams_int.h" +#include "zend_smart_str.h" +#include "php_openssl.h" +#include "php_network.h" +#include +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#include +#include +#endif + +#ifdef PHP_WIN32 +#include "win32/winutil.h" +#include "win32/time.h" +#include +/* These are from Wincrypt.h, they conflict with OpenSSL */ +#undef X509_NAME +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#endif + +#ifndef OPENSSL_NO_SSL3 +#define HAVE_SSL3 1 +#endif + +#define HAVE_TLS11 1 +#define HAVE_TLS12 1 + +#ifndef OPENSSL_NO_ECDH +#define HAVE_ECDH 1 +#endif + +#ifndef OPENSSL_NO_TLSEXT +#define HAVE_TLS_SNI 1 +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#define HAVE_TLS_ALPN 1 +#endif +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_SEC_LEVEL 1 +#endif + +/* Flags for determining allowed stream crypto methods */ +#define STREAM_CRYPTO_IS_CLIENT (1<<0) +#define STREAM_CRYPTO_METHOD_SSLv2 (1<<1) +#define STREAM_CRYPTO_METHOD_SSLv3 (1<<2) +#define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3) +#define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4) +#define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5) + +/* Simplify ssl context option retrieval */ +#define GET_VER_OPT(name) \ + (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL) +#define GET_VER_OPT_STRING(name, str) \ + if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); } +#define GET_VER_OPT_LONG(name, num) \ + if (GET_VER_OPT(name)) { convert_to_long_ex(val); num = Z_LVAL_P(val); } + +/* Used for peer verification in windows */ +#define PHP_X509_NAME_ENTRY_TO_UTF8(ne, i, out) \ + ASN1_STRING_to_UTF8(&out, X509_NAME_ENTRY_get_data(X509_NAME_get_entry(ne, i))) + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) +static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength); +#endif + +extern php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl); +extern zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw); +extern int php_openssl_get_ssl_stream_data_index(); +extern int php_openssl_get_x509_list_id(void); +static struct timeval php_openssl_subtract_timeval(struct timeval a, struct timeval b); +static int php_openssl_compare_timeval(struct timeval a, struct timeval b); +static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count); + +php_stream_ops php_openssl_socket_ops; + +/* Certificate contexts used for server-side SNI selection */ +typedef struct _php_openssl_sni_cert_t { + char *name; + SSL_CTX *ctx; +} php_openssl_sni_cert_t; + +/* Provides leaky bucket handhsake renegotiation rate-limiting */ +typedef struct _php_openssl_handshake_bucket_t { + zend_long prev_handshake; + zend_long limit; + zend_long window; + float tokens; + unsigned should_close; +} php_openssl_handshake_bucket_t; + +#ifdef HAVE_TLS_ALPN +/* Holds the available server ALPN protocols for negotiation */ +typedef struct _php_openssl_alpn_ctx_t { + unsigned char *data; + unsigned short len; +} php_openssl_alpn_ctx; +#endif + +/* This implementation is very closely tied to the that of the native + * sockets implemented in the core. + * Don't try this technique in other extensions! + * */ +typedef struct _php_openssl_netstream_data_t { + php_netstream_data_t s; + SSL *ssl_handle; + SSL_CTX *ctx; + struct timeval connect_timeout; + int enable_on_connect; + int is_client; + int ssl_active; + php_stream_xport_crypt_method_t method; + php_openssl_handshake_bucket_t *reneg; + php_openssl_sni_cert_t *sni_certs; + unsigned sni_cert_count; +#ifdef HAVE_TLS_ALPN + php_openssl_alpn_ctx alpn_ctx; +#endif + char *url_name; + unsigned state_set:1; + unsigned _spare:31; +} php_openssl_netstream_data_t; + +/* it doesn't matter that we do some hash traversal here, since it is done only + * in an error condition arising from a network connection problem */ +static int php_openssl_is_http_stream_talking_to_iis(php_stream *stream) /* {{{ */ +{ + if (Z_TYPE(stream->wrapperdata) == IS_ARRAY && + stream->wrapper && + strcasecmp(stream->wrapper->wops->label, "HTTP") == 0 + ) { + /* the wrapperdata is an array zval containing the headers */ + zval *tmp; + +#define SERVER_MICROSOFT_IIS "Server: Microsoft-IIS" +#define SERVER_GOOGLE "Server: GFE/" + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(stream->wrapperdata), tmp) { + if (strncasecmp(Z_STRVAL_P(tmp), SERVER_MICROSOFT_IIS, sizeof(SERVER_MICROSOFT_IIS)-1) == 0) { + return 1; + } else if (strncasecmp(Z_STRVAL_P(tmp), SERVER_GOOGLE, sizeof(SERVER_GOOGLE)-1) == 0) { + return 1; + } + } ZEND_HASH_FOREACH_END(); + } + return 0; +} +/* }}} */ + +static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes); + char esbuf[512]; + smart_str ebuf = {0}; + unsigned long ecode; + int retry = 1; + + switch(err) { + case SSL_ERROR_ZERO_RETURN: + /* SSL terminated (but socket may still be active) */ + retry = 0; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* re-negotiation, or perhaps the SSL layer needs more + * packets: retry in next iteration */ + errno = EAGAIN; + retry = is_init ? 1 : sslsock->s.is_blocked; + break; + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (nr_bytes == 0) { + if (!php_openssl_is_http_stream_talking_to_iis(stream) && ERR_get_error() != 0) { + php_error_docref(NULL, E_WARNING, "SSL: fatal protocol error"); + } + SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); + stream->eof = 1; + retry = 0; + } else { + char *estr = php_socket_strerror(php_socket_errno(), NULL, 0); + + php_error_docref(NULL, E_WARNING, + "SSL: %s", estr); + + efree(estr); + retry = 0; + } + break; + } + + + /* fall through */ + default: + /* some other error */ + ecode = ERR_get_error(); + + switch (ERR_GET_REASON(ecode)) { + case SSL_R_NO_SHARED_CIPHER: + php_error_docref(NULL, E_WARNING, + "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. " + "This could be because the server is missing an SSL certificate " + "(local_cert context option)"); + retry = 0; + break; + + default: + do { + /* NULL is automatically added */ + ERR_error_string_n(ecode, esbuf, sizeof(esbuf)); + if (ebuf.s) { + smart_str_appendc(&ebuf, '\n'); + } + smart_str_appends(&ebuf, esbuf); + } while ((ecode = ERR_get_error()) != 0); + + smart_str_0(&ebuf); + + php_error_docref(NULL, E_WARNING, + "SSL operation failed with code %d. %s%s", + err, + ebuf.s ? "OpenSSL Error messages:\n" : "", + ebuf.s ? ZSTR_VAL(ebuf.s) : ""); + if (ebuf.s) { + smart_str_free(&ebuf); + } + } + + retry = 0; + errno = 0; + } + return retry; +} +/* }}} */ + +static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ +{ + php_stream *stream; + SSL *ssl; + int err, depth, ret; + zval *val; + zend_ulong allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH; + + + ret = preverify_ok; + + /* determine the status for the current cert */ + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + /* conjure the stream & context to use */ + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + stream = (php_stream*)SSL_get_ex_data(ssl, php_openssl_get_ssl_stream_data_index()); + + /* if allow_self_signed is set, make sure that verification succeeds */ + if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && + GET_VER_OPT("allow_self_signed") && + zend_is_true(val) + ) { + ret = 1; + } + + /* check the depth */ + GET_VER_OPT_LONG("verify_depth", allowed_depth); + if ((zend_ulong)depth > allowed_depth) { + ret = 0; + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); + } + + return ret; +} +/* }}} */ + +static int php_openssl_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected) +{ + zend_string *fingerprint; + int result = -1; + + fingerprint = php_openssl_x509_fingerprint(peer, method, 0); + if (fingerprint) { + result = strcasecmp(expected, ZSTR_VAL(fingerprint)); + zend_string_release(fingerprint); + } + + return result; +} + +static zend_bool php_openssl_x509_fingerprint_match(X509 *peer, zval *val) +{ + if (Z_TYPE_P(val) == IS_STRING) { + const char *method = NULL; + + switch (Z_STRLEN_P(val)) { + case 32: + method = "md5"; + break; + + case 40: + method = "sha1"; + break; + } + + return method && php_openssl_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val)) == 0; + } else if (Z_TYPE_P(val) == IS_ARRAY) { + zval *current; + zend_string *key; + + if (!zend_hash_num_elements(Z_ARRVAL_P(val))) { + php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + return 0; + } + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(val), key, current) { + if (key == NULL || Z_TYPE_P(current) != IS_STRING) { + php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required"); + return 0; + } + if (php_openssl_x509_fingerprint_cmp(peer, ZSTR_VAL(key), Z_STRVAL_P(current)) != 0) { + return 0; + } + } ZEND_HASH_FOREACH_END(); + + return 1; + } else { + php_error_docref(NULL, E_WARNING, + "Invalid peer_fingerprint value; fingerprint string or array of the form [algo => fingerprint] required"); + } + + return 0; +} + +static zend_bool php_openssl_matches_wildcard_name(const char *subjectname, const char *certname) /* {{{ */ +{ + char *wildcard = NULL; + ptrdiff_t prefix_len; + size_t suffix_len, subject_len; + + if (strcasecmp(subjectname, certname) == 0) { + return 1; + } + + /* wildcard, if present, must only be present in the left-most component */ + if (!(wildcard = strchr(certname, '*')) || memchr(certname, '.', wildcard - certname)) { + return 0; + } + + /* 1) prefix, if not empty, must match subject */ + prefix_len = wildcard - certname; + if (prefix_len && strncasecmp(subjectname, certname, prefix_len) != 0) { + return 0; + } + + suffix_len = strlen(wildcard + 1); + subject_len = strlen(subjectname); + if (suffix_len <= subject_len) { + /* 2) suffix must match + * 3) no . between prefix and suffix + **/ + return strcasecmp(wildcard + 1, subjectname + subject_len - suffix_len) == 0 && + memchr(subjectname + prefix_len, '.', subject_len - suffix_len - prefix_len) == NULL; + } + + return 0; +} +/* }}} */ + +static zend_bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) /* {{{ */ +{ + int i, len; + unsigned char *cert_name = NULL; + char ipbuffer[64]; + + GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0); + int alt_name_count = sk_GENERAL_NAME_num(alt_names); + + for (i = 0; i < alt_name_count; i++) { + GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i); + + if (san->type == GEN_DNS) { + ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); + if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) { + OPENSSL_free(cert_name); + /* prevent null-byte poisoning*/ + continue; + } + + /* accommodate valid FQDN entries ending in "." */ + len = strlen((const char*)cert_name); + if (len && strcmp((const char *)&cert_name[len-1], ".") == 0) { + cert_name[len-1] = '\0'; + } + + if (php_openssl_matches_wildcard_name(subject_name, (const char *)cert_name)) { + OPENSSL_free(cert_name); + return 1; + } + OPENSSL_free(cert_name); + } else if (san->type == GEN_IPADD) { + if (san->d.iPAddress->length == 4) { + sprintf(ipbuffer, "%d.%d.%d.%d", + san->d.iPAddress->data[0], + san->d.iPAddress->data[1], + san->d.iPAddress->data[2], + san->d.iPAddress->data[3] + ); + if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) { + return 1; + } + } + /* No, we aren't bothering to check IPv6 addresses. Why? + * Because IP SAN names are officially deprecated and are + * not allowed by CAs starting in 2015. Deal with it. + */ + } + } + + return 0; +} +/* }}} */ + +static zend_bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */ +{ + char buf[1024]; + X509_NAME *cert_name; + zend_bool is_match = 0; + int cert_name_len; + + cert_name = X509_get_subject_name(peer); + cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf)); + + if (cert_name_len == -1) { + php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN"); + } else if ((size_t)cert_name_len != strlen(buf)) { + php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf); + } else if (php_openssl_matches_wildcard_name(subject_name, buf)) { + is_match = 1; + } else { + php_error_docref(NULL, E_WARNING, + "Peer certificate CN=`%.*s' did not match expected CN=`%s'", + cert_name_len, buf, subject_name); + } + + return is_match; +} +/* }}} */ + +static int php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream) /* {{{ */ +{ + zval *val = NULL; + char *peer_name = NULL; + int err, + must_verify_peer, + must_verify_peer_name, + must_verify_fingerprint; + + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + must_verify_peer = GET_VER_OPT("verify_peer") + ? zend_is_true(val) + : sslsock->is_client; + + must_verify_peer_name = GET_VER_OPT("verify_peer_name") + ? zend_is_true(val) + : sslsock->is_client; + + must_verify_fingerprint = GET_VER_OPT("peer_fingerprint"); + + if ((must_verify_peer || must_verify_peer_name || must_verify_fingerprint) && peer == NULL) { + php_error_docref(NULL, E_WARNING, "Could not get peer certificate"); + return FAILURE; + } + + /* Verify the peer against using CA file/path settings */ + if (must_verify_peer) { + err = SSL_get_verify_result(ssl); + switch (err) { + case X509_V_OK: + /* fine */ + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + if (GET_VER_OPT("allow_self_signed") && zend_is_true(val)) { + /* allowed */ + break; + } + /* not allowed, so fall through */ + default: + php_error_docref(NULL, E_WARNING, + "Could not verify peer: code:%d %s", + err, + X509_verify_cert_error_string(err) + ); + return FAILURE; + } + } + + /* If a peer_fingerprint match is required this trumps peer and peer_name verification */ + if (must_verify_fingerprint) { + if (Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_ARRAY) { + if (!php_openssl_x509_fingerprint_match(peer, val)) { + php_error_docref(NULL, E_WARNING, + "peer_fingerprint match failure" + ); + return FAILURE; + } + } else { + php_error_docref(NULL, E_WARNING, + "Expected peer fingerprint must be a string or an array" + ); + return FAILURE; + } + } + + /* verify the host name presented in the peer certificate */ + if (must_verify_peer_name) { + GET_VER_OPT_STRING("peer_name", peer_name); + + /* If no peer name was specified we use the autodetected url name in client environments */ + if (peer_name == NULL && sslsock->is_client) { + peer_name = sslsock->url_name; + } + + if (peer_name) { + if (php_openssl_matches_san_list(peer, peer_name)) { + return SUCCESS; + } else if (php_openssl_matches_common_name(peer, peer_name)) { + return SUCCESS; + } else { + return FAILURE; + } + } else { + return FAILURE; + } + } + + return SUCCESS; +} +/* }}} */ + +static int php_openssl_passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */ +{ + php_stream *stream = (php_stream *)data; + zval *val = NULL; + char *passphrase = NULL; + /* TODO: could expand this to make a callback into PHP user-space */ + + GET_VER_OPT_STRING("passphrase", passphrase); + + if (passphrase) { + if (Z_STRLEN_P(val) < (size_t)num - 1) { + memcpy(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)+1); + return (int)Z_STRLEN_P(val); + } + } + return 0; +} +/* }}} */ + +#ifdef PHP_WIN32 +#define RETURN_CERT_VERIFY_FAILURE(code) X509_STORE_CTX_set_error(x509_store_ctx, code); return 0; +static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) /* {{{ */ +{ + PCCERT_CONTEXT cert_ctx = NULL; + PCCERT_CHAIN_CONTEXT cert_chain_ctx = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + X509 *cert = x509_store_ctx->cert; +#else + X509 *cert = X509_STORE_CTX_get0_cert(x509_store_ctx); +#endif + + php_stream *stream; + php_openssl_netstream_data_t *sslsock; + zval *val; + zend_bool is_self_signed = 0; + + + stream = (php_stream*)arg; + sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + { /* First convert the x509 struct back to a DER encoded buffer and let Windows decode it into a form it can work with */ + unsigned char *der_buf = NULL; + int der_len; + + der_len = i2d_X509(cert, &der_buf); + if (der_len < 0) { + unsigned long err_code, e; + char err_buf[512]; + + while ((e = ERR_get_error()) != 0) { + err_code = e; + } + + php_error_docref(NULL, E_WARNING, "Error encoding X509 certificate: %d: %s", err_code, ERR_error_string(err_code, err_buf)); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + cert_ctx = CertCreateCertificateContext(X509_ASN_ENCODING, der_buf, der_len); + OPENSSL_free(der_buf); + + if (cert_ctx == NULL) { + php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", php_win_err()); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + } + + { /* Next fetch the relevant cert chain from the store */ + CERT_ENHKEY_USAGE enhkey_usage = {0}; + CERT_USAGE_MATCH cert_usage = {0}; + CERT_CHAIN_PARA chain_params = {sizeof(CERT_CHAIN_PARA)}; + LPSTR usages[] = {szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE}; + DWORD chain_flags = 0; + unsigned long allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH; + unsigned int i; + + enhkey_usage.cUsageIdentifier = 3; + enhkey_usage.rgpszUsageIdentifier = usages; + cert_usage.dwType = USAGE_MATCH_TYPE_OR; + cert_usage.Usage = enhkey_usage; + chain_params.RequestedUsage = cert_usage; + chain_flags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; + + if (!CertGetCertificateChain(NULL, cert_ctx, NULL, NULL, &chain_params, chain_flags, NULL, &cert_chain_ctx)) { + php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", php_win_err()); + CertFreeCertificateContext(cert_ctx); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + /* check if the cert is self-signed */ + if (cert_chain_ctx->cChain > 0 && cert_chain_ctx->rgpChain[0]->cElement > 0 + && (cert_chain_ctx->rgpChain[0]->rgpElement[0]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) != 0) { + is_self_signed = 1; + } + + /* check the depth */ + GET_VER_OPT_LONG("verify_depth", allowed_depth); + + for (i = 0; i < cert_chain_ctx->cChain; i++) { + if (cert_chain_ctx->rgpChain[i]->cElement > allowed_depth) { + CertFreeCertificateChain(cert_chain_ctx); + CertFreeCertificateContext(cert_ctx); + RETURN_CERT_VERIFY_FAILURE(X509_V_ERR_CERT_CHAIN_TOO_LONG); + } + } + } + + { /* Then verify it against a policy */ + SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_params = {sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA)}; + CERT_CHAIN_POLICY_PARA chain_policy_params = {sizeof(CERT_CHAIN_POLICY_PARA)}; + CERT_CHAIN_POLICY_STATUS chain_policy_status = {sizeof(CERT_CHAIN_POLICY_STATUS)}; + LPWSTR server_name = NULL; + BOOL verify_result; + + { /* This looks ridiculous and it is - but we validate the name ourselves using the peer_name + ctx option, so just use the CN from the cert here */ + + X509_NAME *cert_name; + unsigned char *cert_name_utf8; + int index, cert_name_utf8_len; + DWORD num_wchars; + + cert_name = X509_get_subject_name(cert); + index = X509_NAME_get_index_by_NID(cert_name, NID_commonName, -1); + if (index < 0) { + php_error_docref(NULL, E_WARNING, "Unable to locate certificate CN"); + CertFreeCertificateChain(cert_chain_ctx); + CertFreeCertificateContext(cert_ctx); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + cert_name_utf8_len = PHP_X509_NAME_ENTRY_TO_UTF8(cert_name, index, cert_name_utf8); + + num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, NULL, 0); + if (num_wchars == 0) { + php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); + OPENSSL_free(cert_name_utf8); + CertFreeCertificateChain(cert_chain_ctx); + CertFreeCertificateContext(cert_ctx); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + server_name = emalloc((num_wchars * sizeof(WCHAR)) + sizeof(WCHAR)); + + num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, server_name, num_wchars); + if (num_wchars == 0) { + php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8); + efree(server_name); + OPENSSL_free(cert_name_utf8); + CertFreeCertificateChain(cert_chain_ctx); + CertFreeCertificateContext(cert_ctx); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + OPENSSL_free(cert_name_utf8); + } + + ssl_policy_params.dwAuthType = (sslsock->is_client) ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT; + ssl_policy_params.pwszServerName = server_name; + chain_policy_params.pvExtraPolicyPara = &ssl_policy_params; + + verify_result = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, cert_chain_ctx, &chain_policy_params, &chain_policy_status); + + efree(server_name); + CertFreeCertificateChain(cert_chain_ctx); + CertFreeCertificateContext(cert_ctx); + + if (!verify_result) { + php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", php_win_err()); + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + + if (chain_policy_status.dwError != 0) { + /* The chain does not match the policy */ + if (is_self_signed && chain_policy_status.dwError == CERT_E_UNTRUSTEDROOT + && GET_VER_OPT("allow_self_signed") && zend_is_true(val)) { + /* allow self-signed certs */ + X509_STORE_CTX_set_error(x509_store_ctx, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); + } else { + RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED); + } + } + } + + return 1; +} +/* }}} */ +#endif + +static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *cafile) /* {{{ */ +{ + php_stream *stream; + X509 *cert; + BIO *buffer; + int buffer_active = 0; + char *line = NULL; + size_t line_len; + long certs_added = 0; + + stream = php_stream_open_wrapper(cafile, "rb", 0, NULL); + + if (stream == NULL) { + php_error(E_WARNING, "failed loading cafile stream: `%s'", cafile); + return 0; + } else if (stream->wrapper->is_url) { + php_stream_close(stream); + php_error(E_WARNING, "remote cafile streams are disabled for security purposes"); + return 0; + } + + cert_start: { + line = php_stream_get_line(stream, NULL, 0, &line_len); + if (line == NULL) { + goto stream_complete; + } else if (!strcmp(line, "-----BEGIN CERTIFICATE-----\n") || + !strcmp(line, "-----BEGIN CERTIFICATE-----\r\n") + ) { + buffer = BIO_new(BIO_s_mem()); + buffer_active = 1; + goto cert_line; + } else { + efree(line); + goto cert_start; + } + } + + cert_line: { + BIO_puts(buffer, line); + efree(line); + line = php_stream_get_line(stream, NULL, 0, &line_len); + if (line == NULL) { + goto stream_complete; + } else if (!strcmp(line, "-----END CERTIFICATE-----") || + !strcmp(line, "-----END CERTIFICATE-----\n") || + !strcmp(line, "-----END CERTIFICATE-----\r\n") + ) { + goto add_cert; + } else { + goto cert_line; + } + } + + add_cert: { + BIO_puts(buffer, line); + efree(line); + cert = PEM_read_bio_X509(buffer, NULL, 0, NULL); + BIO_free(buffer); + buffer_active = 0; + if (cert && X509_STORE_add_cert(cert_store, cert)) { + ++certs_added; + } + goto cert_start; + } + + stream_complete: { + php_stream_close(stream); + if (buffer_active == 1) { + BIO_free(buffer); + } + } + + if (certs_added == 0) { + php_error(E_WARNING, "no valid certs found cafile stream: `%s'", cafile); + } + + return certs_added; +} +/* }}} */ + +static int php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ +{ + zval *val = NULL; + char *cafile = NULL; + char *capath = NULL; + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + GET_VER_OPT_STRING("cafile", cafile); + GET_VER_OPT_STRING("capath", capath); + + if (cafile == NULL) { + cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0); + cafile = strlen(cafile) ? cafile : NULL; + } else if (!sslsock->is_client) { + /* Servers need to load and assign CA names from the cafile */ + STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(cafile); + if (cert_names != NULL) { + SSL_CTX_set_client_CA_list(ctx, cert_names); + } else { + php_error(E_WARNING, "SSL: failed loading CA names from cafile"); + return FAILURE; + } + } + + if (capath == NULL) { + capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0); + capath = strlen(capath) ? capath : NULL; + } + + if (cafile || capath) { + if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) { + if (cafile && !php_openssl_load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile)) { + return FAILURE; + } + } + } else { +#ifdef PHP_WIN32 + SSL_CTX_set_cert_verify_callback(ctx, php_openssl_win_cert_verify_callback, (void *)stream); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); +#else + if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) { + php_error_docref(NULL, E_WARNING, + "Unable to set default verify locations and no CA settings specified"); + return FAILURE; + } +#endif + } + + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback); + + return SUCCESS; +} +/* }}} */ + +static void php_openssl_disable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ +{ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); +} +/* }}} */ + +static int php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */ +{ + zval *val = NULL; + char *certfile = NULL; + + GET_VER_OPT_STRING("local_cert", certfile); + + if (certfile) { + char resolved_path_buff[MAXPATHLEN]; + const char *private_key = NULL; + + if (VCWD_REALPATH(certfile, resolved_path_buff)) { + /* a certificate to use for authentication */ + if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) { + php_error_docref(NULL, 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); + return FAILURE; + } + GET_VER_OPT_STRING("local_pk", private_key); + + if (private_key) { + char resolved_path_buff_pk[MAXPATHLEN]; + if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) { + if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) { + php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk); + return FAILURE; + } + } + } else { + if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) { + php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff); + return FAILURE; + } + } + + if (!SSL_CTX_check_private_key(ctx)) { + php_error_docref(NULL, E_WARNING, "Private key does not match certificate!"); + } + } + } + + return SUCCESS; +} +/* }}} */ + +static const SSL_METHOD *php_openssl_select_crypto_method(zend_long method_value, int is_client) /* {{{ */ +{ + if (method_value == STREAM_CRYPTO_METHOD_SSLv2) { + php_error_docref(NULL, E_WARNING, + "SSLv2 unavailable in this PHP version"); + return NULL; + } else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) { +#ifdef HAVE_SSL3 + return is_client ? SSLv3_client_method() : SSLv3_server_method(); +#else + php_error_docref(NULL, E_WARNING, + "SSLv3 unavailable in the OpenSSL library against which PHP is linked"); + return NULL; +#endif + } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_0) { + return is_client ? TLSv1_client_method() : TLSv1_server_method(); + } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_1) { +#ifdef HAVE_TLS11 + return is_client ? TLSv1_1_client_method() : TLSv1_1_server_method(); +#else + php_error_docref(NULL, E_WARNING, + "TLSv1.1 unavailable in the OpenSSL library against which PHP is linked"); + return NULL; +#endif + } else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2) { +#ifdef HAVE_TLS12 + return is_client ? TLSv1_2_client_method() : TLSv1_2_server_method(); +#else + php_error_docref(NULL, E_WARNING, + "TLSv1.2 unavailable in the OpenSSL library against which PHP is linked"); + return NULL; +#endif + } else { + php_error_docref(NULL, E_WARNING, + "Invalid crypto method"); + return NULL; + } +} +/* }}} */ + +#define PHP_SSL_MAX_VERSION_LEN 32 + +static char *php_openssl_cipher_get_version(const SSL_CIPHER *c, char *buffer, size_t max_len) /* {{{ */ +{ + const char *version = SSL_CIPHER_get_version(c); + + strncpy(buffer, version, max_len); + if (max_len <= strlen(version)) { + buffer[max_len - 1] = 0; + } + + return buffer; +} +/* }}} */ + +static int php_openssl_get_crypto_method_ctx_flags(int method_flags) /* {{{ */ +{ + int ssl_ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_SSLv2 + ssl_ctx_options |= SSL_OP_NO_SSLv2; +#endif +#ifdef HAVE_SSL3 + if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) { + ssl_ctx_options |= SSL_OP_NO_SSLv3; + } +#endif + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_0)) { + ssl_ctx_options |= SSL_OP_NO_TLSv1; + } +#ifdef HAVE_TLS11 + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_1)) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_1; + } +#endif +#ifdef HAVE_TLS12 + if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_2)) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_2; + } +#endif + + return ssl_ctx_options; +} +/* }}} */ + +static void php_openssl_limit_handshake_reneg(const SSL *ssl) /* {{{ */ +{ + php_stream *stream; + php_openssl_netstream_data_t *sslsock; + struct timeval now; + zend_long elapsed_time; + + stream = php_openssl_get_stream_from_ssl_handle(ssl); + sslsock = (php_openssl_netstream_data_t*)stream->abstract; + gettimeofday(&now, NULL); + + /* The initial handshake is never rate-limited */ + if (sslsock->reneg->prev_handshake == 0) { + sslsock->reneg->prev_handshake = now.tv_sec; + return; + } + + elapsed_time = (now.tv_sec - sslsock->reneg->prev_handshake); + sslsock->reneg->prev_handshake = now.tv_sec; + sslsock->reneg->tokens -= (elapsed_time * (sslsock->reneg->limit / sslsock->reneg->window)); + + if (sslsock->reneg->tokens < 0) { + sslsock->reneg->tokens = 0; + } + ++sslsock->reneg->tokens; + + /* The token level exceeds our allowed limit */ + if (sslsock->reneg->tokens > sslsock->reneg->limit) { + zval *val; + + + sslsock->reneg->should_close = 1; + + if (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "reneg_limit_callback")) != NULL + ) { + zval param, retval; + + php_stream_to_zval(stream, ¶m); + + /* Closing the stream inside this callback would segfault! */ + stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; + if (FAILURE == call_user_function_ex(EG(function_table), NULL, val, &retval, 1, ¶m, 0, NULL)) { + php_error(E_WARNING, "SSL: failed invoking reneg limit notification callback"); + } + stream->flags ^= PHP_STREAM_FLAG_NO_FCLOSE; + + /* If the reneg_limit_callback returned true don't auto-close */ + if (Z_TYPE(retval) == IS_TRUE) { + sslsock->reneg->should_close = 0; + } + + zval_ptr_dtor(&retval); + } else { + php_error_docref(NULL, E_WARNING, + "SSL: client-initiated handshake rate limit exceeded by peer"); + } + } +} +/* }}} */ + +static void php_openssl_info_callback(const SSL *ssl, int where, int ret) /* {{{ */ +{ + /* Rate-limit client-initiated handshake renegotiation to prevent DoS */ + if (where & SSL_CB_HANDSHAKE_START) { + php_openssl_limit_handshake_reneg(ssl); + } +} +/* }}} */ + +static void php_openssl_init_server_reneg_limit(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ +{ + zval *val; + zend_long limit = OPENSSL_DEFAULT_RENEG_LIMIT; + zend_long window = OPENSSL_DEFAULT_RENEG_WINDOW; + + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_limit")) + ) { + convert_to_long(val); + limit = Z_LVAL_P(val); + } + + /* No renegotiation rate-limiting */ + if (limit < 0) { + return; + } + + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_window")) + ) { + convert_to_long(val); + window = Z_LVAL_P(val); + } + + sslsock->reneg = (void*)pemalloc(sizeof(php_openssl_handshake_bucket_t), + php_stream_is_persistent(stream) + ); + + sslsock->reneg->limit = limit; + sslsock->reneg->window = window; + sslsock->reneg->prev_handshake = 0; + sslsock->reneg->tokens = 0; + sslsock->reneg->should_close = 0; + + SSL_set_info_callback(sslsock->ssl_handle, php_openssl_info_callback); +} +/* }}} */ + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) +static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength) +{ + BIGNUM *bn = NULL; + static RSA *rsa_tmp = NULL; + + if (!rsa_tmp && ((bn = BN_new()) == NULL)) { + php_error_docref(NULL, E_WARNING, "allocation error generating RSA key"); + } + if (!rsa_tmp && bn) { + if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) == NULL) || + !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) { + if (rsa_tmp) { + RSA_free(rsa_tmp); + } + rsa_tmp = NULL; + } + BN_free(bn); + } + + return (rsa_tmp); +} +#endif + +static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */ +{ + DH *dh; + BIO* bio; + zval *zdhpath; + + zdhpath = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param"); + if (zdhpath == NULL) { +#if 0 + /* Coming in OpenSSL 1.1 ... eventually we'll want to enable this + * in the absence of an explicit dh_param. + */ + SSL_CTX_set_dh_auto(ctx, 1); +#endif + return SUCCESS; + } + + convert_to_string_ex(zdhpath); + bio = BIO_new_file(Z_STRVAL_P(zdhpath), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)); + + if (bio == NULL) { + php_error_docref(NULL, E_WARNING, "invalid dh_param"); + return FAILURE; + } + + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); + + if (dh == NULL) { + php_error_docref(NULL, E_WARNING, "failed reading DH params"); + return FAILURE; + } + + if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) { + php_error_docref(NULL, E_WARNING, "failed assigning DH params"); + DH_free(dh); + return FAILURE; + } + + DH_free(dh); + + return SUCCESS; +} +/* }}} */ + +#if defined(HAVE_ECDH) && (OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)) +static int php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */ +{ + zval *zvcurve; + int curve_nid; + EC_KEY *ecdh; + + zvcurve = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve"); + if (zvcurve == NULL) { +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_CTX_set_ecdh_auto(ctx, 1); + return SUCCESS; +#else + curve_nid = NID_X9_62_prime256v1; +#endif + } else { + convert_to_string_ex(zvcurve); + curve_nid = OBJ_sn2nid(Z_STRVAL_P(zvcurve)); + if (curve_nid == NID_undef) { + php_error_docref(NULL, E_WARNING, "invalid ecdh_curve specified"); + return FAILURE; + } + } + + ecdh = EC_KEY_new_by_curve_name(curve_nid); + if (ecdh == NULL) { + php_error_docref(NULL, E_WARNING, "failed generating ECDH curve"); + return FAILURE; + } + + SSL_CTX_set_tmp_ecdh(ctx, ecdh); + EC_KEY_free(ecdh); + + return SUCCESS; +} +/* }}} */ +#endif + +static int php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */ +{ + zval *zv; + long ssl_ctx_options = SSL_CTX_get_options(ctx); + +#if defined(HAVE_ECDH) && (OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)) + if (php_openssl_set_server_ecdh_curve(stream, ctx) == FAILURE) { + return FAILURE; + } +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) + SSL_CTX_set_tmp_rsa_callback(ctx, php_openssl_tmp_rsa_cb); +#endif + /* We now use php_openssl_tmp_rsa_cb to generate a key of appropriate size whenever necessary */ + if (php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size") != NULL) { + php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed"); + } + + php_openssl_set_server_dh_param(stream, ctx); + zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "single_dh_use"); + if (zv == NULL || zend_is_true(zv)) { + ssl_ctx_options |= SSL_OP_SINGLE_DH_USE; + } + + zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "honor_cipher_order"); + if (zv == NULL || zend_is_true(zv)) { + ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; + } + + SSL_CTX_set_options(ctx, ssl_ctx_options); + + return SUCCESS; +} +/* }}} */ + +#ifdef HAVE_TLS_SNI +static int php_openssl_server_sni_callback(SSL *ssl_handle, int *al, void *arg) /* {{{ */ +{ + php_stream *stream; + php_openssl_netstream_data_t *sslsock; + unsigned i; + const char *server_name; + + server_name = SSL_get_servername(ssl_handle, TLSEXT_NAMETYPE_host_name); + + if (!server_name) { + return SSL_TLSEXT_ERR_NOACK; + } + + stream = (php_stream*)SSL_get_ex_data(ssl_handle, php_openssl_get_ssl_stream_data_index()); + sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + if (!(sslsock->sni_cert_count && sslsock->sni_certs)) { + return SSL_TLSEXT_ERR_NOACK; + } + + for (i=0; i < sslsock->sni_cert_count; i++) { + if (php_openssl_matches_wildcard_name(server_name, sslsock->sni_certs[i].name)) { + SSL_set_SSL_CTX(ssl_handle, sslsock->sni_certs[i].ctx); + return SSL_TLSEXT_ERR_OK; + } + } + + return SSL_TLSEXT_ERR_NOACK; +} +/* }}} */ + +static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_path) /* {{{ */ +{ + /* The hello method is not inherited by SSL structs when assigning a new context + * inside the SNI callback, so the just use SSLv23 */ + SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); + + if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) != 1) { + php_error_docref(NULL, E_WARNING, + "failed setting local cert chain file `%s'; " \ + "check that your cafile/capath settings include " \ + "details of your certificate and its issuer", + cert_path + ); + SSL_CTX_free(ctx); + return NULL; + } else if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) != 1) { + php_error_docref(NULL, E_WARNING, + "failed setting private key from file `%s'", + key_path + ); + SSL_CTX_free(ctx); + return NULL; + } + + return ctx; +} +/* }}} */ + +static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ +{ + zval *val; + zval *current; + zend_string *key; + zend_ulong key_index; + int i = 0; + char resolved_path_buff[MAXPATHLEN]; + SSL_CTX *ctx; + + /* If the stream ctx disables SNI we're finished here */ + if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { + return SUCCESS; + } + + /* If no SNI cert array is specified we're finished here */ + if (!GET_VER_OPT("SNI_server_certs")) { + return SUCCESS; + } + + if (Z_TYPE_P(val) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, + "SNI_server_certs requires an array mapping host names to cert paths" + ); + return FAILURE; + } + + sslsock->sni_cert_count = zend_hash_num_elements(Z_ARRVAL_P(val)); + if (sslsock->sni_cert_count == 0) { + php_error_docref(NULL, E_WARNING, + "SNI_server_certs host cert array must not be empty" + ); + return FAILURE; + } + + sslsock->sni_certs = (php_openssl_sni_cert_t*)safe_pemalloc(sslsock->sni_cert_count, + sizeof(php_openssl_sni_cert_t), 0, php_stream_is_persistent(stream) + ); + memset(sslsock->sni_certs, 0, sslsock->sni_cert_count * sizeof(php_openssl_sni_cert_t)); + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), key_index, key, current) { + (void) key_index; + + if (!key) { + php_error_docref(NULL, E_WARNING, + "SNI_server_certs array requires string host name keys" + ); + return FAILURE; + } + + if (Z_TYPE_P(current) == IS_ARRAY) { + zval *local_pk, *local_cert; + char resolved_cert_path_buff[MAXPATHLEN], resolved_pk_path_buff[MAXPATHLEN]; + + local_cert = zend_hash_str_find(Z_ARRVAL_P(current), "local_cert", sizeof("local_cert")-1); + if (local_cert == NULL) { + php_error_docref(NULL, E_WARNING, + "local_cert not present in the array", + Z_STRVAL_P(local_cert) + ); + return FAILURE; + } + convert_to_string_ex(local_cert); + if (!VCWD_REALPATH(Z_STRVAL_P(local_cert), resolved_cert_path_buff)) { + php_error_docref(NULL, E_WARNING, + "failed setting local cert chain file `%s'; file not found" + ); + return FAILURE; + } + local_pk = zend_hash_str_find(Z_ARRVAL_P(current), "local_pk", sizeof("local_pk")-1); + if (local_pk == NULL) { + php_error_docref(NULL, E_WARNING, + "local_pk not present in the array" + ); + return FAILURE; + } + convert_to_string_ex(local_pk); + if (!VCWD_REALPATH(Z_STRVAL_P(local_pk), resolved_pk_path_buff)) { + php_error_docref(NULL, E_WARNING, + "failed setting local private key file `%s'; file not found", + Z_STRVAL_P(local_pk) + ); + return FAILURE; + } + + ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff); + + } else if (VCWD_REALPATH(Z_STRVAL_P(current), resolved_path_buff)) { + ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + } else { + php_error_docref(NULL, E_WARNING, + "failed setting local cert chain file `%s'; file not found", + Z_STRVAL_P(current) + ); + return FAILURE; + } + + if (ctx == NULL) { + return FAILURE; + } + + sslsock->sni_certs[i].name = pestrdup(ZSTR_VAL(key), php_stream_is_persistent(stream)); + sslsock->sni_certs[i].ctx = ctx; + ++i; + + } ZEND_HASH_FOREACH_END(); + + SSL_CTX_set_tlsext_servername_callback(sslsock->ctx, php_openssl_server_sni_callback); + + return SUCCESS; +} +/* }}} */ + +static void php_openssl_enable_client_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ +{ + zval *val; + char *sni_server_name; + + /* If SNI is explicitly disabled we're finished here */ + if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { + return; + } + + sni_server_name = sslsock->url_name; + + GET_VER_OPT_STRING("peer_name", sni_server_name); + + if (sni_server_name) { + SSL_set_tlsext_host_name(sslsock->ssl_handle, sni_server_name); + } +} +/* }}} */ +#endif + +#ifdef HAVE_TLS_ALPN +/** + * Parses a comma-separated list of strings into a string suitable for SSL_CTX_set_next_protos_advertised + * outlen: (output) set to the length of the resulting buffer on success. + * err: (maybe NULL) on failure, an error message line is written to this BIO. + * in: a NULL terminated string like "abc,def,ghi" + * + * returns: an emalloced buffer or NULL on failure. + */ +static unsigned char *php_openssl_alpn_protos_parse(unsigned short *outlen, const char *in) /* {{{ */ +{ + size_t len; + unsigned char *out; + size_t i, start = 0; + + len = strlen(in); + if (len >= 65535) { + return NULL; + } + + out = emalloc(strlen(in) + 1); + + for (i = 0; i <= len; ++i) { + if (i == len || in[i] == ',') { + if (i - start > 255) { + efree(out); + return NULL; + } + out[start] = i - start; + start = i + 1; + } else { + out[i + 1] = in[i]; + } + } + + *outlen = len + 1; + + return out; +} +/* }}} */ + +static int php_openssl_server_alpn_callback(SSL *ssl_handle, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = arg; + + if (SSL_select_next_proto((unsigned char **)out, outlen, sslsock->alpn_ctx.data, sslsock->alpn_ctx.len, in, inlen) != OPENSSL_NPN_NEGOTIATED) { + return SSL_TLSEXT_ERR_NOACK; + } + + return SSL_TLSEXT_ERR_OK; +} +/* }}} */ + +#endif + +int php_openssl_setup_crypto(php_stream *stream, + php_openssl_netstream_data_t *sslsock, + php_stream_xport_crypto_param *cparam) /* {{{ */ +{ + const SSL_METHOD *method; + int ssl_ctx_options; + int method_flags; + char *cipherlist = NULL; + char *alpn_protocols = NULL; + zval *val; + + if (sslsock->ssl_handle) { + if (sslsock->s.is_blocked) { + php_error_docref(NULL, E_WARNING, "SSL/TLS already set-up for this stream"); + return FAILURE; + } else { + return SUCCESS; + } + } + + ERR_clear_error(); + + /* We need to do slightly different things based on client/server method + * so lets remember which method was selected */ + sslsock->is_client = cparam->inputs.method & STREAM_CRYPTO_IS_CLIENT; + method_flags = ((cparam->inputs.method >> 1) << 1); + + /* Should we use a specific crypto method or is generic SSLv23 okay? */ + if ((method_flags & (method_flags-1)) == 0) { + ssl_ctx_options = SSL_OP_ALL; + method = php_openssl_select_crypto_method(method_flags, sslsock->is_client); + if (method == NULL) { + return FAILURE; + } + } else { + method = sslsock->is_client ? SSLv23_client_method() : SSLv23_server_method(); + ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags(method_flags); + if (ssl_ctx_options == -1) { + return FAILURE; + } + } + + sslsock->ctx = SSL_CTX_new(method); + + if (sslsock->ctx == NULL) { + php_error_docref(NULL, E_WARNING, "SSL context creation failure"); + return FAILURE; + } + + if (GET_VER_OPT("no_ticket") && zend_is_true(val)) { + ssl_ctx_options |= SSL_OP_NO_TICKET; + } + + ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + + if (!GET_VER_OPT("disable_compression") || zend_is_true(val)) { + ssl_ctx_options |= SSL_OP_NO_COMPRESSION; + } + + if (GET_VER_OPT("verify_peer") && !zend_is_true(val)) { + php_openssl_disable_peer_verification(sslsock->ctx, stream); + } else if (FAILURE == php_openssl_enable_peer_verification(sslsock->ctx, stream)) { + return FAILURE; + } + + /* callback for the passphrase (for localcert) */ + if (GET_VER_OPT("passphrase")) { + SSL_CTX_set_default_passwd_cb_userdata(sslsock->ctx, stream); + SSL_CTX_set_default_passwd_cb(sslsock->ctx, php_openssl_passwd_callback); + } + + GET_VER_OPT_STRING("ciphers", cipherlist); +#ifndef USE_OPENSSL_SYSTEM_CIPHERS + if (!cipherlist) { + cipherlist = OPENSSL_DEFAULT_STREAM_CIPHERS; + } +#endif + if (cipherlist) { + if (SSL_CTX_set_cipher_list(sslsock->ctx, cipherlist) != 1) { + return FAILURE; + } + } + + if (GET_VER_OPT("security_level")) { +#ifdef HAVE_SEC_LEVEL + convert_to_long(val); + if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > 5) { + php_error_docref(NULL, E_WARNING, "Security level must be between 0 and 5"); + } + SSL_CTX_set_security_level(sslsock->ctx, Z_LVAL_P(val)); +#else + php_error_docref(NULL, E_WARNING, + "security_level is not supported by the linked OpenSSL library " + "- it is supported from version 1.1.0"); +#endif + } + + GET_VER_OPT_STRING("alpn_protocols", alpn_protocols); + if (alpn_protocols) { +#ifdef HAVE_TLS_ALPN + { + unsigned short alpn_len; + unsigned char *alpn = php_openssl_alpn_protos_parse(&alpn_len, alpn_protocols); + + if (alpn == NULL) { + php_error_docref(NULL, E_WARNING, "Failed parsing comma-separated TLS ALPN protocol string"); + SSL_CTX_free(sslsock->ctx); + sslsock->ctx = NULL; + return FAILURE; + } + if (sslsock->is_client) { + SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len); + } else { + sslsock->alpn_ctx.data = (unsigned char *) pestrndup((const char*)alpn, alpn_len, php_stream_is_persistent(stream)); + sslsock->alpn_ctx.len = alpn_len; + SSL_CTX_set_alpn_select_cb(sslsock->ctx, php_openssl_server_alpn_callback, sslsock); + } + + efree(alpn); + } +#else + php_error_docref(NULL, E_WARNING, + "alpn_protocols support is not compiled into the OpenSSL library against which PHP is linked"); +#endif + } + + if (FAILURE == php_openssl_set_local_cert(sslsock->ctx, stream)) { + return FAILURE; + } + + SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options); + + if (sslsock->is_client == 0 && + PHP_STREAM_CONTEXT(stream) && + FAILURE == php_openssl_set_server_specific_opts(stream, sslsock->ctx) + ) { + return FAILURE; + } + + sslsock->ssl_handle = SSL_new(sslsock->ctx); + + if (sslsock->ssl_handle == NULL) { + php_error_docref(NULL, E_WARNING, "SSL handle creation failure"); + SSL_CTX_free(sslsock->ctx); + sslsock->ctx = NULL; +#ifdef HAVE_TLS_ALPN + if (sslsock->alpn_ctx.data) { + pefree(sslsock->alpn_ctx.data, php_stream_is_persistent(stream)); + sslsock->alpn_ctx.data = NULL; + } +#endif + return FAILURE; + } else { + SSL_set_ex_data(sslsock->ssl_handle, php_openssl_get_ssl_stream_data_index(), stream); + } + + if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) { + php_openssl_handle_ssl_error(stream, 0, 1); + } + +#ifdef HAVE_TLS_SNI + /* Enable server-side SNI */ + if (!sslsock->is_client && php_openssl_enable_server_sni(stream, sslsock) == FAILURE) { + return FAILURE; + } +#endif + + /* Enable server-side handshake renegotiation rate-limiting */ + if (!sslsock->is_client) { + php_openssl_init_server_reneg_limit(stream, sslsock); + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_set_mode(sslsock->ssl_handle, SSL_get_mode(sslsock->ssl_handle) | SSL_MODE_RELEASE_BUFFERS); +#endif + + if (cparam->inputs.session) { + if (cparam->inputs.session->ops != &php_openssl_socket_ops) { + php_error_docref(NULL, E_WARNING, "supplied session stream must be an SSL enabled stream"); + } else if (((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle == NULL) { + php_error_docref(NULL, E_WARNING, "supplied SSL session stream is not initialized"); + } else { + SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle); + } + } + + return SUCCESS; +} +/* }}} */ + +static zend_array *php_openssl_capture_session_meta(SSL *ssl_handle) /* {{{ */ +{ + zval meta_arr; + char *proto_str; + long proto = SSL_version(ssl_handle); + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl_handle); + char version_str[PHP_SSL_MAX_VERSION_LEN]; + + switch (proto) { +#ifdef HAVE_TLS12 + case TLS1_2_VERSION: + proto_str = "TLSv1.2"; + break; +#endif +#ifdef HAVE_TLS11 + case TLS1_1_VERSION: + proto_str = "TLSv1.1"; + break; +#endif + case TLS1_VERSION: + proto_str = "TLSv1"; + break; +#ifdef HAVE_SSL3 + case SSL3_VERSION: + proto_str = "SSLv3"; + break; +#endif + default: proto_str = "UNKNOWN"; + } + + array_init(&meta_arr); + add_assoc_string(&meta_arr, "protocol", proto_str); + add_assoc_string(&meta_arr, "cipher_name", (char *) SSL_CIPHER_get_name(cipher)); + add_assoc_long(&meta_arr, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL)); + add_assoc_string(&meta_arr, "cipher_version", + php_openssl_cipher_get_version(cipher, version_str, PHP_SSL_MAX_VERSION_LEN)); + + return Z_ARR(meta_arr); +} +/* }}} */ + +static int php_openssl_capture_peer_certs(php_stream *stream, + php_openssl_netstream_data_t *sslsock, X509 *peer_cert) /* {{{ */ +{ + zval *val, zcert; + int cert_captured = 0; + + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_peer_cert")) && + zend_is_true(val) + ) { + ZVAL_RES(&zcert, zend_register_resource(peer_cert, php_openssl_get_x509_list_id())); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate", &zcert); + zval_ptr_dtor(&zcert); + cert_captured = 1; + } + + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_peer_cert_chain")) && + zend_is_true(val) + ) { + zval arr; + STACK_OF(X509) *chain; + + chain = SSL_get_peer_cert_chain(sslsock->ssl_handle); + + if (chain && sk_X509_num(chain) > 0) { + int i; + array_init(&arr); + + for (i = 0; i < sk_X509_num(chain); i++) { + X509 *mycert = X509_dup(sk_X509_value(chain, i)); + ZVAL_RES(&zcert, zend_register_resource(mycert, php_openssl_get_x509_list_id())); + add_next_index_zval(&arr, &zcert); + } + + } else { + ZVAL_NULL(&arr); + } + + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate_chain", &arr); + zval_ptr_dtor(&arr); + } + + return cert_captured; +} +/* }}} */ + +static int php_openssl_enable_crypto(php_stream *stream, + php_openssl_netstream_data_t *sslsock, + php_stream_xport_crypto_param *cparam) /* {{{ */ +{ + int n; + int retry = 1; + int cert_captured; + X509 *peer_cert; + + if (cparam->inputs.activate && !sslsock->ssl_active) { + struct timeval start_time, *timeout; + int blocked = sslsock->s.is_blocked, has_timeout = 0; + +#ifdef HAVE_TLS_SNI + if (sslsock->is_client) { + php_openssl_enable_client_sni(stream, sslsock); + } +#endif + + if (!sslsock->state_set) { + if (sslsock->is_client) { + SSL_set_connect_state(sslsock->ssl_handle); + } else { + SSL_set_accept_state(sslsock->ssl_handle); + } + sslsock->state_set = 1; + } + + if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0)) { + sslsock->s.is_blocked = 0; + /* The following mode are added only if we are able to change socket + * to non blocking mode which is also used for read and write */ + SSL_set_mode( + sslsock->ssl_handle, + ( + SSL_get_mode(sslsock->ssl_handle) | + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER + ) + ); + } + + timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout; + has_timeout = !sslsock->s.is_blocked && (timeout->tv_sec || timeout->tv_usec); + /* gettimeofday is not monotonic; using it here is not strictly correct */ + if (has_timeout) { + gettimeofday(&start_time, NULL); + } + + do { + struct timeval cur_time, elapsed_time; + + if (sslsock->is_client) { + n = SSL_connect(sslsock->ssl_handle); + } else { + n = SSL_accept(sslsock->ssl_handle); + } + + if (has_timeout) { + gettimeofday(&cur_time, NULL); + elapsed_time = php_openssl_subtract_timeval(cur_time, start_time); + + if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) { + php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out"); + return -1; + } + } + + if (n <= 0) { + /* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */ + retry = php_openssl_handle_ssl_error(stream, n, blocked); + if (retry) { + /* wait until something interesting happens in the socket. It may be a + * timeout. Also consider the unlikely of possibility of a write block */ + int err = SSL_get_error(sslsock->ssl_handle, n); + struct timeval left_time; + + if (has_timeout) { + left_time = php_openssl_subtract_timeval(*timeout, elapsed_time); + } + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL); + } + } else { + retry = 0; + } + } while (retry); + + if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked)) { + sslsock->s.is_blocked = blocked; + } + + if (n == 1) { + peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); + if (peer_cert && PHP_STREAM_CONTEXT(stream)) { + cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert); + } + + if (FAILURE == php_openssl_apply_peer_verification_policy(sslsock->ssl_handle, peer_cert, stream)) { + SSL_shutdown(sslsock->ssl_handle); + n = -1; + } else { + sslsock->ssl_active = 1; + + if (PHP_STREAM_CONTEXT(stream)) { + zval *val; + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), + "ssl", "capture_session_meta")) + ) { + php_error(E_DEPRECATED, + "capture_session_meta is deprecated; its information is now available via stream_get_meta_data()" + ); + } + + if (val && zend_is_true(val)) { + zval meta_arr; + ZVAL_ARR(&meta_arr, php_openssl_capture_session_meta(sslsock->ssl_handle)); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "session_meta", &meta_arr); + zval_ptr_dtor(&meta_arr); + } + } + } + } else if (errno == EAGAIN) { + n = 0; + } else { + n = -1; + /* We want to capture the peer cert even if verification fails*/ + peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); + if (peer_cert && PHP_STREAM_CONTEXT(stream)) { + cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert); + } + } + + if (n && peer_cert && cert_captured == 0) { + X509_free(peer_cert); + } + + return n; + + } else if (!cparam->inputs.activate && sslsock->ssl_active) { + /* deactivate - common for server/client */ + SSL_shutdown(sslsock->ssl_handle); + sslsock->ssl_active = 0; + } + + return -1; +} +/* }}} */ + +static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count) /* {{{ */ +{ + return php_openssl_sockop_io( 1, stream, buf, count ); +} +/* }}} */ + +static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ +{ + return php_openssl_sockop_io( 0, stream, (char*)buf, count ); +} +/* }}} */ + +/** + * Factored out common functionality (blocking, timeout, loop management) for read and write. + * Perform IO (read or write) to an SSL socket. If we have a timeout, we switch to non-blocking mode + * for the duration of the operation, using select to do our waits. If we time out, or we have an error + * report that back to PHP + */ +static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + /* Only do this if SSL is active. */ + if (sslsock->ssl_active) { + int retry = 1; + struct timeval start_time; + struct timeval *timeout = NULL; + int began_blocked = sslsock->s.is_blocked; + int has_timeout = 0; + int nr_bytes = 0; + + /* prevent overflow in openssl */ + if (count > INT_MAX) { + count = INT_MAX; + } + + /* never use a timeout with non-blocking sockets */ + if (began_blocked) { + timeout = &sslsock->s.timeout; + } + + if (timeout && php_set_sock_blocking(sslsock->s.socket, 0) == SUCCESS) { + sslsock->s.is_blocked = 0; + } + + if (!sslsock->s.is_blocked && timeout && (timeout->tv_sec || timeout->tv_usec)) { + has_timeout = 1; + /* gettimeofday is not monotonic; using it here is not strictly correct */ + gettimeofday(&start_time, NULL); + } + + /* Main IO loop. */ + do { + struct timeval cur_time, elapsed_time, left_time; + + /* If we have a timeout to check, figure out how much time has elapsed since we started. */ + if (has_timeout) { + gettimeofday(&cur_time, NULL); + + /* Determine how much time we've taken so far. */ + elapsed_time = php_openssl_subtract_timeval(cur_time, start_time); + + /* and return an error if we've taken too long. */ + if (php_openssl_compare_timeval(elapsed_time, *timeout) > 0 ) { + /* If the socket was originally blocking, set it back. */ + if (began_blocked) { + php_set_sock_blocking(sslsock->s.socket, 1); + sslsock->s.is_blocked = 1; + } + sslsock->s.timeout_event = 1; + return -1; + } + } + + /* Now, do the IO operation. Don't block if we can't complete... */ + if (read) { + nr_bytes = SSL_read(sslsock->ssl_handle, buf, (int)count); + + if (sslsock->reneg && sslsock->reneg->should_close) { + /* renegotiation rate limiting triggered */ + php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR); + nr_bytes = 0; + stream->eof = 1; + break; + } + } else { + nr_bytes = SSL_write(sslsock->ssl_handle, buf, (int)count); + } + + /* Now, how much time until we time out? */ + if (has_timeout) { + left_time = php_openssl_subtract_timeval( *timeout, elapsed_time ); + } + + /* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */ + if (nr_bytes <= 0) { + + /* Get the error code from SSL, and check to see if it's an error or not. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes ); + retry = php_openssl_handle_ssl_error(stream, nr_bytes, 0); + + /* If we get this (the above doesn't check) then we'll retry as well. */ + if (errno == EAGAIN && err == SSL_ERROR_WANT_READ && read) { + retry = 1; + } + if (errno == EAGAIN && err == SSL_ERROR_WANT_WRITE && read == 0) { + retry = 1; + } + + /* Also, on reads, we may get this condition on an EOF. We should check properly. */ + if (read) { + stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + } + + /* Don't loop indefinitely in non-blocking mode if no data is available */ + if (began_blocked == 0) { + break; + } + + /* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become + * available. Now, php_pollfd_for uses select to wait up to our time_left value only... + */ + if (retry) { + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } + } + } else { + /* Else, if we got bytes back, check for possible errors. */ + int err = SSL_get_error(sslsock->ssl_handle, nr_bytes); + + /* If we didn't get any error, then let's return it to PHP. */ + if (err == SSL_ERROR_NONE) { + break; + } + + /* Otherwise, we need to wait again (up to time_left or we get an error) */ + if (began_blocked) { + if (read) { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ? + (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL); + } else { + php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ? + (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL); + } + } + } + + /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */ + } while (retry); + + /* Tell PHP if we read / wrote bytes. */ + if (nr_bytes > 0) { + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); + } + + /* And if we were originally supposed to be blocking, let's reset the socket to that. */ + if (began_blocked && php_set_sock_blocking(sslsock->s.socket, 1) == SUCCESS) { + sslsock->s.is_blocked = 1; + } + + return 0 > nr_bytes ? 0 : nr_bytes; + } else { + size_t nr_bytes = 0; + + /* This block is if we had no timeout... We will just sit and wait forever on the IO operation. */ + if (read) { + nr_bytes = php_stream_socket_ops.read(stream, buf, count); + } else { + nr_bytes = php_stream_socket_ops.write(stream, buf, count); + } + + return nr_bytes; + } +} +/* }}} */ + +static struct timeval php_openssl_subtract_timeval(struct timeval a, struct timeval b) /* {{{ */ +{ + struct timeval difference; + + difference.tv_sec = a.tv_sec - b.tv_sec; + difference.tv_usec = a.tv_usec - b.tv_usec; + + if (a.tv_usec < b.tv_usec) { + b.tv_sec -= 1L; + b.tv_usec += 1000000L; + } + + return difference; +} +/* }}} */ + +static int php_openssl_compare_timeval( struct timeval a, struct timeval b ) +{ + if (a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec) ) { + return 1; + } else if( a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec ) { + return 0; + } else { + return -1; + } +} + +static int php_openssl_sockop_close(php_stream *stream, int close_handle) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; +#ifdef PHP_WIN32 + int n; +#endif + unsigned i; + + if (close_handle) { + if (sslsock->ssl_active) { + SSL_shutdown(sslsock->ssl_handle); + sslsock->ssl_active = 0; + } + if (sslsock->ssl_handle) { + SSL_free(sslsock->ssl_handle); + sslsock->ssl_handle = NULL; + } + if (sslsock->ctx) { + SSL_CTX_free(sslsock->ctx); + sslsock->ctx = NULL; + } +#ifdef HAVE_TLS_ALPN + if (sslsock->alpn_ctx.data) { + pefree(sslsock->alpn_ctx.data, php_stream_is_persistent(stream)); + } +#endif +#ifdef PHP_WIN32 + if (sslsock->s.socket == -1) + sslsock->s.socket = SOCK_ERR; +#endif + if (sslsock->s.socket != SOCK_ERR) { +#ifdef PHP_WIN32 + /* prevent more data from coming in */ + shutdown(sslsock->s.socket, SHUT_RD); + + /* try to make sure that the OS sends all data before we close the connection. + * Essentially, we are waiting for the socket to become writeable, which means + * that all pending data has been sent. + * We use a small timeout which should encourage the OS to send the data, + * but at the same time avoid hanging indefinitely. + * */ + do { + n = php_pollfd_for_ms(sslsock->s.socket, POLLOUT, 500); + } while (n == -1 && php_socket_errno() == EINTR); +#endif + closesocket(sslsock->s.socket); + sslsock->s.socket = SOCK_ERR; + } + } + + if (sslsock->sni_certs) { + for (i = 0; i < sslsock->sni_cert_count; i++) { + if (sslsock->sni_certs[i].ctx) { + SSL_CTX_free(sslsock->sni_certs[i].ctx); + pefree(sslsock->sni_certs[i].name, php_stream_is_persistent(stream)); + } + } + pefree(sslsock->sni_certs, php_stream_is_persistent(stream)); + sslsock->sni_certs = NULL; + } + + if (sslsock->url_name) { + pefree(sslsock->url_name, php_stream_is_persistent(stream)); + } + + if (sslsock->reneg) { + pefree(sslsock->reneg, php_stream_is_persistent(stream)); + } + + pefree(sslsock, php_stream_is_persistent(stream)); + + return 0; +} +/* }}} */ + +static int php_openssl_sockop_flush(php_stream *stream) /* {{{ */ +{ + return php_stream_socket_ops.flush(stream); +} +/* }}} */ + +static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */ +{ + return php_stream_socket_ops.stat(stream, ssb); +} +/* }}} */ + +static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock, + php_stream_xport_param *xparam STREAMS_DC) /* {{{ */ +{ + int clisock; + zend_bool nodelay = 0; + zval *tmpzval = NULL; + + xparam->outputs.client = NULL; + + if ((tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && + zend_is_true(tmpzval)) { + nodelay = 1; + } + + clisock = php_network_accept_incoming(sock->s.socket, + xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, + xparam->want_addr ? &xparam->outputs.addr : NULL, + xparam->want_addr ? &xparam->outputs.addrlen : NULL, + xparam->inputs.timeout, + xparam->want_errortext ? &xparam->outputs.error_text : NULL, + &xparam->outputs.error_code, + nodelay); + + if (clisock >= 0) { + php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata)); + + /* copy underlying tcp fields */ + memset(clisockdata, 0, sizeof(*clisockdata)); + memcpy(clisockdata, sock, sizeof(clisockdata->s)); + + clisockdata->s.socket = clisock; + + xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); + if (xparam->outputs.client) { + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; + } + } + + if (xparam->outputs.client && sock->enable_on_connect) { + /* remove the client bit */ + if (sock->method & STREAM_CRYPTO_IS_CLIENT) { + sock->method = ((sock->method >> 1) << 1); + } + + clisockdata->method = sock->method; + + if (php_stream_xport_crypto_setup(xparam->outputs.client, clisockdata->method, + NULL) < 0 || php_stream_xport_crypto_enable( + xparam->outputs.client, 1) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); + + php_stream_close(xparam->outputs.client); + xparam->outputs.client = NULL; + xparam->outputs.returncode = -1; + } + } + } + + return xparam->outputs.client == NULL ? -1 : 0; +} +/* }}} */ + +static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + php_stream_xport_crypto_param *cparam = (php_stream_xport_crypto_param *)ptrparam; + php_stream_xport_param *xparam = (php_stream_xport_param *)ptrparam; + + switch (option) { + case PHP_STREAM_OPTION_META_DATA_API: + if (sslsock->ssl_active) { + zval tmp; + char *proto_str; + char version_str[PHP_SSL_MAX_VERSION_LEN]; + const SSL_CIPHER *cipher; + + array_init(&tmp); + + switch (SSL_version(sslsock->ssl_handle)) { +#ifdef HAVE_TLS12 + case TLS1_2_VERSION: proto_str = "TLSv1.2"; break; +#endif +#ifdef HAVE_TLS11 + case TLS1_1_VERSION: proto_str = "TLSv1.1"; break; +#endif + case TLS1_VERSION: proto_str = "TLSv1"; break; +#ifdef HAVE_SSL3 + case SSL3_VERSION: proto_str = "SSLv3"; break; +#endif + default: proto_str = "UNKNOWN"; + } + + cipher = SSL_get_current_cipher(sslsock->ssl_handle); + + add_assoc_string(&tmp, "protocol", proto_str); + add_assoc_string(&tmp, "cipher_name", (char *) SSL_CIPHER_get_name(cipher)); + add_assoc_long(&tmp, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL)); + add_assoc_string(&tmp, "cipher_version", + php_openssl_cipher_get_version(cipher, version_str, PHP_SSL_MAX_VERSION_LEN)); + +#ifdef HAVE_TLS_ALPN + { + const unsigned char *alpn_proto = NULL; + unsigned int alpn_proto_len = 0; + + SSL_get0_alpn_selected(sslsock->ssl_handle, &alpn_proto, &alpn_proto_len); + if (alpn_proto) { + add_assoc_stringl(&tmp, "alpn_protocol", (char *)alpn_proto, alpn_proto_len); + } + } +#endif + add_assoc_zval((zval *)ptrparam, "crypto", &tmp); + } + + add_assoc_bool((zval *)ptrparam, "timed_out", sslsock->s.timeout_event); + add_assoc_bool((zval *)ptrparam, "blocked", sslsock->s.is_blocked); + add_assoc_bool((zval *)ptrparam, "eof", stream->eof); + + return PHP_STREAM_OPTION_RETURN_OK; + + case PHP_STREAM_OPTION_CHECK_LIVENESS: + { + struct timeval tv; + char buf; + int alive = 1; + + if (value == -1) { + if (sslsock->s.timeout.tv_sec == -1) { +#ifdef _WIN32 + tv.tv_sec = (long)FG(default_socket_timeout); +#else + tv.tv_sec = (time_t)FG(default_socket_timeout); +#endif + tv.tv_usec = 0; + } else { + tv = sslsock->connect_timeout; + } + } else { + tv.tv_sec = value; + tv.tv_usec = 0; + } + + if (sslsock->s.socket == -1) { + alive = 0; + } else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { + if (sslsock->ssl_active) { + int n; + + do { + n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf)); + if (n <= 0) { + int err = SSL_get_error(sslsock->ssl_handle, n); + + if (err == SSL_ERROR_SYSCALL) { + alive = php_socket_errno() == EAGAIN; + break; + } + + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + /* re-negotiate */ + continue; + } + + /* any other problem is a fatal error */ + alive = 0; + } + /* either peek succeeded or there was an error; we + * have set the alive flag appropriately */ + break; + } while (1); + } else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) { + alive = 0; + } + } + return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; + } + + case PHP_STREAM_OPTION_CRYPTO_API: + + switch(cparam->op) { + + case STREAM_XPORT_CRYPTO_OP_SETUP: + cparam->outputs.returncode = php_openssl_setup_crypto(stream, sslsock, cparam); + return PHP_STREAM_OPTION_RETURN_OK; + break; + case STREAM_XPORT_CRYPTO_OP_ENABLE: + cparam->outputs.returncode = php_openssl_enable_crypto(stream, sslsock, cparam); + return PHP_STREAM_OPTION_RETURN_OK; + break; + default: + /* fall through */ + break; + } + + break; + + case PHP_STREAM_OPTION_XPORT_API: + switch(xparam->op) { + + case STREAM_XPORT_OP_CONNECT: + case STREAM_XPORT_OP_CONNECT_ASYNC: + /* TODO: Async connects need to check the enable_on_connect option when + * we notice that the connect has actually been established */ + php_stream_socket_ops.set_option(stream, option, value, ptrparam); + + if ((sslsock->enable_on_connect) && + ((xparam->outputs.returncode == 0) || + (xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && + xparam->outputs.returncode == 1 && xparam->outputs.error_code == EINPROGRESS))) + { + if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL) < 0 || + php_stream_xport_crypto_enable(stream, 1) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to enable crypto"); + xparam->outputs.returncode = -1; + } + } + return PHP_STREAM_OPTION_RETURN_OK; + + case STREAM_XPORT_OP_ACCEPT: + /* we need to copy the additional fields that the underlying tcp transport + * doesn't know about */ + xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC); + + + return PHP_STREAM_OPTION_RETURN_OK; + + default: + /* fall through */ + break; + } + } + + return php_stream_socket_ops.set_option(stream, option, value, ptrparam); +} +/* }}} */ + +static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret) /* {{{ */ +{ + php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract; + + switch(castas) { + case PHP_STREAM_AS_STDIO: + if (sslsock->ssl_active) { + return FAILURE; + } + if (ret) { + *ret = fdopen(sslsock->s.socket, stream->mode); + if (*ret) { + return SUCCESS; + } + return FAILURE; + } + return SUCCESS; + + case PHP_STREAM_AS_FD_FOR_SELECT: + if (ret) { + size_t pending; + if (stream->writepos == stream->readpos + && sslsock->ssl_active + && (pending = (size_t)SSL_pending(sslsock->ssl_handle)) > 0) { + php_stream_fill_read_buffer(stream, pending < stream->chunk_size + ? pending + : stream->chunk_size); + } + + *(php_socket_t *)ret = sslsock->s.socket; + } + return SUCCESS; + + case PHP_STREAM_AS_FD: + case PHP_STREAM_AS_SOCKETD: + if (sslsock->ssl_active) { + return FAILURE; + } + if (ret) { + *(php_socket_t *)ret = sslsock->s.socket; + } + return SUCCESS; + default: + return FAILURE; + } +} +/* }}} */ + +php_stream_ops php_openssl_socket_ops = { + php_openssl_sockop_write, php_openssl_sockop_read, + php_openssl_sockop_close, php_openssl_sockop_flush, + "tcp_socket/ssl", + NULL, /* seek */ + php_openssl_sockop_cast, + php_openssl_sockop_stat, + php_openssl_sockop_set_option, +}; + +static zend_long php_openssl_get_crypto_method( + php_stream_context *ctx, zend_long crypto_method) /* {{{ */ +{ + zval *val; + + if (ctx && (val = php_stream_context_get_option(ctx, "ssl", "crypto_method")) != NULL) { + convert_to_long_ex(val); + crypto_method = (zend_long)Z_LVAL_P(val); + crypto_method |= STREAM_CRYPTO_IS_CLIENT; + } + + return crypto_method; +} +/* }}} */ + +static char *php_openssl_get_url_name(const char *resourcename, + size_t resourcenamelen, int is_persistent) /* {{{ */ +{ + php_url *url; + + if (!resourcename) { + return NULL; + } + + url = php_url_parse_ex(resourcename, resourcenamelen); + if (!url) { + return NULL; + } + + if (url->host) { + const char * host = url->host; + char * url_name = NULL; + size_t len = strlen(host); + + /* skip trailing dots */ + while (len && host[len-1] == '.') { + --len; + } + + if (len) { + url_name = pestrndup(host, len, is_persistent); + } + + php_url_free(url); + return url_name; + } + + php_url_free(url); + return NULL; +} +/* }}} */ + +php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, + const char *resourcename, size_t resourcenamelen, + const char *persistent_id, int options, int flags, + struct timeval *timeout, + php_stream_context *context STREAMS_DC) /* {{{ */ +{ + php_stream *stream = NULL; + php_openssl_netstream_data_t *sslsock = NULL; + + sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0); + memset(sslsock, 0, sizeof(*sslsock)); + + sslsock->s.is_blocked = 1; + /* this timeout is used by standard stream funcs, therefor it should use the default value */ +#ifdef _WIN32 + sslsock->s.timeout.tv_sec = (long)FG(default_socket_timeout); +#else + sslsock->s.timeout.tv_sec = (time_t)FG(default_socket_timeout); +#endif + sslsock->s.timeout.tv_usec = 0; + + /* use separate timeout for our private funcs */ + sslsock->connect_timeout.tv_sec = timeout->tv_sec; + sslsock->connect_timeout.tv_usec = timeout->tv_usec; + + /* we don't know the socket until we have determined if we are binding or + * connecting */ + sslsock->s.socket = -1; + + /* Initialize context as NULL */ + sslsock->ctx = NULL; + + stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+"); + + if (stream == NULL) { + pefree(sslsock, persistent_id ? 1 : 0); + return NULL; + } + + if (strncmp(proto, "ssl", protolen) == 0) { + sslsock->enable_on_connect = 1; + sslsock->method = php_openssl_get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT); + } else if (strncmp(proto, "sslv2", protolen) == 0) { + php_error_docref(NULL, E_WARNING, "SSLv2 unavailable in this PHP version"); + php_stream_close(stream); + return NULL; + } else if (strncmp(proto, "sslv3", protolen) == 0) { +#ifdef HAVE_SSL3 + sslsock->enable_on_connect = 1; + sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; +#else + php_error_docref(NULL, E_WARNING, + "SSLv3 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; +#endif + } else if (strncmp(proto, "tls", protolen) == 0) { + sslsock->enable_on_connect = 1; + sslsock->method = php_openssl_get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT); + } else if (strncmp(proto, "tlsv1.0", protolen) == 0) { + sslsock->enable_on_connect = 1; + sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; + } else if (strncmp(proto, "tlsv1.1", protolen) == 0) { +#ifdef HAVE_TLS11 + sslsock->enable_on_connect = 1; + sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; +#else + php_error_docref(NULL, E_WARNING, + "TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; +#endif + } else if (strncmp(proto, "tlsv1.2", protolen) == 0) { +#ifdef HAVE_TLS12 + sslsock->enable_on_connect = 1; + sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; +#else + php_error_docref(NULL, E_WARNING, + "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked"); + php_stream_close(stream); + return NULL; +#endif + } + + sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id); + + return stream; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php/gmssltest.php b/php/gmssltest.php new file mode 100644 index 00000000..16fff27b --- /dev/null +++ b/php/gmssltest.php @@ -0,0 +1,112 @@ + OPENSSL_KEYTYPE_EC, "curve_name" => "sm2p256v1")); +openssl_pkey_export($prikey, $prikeypem); +echo $prikeypem; +$pubkeypem = openssl_pkey_get_details($prikey)["key"]; +echo $pubkeypem; +$pubkey = openssl_pkey_get_public($pubkeypem); + +$point = openssl_pkey_get_details($pubkey)["ec"]; +printf("SM2 Public Key: (%s, %s)\n", bin2hex($point["x"]), bin2hex($point["y"])); +$ec = openssl_pkey_get_details($prikey)["ec"]; +printf("SM2 Private Key: %s\n", bin2hex($ec["d"])); + +openssl_sign($msg, $signature, $prikey, "sm3"); +$ok = openssl_verify($msg, $signature, $pubkey, OPENSSL_ALGO_SM3); +printf("sm2sign(\"%s\") = %s\n", $msg, bin2hex($signature)); +printf("sm2verify(\"%s\", %s) = %s\n", $msg, bin2hex($signature), $ok ? "OK" : "Failure"); + +openssl_seal($plaintext, $sealed, $ekeys, array($pubkey), "sms4", $iv); +openssl_open($sealed, $opened, $ekeys[0], $prikey, "sms4", $iv); +printf("sm2seal(\"%s\") = %s\n", $plaintext, bin2hex($sealed)); +printf("sm2open(%s) = \"%s\"\n", bin2hex($sealed), $opened); + +?>