From 915c55f0f72e72afc56015d11fe3651629234065 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 2 Nov 2022 10:45:45 -0700 Subject: [PATCH 1/4] Commit 3 Differential Revision: D40942193 fbshipit-source-id: 87117195d1afe3ddf2daddd20947478f8210db6b --- hphp/runtime/ext/openssl/ext_openssl.cpp | 70 ++++++++++++++++-------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/hphp/runtime/ext/openssl/ext_openssl.cpp b/hphp/runtime/ext/openssl/ext_openssl.cpp index c90ea3ace3ebc7..f5c96be42342c0 100644 --- a/hphp/runtime/ext/openssl/ext_openssl.cpp +++ b/hphp/runtime/ext/openssl/ext_openssl.cpp @@ -1907,7 +1907,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const Resource& key) { case EVP_PKEY_RSA2: { ktype = OPENSSL_KEYTYPE_RSA; - RSA *rsa = EVP_PKEY_get0_RSA(pkey); + auto rsa = EVP_PKEY_get0_RSA(pkey); assertx(rsa); const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; RSA_get0_key(rsa, &n, &e, &d); @@ -1930,7 +1930,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const Resource& key) { case EVP_PKEY_DSA4: { ktype = OPENSSL_KEYTYPE_DSA; - DSA *dsa = EVP_PKEY_get0_DSA(pkey); + auto dsa = EVP_PKEY_get0_DSA(pkey); assertx(dsa); const BIGNUM *p, *q, *g, *pub_key, *priv_key; DSA_get0_pqg(dsa, &p, &q, &g); @@ -1946,7 +1946,7 @@ Array HHVM_FUNCTION(openssl_pkey_get_details, const Resource& key) { case EVP_PKEY_DH: { ktype = OPENSSL_KEYTYPE_DH; - DH *dh = EVP_PKEY_get0_DH(pkey); + auto dh = EVP_PKEY_get0_DH(pkey); assertx(dh); const BIGNUM *p, *q, *g, *pub_key, *priv_key; DH_get0_pqg(dh, &p, &q, &g); @@ -2060,11 +2060,17 @@ bool HHVM_FUNCTION(openssl_private_decrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_private_decrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + cryptedlen = RSA_private_decrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding); + } if (cryptedlen != -1) { successful = 1; } @@ -2100,11 +2106,17 @@ bool HHVM_FUNCTION(openssl_private_encrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_private_encrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding) == cryptedlen); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + successful = (RSA_private_encrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding) == cryptedlen); + } break; default: raise_warning("key type not supported"); @@ -2136,11 +2148,17 @@ bool HHVM_FUNCTION(openssl_public_decrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - cryptedlen = RSA_public_decrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + cryptedlen = RSA_public_decrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding); + } if (cryptedlen != -1) { successful = 1; } @@ -2176,11 +2194,17 @@ bool HHVM_FUNCTION(openssl_public_encrypt, const String& data, switch (EVP_PKEY_id(pkey)) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: - successful = (RSA_public_encrypt(data.size(), - (unsigned char *)data.data(), - cryptedbuf, - EVP_PKEY_get0_RSA(pkey), - padding) == cryptedlen); + { + auto rsa = EVP_PKEY_get1_RSA(pkey); + SCOPE_EXIT { + RSA_free(rsa); + }; + successful = (RSA_public_encrypt(data.size(), + (unsigned char *)data.data(), + cryptedbuf, + rsa, + padding) == cryptedlen); + } break; default: raise_warning("key type not supported"); From 8564a33b6aec868bd9a181d8d8972c8ec3e826b2 Mon Sep 17 00:00:00 2001 From: "Yang, Bo" Date: Wed, 2 Nov 2022 10:45:45 -0700 Subject: [PATCH 2/4] Extract public key portion via PEM roundtrip (#9282) Summary: This diff applies the approach similar to https://github.com/php/php-src/commit/26a51e8d7a6026f6bd69813d044785d154a296a3 in order to fix behavior changes in OpenSSL 3 Pull Request resolved: https://github.com/facebook/hhvm/pull/9282 Test Plan: The existing tests should still pass with OpenSSL 1.1 ``` "$HHVM_BIN" hphp/test/run.php hphp/test/slow/ext_openssl/ext_openssl.php ``` Differential Revision: D40876120 Pulled By: Atry fbshipit-source-id: 402e333b76853d70931f6898dd15ae9e88d8ecd8 --- hphp/runtime/ext/openssl/ext_openssl.cpp | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/hphp/runtime/ext/openssl/ext_openssl.cpp b/hphp/runtime/ext/openssl/ext_openssl.cpp index f5c96be42342c0..7dc120ac791370 100644 --- a/hphp/runtime/ext/openssl/ext_openssl.cpp +++ b/hphp/runtime/ext/openssl/ext_openssl.cpp @@ -998,25 +998,27 @@ bool HHVM_FUNCTION(openssl_csr_export, const Variant& csr, Variant& out, return false; } +static EVP_PKEY *duplicate_public_key(EVP_PKEY *priv_key) { + /* Extract public key portion by round-tripping through PEM. */ + BIO *bio = BIO_new(BIO_s_mem()); + SCOPE_EXIT { BIO_free(bio); }; + if (!bio || !PEM_write_bio_PUBKEY(bio, priv_key)) { + return nullptr; + } + + EVP_PKEY *pub_key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + return pub_key; +} + Variant HHVM_FUNCTION(openssl_csr_get_public_key, const Variant& csr) { auto pcsr = CSRequest::Get(csr); if (!pcsr) return false; auto input_csr = pcsr->csr(); -#if OPENSSL_VERSION_NUMBER >= 0x10100000 - /* 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 */ - input_csr = X509_REQ_dup(input_csr); - /* We need to free the CSR as it was duplicated */ - SCOPE_EXIT { X509_REQ_free(input_csr); }; -#endif - auto pubkey = X509_REQ_get_pubkey(input_csr); + auto pubkey = X509_REQ_get0_pubkey(input_csr); if (!pubkey) return false; - return Variant(req::make(pubkey)); + return Variant(req::make(duplicate_public_key(pubkey))); } Variant HHVM_FUNCTION(openssl_csr_get_subject, const Variant& csr, From b144fb563e68b3a647636912504c62ef86f44c63 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 2 Nov 2022 10:45:45 -0700 Subject: [PATCH 3/4] Commit 2 Differential Revision: D40942189 fbshipit-source-id: 6383c8922e5b9118582fba72a923d3d5d19380c2 --- hphp/runtime/ext/openssl/ext_openssl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hphp/runtime/ext/openssl/ext_openssl.cpp b/hphp/runtime/ext/openssl/ext_openssl.cpp index 7dc120ac791370..3a63bdb4e21180 100644 --- a/hphp/runtime/ext/openssl/ext_openssl.cpp +++ b/hphp/runtime/ext/openssl/ext_openssl.cpp @@ -28,6 +28,9 @@ #include #include #include +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#include +#endif #include #include @@ -66,6 +69,12 @@ struct OpenSSLInitializer { ERR_load_crypto_strings(); ERR_load_EVP_strings(); +// RC4 is only available in legacy providers +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + OSSL_PROVIDER_load(nullptr, "default"); + OSSL_PROVIDER_load(nullptr, "legacy"); +#endif + /* Determine default SSL configuration file */ char *config_filename = getenv("OPENSSL_CONF"); if (config_filename == nullptr) { From ba8ec3d683cffa7ce92fb4fdcff375fcaa271786 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 2 Nov 2022 10:46:11 -0700 Subject: [PATCH 4/4] Allow optional newline in OpenSSL output Summary: OpenSSL 3 does not include the trailing newline in its output. This diff adjust `expectf` so that it is now compatible with both OpenSSL 1.1 and 3.0. Differential Revision: D40942191 fbshipit-source-id: 300a35d617566f4335b04c4d7fab03ec774aecf1 --- .../ext_openssl/openssl_x509_parse_basic.php.expectf | 10 ++++------ .../zend/good/ext/openssl/tests/bug28382.php.expectf | 8 +++----- .../good/ext/openssl/tests/cve2013_4073.php.expectf | 3 +-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/hphp/test/slow/ext_openssl/openssl_x509_parse_basic.php.expectf b/hphp/test/slow/ext_openssl/openssl_x509_parse_basic.php.expectf index 671c6face45bfb..7e7a0edef0965d 100644 --- a/hphp/test/slow/ext_openssl/openssl_x509_parse_basic.php.expectf +++ b/hphp/test/slow/ext_openssl/openssl_x509_parse_basic.php.expectf @@ -105,10 +105,9 @@ dict(13) { ["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 + string(%d) "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 -" +serial:AE:C5:56:CC:72:37:50:A2%w" ["basicConstraints"]=> string(7) "CA:TRUE" } @@ -220,10 +219,9 @@ dict(13) { ["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 + string(%d) "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 -" +serial:AE:C5:56:CC:72:37:50:A2%w" ["basicConstraints"]=> string(7) "CA:TRUE" } diff --git a/hphp/test/zend/good/ext/openssl/tests/bug28382.php.expectf b/hphp/test/zend/good/ext/openssl/tests/bug28382.php.expectf index 3b68349dcba308..78619ac7e7ca4a 100644 --- a/hphp/test/zend/good/ext/openssl/tests/bug28382.php.expectf +++ b/hphp/test/zend/good/ext/openssl/tests/bug28382.php.expectf @@ -6,8 +6,7 @@ dict(11) { ["nsCertType"]=> string(30) "SSL Client, SSL Server, S/MIME" ["crlDistributionPoints"]=> - string(%d) "%AURI:http://mobile.blue-software.ro:90/ca/crl.shtml -" + string(%d) "%AURI:http://mobile.blue-software.ro:90/ca/crl.shtml%w" ["nsCaPolicyUrl"]=> string(38) "http://mobile.blue-software.ro:90/pub/" ["subjectAltName"]=> @@ -15,9 +14,8 @@ dict(11) { ["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 -" + string(%d) "DirName:/C=RO/ST=Romania/L=Craiova/O=Sergiu/OU=Sergiu SRL/CN=Sergiu CA/emailAddress=n_sergiu@hotmail.com +serial:00%w" ["keyUsage"]=> string(71) "Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment" ["nsBaseUrl"]=> diff --git a/hphp/test/zend/good/ext/openssl/tests/cve2013_4073.php.expectf b/hphp/test/zend/good/ext/openssl/tests/cve2013_4073.php.expectf index 08a55f3312ce55..8a8157c0d64292 100644 --- a/hphp/test/zend/good/ext/openssl/tests/cve2013_4073.php.expectf +++ b/hphp/test/zend/good/ext/openssl/tests/cve2013_4073.php.expectf @@ -2,6 +2,5 @@ dict [ 'basicConstraints' => '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 -', + '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%w', ] \ No newline at end of file