1199 lines
39 KiB
Diff
1199 lines
39 KiB
Diff
|
From 4ca75ff1f3c341b83932f85310595f5c0a10f57e Mon Sep 17 00:00:00 2001
|
||
|
From: Remi Collet <fedora@famillecollet.com>
|
||
|
Date: Mon, 20 Mar 2017 11:45:54 +0100
|
||
|
Subject: [PATCH] backport needed changes for OpenSSL 1.1
|
||
|
|
||
|
---
|
||
|
ext/openssl/openssl.c | 528 ++++++++++++++--------
|
||
|
ext/openssl/tests/001.phpt | 7 +-
|
||
|
ext/openssl/tests/bug41033.phpt | 4 +-
|
||
|
ext/openssl/tests/bug66501.phpt | 2 +-
|
||
|
ext/openssl/tests/openssl_error_string_basic.phpt | 6 +-
|
||
|
ext/openssl/tests/sni_server.phpt | 2 +
|
||
|
ext/openssl/xp_ssl.c | 15 -
|
||
|
ext/phar/util.c | 13 +-
|
||
|
8 files changed, 371 insertions(+), 206 deletions(-)
|
||
|
|
||
|
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
|
||
|
index a78a8fb..eda68f2 100644
|
||
|
--- a/ext/openssl/openssl.c
|
||
|
+++ b/ext/openssl/openssl.c
|
||
|
@@ -68,7 +68,9 @@
|
||
|
#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
|
||
|
#if OPENSSL_VERSION_NUMBER >= 0x0090708fL
|
||
|
#define OPENSSL_ALGO_SHA224 6
|
||
|
#define OPENSSL_ALGO_SHA256 7
|
||
|
@@ -825,7 +827,8 @@ static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
|
||
|
}
|
||
|
for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
|
||
|
cnf = sk_CONF_VALUE_value(sktmp, i);
|
||
|
- if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
|
||
|
+ if (OBJ_sn2nid(cnf->name) == NID_undef && OBJ_ln2nid(cnf->name) == NID_undef &&
|
||
|
+ OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
|
||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
|
||
|
return FAILURE;
|
||
|
}
|
||
|
@@ -1053,9 +1056,11 @@ static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
|
||
|
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
|
||
|
#if OPENSSL_VERSION_NUMBER >= 0x0090708fL
|
||
|
case OPENSSL_ALGO_SHA224:
|
||
|
mdtype = (EVP_MD *) EVP_sha224();
|
||
|
@@ -1173,7 +1178,9 @@ PHP_MINIT_FUNCTION(openssl)
|
||
|
#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
|
||
|
#if OPENSSL_VERSION_NUMBER >= 0x0090708fL
|
||
|
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);
|
||
|
@@ -1893,6 +1900,7 @@ 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;
|
||
|
|
||
|
@@ -1901,8 +1909,9 @@ static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
- p = extension->value->data;
|
||
|
- length = extension->value->length;
|
||
|
+ 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)));
|
||
|
@@ -1965,6 +1974,8 @@ PHP_FUNCTION(openssl_x509_parse)
|
||
|
char * tmpstr;
|
||
|
zval * subitem;
|
||
|
X509_EXTENSION *extension;
|
||
|
+ X509_NAME *subject_name;
|
||
|
+ char *cert_name;
|
||
|
char *extname;
|
||
|
BIO *bio_out;
|
||
|
BUF_MEM *bio_buf;
|
||
|
@@ -1979,12 +1990,14 @@ PHP_FUNCTION(openssl_x509_parse)
|
||
|
}
|
||
|
array_init(return_value);
|
||
|
|
||
|
- if (cert->name) {
|
||
|
- add_assoc_string(return_value, "name", cert->name, 1);
|
||
|
- }
|
||
|
+ subject_name = X509_get_subject_name(cert);
|
||
|
+ cert_name = X509_NAME_oneline(subject_name, NULL, 0);
|
||
|
+ add_assoc_string(return_value, "name", cert_name, 1);
|
||
|
+ OPENSSL_free(cert_name);
|
||
|
+
|
||
|
/* add_assoc_bool(return_value, "valid", cert->valid); */
|
||
|
|
||
|
- add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames TSRMLS_CC);
|
||
|
+ add_assoc_name_entry(return_value, "subject", subject_name, useshortnames TSRMLS_CC);
|
||
|
/* hash as used in CA directories to lookup cert by subject name */
|
||
|
{
|
||
|
char buf[32];
|
||
|
@@ -2008,7 +2021,7 @@ PHP_FUNCTION(openssl_x509_parse)
|
||
|
add_assoc_string(return_value, "alias", tmpstr, 1);
|
||
|
}
|
||
|
|
||
|
- sig_nid = OBJ_obj2nid((cert)->sig_alg->algorithm);
|
||
|
+ sig_nid = X509_get_signature_nid(cert);
|
||
|
add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid), 1);
|
||
|
add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid), 1);
|
||
|
add_assoc_long(return_value, "signatureTypeNID", sig_nid);
|
||
|
@@ -3482,14 +3495,21 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
|
||
|
{
|
||
|
assert(pkey != NULL);
|
||
|
|
||
|
- switch (pkey->type) {
|
||
|
+ switch (EVP_PKEY_id(pkey)) {
|
||
|
#ifndef NO_RSA
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
- assert(pkey->pkey.rsa != NULL);
|
||
|
- if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q)) {
|
||
|
- return 0;
|
||
|
- }
|
||
|
+ {
|
||
|
+ 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;
|
||
|
#endif
|
||
|
#ifndef NO_DSA
|
||
|
@@ -3498,29 +3518,50 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
|
||
|
case EVP_PKEY_DSA2:
|
||
|
case EVP_PKEY_DSA3:
|
||
|
case EVP_PKEY_DSA4:
|
||
|
- assert(pkey->pkey.dsa != NULL);
|
||
|
-
|
||
|
- if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){
|
||
|
- return 0;
|
||
|
- }
|
||
|
+ {
|
||
|
+ 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;
|
||
|
#endif
|
||
|
#ifndef NO_DH
|
||
|
case EVP_PKEY_DH:
|
||
|
- assert(pkey->pkey.dh != NULL);
|
||
|
-
|
||
|
- if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key) {
|
||
|
- return 0;
|
||
|
- }
|
||
|
+ {
|
||
|
+ 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;
|
||
|
#endif
|
||
|
#ifdef HAVE_EVP_PKEY_EC
|
||
|
case EVP_PKEY_EC:
|
||
|
- assert(pkey->pkey.ec != NULL);
|
||
|
-
|
||
|
- if ( NULL == EC_KEY_get0_private_key(pkey->pkey.ec)) {
|
||
|
- return 0;
|
||
|
- }
|
||
|
+ {
|
||
|
+ EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
|
||
|
+ if (ec != NULL && NULL == EC_KEY_get0_private_key(ec)) {
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
@@ -3531,42 +3572,91 @@ static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
-#define OPENSSL_PKEY_GET_BN(_type, _name) do { \
|
||
|
- if (pkey->pkey._type->_name != NULL) { \
|
||
|
- int len = BN_num_bytes(pkey->pkey._type->_name); \
|
||
|
+#define OPENSSL_GET_BN(_array, _bn, _name) do { \
|
||
|
+ if (_bn != NULL) { \
|
||
|
+ int len = BN_num_bytes(_bn); \
|
||
|
char *str = emalloc(len + 1); \
|
||
|
- BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)str); \
|
||
|
+ BN_bn2bin(_bn, (unsigned char*)str); \
|
||
|
str[len] = 0; \
|
||
|
- add_assoc_stringl(_type, #_name, str, len, 0); \
|
||
|
+ add_assoc_stringl(_array, #_name, str, len, 0); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
-#define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \
|
||
|
+#define OPENSSL_PKEY_GET_BN(_type, _name) OPENSSL_GET_BN(_type, _name, _name)
|
||
|
+
|
||
|
+#define OPENSSL_PKEY_SET_BN(_data, _name) do { \
|
||
|
zval **bn; \
|
||
|
- if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \
|
||
|
+ if (zend_hash_find(Z_ARRVAL_P(_data), #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \
|
||
|
Z_TYPE_PP(bn) == IS_STRING) { \
|
||
|
- _type->_name = BN_bin2bn( \
|
||
|
+ _name = BN_bin2bn( \
|
||
|
(unsigned char*)Z_STRVAL_PP(bn), \
|
||
|
Z_STRLEN_PP(bn), NULL); \
|
||
|
+ } else { \
|
||
|
+ _name = NULL; \
|
||
|
} \
|
||
|
} while (0);
|
||
|
|
||
|
-/* {{{ php_openssl_pkey_init_dsa */
|
||
|
-zend_bool php_openssl_pkey_init_dsa(DSA *dsa)
|
||
|
+/* {{{ php_openssl_pkey_init_rsa */
|
||
|
+zend_bool php_openssl_pkey_init_and_assign_rsa(EVP_PKEY *pkey, RSA *rsa, zval *data)
|
||
|
{
|
||
|
- if (!dsa->p || !dsa->q || !dsa->g) {
|
||
|
+ 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;
|
||
|
}
|
||
|
- if (dsa->priv_key || dsa->pub_key) {
|
||
|
- return 1;
|
||
|
+
|
||
|
+ 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)) {
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+/* {{{ php_openssl_pkey_init_dsa */
|
||
|
+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)) {
|
||
|
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 */
|
||
|
- if (!dsa->pub_key || BN_is_zero(dsa->pub_key)) {
|
||
|
+ DSA_get0_key(dsa, &pub_key_const, &priv_key_const);
|
||
|
+ if (!pub_key_const || BN_is_zero(pub_key_const)) {
|
||
|
return 0;
|
||
|
}
|
||
|
/* all good */
|
||
|
@@ -3574,15 +3664,69 @@ zend_bool php_openssl_pkey_init_dsa(DSA *dsa)
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
+/* {{{ 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) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ priv_key_const_time = BN_new();
|
||
|
+ if (priv_key_const_time == NULL) {
|
||
|
+ BN_free(pub_key);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ ctx = BN_CTX_new();
|
||
|
+ if (ctx == NULL) {
|
||
|
+ BN_free(pub_key);
|
||
|
+ BN_free(priv_key_const_time);
|
||
|
+ 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);
|
||
|
+ pub_key = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ BN_free(priv_key_const_time);
|
||
|
+ BN_CTX_free(ctx);
|
||
|
+
|
||
|
+ return pub_key;
|
||
|
+}
|
||
|
+/* }}} */
|
||
|
+
|
||
|
/* {{{ php_openssl_pkey_init_dh */
|
||
|
-zend_bool php_openssl_pkey_init_dh(DH *dh)
|
||
|
+zend_bool php_openssl_pkey_init_dh(DH *dh, zval *data)
|
||
|
{
|
||
|
- if (!dh->p || !dh->g) {
|
||
|
+ 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;
|
||
|
}
|
||
|
- if (dh->pub_key) {
|
||
|
- return 1;
|
||
|
+
|
||
|
+ 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)) {
|
||
|
return 0;
|
||
|
@@ -3614,18 +3758,8 @@ PHP_FUNCTION(openssl_pkey_new)
|
||
|
if (pkey) {
|
||
|
RSA *rsa = RSA_new();
|
||
|
if (rsa) {
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, n);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, e);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, d);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, p);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, q);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmp1);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmq1);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp);
|
||
|
- if (rsa->n && rsa->d) {
|
||
|
- if (EVP_PKEY_assign_RSA(pkey, rsa)) {
|
||
|
- RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
|
||
|
- }
|
||
|
+ if (php_openssl_pkey_init_and_assign_rsa(pkey, rsa, *data)) {
|
||
|
+ RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
|
||
|
}
|
||
|
RSA_free(rsa);
|
||
|
}
|
||
|
@@ -3638,12 +3772,7 @@ PHP_FUNCTION(openssl_pkey_new)
|
||
|
if (pkey) {
|
||
|
DSA *dsa = DSA_new();
|
||
|
if (dsa) {
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, p);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, q);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, g);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, priv_key);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, pub_key);
|
||
|
- if (php_openssl_pkey_init_dsa(dsa)) {
|
||
|
+ if (php_openssl_pkey_init_dsa(dsa, *data)) {
|
||
|
if (EVP_PKEY_assign_DSA(pkey, dsa)) {
|
||
|
RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
|
||
|
}
|
||
|
@@ -3659,11 +3788,7 @@ PHP_FUNCTION(openssl_pkey_new)
|
||
|
if (pkey) {
|
||
|
DH *dh = DH_new();
|
||
|
if (dh) {
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, p);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, g);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, priv_key);
|
||
|
- OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, pub_key);
|
||
|
- if (php_openssl_pkey_init_dh(dh)) {
|
||
|
+ if (php_openssl_pkey_init_dh(dh, *data)) {
|
||
|
if (EVP_PKEY_assign_DH(pkey, dh)) {
|
||
|
RETURN_RESOURCE(zend_list_insert(pkey, le_key TSRMLS_CC));
|
||
|
}
|
||
|
@@ -3738,7 +3863,7 @@ PHP_FUNCTION(openssl_pkey_export_to_file)
|
||
|
cipher = NULL;
|
||
|
}
|
||
|
|
||
|
- switch (EVP_PKEY_type(key->type)) {
|
||
|
+ 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_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL);
|
||
|
@@ -3807,7 +3932,7 @@ PHP_FUNCTION(openssl_pkey_export)
|
||
|
cipher = NULL;
|
||
|
}
|
||
|
|
||
|
- switch (EVP_PKEY_type(key->type)) {
|
||
|
+ 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_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL);
|
||
|
@@ -3928,68 +4053,88 @@ PHP_FUNCTION(openssl_pkey_get_details)
|
||
|
/*TODO: Use the real values once the openssl constants are used
|
||
|
* See the enum at the top of this file
|
||
|
*/
|
||
|
- switch (EVP_PKEY_type(pkey->type)) {
|
||
|
+ switch (EVP_PKEY_base_id(pkey)) {
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
- ktype = OPENSSL_KEYTYPE_RSA;
|
||
|
-
|
||
|
- if (pkey->pkey.rsa != NULL) {
|
||
|
- zval *rsa;
|
||
|
-
|
||
|
- ALLOC_INIT_ZVAL(rsa);
|
||
|
- array_init(rsa);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, n);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, e);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, d);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, p);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, q);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, dmp1);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, dmq1);
|
||
|
- OPENSSL_PKEY_GET_BN(rsa, iqmp);
|
||
|
- add_assoc_zval(return_value, "rsa", rsa);
|
||
|
- }
|
||
|
+ {
|
||
|
+ 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);
|
||
|
+
|
||
|
+ ALLOC_INIT_ZVAL(z_rsa);
|
||
|
+ 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:
|
||
|
- ktype = OPENSSL_KEYTYPE_DSA;
|
||
|
-
|
||
|
- if (pkey->pkey.dsa != NULL) {
|
||
|
- zval *dsa;
|
||
|
-
|
||
|
- ALLOC_INIT_ZVAL(dsa);
|
||
|
- array_init(dsa);
|
||
|
- OPENSSL_PKEY_GET_BN(dsa, p);
|
||
|
- OPENSSL_PKEY_GET_BN(dsa, q);
|
||
|
- OPENSSL_PKEY_GET_BN(dsa, g);
|
||
|
- OPENSSL_PKEY_GET_BN(dsa, priv_key);
|
||
|
- OPENSSL_PKEY_GET_BN(dsa, pub_key);
|
||
|
- add_assoc_zval(return_value, "dsa", dsa);
|
||
|
- }
|
||
|
+ {
|
||
|
+ 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);
|
||
|
+
|
||
|
+ ALLOC_INIT_ZVAL(z_dsa);
|
||
|
+ 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:
|
||
|
-
|
||
|
- ktype = OPENSSL_KEYTYPE_DH;
|
||
|
-
|
||
|
- if (pkey->pkey.dh != NULL) {
|
||
|
- zval *dh;
|
||
|
-
|
||
|
- ALLOC_INIT_ZVAL(dh);
|
||
|
- array_init(dh);
|
||
|
- OPENSSL_PKEY_GET_BN(dh, p);
|
||
|
- OPENSSL_PKEY_GET_BN(dh, g);
|
||
|
- OPENSSL_PKEY_GET_BN(dh, priv_key);
|
||
|
- OPENSSL_PKEY_GET_BN(dh, pub_key);
|
||
|
- add_assoc_zval(return_value, "dh", 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);
|
||
|
+
|
||
|
+ ALLOC_INIT_ZVAL(z_dh);
|
||
|
+ 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 (pkey->pkey.ec != NULL) {
|
||
|
+ if (EVP_PKEY_get0_EC_KEY(pkey) != NULL) {
|
||
|
zval *ec;
|
||
|
const EC_GROUP *ec_group;
|
||
|
int nid;
|
||
|
@@ -4546,13 +4691,13 @@ PHP_FUNCTION(openssl_private_encrypt)
|
||
|
cryptedlen = EVP_PKEY_size(pkey);
|
||
|
cryptedbuf = emalloc(cryptedlen + 1);
|
||
|
|
||
|
- switch (pkey->type) {
|
||
|
+ switch (EVP_PKEY_id(pkey)) {
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
successful = (RSA_private_encrypt(data_len,
|
||
|
(unsigned char *)data,
|
||
|
cryptedbuf,
|
||
|
- pkey->pkey.rsa,
|
||
|
+ EVP_PKEY_get0_RSA(pkey),
|
||
|
padding) == cryptedlen);
|
||
|
break;
|
||
|
default:
|
||
|
@@ -4604,13 +4749,13 @@ PHP_FUNCTION(openssl_private_decrypt)
|
||
|
cryptedlen = EVP_PKEY_size(pkey);
|
||
|
crypttemp = emalloc(cryptedlen + 1);
|
||
|
|
||
|
- switch (pkey->type) {
|
||
|
+ switch (EVP_PKEY_id(pkey)) {
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
cryptedlen = RSA_private_decrypt(data_len,
|
||
|
(unsigned char *)data,
|
||
|
crypttemp,
|
||
|
- pkey->pkey.rsa,
|
||
|
+ EVP_PKEY_get0_RSA(pkey),
|
||
|
padding);
|
||
|
if (cryptedlen != -1) {
|
||
|
cryptedbuf = emalloc(cryptedlen + 1);
|
||
|
@@ -4669,13 +4814,13 @@ PHP_FUNCTION(openssl_public_encrypt)
|
||
|
cryptedlen = EVP_PKEY_size(pkey);
|
||
|
cryptedbuf = emalloc(cryptedlen + 1);
|
||
|
|
||
|
- switch (pkey->type) {
|
||
|
+ switch (EVP_PKEY_id(pkey)) {
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
successful = (RSA_public_encrypt(data_len,
|
||
|
(unsigned char *)data,
|
||
|
cryptedbuf,
|
||
|
- pkey->pkey.rsa,
|
||
|
+ EVP_PKEY_get0_RSA(pkey),
|
||
|
padding) == cryptedlen);
|
||
|
break;
|
||
|
default:
|
||
|
@@ -4728,13 +4873,13 @@ PHP_FUNCTION(openssl_public_decrypt)
|
||
|
cryptedlen = EVP_PKEY_size(pkey);
|
||
|
crypttemp = emalloc(cryptedlen + 1);
|
||
|
|
||
|
- switch (pkey->type) {
|
||
|
+ switch (EVP_PKEY_id(pkey)) {
|
||
|
case EVP_PKEY_RSA:
|
||
|
case EVP_PKEY_RSA2:
|
||
|
cryptedlen = RSA_public_decrypt(data_len,
|
||
|
(unsigned char *)data,
|
||
|
crypttemp,
|
||
|
- pkey->pkey.rsa,
|
||
|
+ EVP_PKEY_get0_RSA(pkey),
|
||
|
padding);
|
||
|
if (cryptedlen != -1) {
|
||
|
cryptedbuf = emalloc(cryptedlen + 1);
|
||
|
@@ -4798,7 +4943,7 @@ PHP_FUNCTION(openssl_sign)
|
||
|
long keyresource = -1;
|
||
|
char * data;
|
||
|
int data_len;
|
||
|
- EVP_MD_CTX md_ctx;
|
||
|
+ EVP_MD_CTX *md_ctx;
|
||
|
zval *method = NULL;
|
||
|
long signature_algo = OPENSSL_ALGO_SHA1;
|
||
|
const EVP_MD *mdtype;
|
||
|
@@ -4831,9 +4976,11 @@ PHP_FUNCTION(openssl_sign)
|
||
|
siglen = EVP_PKEY_size(pkey);
|
||
|
sigbuf = emalloc(siglen + 1);
|
||
|
|
||
|
- EVP_SignInit(&md_ctx, mdtype);
|
||
|
- EVP_SignUpdate(&md_ctx, data, data_len);
|
||
|
- if (EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) {
|
||
|
+ md_ctx = EVP_MD_CTX_create();
|
||
|
+ if (md_ctx != NULL &&
|
||
|
+ EVP_SignInit(md_ctx, mdtype) &&
|
||
|
+ EVP_SignUpdate(md_ctx, data, data_len) &&
|
||
|
+ EVP_SignFinal(md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) {
|
||
|
zval_dtor(signature);
|
||
|
sigbuf[siglen] = '\0';
|
||
|
ZVAL_STRINGL(signature, (char *)sigbuf, siglen, 0);
|
||
|
@@ -4842,7 +4989,7 @@ PHP_FUNCTION(openssl_sign)
|
||
|
efree(sigbuf);
|
||
|
RETVAL_FALSE;
|
||
|
}
|
||
|
- EVP_MD_CTX_cleanup(&md_ctx);
|
||
|
+ EVP_MD_CTX_destroy(md_ctx);
|
||
|
if (keyresource == -1) {
|
||
|
EVP_PKEY_free(pkey);
|
||
|
}
|
||
|
@@ -4855,8 +5002,8 @@ PHP_FUNCTION(openssl_verify)
|
||
|
{
|
||
|
zval **key;
|
||
|
EVP_PKEY *pkey;
|
||
|
- int err;
|
||
|
- EVP_MD_CTX md_ctx;
|
||
|
+ int err = 0;
|
||
|
+ EVP_MD_CTX *md_ctx;
|
||
|
const EVP_MD *mdtype;
|
||
|
long keyresource = -1;
|
||
|
char * data; int data_len;
|
||
|
@@ -4890,10 +5037,13 @@ PHP_FUNCTION(openssl_verify)
|
||
|
RETURN_FALSE;
|
||
|
}
|
||
|
|
||
|
- EVP_VerifyInit (&md_ctx, mdtype);
|
||
|
- EVP_VerifyUpdate (&md_ctx, data, data_len);
|
||
|
- err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
|
||
|
- EVP_MD_CTX_cleanup(&md_ctx);
|
||
|
+ md_ctx = EVP_MD_CTX_create();
|
||
|
+ if (md_ctx) {
|
||
|
+ EVP_VerifyInit (md_ctx, mdtype);
|
||
|
+ EVP_VerifyUpdate (md_ctx, data, data_len);
|
||
|
+ err = EVP_VerifyFinal(md_ctx, (unsigned char *)signature, signature_len, pkey);
|
||
|
+ }
|
||
|
+ EVP_MD_CTX_destroy(md_ctx);
|
||
|
|
||
|
if (keyresource == -1) {
|
||
|
EVP_PKEY_free(pkey);
|
||
|
@@ -4917,7 +5067,7 @@ PHP_FUNCTION(openssl_seal)
|
||
|
char *method =NULL;
|
||
|
int method_len = 0;
|
||
|
const EVP_CIPHER *cipher;
|
||
|
- EVP_CIPHER_CTX ctx;
|
||
|
+ EVP_CIPHER_CTX *ctx;
|
||
|
|
||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
|
||
|
return;
|
||
|
@@ -4967,9 +5117,10 @@ PHP_FUNCTION(openssl_seal)
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
- if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
|
||
|
+ ctx = EVP_CIPHER_CTX_new();
|
||
|
+ if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) {
|
||
|
RETVAL_FALSE;
|
||
|
- EVP_CIPHER_CTX_cleanup(&ctx);
|
||
|
+ EVP_CIPHER_CTX_free(ctx);
|
||
|
goto clean_exit;
|
||
|
}
|
||
|
|
||
|
@@ -4979,15 +5130,15 @@ PHP_FUNCTION(openssl_seal)
|
||
|
iv = ivlen ? emalloc(ivlen + 1) : NULL;
|
||
|
#endif
|
||
|
/* allocate one byte extra to make room for \0 */
|
||
|
- buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
|
||
|
- EVP_CIPHER_CTX_cleanup(&ctx);
|
||
|
+ buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(ctx));
|
||
|
+ EVP_CIPHER_CTX_cleanup(ctx);
|
||
|
|
||
|
- if (EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) <= 0 ||
|
||
|
- !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len) ||
|
||
|
- !EVP_SealFinal(&ctx, buf + len1, &len2)) {
|
||
|
+ if (EVP_SealInit(ctx, cipher, eks, eksl, NULL, pkeys, nkeys) <= 0 ||
|
||
|
+ !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, data_len) ||
|
||
|
+ !EVP_SealFinal(ctx, buf + len1, &len2)) {
|
||
|
RETVAL_FALSE;
|
||
|
efree(buf);
|
||
|
- EVP_CIPHER_CTX_cleanup(&ctx);
|
||
|
+ EVP_CIPHER_CTX_free(ctx);
|
||
|
goto clean_exit;
|
||
|
}
|
||
|
|
||
|
@@ -5018,7 +5169,7 @@ PHP_FUNCTION(openssl_seal)
|
||
|
efree(buf);
|
||
|
}
|
||
|
RETVAL_LONG(len1 + len2);
|
||
|
- EVP_CIPHER_CTX_cleanup(&ctx);
|
||
|
+ EVP_CIPHER_CTX_free(ctx);
|
||
|
|
||
|
clean_exit:
|
||
|
for (i=0; i<nkeys; i++) {
|
||
|
@@ -5045,7 +5196,7 @@ PHP_FUNCTION(openssl_open)
|
||
|
int len1, len2;
|
||
|
unsigned char *buf;
|
||
|
long keyresource = -1;
|
||
|
- EVP_CIPHER_CTX ctx;
|
||
|
+ EVP_CIPHER_CTX *ctx;
|
||
|
char * data; int data_len;
|
||
|
char * ekey; int ekey_len;
|
||
|
char *method =NULL;
|
||
|
@@ -5074,8 +5225,10 @@ PHP_FUNCTION(openssl_open)
|
||
|
|
||
|
buf = emalloc(data_len + 1);
|
||
|
|
||
|
- if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
|
||
|
- if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
|
||
|
+ ctx = EVP_CIPHER_CTX_new();
|
||
|
+ if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, NULL, pkey) &&
|
||
|
+ EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, data_len)) {
|
||
|
+ if (!EVP_OpenFinal(ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
|
||
|
efree(buf);
|
||
|
RETVAL_FALSE;
|
||
|
} else {
|
||
|
@@ -5091,7 +5244,7 @@ PHP_FUNCTION(openssl_open)
|
||
|
if (keyresource == -1) {
|
||
|
EVP_PKEY_free(pkey);
|
||
|
}
|
||
|
- EVP_CIPHER_CTX_cleanup(&ctx);
|
||
|
+ EVP_CIPHER_CTX_free(ctx);
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
@@ -5151,7 +5304,7 @@ PHP_FUNCTION(openssl_digest)
|
||
|
char *data, *method;
|
||
|
int data_len, method_len;
|
||
|
const EVP_MD *mdtype;
|
||
|
- EVP_MD_CTX md_ctx;
|
||
|
+ EVP_MD_CTX *md_ctx;
|
||
|
int siglen;
|
||
|
unsigned char *sigbuf;
|
||
|
|
||
|
@@ -5167,9 +5320,10 @@ PHP_FUNCTION(openssl_digest)
|
||
|
siglen = EVP_MD_size(mdtype);
|
||
|
sigbuf = emalloc(siglen + 1);
|
||
|
|
||
|
- EVP_DigestInit(&md_ctx, mdtype);
|
||
|
- EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
|
||
|
- if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int *)&siglen)) {
|
||
|
+ 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 *)sigbuf, (unsigned int *)&siglen)) {
|
||
|
if (raw_output) {
|
||
|
sigbuf[siglen] = '\0';
|
||
|
RETVAL_STRINGL((char *)sigbuf, siglen, 0);
|
||
|
@@ -5185,6 +5339,8 @@ PHP_FUNCTION(openssl_digest)
|
||
|
efree(sigbuf);
|
||
|
RETVAL_FALSE;
|
||
|
}
|
||
|
+
|
||
|
+ EVP_MD_CTX_destroy(md_ctx);
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
@@ -5230,7 +5386,7 @@ PHP_FUNCTION(openssl_encrypt)
|
||
|
char *data, *method, *password, *iv = "";
|
||
|
int data_len, method_len, password_len, iv_len = 0, max_iv_len;
|
||
|
const EVP_CIPHER *cipher_type;
|
||
|
- EVP_CIPHER_CTX cipher_ctx;
|
||
|
+ EVP_CIPHER_CTX *cipher_ctx;
|
||
|
int i=0, outlen, keylen;
|
||
|
unsigned char *outbuf, *key;
|
||
|
zend_bool free_iv;
|
||
|
@@ -5244,6 +5400,12 @@ PHP_FUNCTION(openssl_encrypt)
|
||
|
RETURN_FALSE;
|
||
|
}
|
||
|
|
||
|
+ cipher_ctx = EVP_CIPHER_CTX_new();
|
||
|
+ if (!cipher_ctx) {
|
||
|
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create cipher context");
|
||
|
+ RETURN_FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
keylen = EVP_CIPHER_key_length(cipher_type);
|
||
|
if (keylen > password_len) {
|
||
|
key = emalloc(keylen);
|
||
|
@@ -5262,19 +5424,19 @@ PHP_FUNCTION(openssl_encrypt)
|
||
|
outlen = data_len + EVP_CIPHER_block_size(cipher_type);
|
||
|
outbuf = safe_emalloc(outlen, 1, 1);
|
||
|
|
||
|
- EVP_EncryptInit(&cipher_ctx, cipher_type, NULL, NULL);
|
||
|
+ EVP_EncryptInit(cipher_ctx, cipher_type, NULL, NULL);
|
||
|
if (password_len > keylen) {
|
||
|
- EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
|
||
|
+ EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len);
|
||
|
}
|
||
|
- EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
|
||
|
+ EVP_EncryptInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
|
||
|
if (options & OPENSSL_ZERO_PADDING) {
|
||
|
- EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
|
||
|
+ EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
|
||
|
}
|
||
|
if (data_len > 0) {
|
||
|
- EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
|
||
|
+ EVP_EncryptUpdate(cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
|
||
|
}
|
||
|
outlen = i;
|
||
|
- if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
|
||
|
+ if (EVP_EncryptFinal(cipher_ctx, (unsigned char *)outbuf + i, &i)) {
|
||
|
outlen += i;
|
||
|
if (options & OPENSSL_RAW_DATA) {
|
||
|
outbuf[outlen] = '\0';
|
||
|
@@ -5301,7 +5463,7 @@ PHP_FUNCTION(openssl_encrypt)
|
||
|
if (free_iv) {
|
||
|
efree(iv);
|
||
|
}
|
||
|
- EVP_CIPHER_CTX_cleanup(&cipher_ctx);
|
||
|
+ EVP_CIPHER_CTX_free(cipher_ctx);
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
@@ -5313,7 +5475,7 @@ PHP_FUNCTION(openssl_decrypt)
|
||
|
char *data, *method, *password, *iv = "";
|
||
|
int data_len, method_len, password_len, iv_len = 0;
|
||
|
const EVP_CIPHER *cipher_type;
|
||
|
- EVP_CIPHER_CTX cipher_ctx;
|
||
|
+ EVP_CIPHER_CTX *cipher_ctx;
|
||
|
int i, outlen, keylen;
|
||
|
unsigned char *outbuf, *key;
|
||
|
int base64_str_len;
|
||
|
@@ -5335,10 +5497,17 @@ PHP_FUNCTION(openssl_decrypt)
|
||
|
RETURN_FALSE;
|
||
|
}
|
||
|
|
||
|
+ cipher_ctx = EVP_CIPHER_CTX_new();
|
||
|
+ if (!cipher_ctx) {
|
||
|
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create cipher context");
|
||
|
+ RETURN_FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
if (!(options & OPENSSL_RAW_DATA)) {
|
||
|
base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len);
|
||
|
if (!base64_str) {
|
||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to base64 decode the input");
|
||
|
+ EVP_CIPHER_CTX_free(cipher_ctx);
|
||
|
RETURN_FALSE;
|
||
|
}
|
||
|
data_len = base64_str_len;
|
||
|
@@ -5359,17 +5528,17 @@ PHP_FUNCTION(openssl_decrypt)
|
||
|
outlen = data_len + EVP_CIPHER_block_size(cipher_type);
|
||
|
outbuf = emalloc(outlen + 1);
|
||
|
|
||
|
- EVP_DecryptInit(&cipher_ctx, cipher_type, NULL, NULL);
|
||
|
+ EVP_DecryptInit(cipher_ctx, cipher_type, NULL, NULL);
|
||
|
if (password_len > keylen) {
|
||
|
- EVP_CIPHER_CTX_set_key_length(&cipher_ctx, password_len);
|
||
|
+ EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len);
|
||
|
}
|
||
|
- EVP_DecryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
|
||
|
+ EVP_DecryptInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
|
||
|
if (options & OPENSSL_ZERO_PADDING) {
|
||
|
- EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
|
||
|
+ EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
|
||
|
}
|
||
|
- EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
|
||
|
+ EVP_DecryptUpdate(cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
|
||
|
outlen = i;
|
||
|
- if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
|
||
|
+ if (EVP_DecryptFinal(cipher_ctx, (unsigned char *)outbuf + i, &i)) {
|
||
|
outlen += i;
|
||
|
outbuf[outlen] = '\0';
|
||
|
RETVAL_STRINGL((char *)outbuf, outlen, 0);
|
||
|
@@ -5386,7 +5555,7 @@ PHP_FUNCTION(openssl_decrypt)
|
||
|
if (base64_str) {
|
||
|
efree(base64_str);
|
||
|
}
|
||
|
- EVP_CIPHER_CTX_cleanup(&cipher_ctx);
|
||
|
+ EVP_CIPHER_CTX_free(cipher_ctx);
|
||
|
}
|
||
|
/* }}} */
|
||
|
|
||
|
@@ -5424,6 +5593,7 @@ PHP_FUNCTION(openssl_dh_compute_key)
|
||
|
zval *key;
|
||
|
char *pub_str;
|
||
|
int pub_len;
|
||
|
+ DH *dh;
|
||
|
EVP_PKEY *pkey;
|
||
|
BIGNUM *pub;
|
||
|
char *data;
|
||
|
@@ -5433,14 +5603,20 @@ PHP_FUNCTION(openssl_dh_compute_key)
|
||
|
return;
|
||
|
}
|
||
|
ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
|
||
|
- if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
|
||
|
+ if (!pkey) {
|
||
|
RETURN_FALSE;
|
||
|
}
|
||
|
-
|
||
|
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
|
||
|
+ RETURN_FALSE;
|
||
|
+ }
|
||
|
+ dh = EVP_PKEY_get0_DH(pkey);
|
||
|
+ if (dh == NULL) {
|
||
|
+ RETURN_FALSE;
|
||
|
+ }
|
||
|
pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
|
||
|
|
||
|
- data = emalloc(DH_size(pkey->pkey.dh) + 1);
|
||
|
- len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
|
||
|
+ data = emalloc(DH_size(dh) + 1);
|
||
|
+ len = DH_compute_key((unsigned char*)data, pub, dh);
|
||
|
|
||
|
if (len >= 0) {
|
||
|
data[len] = 0;
|
||
|
diff --git a/ext/openssl/tests/001.phpt b/ext/openssl/tests/001.phpt
|
||
|
index 4ca9970..2d0aa90 100644
|
||
|
--- a/ext/openssl/tests/001.phpt
|
||
|
+++ b/ext/openssl/tests/001.phpt
|
||
|
@@ -18,19 +18,20 @@ for ($z = "", $i = 0; $i < 1024; $i++) {
|
||
|
usleep($i);
|
||
|
}
|
||
|
|
||
|
-$privkey = openssl_pkey_new();
|
||
|
+$conf = array('config' => 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("/tmp", "ssl");
|
||
|
+$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) or die("failed to export to file $key_file_name");
|
||
|
+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";
|
||
|
|
||
|
diff --git a/ext/openssl/tests/bug41033.phpt b/ext/openssl/tests/bug41033.phpt
|
||
|
index 4aeae66..4e9bea3 100644
|
||
|
--- a/ext/openssl/tests/bug41033.phpt
|
||
|
+++ b/ext/openssl/tests/bug41033.phpt
|
||
|
@@ -13,11 +13,11 @@ $pub = 'file://' . dirname(__FILE__) . '/' . 'bug41033pub.pem';
|
||
|
|
||
|
$prkeyid = openssl_get_privatekey($prv, "1234");
|
||
|
$ct = "Hello I am some text!";
|
||
|
-openssl_sign($ct, $signature, $prkeyid, OPENSSL_ALGO_DSS1);
|
||
|
+openssl_sign($ct, $signature, $prkeyid, OPENSSL_ALGO_SHA1);
|
||
|
echo "Signature: ".base64_encode($signature) . "\n";
|
||
|
|
||
|
$pukeyid = openssl_get_publickey($pub);
|
||
|
-$valid = openssl_verify($ct, $signature, $pukeyid, OPENSSL_ALGO_DSS1);
|
||
|
+$valid = openssl_verify($ct, $signature, $pukeyid, OPENSSL_ALGO_SHA1);
|
||
|
echo "Signature validity: " . $valid . "\n";
|
||
|
|
||
|
|
||
|
diff --git a/ext/openssl/tests/bug66501.phpt b/ext/openssl/tests/bug66501.phpt
|
||
|
index 7ad5e21..99ac4f5 100644
|
||
|
--- a/ext/openssl/tests/bug66501.phpt
|
||
|
+++ b/ext/openssl/tests/bug66501.phpt
|
||
|
@@ -16,7 +16,7 @@ AwEHoUQDQgAEPq4hbIWHvB51rdWr8ejrjWo4qVNWVugYFtPg/xLQw0mHkIPZ4DvK
|
||
|
sqOTOnMoezkbSmVVMuwz9flvnqHGmQvmug==
|
||
|
-----END EC PRIVATE KEY-----';
|
||
|
$key = openssl_pkey_get_private($pkey);
|
||
|
-$res = openssl_sign($data ='alpha', $sign, $key, 'ecdsa-with-SHA1');
|
||
|
+$res = openssl_sign($data ='alpha', $sign, $key, 'SHA1');
|
||
|
var_dump($res);
|
||
|
--EXPECTF--
|
||
|
bool(true)
|
||
|
diff --git a/ext/openssl/tests/openssl_error_string_basic.phpt b/ext/openssl/tests/openssl_error_string_basic.phpt
|
||
|
index 82f3099..04cc550 100644
|
||
|
--- a/ext/openssl/tests/openssl_error_string_basic.phpt
|
||
|
+++ b/ext/openssl/tests/openssl_error_string_basic.phpt
|
||
|
@@ -89,7 +89,7 @@ expect_openssl_errors('openssl_pkey_export_to_file opening', ['02001002', '2006D
|
||
|
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', '09072007']);
|
||
|
+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']);
|
||
|
@@ -105,7 +105,7 @@ 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', '0407006A', '04067072']);
|
||
|
+expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0906D06C', '04068076', '04067072']);
|
||
|
|
||
|
// X509
|
||
|
echo "X509 errors\n";
|
||
|
@@ -126,7 +126,7 @@ expect_openssl_errors('openssl_x509_checkpurpose purpose', ['0B086079']);
|
||
|
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', '20068079', '0906D06C']);
|
||
|
+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']);
|
||
|
diff --git a/ext/openssl/tests/sni_server.phpt b/ext/openssl/tests/sni_server.phpt
|
||
|
index d44a69f..2d045df 100644
|
||
|
--- a/ext/openssl/tests/sni_server.phpt
|
||
|
+++ b/ext/openssl/tests/sni_server.phpt
|
||
|
@@ -3,6 +3,8 @@ sni_server
|
||
|
--SKIPIF--
|
||
|
<?php
|
||
|
if (!extension_loaded("openssl")) die("skip openssl not loaded");
|
||
|
+--XFAIL--
|
||
|
+Known to fail with OpenSSL 1.1
|
||
|
--FILE--
|
||
|
<?php
|
||
|
$serverCode = <<<'CODE'
|
||
|
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
|
||
|
index d549033..589dc8a 100644
|
||
|
--- a/ext/openssl/xp_ssl.c
|
||
|
+++ b/ext/openssl/xp_ssl.c
|
||
|
@@ -935,13 +935,9 @@ static int set_local_cert(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */
|
||
|
static const SSL_METHOD *php_select_crypto_method(long method_value, int is_client TSRMLS_DC) /* {{{ */
|
||
|
{
|
||
|
if (method_value == STREAM_CRYPTO_METHOD_SSLv2) {
|
||
|
-#ifndef OPENSSL_NO_SSL2
|
||
|
- return is_client ? SSLv2_client_method() : SSLv2_server_method();
|
||
|
-#else
|
||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||
|
"SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
|
||
|
return NULL;
|
||
|
-#endif
|
||
|
} else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) {
|
||
|
#ifndef OPENSSL_NO_SSL3
|
||
|
return is_client ? SSLv3_client_method() : SSLv3_server_method();
|
||
|
@@ -980,11 +976,6 @@ static long php_get_crypto_method_ctx_flags(long method_flags TSRMLS_DC) /* {{{
|
||
|
{
|
||
|
long ssl_ctx_options = SSL_OP_ALL;
|
||
|
|
||
|
-#ifndef OPENSSL_NO_SSL2
|
||
|
- if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv2)) {
|
||
|
- ssl_ctx_options |= SSL_OP_NO_SSLv2;
|
||
|
- }
|
||
|
-#endif
|
||
|
#ifndef OPENSSL_NO_SSL3
|
||
|
if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) {
|
||
|
ssl_ctx_options |= SSL_OP_NO_SSLv3;
|
||
|
@@ -1602,7 +1593,6 @@ static zval *capture_session_meta(SSL *ssl_handle) /* {{{ */
|
||
|
#endif
|
||
|
case TLS1_VERSION: proto_str = "TLSv1"; break;
|
||
|
case SSL3_VERSION: proto_str = "SSLv3"; break;
|
||
|
- case SSL2_VERSION: proto_str = "SSLv2"; break;
|
||
|
default: proto_str = "UNKNOWN";
|
||
|
}
|
||
|
|
||
|
@@ -2416,13 +2406,8 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen,
|
||
|
sslsock->enable_on_connect = 1;
|
||
|
sslsock->method = get_crypto_method(context, STREAM_CRYPTO_METHOD_ANY_CLIENT);
|
||
|
} else if (strncmp(proto, "sslv2", protolen) == 0) {
|
||
|
-#ifdef OPENSSL_NO_SSL2
|
||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
|
||
|
return NULL;
|
||
|
-#else
|
||
|
- sslsock->enable_on_connect = 1;
|
||
|
- sslsock->method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT;
|
||
|
-#endif
|
||
|
} else if (strncmp(proto, "sslv3", protolen) == 0) {
|
||
|
#ifdef OPENSSL_NO_SSL3
|
||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library PHP is linked against");
|
||
|
diff --git a/ext/phar/util.c b/ext/phar/util.c
|
||
|
index 828be8f..06e4e55 100644
|
||
|
--- a/ext/phar/util.c
|
||
|
+++ b/ext/phar/util.c
|
||
|
@@ -1531,7 +1531,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
|
||
|
BIO *in;
|
||
|
EVP_PKEY *key;
|
||
|
EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
|
||
|
- EVP_MD_CTX md_ctx;
|
||
|
+ EVP_MD_CTX *md_ctx;
|
||
|
#else
|
||
|
int tempsig;
|
||
|
#endif
|
||
|
@@ -1608,7 +1608,8 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
|
||
|
return FAILURE;
|
||
|
}
|
||
|
|
||
|
- EVP_VerifyInit(&md_ctx, mdtype);
|
||
|
+ md_ctx = EVP_MD_CTX_create();
|
||
|
+ EVP_VerifyInit(md_ctx, mdtype);
|
||
|
read_len = end_of_phar;
|
||
|
|
||
|
if (read_len > sizeof(buf)) {
|
||
|
@@ -1620,7 +1621,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
|
||
|
php_stream_seek(fp, 0, SEEK_SET);
|
||
|
|
||
|
while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
|
||
|
- EVP_VerifyUpdate (&md_ctx, buf, len);
|
||
|
+ EVP_VerifyUpdate (md_ctx, buf, len);
|
||
|
read_len -= (off_t)len;
|
||
|
|
||
|
if (read_len < read_size) {
|
||
|
@@ -1628,9 +1629,9 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
|
||
|
+ if (EVP_VerifyFinal(md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
|
||
|
/* 1: signature verified, 0: signature does not match, -1: failed signature operation */
|
||
|
- EVP_MD_CTX_cleanup(&md_ctx);
|
||
|
+ EVP_MD_CTX_destroy(md_ctx);
|
||
|
|
||
|
if (error) {
|
||
|
spprintf(error, 0, "broken openssl signature");
|
||
|
@@ -1639,7 +1640,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
|
||
|
return FAILURE;
|
||
|
}
|
||
|
|
||
|
- EVP_MD_CTX_cleanup(&md_ctx);
|
||
|
+ EVP_MD_CTX_destroy(md_ctx);
|
||
|
#endif
|
||
|
|
||
|
*signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
|
||
|
--
|
||
|
2.9.4
|
||
|
|