From b9eb75e9eae1372d6acd245654e1f4bd4b03f199 Mon Sep 17 00:00:00 2001 From: Omair Majid Date: Tue, 8 Jun 2021 10:58:25 -0400 Subject: [PATCH] Support building against OpenSSL 3.0 Resolves: RHBZ#1965045 --- ...-Use-EVP_PKEY-for-RSA-key-generation.patch | 349 ++++++ ...sl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch | 1035 +++++++++++++++++ ...-EVP_PKEY-for-RSA-signing-operations.patch | 538 +++++++++ ...-compiling-against-OpenSSL-3-headers.patch | 648 +++++++++++ ...ilds-work-across-OpenSSL-1.0.2-1.1.1.patch | 828 +++++++++++++ ...merge-issues-and-make-the-build-work.patch | 36 + ...gister-legacy-algorithms-when-needed.patch | 179 +++ ...SSL-3.0-ciphers-not-restoring-origin.patch | 79 ++ ...stead-of-true-for-more-portable-code.patch | 48 + dotnet3.1.spec | 26 +- 10 files changed, 3765 insertions(+), 1 deletion(-) create mode 100644 corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch create mode 100644 corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch create mode 100644 corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch create mode 100644 corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch create mode 100644 corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch create mode 100644 corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch create mode 100644 corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch create mode 100644 corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch create mode 100644 corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch diff --git a/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch b/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch new file mode 100644 index 0000000..505b839 --- /dev/null +++ b/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch @@ -0,0 +1,349 @@ +From 2b6b45878b1be4d77eec34ab5bc80b626995a8c5 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 19 Mar 2021 15:05:41 -0700 +Subject: [PATCH 1/9] Use EVP_PKEY for RSA key generation + +--- + .../Interop.EvpPkey.Rsa.cs | 16 ++++++++ + .../Interop.Rsa.cs | 3 -- + .../Security/Cryptography/RSAOpenSsl.cs | 37 ++++--------------- + .../apibridge.c | 8 ++++ + .../apibridge.h | 1 + + .../opensslshim.h | 23 ++++++++++++ + .../pal_evp_pkey_rsa.c | 29 +++++++++++++++ + .../pal_evp_pkey_rsa.h | 5 +++ + .../pal_rsa.c | 5 --- + .../pal_rsa.h | 7 ---- + ...em.Security.Cryptography.Algorithms.csproj | 3 ++ + 11 files changed, 93 insertions(+), 44 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index 1f61a826a9..c28522784b 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -10,6 +10,22 @@ internal static partial class Interop + { + internal static partial class Crypto + { ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKey")] ++ private static extern SafeEvpPKeyHandle CryptoNative_RsaGenerateKey(int keySize); ++ ++ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) ++ { ++ SafeEvpPKeyHandle pkey = CryptoNative_RsaGenerateKey(keySize); ++ ++ if (pkey.IsInvalid) ++ { ++ pkey.Dispose(); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return pkey; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index a7b85ae011..a05f020ada 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -89,9 +89,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] + internal static extern int RsaSize(SafeRsaHandle rsa); + +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKeyEx")] +- internal static extern int RsaGenerateKeyEx(SafeRsaHandle rsa, int bits, SafeBignumHandle e); +- + internal static bool RsaSign(int type, ReadOnlySpan m, int m_len, Span sigret, out int siglen, SafeRsaHandle rsa) => + RsaSign(type, ref MemoryMarshal.GetReference(m), m_len, ref MemoryMarshal.GetReference(sigret), out siglen, rsa); + +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 6741d28bba..4d4a8414b3 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -25,9 +25,6 @@ public sealed partial class RSAOpenSsl : RSA + { + private const int BitsPerByte = 8; + +- // 65537 (0x10001) in big-endian form +- private static readonly byte[] s_defaultExponent = { 0x01, 0x00, 0x01 }; +- + private Lazy _key; + + public RSAOpenSsl() +@@ -585,36 +582,18 @@ private static void CheckBoolReturn(int returnValue) + + private SafeRsaHandle GenerateKey() + { +- SafeRsaHandle key = Interop.Crypto.RsaCreate(); +- bool generated = false; +- +- Interop.Crypto.CheckValidOpenSslHandle(key); +- +- try ++ using (SafeEvpPKeyHandle pkey = Interop.Crypto.RsaGenerateKey(KeySize)) + { +- using (SafeBignumHandle exponent = Interop.Crypto.CreateBignum(s_defaultExponent)) +- { +- // The documentation for RSA_generate_key_ex does not say that it returns only +- // 0 or 1, so the call marshals it back as a full Int32 and checks for a value +- // of 1 explicitly. +- int response = Interop.Crypto.RsaGenerateKeyEx( +- key, +- KeySize, +- exponent); +- +- CheckBoolReturn(response); +- generated = true; +- } +- } +- finally +- { +- if (!generated) ++ SafeRsaHandle rsa = Interop.Crypto.EvpPkeyGetRsa(pkey); ++ ++ if (rsa.IsInvalid) + { +- key.Dispose(); ++ rsa.Dispose(); ++ throw Interop.Crypto.CreateOpenSslCryptographicException(); + } +- } + +- return key; ++ return rsa; ++ } + } + + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +index 167de7fd8e..def7198deb 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +@@ -728,4 +728,12 @@ void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level) + (void)ctx; + (void)level; + } ++ ++int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2) ++{ ++ // On OpenSSL 1.0.2 there aren't two different identifiers for RSA, ++ // so just pass the request on th EVP_PKEY_CTX_ctrl with the only identifier defined. ++ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, optype, cmd, p1, p2); ++} ++ + #endif +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +index 5f62864b24..b58611ae73 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +@@ -26,6 +26,7 @@ int32_t local_RSA_meth_get_flags(const RSA_METHOD* meth); + int32_t local_RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); + int32_t local_RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); + int32_t local_RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); ++int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); + int32_t local_SSL_is_init_finished(const SSL* ssl); + unsigned long local_SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); + void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index ed3994926d..dff6091e9e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -145,6 +145,7 @@ void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); + void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); + int32_t RSA_meth_get_flags(const RSA_METHOD* meth); + const RSA_METHOD* RSA_PKCS1_OpenSSL(void); ++int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); + int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); + int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); + int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); +@@ -170,6 +171,13 @@ const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); + X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); + int32_t X509_get_version(const X509* x509); + int32_t X509_up_ref(X509* x509); ++ ++// Redefine EVP_PKEY_CTX_set_rsa operations to use (local_)RSA_pkey_ctx_ctrl so the path is the same ++// for 1.0-built on 1.1 as on 1.1-built on 1.1. ++#undef EVP_PKEY_CTX_set_rsa_keygen_bits ++#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ ++ RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) ++ + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +@@ -341,8 +349,12 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + RENAMED_FUNCTION(EVP_MD_CTX_free, EVP_MD_CTX_destroy) \ + RENAMED_FUNCTION(EVP_MD_CTX_new, EVP_MD_CTX_create) \ + REQUIRED_FUNCTION(EVP_MD_size) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ ++ REQUIRED_FUNCTION(EVP_PKEY_base_id) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive) \ +@@ -350,6 +362,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_keygen) \ ++ REQUIRED_FUNCTION(EVP_PKEY_keygen_init) \ + REQUIRED_FUNCTION(EVP_PKEY_new) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ +@@ -432,6 +446,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + FALLBACK_FUNCTION(RSA_get0_key) \ + FALLBACK_FUNCTION(RSA_meth_get_flags) \ + REQUIRED_FUNCTION(RSA_new) \ ++ FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ + REQUIRED_FUNCTION(RSA_private_decrypt) \ + REQUIRED_FUNCTION(RSA_private_encrypt) \ +@@ -727,8 +742,12 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_MD_CTX_free EVP_MD_CTX_free_ptr + #define EVP_MD_CTX_new EVP_MD_CTX_new_ptr + #define EVP_MD_size EVP_MD_size_ptr ++#define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr + #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr ++#define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr + #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr ++#define EVP_PKEY_CTX_new_id EVP_PKEY_CTX_new_id_ptr ++#define EVP_PKEY_base_id EVP_PKEY_base_id_ptr + #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr + #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr + #define EVP_PKEY_derive EVP_PKEY_derive_ptr +@@ -736,6 +755,8 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr + #define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr + #define EVP_PKEY_get1_RSA EVP_PKEY_get1_RSA_ptr ++#define EVP_PKEY_keygen EVP_PKEY_keygen_ptr ++#define EVP_PKEY_keygen_init EVP_PKEY_keygen_init_ptr + #define EVP_PKEY_new EVP_PKEY_new_ptr + #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr +@@ -818,6 +839,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_get_method RSA_get_method_ptr + #define RSA_meth_get_flags RSA_meth_get_flags_ptr + #define RSA_new RSA_new_ptr ++#define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr + #define RSA_private_decrypt RSA_private_decrypt_ptr + #define RSA_private_encrypt RSA_private_encrypt_ptr +@@ -1026,6 +1048,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_set0_crt_params local_RSA_set0_crt_params + #define RSA_set0_factors local_RSA_set0_factors + #define RSA_set0_key local_RSA_set0_key ++#define RSA_pkey_ctx_ctrl local_RSA_pkey_ctx_ctrl + #define SSL_CTX_set_security_level local_SSL_CTX_set_security_level + #define SSL_is_init_finished local_SSL_is_init_finished + #define X509_CRL_get0_nextUpdate local_X509_CRL_get0_nextUpdate +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index e8d961dbd2..29f9238ce9 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -4,6 +4,35 @@ + + #include "pal_evp_pkey_rsa.h" + ++EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) ++{ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); ++ ++ if (ctx == NULL) ++ { ++ return NULL; ++ } ++ ++ EVP_PKEY* pkey = NULL; ++ EVP_PKEY* ret = NULL; ++ ++ if (EVP_PKEY_keygen_init(ctx) == 1 && ++ EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && ++ EVP_PKEY_keygen(ctx, &pkey) == 1) ++ { ++ ret = pkey; ++ pkey = NULL; ++ } ++ ++ if (pkey != NULL) ++ { ++ EVP_PKEY_free(pkey); ++ } ++ ++ EVP_PKEY_CTX_free(ctx); ++ return ret; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index d8ff369670..1fda149414 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -6,6 +6,11 @@ + #include "pal_compiler.h" + #include "opensslshim.h" + ++/* ++Creates an RSA key of the requested size. ++*/ ++DLLEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index f764815a04..080027de0e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -143,11 +143,6 @@ int32_t CryptoNative_RsaSize(RSA* rsa) + return RSA_size(rsa); + } + +-int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e) +-{ +- return RSA_generate_key_ex(rsa, bits, e, NULL); +-} +- + int32_t + CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa) + { +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +index b85fed627f..1c0bc2df47 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +@@ -86,13 +86,6 @@ Returns the RSA modulus size in bytes. + */ + DLLEXPORT int32_t CryptoNative_RsaSize(RSA* rsa); + +-/* +-Shims the RSA_generate_key_ex method. +- +-Returns 1 upon success, otherwise 0. +-*/ +-DLLEXPORT int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e); +- + /* + Shims the RSA_sign method. + +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index fa63b6e2fe..6ad2b78e01 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -507,6 +507,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs + +-- +2.31.1 + diff --git a/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch b/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch new file mode 100644 index 0000000..4285e23 --- /dev/null +++ b/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch @@ -0,0 +1,1035 @@ +From 16f162f76cdbdd150487eb9824f9d8f8e39df5ca Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Wed, 24 Mar 2021 10:27:42 -0700 +Subject: [PATCH 2/9] Use EVP_PKEY for RSA Decrypt + +--- + .../Interop.EVP.DigestAlgs.cs | 58 +++++ + .../Interop.EVP.cs | 18 +- + .../Interop.EvpPkey.Rsa.cs | 37 +++ + .../Interop.EvpPkey.cs | 3 + + .../Interop.Rsa.cs | 16 -- + .../Security/Cryptography/RSAOpenSsl.cs | 222 ++++++++++-------- + .../apibridge.c | 17 ++ + .../apibridge.h | 1 + + .../opensslshim.h | 17 +- + .../pal_evp_pkey.c | 7 + + .../pal_evp_pkey.h | 5 + + .../pal_evp_pkey_rsa.c | 137 ++++++++++- + .../pal_evp_pkey_rsa.h | 27 ++- + .../pal_rsa.c | 13 - + .../pal_rsa.h | 8 - + .../HashProviderDispenser.Unix.cs | 36 +-- + ...em.Security.Cryptography.Algorithms.csproj | 3 + + ...ystem.Security.Cryptography.OpenSsl.csproj | 3 + + 18 files changed, 444 insertions(+), 184 deletions(-) + create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs +new file mode 100644 +index 0000000000..53ef644d84 +--- /dev/null ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs +@@ -0,0 +1,58 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++using System; ++using System.Runtime.InteropServices; ++using System.Security.Cryptography; ++ ++internal static partial class Interop ++{ ++ internal static partial class Crypto ++ { ++ private static volatile IntPtr s_evpMd5; ++ private static volatile IntPtr s_evpSha1; ++ private static volatile IntPtr s_evpSha256; ++ private static volatile IntPtr s_evpSha384; ++ private static volatile IntPtr s_evpSha512; ++ ++ [DllImport(Libraries.CryptoNative)] ++ private static extern IntPtr CryptoNative_EvpMd5(); ++ ++ internal static IntPtr EvpMd5() => ++ s_evpMd5 != IntPtr.Zero ? s_evpMd5 : (s_evpMd5 = CryptoNative_EvpMd5()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha1(); ++ ++ internal static IntPtr EvpSha1() => ++ s_evpSha1 != IntPtr.Zero ? s_evpSha1 : (s_evpSha1 = CryptoNative_EvpSha1()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha256(); ++ ++ internal static IntPtr EvpSha256() => ++ s_evpSha256 != IntPtr.Zero ? s_evpSha256 : (s_evpSha256 = CryptoNative_EvpSha256()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha384(); ++ ++ internal static IntPtr EvpSha384() => ++ s_evpSha384 != IntPtr.Zero ? s_evpSha384 : (s_evpSha384 = CryptoNative_EvpSha384()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha512(); ++ ++ internal static IntPtr EvpSha512() => ++ s_evpSha512 != IntPtr.Zero ? s_evpSha512 : (s_evpSha512 = CryptoNative_EvpSha512()); ++ ++ internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch ++ { ++ nameof(HashAlgorithmName.SHA1) => EvpSha1(), ++ nameof(HashAlgorithmName.SHA256) => EvpSha256(), ++ nameof(HashAlgorithmName.SHA384) => EvpSha384(), ++ nameof(HashAlgorithmName.SHA512) => EvpSha512(), ++ nameof(HashAlgorithmName.MD5) => EvpMd5(), ++ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)) ++ }; ++ } ++} +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs +index 67a9b54230..ea9dc5186d 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs +@@ -4,6 +4,7 @@ + + using System; + using System.Runtime.InteropServices; ++using System.Security.Cryptography; + using Microsoft.Win32.SafeHandles; + + internal static partial class Interop +@@ -31,23 +32,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMdSize")] + internal extern static int EvpMdSize(IntPtr md); + +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMd5")] +- internal extern static IntPtr EvpMd5(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha1")] +- internal extern static IntPtr EvpSha1(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha256")] +- internal extern static IntPtr EvpSha256(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha384")] +- internal extern static IntPtr EvpSha384(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha512")] +- internal extern static IntPtr EvpSha512(); +- +- + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetMaxMdSize")] + private extern static int GetMaxMdSize(); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index c28522784b..f023ced7f9 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -2,6 +2,8 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + ++using System; ++using System.Diagnostics; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using Microsoft.Win32.SafeHandles; +@@ -26,6 +28,41 @@ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) + return pkey; + } + ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaDecrypt")] ++ private static extern int CryptoNative_RsaDecrypt( ++ SafeEvpPKeyHandle pkey, ++ ref byte source, ++ int sourceLength, ++ RSAEncryptionPaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ref byte destination, ++ int destinationLength); ++ ++ internal static int RsaDecrypt( ++ SafeEvpPKeyHandle pkey, ++ ReadOnlySpan source, ++ RSAEncryptionPaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ Span destination) ++ { ++ int written = CryptoNative_RsaDecrypt( ++ pkey, ++ ref MemoryMarshal.GetReference(source), ++ source.Length, ++ paddingMode, ++ digestAlgorithm, ++ ref MemoryMarshal.GetReference(destination), ++ destination.Length); ++ ++ if (written < 0) ++ { ++ Debug.Assert(written == -1); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return written; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +index 2eff6bfcd1..3ad4bc9d08 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +@@ -16,6 +16,9 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyDestroy")] + internal static extern void EvpPkeyDestroy(IntPtr pkey); + ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeySize")] ++ internal static extern int EvpPKeySize(SafeEvpPKeyHandle pkey); ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_UpRefEvpPkey")] + internal static extern int UpRefEvpPkey(SafeEvpPKeyHandle handle); + } +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index a05f020ada..5ad534a8f2 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -44,22 +44,6 @@ internal static partial class Crypto + SafeRsaHandle rsa, + RsaPadding padding); + +- internal static int RsaPrivateDecrypt( +- int flen, +- ReadOnlySpan from, +- Span to, +- SafeRsaHandle rsa, +- RsaPadding padding) => +- RsaPrivateDecrypt(flen, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa, padding); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaPrivateDecrypt")] +- private extern static int RsaPrivateDecrypt( +- int flen, +- ref byte from, +- ref byte to, +- SafeRsaHandle rsa, +- RsaPadding padding); +- + internal static int RsaSignPrimitive( + ReadOnlySpan from, + Span to, +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 4d4a8414b3..87e31b9dde 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -85,10 +85,9 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + if (padding == null) + throw new ArgumentNullException(nameof(padding)); + +- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor); +- SafeRsaHandle key = GetKey(); +- +- int rsaSize = Interop.Crypto.RsaSize(key); ++ ValidatePadding(padding); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int rsaSize = Interop.Crypto.EvpPKeySize(key); + byte[] buf = null; + Span destination = default; + +@@ -97,18 +96,15 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + buf = CryptoPool.Rent(rsaSize); + destination = new Span(buf, 0, rsaSize); + +- if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out int bytesWritten)) +- { +- Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer"); +- throw new CryptographicException(); +- } +- ++ int bytesWritten = Decrypt(key, data, destination, padding); + return destination.Slice(0, bytesWritten).ToArray(); + } + finally + { + CryptographicOperations.ZeroMemory(destination); + CryptoPool.Return(buf, clearSize: 0); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); + } + } + +@@ -119,82 +115,73 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + out int bytesWritten) + { + if (padding == null) +- { + throw new ArgumentNullException(nameof(padding)); +- } +- +- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor); +- SafeRsaHandle key = GetKey(); + +- int keySizeBytes = Interop.Crypto.RsaSize(key); ++ ValidatePadding(padding); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int keySizeBytes = Interop.Crypto.EvpPKeySize(key); + +- // OpenSSL does not take a length value for the destination, so it can write out of bounds. +- // To prevent the OOB write, decrypt into a temporary buffer. ++ // OpenSSL requires that the decryption buffer be at least as large as EVP_PKEY_size. ++ // So if the destination is too small, use a temporary buffer so we can match ++ // Windows behavior of succeeding so long as the buffer can hold the final output. + if (destination.Length < keySizeBytes) + { +- Span tmp = stackalloc byte[0]; ++ // RSA up through 4096 bits use a stackalloc ++ Span tmp = stackalloc byte[512]; + byte[] rent = null; + +- // RSA up through 4096 stackalloc +- if (keySizeBytes <= 512) ++ if (keySizeBytes > tmp.Length) + { +- tmp = stackalloc byte[keySizeBytes]; +- } +- else +- { +- rent = ArrayPool.Shared.Rent(keySizeBytes); ++ rent = CryptoPool.Rent(keySizeBytes); + tmp = rent; + } + +- bool ret = TryDecrypt(key, data, tmp, rsaPadding, oaepProcessor, out bytesWritten); ++ int written = Decrypt(key, data, tmp, padding); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ bool ret; + +- if (ret) ++ if (destination.Length < written) + { +- tmp = tmp.Slice(0, bytesWritten); +- +- if (bytesWritten > destination.Length) +- { +- ret = false; +- bytesWritten = 0; +- } +- else +- { +- tmp.CopyTo(destination); +- } +- +- CryptographicOperations.ZeroMemory(tmp); ++ bytesWritten = 0; ++ ret = false; ++ } ++ else ++ { ++ tmp.Slice(0, written).CopyTo(destination); ++ bytesWritten = written; ++ ret = true; + } + ++ // Whether a stackalloc or a rented array, clear our copy of ++ // the decrypted content. ++ CryptographicOperations.ZeroMemory(tmp.Slice(0, written)); ++ + if (rent != null) + { +- // Already cleared +- ArrayPool.Shared.Return(rent); ++ // Already cleared. ++ CryptoPool.Return(rent, clearSize: 0); + } + + return ret; + } + +- return TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten); ++ bytesWritten = Decrypt(key, data, destination, padding); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ return true; + } + +- private static bool TryDecrypt( +- SafeRsaHandle key, ++ private static int Decrypt( ++ SafeEvpPKeyHandle key, + ReadOnlySpan data, + Span destination, +- Interop.Crypto.RsaPadding rsaPadding, +- RsaPaddingProcessor rsaPaddingProcessor, +- out int bytesWritten) ++ RSAEncryptionPadding padding) + { +- // If rsaPadding is PKCS1 or OAEP-SHA1 then no depadding method should be present. +- // If rsaPadding is NoPadding then a depadding method should be present. +- Debug.Assert( +- (rsaPadding == Interop.Crypto.RsaPadding.NoPadding) == +- (rsaPaddingProcessor != null)); +- + // Caller should have already checked this. + Debug.Assert(!key.IsInvalid); + +- int rsaSize = Interop.Crypto.RsaSize(key); ++ int rsaSize = Interop.Crypto.EvpPKeySize(key); + + if (data.Length != rsaSize) + { +@@ -203,50 +190,24 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + + if (destination.Length < rsaSize) + { +- bytesWritten = 0; +- return false; ++ Debug.Fail("Caller is responsible for temporary decryption buffer creation"); ++ throw new CryptographicException(); + } + +- Span decryptBuf = destination; +- byte[] paddingBuf = null; ++ IntPtr hashAlgorithm = IntPtr.Zero; + +- if (rsaPaddingProcessor != null) ++ if (padding.Mode == RSAEncryptionPaddingMode.Oaep) + { +- paddingBuf = CryptoPool.Rent(rsaSize); +- decryptBuf = paddingBuf; ++ Debug.Assert(padding.OaepHashAlgorithm.Name != null); ++ hashAlgorithm = Interop.Crypto.HashAlgorithmToEvp(padding.OaepHashAlgorithm.Name); + } + +- try +- { +- int returnValue = Interop.Crypto.RsaPrivateDecrypt(data.Length, data, decryptBuf, key, rsaPadding); +- CheckReturn(returnValue); +- +- if (rsaPaddingProcessor != null) +- { +- return rsaPaddingProcessor.DepadOaep(paddingBuf, destination, out bytesWritten); +- } +- else +- { +- // If the padding mode is RSA_NO_PADDING then the size of the decrypted block +- // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm) +- // will have been reduced, and only returnValue bytes were part of the decrypted +- // body. Either way, we can just use returnValue, but some additional bytes may have been overwritten +- // in the destination span. +- bytesWritten = returnValue; +- } +- +- return true; +- } +- finally +- { +- if (paddingBuf != null) +- { +- // DecryptBuf is paddingBuf if paddingBuf is not null, erase it before returning it. +- // If paddingBuf IS null then decryptBuf was destination, and shouldn't be cleared. +- CryptographicOperations.ZeroMemory(decryptBuf); +- CryptoPool.Return(paddingBuf, clearSize: 0); +- } +- } ++ return Interop.Crypto.RsaDecrypt( ++ key, ++ data, ++ padding.Mode, ++ hashAlgorithm, ++ destination); + } + + public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) +@@ -550,6 +511,30 @@ private void ThrowIfDisposed() + } + } + ++ private SafeEvpPKeyHandle GetPKey() ++ { ++ SafeRsaHandle currentKey = GetKey(); ++ SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate(); ++ ++ try ++ { ++ // Wrapping our key in an EVP_PKEY will up_ref our key. ++ // When the EVP_PKEY is Disposed it will down_ref the key. ++ // So everything should be copacetic. ++ if (!Interop.Crypto.EvpPkeySetRsa(pkeyHandle, currentKey)) ++ { ++ throw Interop.Crypto.CreateOpenSslCryptographicException(); ++ } ++ } ++ catch ++ { ++ pkeyHandle.Dispose(); ++ throw; ++ } ++ ++ return pkeyHandle; ++ } ++ + private SafeRsaHandle GetKey() + { + ThrowIfDisposed(); +@@ -843,6 +828,55 @@ private static int GetAlgorithmNid(HashAlgorithmName hashAlgorithmName) + return nid; + } + ++ private static void ValidatePadding(RSAEncryptionPadding padding) ++ { ++ if (padding == null) ++ { ++ throw new ArgumentNullException(nameof(padding)); ++ } ++ ++ // There are currently two defined padding modes: ++ // * Oaep has an option (the hash algorithm) ++ // * Pkcs1 has no options ++ // ++ // Anything other than those to modes is an error, ++ // and Pkcs1 having options set is an error, so compare it to ++ // the padding struct instead of the padding mode enum. ++ if (padding.Mode != RSAEncryptionPaddingMode.Oaep && ++ padding != RSAEncryptionPadding.Pkcs1) ++ { ++ throw PaddingModeNotSupported(); ++ } ++ } ++ ++ private static void ValidatePadding(RSASignaturePadding padding) ++ { ++ if (padding == null) ++ { ++ throw new ArgumentNullException(nameof(padding)); ++ } ++ ++ // RSASignaturePadding currently only has the mode property, so ++ // there's no need for a runtime check that PKCS#1 doesn't use ++ // nonsensical options like with RSAEncryptionPadding. ++ // ++ // This would change if we supported PSS with an MGF other than MGF-1, ++ // or with a custom salt size, or with a different MGF digest algorithm ++ // than the data digest algorithm. ++ if (padding.Mode == RSASignaturePaddingMode.Pkcs1) ++ { ++ Debug.Assert(padding == RSASignaturePadding.Pkcs1); ++ } ++ else if (padding.Mode == RSASignaturePaddingMode.Pss) ++ { ++ Debug.Assert(padding == RSASignaturePadding.Pss); ++ } ++ else ++ { ++ throw PaddingModeNotSupported(); ++ } ++ } ++ + private static Exception PaddingModeNotSupported() => + new CryptographicException(SR.Cryptography_InvalidPaddingMode); + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +index def7198deb..ff71105837 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +@@ -258,6 +258,23 @@ int32_t local_DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX) + return 1; + } + ++RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey) ++{ ++ if (pkey == NULL) ++ { ++ return NULL; ++ } ++ ++ RSA* rsa = EVP_PKEY_get1_RSA(pkey); ++ ++ if (rsa != NULL) ++ { ++ RSA_free(rsa); ++ } ++ ++ return rsa; ++} ++ + int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey) + { + if (!pkey) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +index b58611ae73..e1315499f3 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +@@ -15,6 +15,7 @@ int32_t local_DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); + void local_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); + EVP_CIPHER_CTX* local_EVP_CIPHER_CTX_new(void); + int32_t local_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); ++RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey); + int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey); + void local_HMAC_CTX_free(HMAC_CTX* ctx); + HMAC_CTX* local_HMAC_CTX_new(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index dff6091e9e..47cb142d25 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -128,6 +128,7 @@ EVP_CIPHER_CTX* EVP_CIPHER_CTX_new(void); + int32_t EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); + void EVP_MD_CTX_free(EVP_MD_CTX* ctx); + EVP_MD_CTX* EVP_MD_CTX_new(void); ++RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); + int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); + void HMAC_CTX_free(HMAC_CTX* ctx); + HMAC_CTX* HMAC_CTX_new(void); +@@ -178,6 +179,12 @@ int32_t X509_up_ref(X509* x509); + #define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + ++#undef EVP_PKEY_CTX_set_rsa_padding ++#define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ ++ RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) ++ ++// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++ + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +@@ -355,10 +362,13 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ + REQUIRED_FUNCTION(EVP_PKEY_base_id) \ ++ REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ ++ REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive) \ + REQUIRED_FUNCTION(EVP_PKEY_free) \ ++ FALLBACK_FUNCTION(EVP_PKEY_get0_RSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_RSA) \ +@@ -368,6 +378,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_up_ref) \ + REQUIRED_FUNCTION(EVP_rc2_cbc) \ + REQUIRED_FUNCTION(EVP_rc2_ecb) \ +@@ -448,7 +459,6 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(RSA_new) \ + FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ +- REQUIRED_FUNCTION(RSA_private_decrypt) \ + REQUIRED_FUNCTION(RSA_private_encrypt) \ + REQUIRED_FUNCTION(RSA_public_decrypt) \ + REQUIRED_FUNCTION(RSA_public_encrypt) \ +@@ -748,10 +758,13 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr + #define EVP_PKEY_CTX_new_id EVP_PKEY_CTX_new_id_ptr + #define EVP_PKEY_base_id EVP_PKEY_base_id_ptr ++#define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr ++#define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr + #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr + #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr + #define EVP_PKEY_derive EVP_PKEY_derive_ptr + #define EVP_PKEY_free EVP_PKEY_free_ptr ++#define EVP_PKEY_get0_RSA EVP_PKEY_get0_RSA_ptr + #define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr + #define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr + #define EVP_PKEY_get1_RSA EVP_PKEY_get1_RSA_ptr +@@ -761,6 +774,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr + #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr ++#define EVP_PKEY_size EVP_PKEY_size_ptr + #define EVP_PKEY_up_ref EVP_PKEY_up_ref_ptr + #define EVP_rc2_cbc EVP_rc2_cbc_ptr + #define EVP_rc2_ecb EVP_rc2_ecb_ptr +@@ -841,7 +855,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_new RSA_new_ptr + #define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr +-#define RSA_private_decrypt RSA_private_decrypt_ptr + #define RSA_private_encrypt RSA_private_encrypt_ptr + #define RSA_public_decrypt RSA_public_decrypt_ptr + #define RSA_public_encrypt RSA_public_encrypt_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +index 4d479dde6c..f232b382ea 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +@@ -2,6 +2,7 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + ++#include + #include "pal_evp_pkey.h" + + EVP_PKEY* CryptoNative_EvpPkeyCreate() +@@ -17,6 +18,12 @@ void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey) + } + } + ++int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey) ++{ ++ assert(pkey != NULL); ++ return EVP_PKEY_size(pkey); ++} ++ + int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey) + { + if (!pkey) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +index 7baf997d8d..750282efdb 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +@@ -24,6 +24,11 @@ Always succeeds. + */ + DLLEXPORT void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey); + ++/* ++Returns the maximum size, in bytes, of an operation with the provided key. ++*/ ++DLLEXPORT int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey); ++ + /* + Used by System.Security.Cryptography.X509Certificates' OpenSslX509CertificateReader when + duplicating a private key context as part of duplicating the Pal object. +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 29f9238ce9..6235c905db 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -3,6 +3,10 @@ + // See the LICENSE file in the project root for more information. + + #include "pal_evp_pkey_rsa.h" ++#include "pal_utilities.h" ++#include ++ ++static int HasNoPrivateKey(RSA* rsa); + + EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + { +@@ -16,8 +20,7 @@ EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + EVP_PKEY* pkey = NULL; + EVP_PKEY* ret = NULL; + +- if (EVP_PKEY_keygen_init(ctx) == 1 && +- EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && ++ if (EVP_PKEY_keygen_init(ctx) == 1 && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && + EVP_PKEY_keygen(ctx, &pkey) == 1) + { + ret = pkey; +@@ -33,6 +36,82 @@ EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + return ret; + } + ++int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, ++ const uint8_t* source, ++ int32_t sourceLen, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ uint8_t* destination, ++ int32_t destinationLen) ++{ ++ assert(pkey != NULL); ++ assert(source != NULL); ++ assert(destination != NULL); ++ assert(padding >= RsaPaddingPkcs1 && padding <= RsaPaddingOaepOrPss); ++ assert(digest != NULL || padding == RsaPaddingPkcs1); ++ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ ++ int ret = -1; ++ ++ if (ctx == NULL || EVP_PKEY_decrypt_init(ctx) <= 0) ++ { ++ goto done; ++ } ++ ++ if (padding == RsaPaddingPkcs1) ++ { ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) ++ { ++ goto done; ++ } ++ } ++ else ++ { ++ assert(padding == RsaPaddingOaepOrPss); ++ ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) ++ { ++ goto done; ++ } ++ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, digest) <= 0) ++#pragma clang diagnostic pop ++ { ++ goto done; ++ } ++ } ++ ++ // This check may no longer be needed on OpenSSL 3.0 ++ { ++ RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ ++ if (rsa == NULL || HasNoPrivateKey(rsa)) ++ { ++ ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); ++ ret = -1; ++ goto done; ++ } ++ } ++ ++ size_t written = Int32ToSizeT(destinationLen); ++ ++ if (EVP_PKEY_decrypt(ctx, destination, &written, source, Int32ToSizeT(sourceLen)) > 0) ++ { ++ ret = SizeTToInt32(written); ++ } ++ ++done: ++ if (ctx != NULL) ++ { ++ EVP_PKEY_CTX_free(ctx); ++ } ++ ++ return ret; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +@@ -42,3 +121,57 @@ int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa) + { + return EVP_PKEY_set1_RSA(pkey, rsa); + } ++ ++static int HasNoPrivateKey(RSA* rsa) ++{ ++ if (rsa == NULL) ++ return 1; ++ ++ // Shared pointer, don't free. ++ const RSA_METHOD* meth = RSA_get_method(rsa); ++ ++ // The method has descibed itself as having the private key external to the structure. ++ // That doesn't mean it's actually present, but we can't tell. ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (RSA_meth_get_flags((RSA_METHOD*)meth) & RSA_FLAG_EXT_PKEY) ++#pragma clang diagnostic pop ++ { ++ return 0; ++ } ++ ++ // In the event that there's a middle-ground where we report failure when success is expected, ++ // one could do something like check if the RSA_METHOD intercepts all private key operations: ++ // ++ // * meth->rsa_priv_enc ++ // * meth->rsa_priv_dec ++ // * meth->rsa_sign (in 1.0.x this is only respected if the RSA_FLAG_SIGN_VER flag is asserted) ++ // ++ // But, for now, leave it at the EXT_PKEY flag test. ++ ++ // The module is documented as accepting either d or the full set of CRT parameters (p, q, dp, dq, qInv) ++ // So if we see d, we're good. Otherwise, if any of the rest are missing, we're public-only. ++ const BIGNUM* d; ++ RSA_get0_key(rsa, NULL, NULL, &d); ++ ++ if (d != NULL) ++ { ++ return 0; ++ } ++ ++ const BIGNUM* p; ++ const BIGNUM* q; ++ const BIGNUM* dmp1; ++ const BIGNUM* dmq1; ++ const BIGNUM* iqmp; ++ ++ RSA_get0_factors(rsa, &p, &q); ++ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); ++ ++ if (p == NULL || q == NULL || dmp1 == NULL || dmq1 == NULL || iqmp == NULL) ++ { ++ return 1; ++ } ++ ++ return 0; ++} +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index 1fda149414..d220065adf 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -2,15 +2,38 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + +-#include "pal_types.h" +-#include "pal_compiler.h" + #include "opensslshim.h" ++#include "pal_compiler.h" ++#include "pal_types.h" ++ ++/* ++Padding options for RSA. ++Matches RSAEncryptionPaddingMode / RSASignaturePaddingMode. ++*/ ++typedef enum ++{ ++ RsaPaddingPkcs1, ++ RsaPaddingOaepOrPss, ++} RsaPaddingMode; + + /* + Creates an RSA key of the requested size. + */ + DLLEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); + ++/* ++Decrypt source into destination using the specified RSA key (wrapped in an EVP_PKEY) and padding/digest options. ++ ++Returns the number of bytes written to destination, -1 on error. ++*/ ++DLLEXPORT int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, ++ const uint8_t* source, ++ int32_t sourceLen, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ uint8_t* destination, ++ int32_t destinationLen); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index 080027de0e..0c635dfca7 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -109,19 +109,6 @@ CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RS + return RSA_public_encrypt(flen, from, to, rsa, openSslPadding); + } + +-int32_t +-CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding) +-{ +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return -1; +- } +- +- int openSslPadding = GetOpenSslPadding(padding); +- return RSA_private_decrypt(flen, from, to, rsa, openSslPadding); +-} +- + int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) + { + if (HasNoPrivateKey(rsa)) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +index 1c0bc2df47..30d7d9fa59 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +@@ -55,14 +55,6 @@ Returns the size of the signature, or -1 on error. + DLLEXPORT int32_t + CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding); + +-/* +-Shims the RSA_private_decrypt method. +- +-Returns the size of the signature, or -1 on error. +-*/ +-DLLEXPORT int32_t +-CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding); +- + /* + Shims RSA_private_encrypt with a fixed value of RSA_NO_PADDING. + +diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs +index ff8e91e7c9..589ff882bf 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs +@@ -12,40 +12,16 @@ namespace Internal.Cryptography + { + internal static partial class HashProviderDispenser + { +- public static HashProvider CreateHashProvider(string hashAlgorithmId) ++ internal static HashProvider CreateHashProvider(string hashAlgorithmId) + { +- switch (hashAlgorithmId) +- { +- case HashAlgorithmNames.SHA1: +- return new EvpHashProvider(Interop.Crypto.EvpSha1()); +- case HashAlgorithmNames.SHA256: +- return new EvpHashProvider(Interop.Crypto.EvpSha256()); +- case HashAlgorithmNames.SHA384: +- return new EvpHashProvider(Interop.Crypto.EvpSha384()); +- case HashAlgorithmNames.SHA512: +- return new EvpHashProvider(Interop.Crypto.EvpSha512()); +- case HashAlgorithmNames.MD5: +- return new EvpHashProvider(Interop.Crypto.EvpMd5()); +- } +- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)); ++ IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); ++ return new EvpHashProvider(evpType); + } + +- public static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key) ++ internal static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key) + { +- switch (hashAlgorithmId) +- { +- case HashAlgorithmNames.SHA1: +- return new HmacHashProvider(Interop.Crypto.EvpSha1(), key); +- case HashAlgorithmNames.SHA256: +- return new HmacHashProvider(Interop.Crypto.EvpSha256(), key); +- case HashAlgorithmNames.SHA384: +- return new HmacHashProvider(Interop.Crypto.EvpSha384(), key); +- case HashAlgorithmNames.SHA512: +- return new HmacHashProvider(Interop.Crypto.EvpSha512(), key); +- case HashAlgorithmNames.MD5: +- return new HmacHashProvider(Interop.Crypto.EvpMd5(), key); +- } +- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)); ++ IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); ++ return new HmacHashProvider(evpType, key); + } + + // ----------------------------- +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index 6ad2b78e01..c6e8b5b69a 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -513,6 +513,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.DigestAlgs.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs + +diff --git a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +index 17ab176ec2..dbbc4848e8 100644 +--- a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj ++++ b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +@@ -57,6 +57,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.DigestAlgs.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.cs + +-- +2.31.1 + diff --git a/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch b/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch new file mode 100644 index 0000000..43e8e2b --- /dev/null +++ b/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch @@ -0,0 +1,538 @@ +From 7111a92546253d6fc857f7cad8b0bff425df0798 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 2 Apr 2021 09:10:08 -0700 +Subject: [PATCH 3/9] Use EVP_PKEY for RSA signing operations + +With this change all RSA private key operations (excluding import/export) use the EVP_PKEY APIs. + +* RSAPaddingProcessor is no longer used in conjunction with the private keys, on Linux. +* The pal_rsa.c copy of HasPrivateKey has been removed. +--- + .../Interop.EvpPkey.Rsa.cs | 35 ++++++ + .../Interop.Rsa.cs | 20 ---- + .../Security/Cryptography/RSAOpenSsl.cs | 87 ++++----------- + .../opensslshim.h | 19 +++- + .../pal_evp_pkey_rsa.c | 76 ++++++++++++- + .../pal_evp_pkey_rsa.h | 14 +++ + .../pal_rsa.c | 100 ------------------ + 7 files changed, 156 insertions(+), 195 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index f023ced7f9..6aab764cff 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -63,6 +63,41 @@ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) + return written; + } + ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSignHash")] ++ private static extern int CryptoNative_RsaSignHash( ++ SafeEvpPKeyHandle pkey, ++ RSASignaturePaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ref byte hash, ++ int hashLength, ++ ref byte destination, ++ int destinationLength); ++ ++ internal static int RsaSignHash( ++ SafeEvpPKeyHandle pkey, ++ RSASignaturePaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ReadOnlySpan hash, ++ Span destination) ++ { ++ int written = CryptoNative_RsaSignHash( ++ pkey, ++ paddingMode, ++ digestAlgorithm, ++ ref MemoryMarshal.GetReference(hash), ++ hash.Length, ++ ref MemoryMarshal.GetReference(destination), ++ destination.Length); ++ ++ if (written < 0) ++ { ++ Debug.Assert(written == -1); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return written; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index 5ad534a8f2..b2f250ffe9 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -44,19 +44,6 @@ internal static partial class Crypto + SafeRsaHandle rsa, + RsaPadding padding); + +- internal static int RsaSignPrimitive( +- ReadOnlySpan from, +- Span to, +- SafeRsaHandle rsa) => +- RsaSignPrimitive(from.Length, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSignPrimitive")] +- private static extern int RsaSignPrimitive( +- int flen, +- ref byte from, +- ref byte to, +- SafeRsaHandle rsa); +- + internal static int RsaVerificationPrimitive( + ReadOnlySpan from, + Span to, +@@ -73,13 +60,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] + internal static extern int RsaSize(SafeRsaHandle rsa); + +- internal static bool RsaSign(int type, ReadOnlySpan m, int m_len, Span sigret, out int siglen, SafeRsaHandle rsa) => +- RsaSign(type, ref MemoryMarshal.GetReference(m), m_len, ref MemoryMarshal.GetReference(sigret), out siglen, rsa); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSign")] +- [return: MarshalAs(UnmanagedType.Bool)] +- private static extern bool RsaSign(int type, ref byte m, int m_len, ref byte sigret, out int siglen, SafeRsaHandle rsa); +- + internal static bool RsaVerify(int type, ReadOnlySpan m, ReadOnlySpan sigbuf, SafeRsaHandle rsa) + { + bool ret = RsaVerify( +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 87e31b9dde..225968fc50 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -655,84 +655,33 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS + { + Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); + Debug.Assert(padding != null); ++ ValidatePadding(padding); + + signature = null; + +- // Do not factor out getting _key.Value, since the key creation should not happen on +- // invalid padding modes. ++ IntPtr digestAlgorithm = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithm.Name); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int bytesRequired = Interop.Crypto.EvpPKeySize(key); + +- if (padding.Mode == RSASignaturePaddingMode.Pkcs1) ++ if (allocateSignature) + { +- int algorithmNid = GetAlgorithmNid(hashAlgorithm); +- SafeRsaHandle rsa = GetKey(); +- +- int bytesRequired = Interop.Crypto.RsaSize(rsa); +- +- if (allocateSignature) +- { +- Debug.Assert(destination.Length == 0); +- signature = new byte[bytesRequired]; +- destination = signature; +- } +- +- if (destination.Length < bytesRequired) +- { +- bytesWritten = 0; +- return false; +- } +- +- if (!Interop.Crypto.RsaSign(algorithmNid, hash, hash.Length, destination, out int signatureSize, rsa)) +- { +- throw Interop.Crypto.CreateOpenSslCryptographicException(); +- } +- +- Debug.Assert( +- signatureSize == bytesRequired, +- $"RSA_sign reported signatureSize was {signatureSize}, when {bytesRequired} was expected"); +- +- bytesWritten = signatureSize; +- return true; ++ Debug.Assert(destination.Length == 0); ++ signature = new byte[bytesRequired]; ++ destination = signature; + } +- else if (padding.Mode == RSASignaturePaddingMode.Pss) ++ else if (destination.Length < bytesRequired) + { +- RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); +- SafeRsaHandle rsa = GetKey(); +- +- int bytesRequired = Interop.Crypto.RsaSize(rsa); +- +- if (allocateSignature) +- { +- Debug.Assert(destination.Length == 0); +- signature = new byte[bytesRequired]; +- destination = signature; +- } +- +- if (destination.Length < bytesRequired) +- { +- bytesWritten = 0; +- return false; +- } +- +- byte[] pssRented = CryptoPool.Rent(bytesRequired); +- Span pssBytes = new Span(pssRented, 0, bytesRequired); +- +- processor.EncodePss(hash, pssBytes, KeySize); +- +- int ret = Interop.Crypto.RsaSignPrimitive(pssBytes, destination, rsa); +- +- CryptoPool.Return(pssRented, bytesRequired); +- +- CheckReturn(ret); +- +- Debug.Assert( +- ret == bytesRequired, +- $"RSA_private_encrypt returned {ret} when {bytesRequired} was expected"); +- +- bytesWritten = ret; +- return true; ++ bytesWritten = 0; ++ return false; + } + +- throw PaddingModeNotSupported(); ++ int written = Interop.Crypto.RsaSignHash(key, padding.Mode, digestAlgorithm, hash, destination); ++ Debug.Assert(written == bytesRequired); ++ bytesWritten = written; ++ ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ return true; + } + + public override bool VerifyHash( +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 47cb142d25..4c15914d25 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -179,11 +179,15 @@ int32_t X509_up_ref(X509* x509); + #define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + ++// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++ + #undef EVP_PKEY_CTX_set_rsa_padding + #define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ + RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) + +-// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++#undef EVP_PKEY_CTX_set_rsa_pss_saltlen ++#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ ++ RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) + + #endif + +@@ -209,6 +213,11 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, + void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsigned int* len); + #endif + ++// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. ++#ifndef RSA_PSS_SALTLEN_DIGEST ++#define RSA_PSS_SALTLEN_DIGEST -1 ++#endif ++ + #define API_EXISTS(fn) (fn != NULL) + + // List of all functions from the libssl that are used in the System.Security.Cryptography.Native. +@@ -378,6 +387,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_sign) \ ++ REQUIRED_FUNCTION(EVP_PKEY_sign_init) \ + REQUIRED_FUNCTION(EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_up_ref) \ + REQUIRED_FUNCTION(EVP_rc2_cbc) \ +@@ -459,14 +470,12 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(RSA_new) \ + FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ +- REQUIRED_FUNCTION(RSA_private_encrypt) \ + REQUIRED_FUNCTION(RSA_public_decrypt) \ + REQUIRED_FUNCTION(RSA_public_encrypt) \ + FALLBACK_FUNCTION(RSA_set0_crt_params) \ + FALLBACK_FUNCTION(RSA_set0_factors) \ + FALLBACK_FUNCTION(RSA_set0_key) \ + REQUIRED_FUNCTION(RSA_set_method) \ +- REQUIRED_FUNCTION(RSA_sign) \ + REQUIRED_FUNCTION(RSA_size) \ + REQUIRED_FUNCTION(RSA_up_ref) \ + REQUIRED_FUNCTION(RSA_verify) \ +@@ -774,6 +783,8 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr + #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr ++#define EVP_PKEY_sign_init EVP_PKEY_sign_init_ptr ++#define EVP_PKEY_sign EVP_PKEY_sign_ptr + #define EVP_PKEY_size EVP_PKEY_size_ptr + #define EVP_PKEY_up_ref EVP_PKEY_up_ref_ptr + #define EVP_rc2_cbc EVP_rc2_cbc_ptr +@@ -855,14 +866,12 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_new RSA_new_ptr + #define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr +-#define RSA_private_encrypt RSA_private_encrypt_ptr + #define RSA_public_decrypt RSA_public_decrypt_ptr + #define RSA_public_encrypt RSA_public_encrypt_ptr + #define RSA_set0_crt_params RSA_set0_crt_params_ptr + #define RSA_set0_factors RSA_set0_factors_ptr + #define RSA_set0_key RSA_set0_key_ptr + #define RSA_set_method RSA_set_method_ptr +-#define RSA_sign RSA_sign_ptr + #define RSA_size RSA_size_ptr + #define RSA_up_ref RSA_up_ref_ptr + #define RSA_verify RSA_verify_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 6235c905db..68b6a34a5d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -91,7 +91,6 @@ int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + if (rsa == NULL || HasNoPrivateKey(rsa)) + { + ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- ret = -1; + goto done; + } + } +@@ -112,6 +111,81 @@ done: + return ret; + } + ++int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ const uint8_t* hash, ++ int32_t hashLen, ++ uint8_t* destination, ++ int32_t destinationLen) ++{ ++ assert(pkey != NULL); ++ assert(destination != NULL); ++ assert(padding >= RsaPaddingPkcs1 && padding <= RsaPaddingOaepOrPss); ++ assert(digest != NULL || padding == RsaPaddingPkcs1); ++ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ ++ int ret = -1; ++ ++ if (ctx == NULL || EVP_PKEY_sign_init(ctx) <= 0) ++ { ++ goto done; ++ } ++ ++ if (padding == RsaPaddingPkcs1) ++ { ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) ++ { ++ goto done; ++ } ++ } ++ else ++ { ++ assert(padding == RsaPaddingOaepOrPss); ++ ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0 || ++ EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) <= 0) ++ { ++ goto done; ++ } ++ } ++ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (EVP_PKEY_CTX_set_signature_md(ctx, digest) <= 0) ++#pragma clang diagnostic pop ++ { ++ goto done; ++ } ++ ++ // This check may no longer be needed on OpenSSL 3.0 ++ { ++ RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ ++ if (rsa == NULL || HasNoPrivateKey(rsa)) ++ { ++ ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); ++ goto done; ++ } ++ } ++ ++ size_t written = Int32ToSizeT(destinationLen); ++ ++ if (EVP_PKEY_sign(ctx, destination, &written, hash, Int32ToSizeT(hashLen)) > 0) ++ { ++ ret = SizeTToInt32(written); ++ } ++ ++done: ++ if (ctx != NULL) ++ { ++ EVP_PKEY_CTX_free(ctx); ++ } ++ ++ return ret; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index d220065adf..f811523f78 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -34,6 +34,20 @@ DLLEXPORT int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + uint8_t* destination, + int32_t destinationLen); + ++/* ++Complete the RSA signature generation for the specified hash using the provided RSA key ++(wrapped in an EVP_PKEY) and padding/digest options. ++ ++Returns the number of bytes written to destination, -1 on error. ++*/ ++DLLEXPORT int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ const uint8_t* hash, ++ int32_t hashLen, ++ uint8_t* destination, ++ int32_t destinationLen); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index 0c635dfca7..43268e88e1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -48,60 +48,6 @@ static int GetOpenSslPadding(RsaPadding padding) + } + } + +-static int HasNoPrivateKey(RSA* rsa) +-{ +- if (rsa == NULL) +- return 1; +- +- // Shared pointer, don't free. +- const RSA_METHOD* meth = RSA_get_method(rsa); +- +- // The method has descibed itself as having the private key external to the structure. +- // That doesn't mean it's actually present, but we can't tell. +-#pragma clang diagnostic push +-#pragma clang diagnostic ignored "-Wcast-qual" +- if (RSA_meth_get_flags((RSA_METHOD*)meth) & RSA_FLAG_EXT_PKEY) +-#pragma clang diagnostic pop +- { +- return 0; +- } +- +- // In the event that there's a middle-ground where we report failure when success is expected, +- // one could do something like check if the RSA_METHOD intercepts all private key operations: +- // +- // * meth->rsa_priv_enc +- // * meth->rsa_priv_dec +- // * meth->rsa_sign (in 1.0.x this is only respected if the RSA_FLAG_SIGN_VER flag is asserted) +- // +- // But, for now, leave it at the EXT_PKEY flag test. +- +- // The module is documented as accepting either d or the full set of CRT parameters (p, q, dp, dq, qInv) +- // So if we see d, we're good. Otherwise, if any of the rest are missing, we're public-only. +- const BIGNUM* d; +- RSA_get0_key(rsa, NULL, NULL, &d); +- +- if (d != NULL) +- { +- return 0; +- } +- +- const BIGNUM* p; +- const BIGNUM* q; +- const BIGNUM* dmp1; +- const BIGNUM* dmq1; +- const BIGNUM* iqmp; +- +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- +- if (p == NULL || q == NULL || dmp1 == NULL || dmq1 == NULL || iqmp == NULL) +- { +- return 1; +- } +- +- return 0; +-} +- + int32_t + CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding) + { +@@ -109,17 +55,6 @@ CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RS + return RSA_public_encrypt(flen, from, to, rsa, openSslPadding); + } + +-int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) +-{ +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_ENCRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return -1; +- } +- +- return RSA_private_encrypt(flen, from, to, rsa, RSA_NO_PADDING); +-} +- + int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) + { + return RSA_public_decrypt(flen, from, to, rsa, RSA_NO_PADDING); +@@ -130,41 +65,6 @@ int32_t CryptoNative_RsaSize(RSA* rsa) + return RSA_size(rsa); + } + +-int32_t +-CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa) +-{ +- if (siglen == NULL) +- { +- assert(false); +- return 0; +- } +- +- *siglen = 0; +- +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return 0; +- } +- +- // Shared pointer to the metadata about the message digest algorithm +- const EVP_MD* digest = EVP_get_digestbynid(type); +- +- // If the digest itself isn't known then RSA_R_UNKNOWN_ALGORITHM_TYPE will get reported, but +- // we have to check that the digest size matches what we expect. +- if (digest != NULL && mlen != EVP_MD_size(digest)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_INVALID_MESSAGE_LENGTH, __FILE__, __LINE__); +- return 0; +- } +- +- unsigned int unsignedSigLen = 0; +- int32_t ret = RSA_sign(type, m, Int32ToUint32(mlen), sigret, &unsignedSigLen, rsa); +- assert(unsignedSigLen <= INT32_MAX); +- *siglen = (int32_t)unsignedSigLen; +- return ret; +-} +- + int32_t + CryptoNative_RsaVerify(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigbuf, int32_t siglen, RSA* rsa) + { +-- +2.31.1 + diff --git a/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch b/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch new file mode 100644 index 0000000..3cf4a21 --- /dev/null +++ b/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch @@ -0,0 +1,648 @@ +From 49dc6e515d9ec0db1841e5d2d86f52916d35f667 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Mon, 5 Apr 2021 11:07:29 -0700 +Subject: [PATCH 4/9] Support compiling against OpenSSL 3 headers + +Building against OpenSSL 3's headers fails to compile, as X509_V_ERR_INVALID_CA has changed from 24 to 79, tripping a static assert. + +* Rename the managed X509VerifyStatusCode enum to X509VerifyStatusCodeUniversal, to represent the name/values that are present in all current versions of OpenSSL (1.0.2, 1.1.1, 3.0 alpha) +* Add new enums for the name/value pairs that are unique to a given version +* Add an X509VerifyStatusCode struct that just wraps the int and is a faux-union of the various enums +* Use the OpenSSL runtime version to determine which mapping table to use (after the Universal table fails) + +In addition to that, there are a few const-related changes in the 3.0 headers that are addressed. + +`corefx/src/Native$ ./build_native.sh -portablebuild=false` on systems where find_package(OpenSSL) maps to 3.0 succeeds with these changes. Portable builds still fail. + +Not all tests pass with OpenSSL 3.0 (alpha 13) with these changes, but it does reduce to three categories of error: + +* ICryptoTransform reset/reuse tests fail (OpenSSL regression is open) +* DSA small key generation fails (OpenSSL has fixed the regression for the next alpha/beta release) +* Some OuterLoop X.509 tests are failing as positively revoked when they expect ambiguous revocation states (investigation pending) +--- + .../Interop.OCSP.cs | 4 +- + .../Interop.X509.cs | 109 +++++++++++- + .../pal_evp_pkey_rsa.c | 8 +- + .../pal_x509.c | 24 ++- + .../pal_x509.h | 29 +++- + .../Pal.Unix/OpenSslX509ChainProcessor.cs | 155 ++++++++++++------ + 6 files changed, 266 insertions(+), 63 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs +index bcf9e2af48..8be162e284 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs +@@ -43,7 +43,7 @@ internal static X509VerifyStatusCode X509ChainGetCachedOcspStatus(SafeX509StoreC + { + X509VerifyStatusCode response = CryptoNative_X509ChainGetCachedOcspStatus(ctx, cachePath); + +- if (response < 0) ++ if (response.Code < 0) + { + Debug.Fail($"Unexpected response from X509ChainGetCachedOcspSuccess: {response}"); + throw new CryptographicException(); +@@ -67,7 +67,7 @@ internal static X509VerifyStatusCode X509ChainGetCachedOcspStatus(SafeX509StoreC + { + X509VerifyStatusCode response = CryptoNative_X509ChainVerifyOcsp(ctx, req, resp, cachePath); + +- if (response < 0) ++ if (response.Code < 0) + { + Debug.Fail($"Unexpected response from X509ChainGetCachedOcspSuccess: {response}"); + throw new CryptographicException(); +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs +index 8ffc70af6a..99747c276b 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs +@@ -216,13 +216,13 @@ internal static bool X509StoreCtxRebuildChain(SafeX509StoreCtxHandle ctx) + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509StoreCtxSetVerifyCallback")] + internal static extern void X509StoreCtxSetVerifyCallback(SafeX509StoreCtxHandle ctx, X509StoreVerifyCallback callback); + +- internal static string GetX509VerifyCertErrorString(X509VerifyStatusCode n) ++ internal static string GetX509VerifyCertErrorString(int n) + { + return Marshal.PtrToStringAnsi(X509VerifyCertErrorString(n)); + } + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509VerifyCertErrorString")] +- private static extern IntPtr X509VerifyCertErrorString(X509VerifyStatusCode n); ++ private static extern IntPtr X509VerifyCertErrorString(int n); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509CrlDestroy")] + internal static extern void X509CrlDestroy(IntPtr a); +@@ -239,11 +239,13 @@ internal static string GetX509VerifyCertErrorString(X509VerifyStatusCode n) + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EncodeX509SubjectPublicKeyInfo")] + internal static extern int EncodeX509SubjectPublicKeyInfo(SafeX509Handle x509, byte[] buf); + +- internal enum X509VerifyStatusCode : int ++ internal enum X509VerifyStatusCodeUniversal + { + X509_V_OK = 0, ++ X509_V_ERR_UNSPECIFIED = 1, + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2, + X509_V_ERR_UNABLE_TO_GET_CRL = 3, ++ X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4, + X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5, + X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6, + X509_V_ERR_CERT_SIGNATURE_FAILURE = 7, +@@ -263,18 +265,25 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21, + X509_V_ERR_CERT_CHAIN_TOO_LONG = 22, + X509_V_ERR_CERT_REVOKED = 23, +- X509_V_ERR_INVALID_CA = 24, ++ ++ // Code 24 varies. ++ + X509_V_ERR_PATH_LENGTH_EXCEEDED = 25, + X509_V_ERR_INVALID_PURPOSE = 26, + X509_V_ERR_CERT_UNTRUSTED = 27, + X509_V_ERR_CERT_REJECTED = 28, ++ X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29, ++ X509_V_ERR_AKID_SKID_MISMATCH = 30, ++ X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31, + X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32, + X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33, + X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34, + X509_V_ERR_KEYUSAGE_NO_CRL_SIGN = 35, + X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION = 36, + X509_V_ERR_INVALID_NON_CA = 37, ++ X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED = 38, + X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE = 39, ++ X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED = 40, + X509_V_ERR_INVALID_EXTENSION = 41, + X509_V_ERR_INVALID_POLICY_EXTENSION = 42, + X509_V_ERR_NO_EXPLICIT_POLICY = 43, +@@ -289,7 +298,6 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 52, + X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 53, + X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 54, +- X509_V_ERR_PATH_LOOP = 55, + X509_V_ERR_SUITE_B_INVALID_VERSION = 56, + X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 57, + X509_V_ERR_SUITE_B_INVALID_CURVE = 58, +@@ -299,6 +307,41 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_HOSTNAME_MISMATCH = 62, + X509_V_ERR_EMAIL_MISMATCH = 63, + X509_V_ERR_IP_ADDRESS_MISMATCH = 64, ++ } ++ internal enum X509VerifyStatusCode102 ++ { ++ X509_V_ERR_INVALID_CA = 24, ++ ++ X509_V_ERR_INVALID_CALL = 65, ++ X509_V_ERR_STORE_LOOKUP = 66, ++ X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION = 67, ++ } ++ ++ internal enum X509VerifyStatusCode111 ++ { ++ X509_V_ERR_INVALID_CA = 24, ++ ++ X509_V_ERR_DANE_NO_MATCH = 65, ++ X509_V_ERR_EE_KEY_TOO_SMALL = 66, ++ X509_V_ERR_CA_KEY_TOO_SMALL = 67, ++ X509_V_ERR_CA_MD_TOO_WEAK = 68, ++ X509_V_ERR_INVALID_CALL = 69, ++ X509_V_ERR_STORE_LOOKUP = 70, ++ X509_V_ERR_NO_VALID_SCTS = 71, ++ X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION = 72, ++ X509_V_ERR_OCSP_VERIFY_NEEDED = 73, ++ X509_V_ERR_OCSP_VERIFY_FAILED = 74, ++ X509_V_ERR_OCSP_CERT_UNKNOWN = 75, ++ X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH = 76, ++ X509_V_ERR_NO_ISSUER_PUBLIC_KEY = 77, ++ X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM = 78, ++ X509_V_ERR_EC_KEY_EXPLICIT_PARAMS = 79, ++ } ++ ++ internal enum X509VerifyStatusCode30 ++ { ++ X509_V_ERR_NO_ISSUER_PUBLIC_KEY = 24, ++ + X509_V_ERR_DANE_NO_MATCH = 65, + X509_V_ERR_EE_KEY_TOO_SMALL = 66, + X509_V_ERR_CA_KEY_TOO_SMALL = 67, +@@ -310,6 +353,62 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_OCSP_VERIFY_NEEDED = 73, + X509_V_ERR_OCSP_VERIFY_FAILED = 74, + X509_V_ERR_OCSP_CERT_UNKNOWN = 75, ++ X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM = 76, ++ X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH = 77, ++ X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY = 78, ++ X509_V_ERR_INVALID_CA = 79, ++ X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA = 80, ++ X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN = 81, ++ X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA = 82, ++ X509_V_ERR_ISSUER_NAME_EMPTY = 83, ++ X509_V_ERR_SUBJECT_NAME_EMPTY = 84, ++ X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER = 85, ++ X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER = 86, ++ X509_V_ERR_EMPTY_SUBJECT_ALT_NAME = 87, ++ X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL = 88, ++ X509_V_ERR_CA_BCONS_NOT_CRITICAL = 89, ++ X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL = 90, ++ X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL = 91, ++ X509_V_ERR_CA_CERT_MISSING_KEY_USAGE = 92, ++ X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3 = 93, ++ X509_V_ERR_EC_KEY_EXPLICIT_PARAMS = 94, ++ } ++ ++ internal readonly struct X509VerifyStatusCode : IEquatable ++ { ++ internal static readonly X509VerifyStatusCode X509_V_OK = X509VerifyStatusCodeUniversal.X509_V_OK; ++ ++ public int Code { get; } ++ ++ internal X509VerifyStatusCode(int code) ++ { ++ Code = code; ++ } ++ ++ public X509VerifyStatusCodeUniversal UniversalCode => (X509VerifyStatusCodeUniversal)Code; ++ public X509VerifyStatusCode102 Code102 => (X509VerifyStatusCode102)Code; ++ public X509VerifyStatusCode111 Code111 => (X509VerifyStatusCode111)Code; ++ public X509VerifyStatusCode30 Code30 => (X509VerifyStatusCode30)Code; ++ ++ public bool Equals(X509VerifyStatusCode other) => Code == other.Code; ++ ++ public override bool Equals(object obj) => obj is X509VerifyStatusCode other && Equals(other); ++ ++ public override int GetHashCode() => Code.GetHashCode(); ++ ++ public static bool operator ==(X509VerifyStatusCode left, X509VerifyStatusCode right) => left.Equals(right); ++ ++ public static bool operator !=(X509VerifyStatusCode left, X509VerifyStatusCode right) => !left.Equals(right); ++ ++ public static explicit operator X509VerifyStatusCode(int code) ++ { ++ return new X509VerifyStatusCode(code); ++ } ++ ++ public static implicit operator X509VerifyStatusCode(X509VerifyStatusCodeUniversal code) ++ { ++ return new X509VerifyStatusCode((int)code); ++ } + } + } + } +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 68b6a34a5d..02b31b4737 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -6,7 +6,7 @@ + #include "pal_utilities.h" + #include + +-static int HasNoPrivateKey(RSA* rsa); ++static int HasNoPrivateKey(const RSA* rsa); + + EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + { +@@ -86,7 +86,7 @@ int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + + // This check may no longer be needed on OpenSSL 3.0 + { +- RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ const RSA* rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa == NULL || HasNoPrivateKey(rsa)) + { +@@ -161,7 +161,7 @@ int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, + + // This check may no longer be needed on OpenSSL 3.0 + { +- RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ const RSA* rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa == NULL || HasNoPrivateKey(rsa)) + { +@@ -196,7 +196,7 @@ int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa) + return EVP_PKEY_set1_RSA(pkey, rsa); + } + +-static int HasNoPrivateKey(RSA* rsa) ++static int HasNoPrivateKey(const RSA* rsa) + { + if (rsa == NULL) + return 1; +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c +index 5dd31d0e62..0554c8d3e8 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c +@@ -33,7 +33,6 @@ c_static_assert(PAL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY == X509_V_ERR_U + c_static_assert(PAL_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); + c_static_assert(PAL_X509_V_ERR_CERT_CHAIN_TOO_LONG == X509_V_ERR_CERT_CHAIN_TOO_LONG); + c_static_assert(PAL_X509_V_ERR_CERT_REVOKED == X509_V_ERR_CERT_REVOKED); +-c_static_assert(PAL_X509_V_ERR_INVALID_CA == X509_V_ERR_INVALID_CA); + c_static_assert(PAL_X509_V_ERR_PATH_LENGTH_EXCEEDED == X509_V_ERR_PATH_LENGTH_EXCEEDED); + c_static_assert(PAL_X509_V_ERR_INVALID_PURPOSE == X509_V_ERR_INVALID_PURPOSE); + c_static_assert(PAL_X509_V_ERR_CERT_UNTRUSTED == X509_V_ERR_CERT_UNTRUSTED); +@@ -48,6 +47,26 @@ c_static_assert(PAL_X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE == X509_V_ERR_KEYUS + c_static_assert(PAL_X509_V_ERR_INVALID_EXTENSION == X509_V_ERR_INVALID_EXTENSION); + c_static_assert(PAL_X509_V_ERR_INVALID_POLICY_EXTENSION == X509_V_ERR_INVALID_POLICY_EXTENSION); + c_static_assert(PAL_X509_V_ERR_NO_EXPLICIT_POLICY == X509_V_ERR_NO_EXPLICIT_POLICY); ++c_static_assert(PAL_X509_V_ERR_DIFFERENT_CRL_SCOPE == X509_V_ERR_DIFFERENT_CRL_SCOPE); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE == X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); ++c_static_assert(PAL_X509_V_ERR_UNNESTED_RESOURCE == X509_V_ERR_UNNESTED_RESOURCE); ++c_static_assert(PAL_X509_V_ERR_PERMITTED_VIOLATION == X509_V_ERR_PERMITTED_VIOLATION); ++c_static_assert(PAL_X509_V_ERR_EXCLUDED_VIOLATION == X509_V_ERR_EXCLUDED_VIOLATION); ++c_static_assert(PAL_X509_V_ERR_SUBTREE_MINMAX == X509_V_ERR_SUBTREE_MINMAX); ++c_static_assert(PAL_X509_V_ERR_APPLICATION_VERIFICATION == X509_V_ERR_APPLICATION_VERIFICATION); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE == X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX == X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_NAME_SYNTAX == X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); ++c_static_assert(PAL_X509_V_ERR_CRL_PATH_VALIDATION_ERROR == X509_V_ERR_CRL_PATH_VALIDATION_ERROR); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_VERSION == X509_V_ERR_SUITE_B_INVALID_VERSION); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_ALGORITHM == X509_V_ERR_SUITE_B_INVALID_ALGORITHM); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_CURVE == X509_V_ERR_SUITE_B_INVALID_CURVE); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 == X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256); ++c_static_assert(PAL_X509_V_ERR_HOSTNAME_MISMATCH == X509_V_ERR_HOSTNAME_MISMATCH); ++c_static_assert(PAL_X509_V_ERR_EMAIL_MISMATCH == X509_V_ERR_EMAIL_MISMATCH); ++c_static_assert(PAL_X509_V_ERR_IP_ADDRESS_MISMATCH == X509_V_ERR_IP_ADDRESS_MISMATCH); + + EVP_PKEY* CryptoNative_GetX509EvpPublicKey(X509* x509) + { +@@ -1109,7 +1128,10 @@ CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OC + + if (bio != NULL) + { ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" + if (i2d_OCSP_RESPONSE_bio(bio, resp)) ++#pragma clang diagnostic pop + { + clearErr = 0; + } +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h +index 7f242b4c2e..f7114e9642 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h +@@ -18,7 +18,10 @@ typedef enum { + /* + The error codes used when verifying X509 certificate chains. + +-These values should be kept in sync with Interop.Crypto.X509VerifyStatusCode. ++These values should be kept in sync with Interop.Crypto.X509VerifyStatusCodeUniversal. ++ ++Codes specific to specific versions of OpenSSL can also be returned, ++but are not represented in this enum due to their non-constant nature. + */ + typedef enum { + PAL_X509_V_OK = 0, +@@ -43,7 +46,9 @@ typedef enum { + PAL_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21, + PAL_X509_V_ERR_CERT_CHAIN_TOO_LONG = 22, + PAL_X509_V_ERR_CERT_REVOKED = 23, +- PAL_X509_V_ERR_INVALID_CA = 24, ++ ++ // Code 24 varies ++ + PAL_X509_V_ERR_PATH_LENGTH_EXCEEDED = 25, + PAL_X509_V_ERR_INVALID_PURPOSE = 26, + PAL_X509_V_ERR_CERT_UNTRUSTED = 27, +@@ -58,6 +63,26 @@ typedef enum { + PAL_X509_V_ERR_INVALID_EXTENSION = 41, + PAL_X509_V_ERR_INVALID_POLICY_EXTENSION = 42, + PAL_X509_V_ERR_NO_EXPLICIT_POLICY = 43, ++ PAL_X509_V_ERR_DIFFERENT_CRL_SCOPE = 44, ++ PAL_X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = 45, ++ PAL_X509_V_ERR_UNNESTED_RESOURCE = 46, ++ PAL_X509_V_ERR_PERMITTED_VIOLATION = 47, ++ PAL_X509_V_ERR_EXCLUDED_VIOLATION = 48, ++ PAL_X509_V_ERR_SUBTREE_MINMAX = 49, ++ PAL_X509_V_ERR_APPLICATION_VERIFICATION = 50, ++ PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = 51, ++ PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 52, ++ PAL_X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 53, ++ PAL_X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 54, ++ PAL_X509_V_ERR_SUITE_B_INVALID_VERSION = 56, ++ PAL_X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 57, ++ PAL_X509_V_ERR_SUITE_B_INVALID_CURVE = 58, ++ PAL_X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 59, ++ PAL_X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 60, ++ PAL_X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 61, ++ PAL_X509_V_ERR_HOSTNAME_MISMATCH = 62, ++ PAL_X509_V_ERR_EMAIL_MISMATCH = 63, ++ PAL_X509_V_ERR_IP_ADDRESS_MISMATCH = 64, + } X509VerifyStatusCode; + + typedef int32_t (*X509StoreVerifyCallback)(int32_t, X509_STORE_CTX*); +diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +index d28286f016..a7f777261e 100644 +--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs ++++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +@@ -13,10 +13,14 @@ + using System.Security.Cryptography.X509Certificates.Asn1; + using Microsoft.Win32.SafeHandles; + ++using X509VerifyStatusCodeUniversal = Interop.Crypto.X509VerifyStatusCodeUniversal; ++ + namespace Internal.Cryptography.Pal + { + internal sealed class OpenSslX509ChainProcessor : IChainPal + { ++ private delegate X509ChainStatusFlags MapVersionSpecificCode(Interop.Crypto.X509VerifyStatusCode code); ++ + // The average chain is 3 (End-Entity, Intermediate, Root) + // 10 is plenty big. + private const int DefaultChainCapacity = 10; +@@ -30,6 +34,8 @@ internal sealed class OpenSslX509ChainProcessor : IChainPal + private static readonly CachedDirectoryStoreProvider s_userPersonalStore = + new CachedDirectoryStoreProvider(X509Store.MyStoreName); + ++ private static readonly MapVersionSpecificCode s_mapVersionSpecificCode = GetVersionLookup(); ++ + private SafeX509Handle _leafHandle; + private SafeX509StoreHandle _store; + private readonly SafeX509StackHandle _untrustedLookup; +@@ -156,10 +162,10 @@ internal Interop.Crypto.X509VerifyStatusCode FindFirstChain(X509Certificate2Coll + + internal static bool IsCompleteChain(Interop.Crypto.X509VerifyStatusCode statusCode) + { +- switch (statusCode) ++ switch (statusCode.UniversalCode) + { +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + return false; + default: + return true; +@@ -173,7 +179,7 @@ internal static bool IsCompleteChain(Interop.Crypto.X509VerifyStatusCode statusC + SafeX509StoreCtxHandle storeCtx = _storeCtx; + + Interop.Crypto.X509VerifyStatusCode statusCode = +- Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; ++ X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; + + while (!IsCompleteChain(statusCode)) + { +@@ -426,7 +432,7 @@ private Interop.Crypto.X509VerifyStatusCode CheckOcsp() + Interop.Crypto.X509VerifyStatusCode status = + Interop.Crypto.X509ChainGetCachedOcspStatus(_storeCtx, ocspCache); + +- if (status != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL) ++ if (status != X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL) + { + return status; + } +@@ -468,7 +474,7 @@ private Interop.Crypto.X509VerifyStatusCode CheckOcsp() + { + if (resp == null || resp.IsInvalid) + { +- return Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL; ++ return X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL; + } + + try +@@ -744,77 +750,111 @@ private static void AddUniqueStatus(IList list, ref X509ChainSt + + private static X509ChainStatusFlags MapVerifyErrorToChainStatus(Interop.Crypto.X509VerifyStatusCode code) + { +- switch (code) ++ switch (code.UniversalCode) + { +- case Interop.Crypto.X509VerifyStatusCode.X509_V_OK: ++ case X509VerifyStatusCodeUniversal.X509_V_OK: + return X509ChainStatusFlags.NoError; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_NOT_YET_VALID: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_HAS_EXPIRED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_NOT_YET_VALID: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_HAS_EXPIRED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + return X509ChainStatusFlags.NotTimeValid; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_REVOKED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_REVOKED: + return X509ChainStatusFlags.Revoked; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_SIGNATURE_FAILURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_SIGNATURE_FAILURE: + return X509ChainStatusFlags.NotSignatureValid; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_UNTRUSTED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_UNTRUSTED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + return X509ChainStatusFlags.UntrustedRoot; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_HAS_EXPIRED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_HAS_EXPIRED: + return X509ChainStatusFlags.OfflineRevocation; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_NOT_YET_VALID: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_SIGNATURE_FAILURE: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_NOT_YET_VALID: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_SIGNATURE_FAILURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: + return X509ChainStatusFlags.RevocationStatusUnknown; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_EXTENSION: + return X509ChainStatusFlags.InvalidExtension; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + return X509ChainStatusFlags.PartialChain; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_PURPOSE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_PURPOSE: + return X509ChainStatusFlags.NotValidForUsage; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_CA: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_NON_CA: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_PATH_LENGTH_EXCEEDED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_CERTSIGN: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_NON_CA: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_PATH_LENGTH_EXCEEDED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_CERTSIGN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: + return X509ChainStatusFlags.InvalidBasicConstraints; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_POLICY_EXTENSION: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_NO_EXPLICIT_POLICY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_POLICY_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_NO_EXPLICIT_POLICY: + return X509ChainStatusFlags.InvalidPolicyConstraints; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_REJECTED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_REJECTED: + return X509ChainStatusFlags.ExplicitDistrust; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + return X509ChainStatusFlags.HasNotSupportedCriticalExtension; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_CHAIN_TOO_LONG: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_CHAIN_TOO_LONG: + throw new CryptographicException(); + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_OUT_OF_MEM: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_OUT_OF_MEM: + throw new OutOfMemoryException(); + ++ default: ++ return s_mapVersionSpecificCode(code); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl30Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code30) ++ { ++ case Interop.Crypto.X509VerifyStatusCode30.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; ++ default: ++ Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); ++ throw new CryptographicException(); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl102Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code102) ++ { ++ case Interop.Crypto.X509VerifyStatusCode102.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; ++ default: ++ Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); ++ throw new CryptographicException(); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl111Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code111) ++ { ++ case Interop.Crypto.X509VerifyStatusCode111.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; + default: + Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); + throw new CryptographicException(); +@@ -969,7 +1009,7 @@ internal int VerifyCallback(int ok, IntPtr ctx) + int errorDepth = Interop.Crypto.X509StoreCtxGetErrorDepth(storeCtx); + + if (AbortOnSignatureError && +- errorCode == Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_SIGNATURE_FAILURE) ++ errorCode == X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_SIGNATURE_FAILURE) + { + AbortedForSignatureError = true; + return 0; +@@ -979,9 +1019,9 @@ internal int VerifyCallback(int ok, IntPtr ctx) + // * For compatibility with Windows / .NET Framework, do not report X509_V_CRL_NOT_YET_VALID. + // * X509_V_ERR_DIFFERENT_CRL_SCOPE will result in X509_V_ERR_UNABLE_TO_GET_CRL + // which will trigger OCSP, so is ignorable. +- if (errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_OK && +- errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_NOT_YET_VALID && +- errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_DIFFERENT_CRL_SCOPE) ++ if (errorCode != X509VerifyStatusCodeUniversal.X509_V_OK && ++ errorCode != X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_NOT_YET_VALID && ++ errorCode != X509VerifyStatusCodeUniversal.X509_V_ERR_DIFFERENT_CRL_SCOPE) + { + if (_errors == null) + { +@@ -1016,6 +1056,23 @@ internal int VerifyCallback(int ok, IntPtr ctx) + } + } + ++ private static MapVersionSpecificCode GetVersionLookup() ++ { ++ // 3.0+ are M_NN_00_PP_p (Major, Minor, 0, Patch, Preview) ++ // 1.x.y are 1_XX_YY_PP_p ++ if (SafeEvpPKeyHandle.OpenSslVersion >= 0x3_00_00_00_0) ++ { ++ return MapOpenSsl30Code; ++ } ++ ++ if (SafeEvpPKeyHandle.OpenSslVersion >= 0x1_01_01_00_0) ++ { ++ return MapOpenSsl111Code; ++ } ++ ++ return MapOpenSsl102Code; ++ } ++ + private unsafe struct ErrorCollection + { + // As of OpenSSL 1.1.1 there are 75 defined X509_V_ERR values, +@@ -1059,7 +1116,7 @@ public Enumerator GetEnumerator() + + private static int FindBucket(Interop.Crypto.X509VerifyStatusCode statusCode, out int bitValue) + { +- int val = (int)statusCode; ++ int val = statusCode.Code; + + int bucket; + +-- +2.31.1 + diff --git a/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch b/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch new file mode 100644 index 0000000..ad95fcc --- /dev/null +++ b/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch @@ -0,0 +1,828 @@ +From 07c2b5773e994e8922a24757605a5eff05073167 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Wed, 14 Apr 2021 16:38:19 -0700 +Subject: [PATCH 5/9] Make portable builds work across OpenSSL 1.0.2/1.1.1/3.0 + +Overall structure of changes + +* Pull compatibility headers out into separate include files, because opensslshim.h is too big. +* Use forward definition of EVP_PKEY_CTX_set_rsa_keygen_bits and friends. + * These are in a new apibridge file because they're for bridging up to 3.0, and the existing one was for 1.1(.1) + * Some constants needed for this file changed between 1.1 and 3.0, so there are a lot of asserts and redefines. +* On OpenSSL 3.0, build a legacy version of ERR_put_error since it has the easier signature to work with. +* FALLBACK_FUNCTION doesn't care which version it bound to, if it doesn't find it use a local_ function. +* Renamed NEW_REQUIRED_FUNCTION to REQUIRED_FUNCTION_110 because "new" is now "sort of old". +* There's a manual sanity test that either ERR_put_error or the three new functions that together replace it are found, so we don't end up in a state where we can't report shim-injected errors. + +Portable build checker: +* Built with OpenSSL 1.0.2 headers (Ubuntu 16.04 default libssl-dev) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) +* Built with OpenSSL 1.1.1 headers (Ubuntu 18.04 default libssl-dev) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) +* Built with OpenSSL 3.0 headers (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13 and some surgery to the extra_libs.cmake) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) + +3.0 doesn't run error-free, but it runs with the same error rate from portable and direct builds. All verification was limited to the System.Security.Cryptography.Algorithms.Tests run, but that's generally representative of the bindings. +--- + .../CMakeLists.txt | 1 + + .../apibridge_30.c | 104 +++++++++ + .../apibridge_30.h | 13 ++ + .../apibridge_30_rev.h | 10 + + .../openssl.c | 2 +- + .../opensslshim.c | 29 ++- + .../opensslshim.h | 204 +++++++----------- + .../osslcompat_102.h | 34 +++ + .../osslcompat_111.h | 80 +++++++ + .../osslcompat_30.h | 23 ++ + .../pal_ssl.c | 2 +- + 11 files changed, 367 insertions(+), 135 deletions(-) + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +index b2f4e33f0b..19dab3035d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt ++++ b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +@@ -23,6 +23,7 @@ include_directories(${OPENSSL_INCLUDE_DIR}) + + set(NATIVECRYPTO_SOURCES + apibridge.c ++ apibridge_30.c + openssl.c + pal_asn1.c + pal_bignum.c +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c +new file mode 100644 +index 0000000000..63b5531863 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c +@@ -0,0 +1,104 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++#include "opensslshim.h" ++#include "pal_crypto_types.h" ++#include "pal_types.h" ++ ++#include "../Common/pal_safecrt.h" ++#include ++ ++#if defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1 ++ ++#include "apibridge_30.h" ++ ++// 1.0 and 1.1 agree on the values of the EVP_PKEY_ values, but some of them changed in 3.0. ++// If we're running on 3.0 we already call the real methods, not these fallbacks, so we need to always use ++// the 1.0/1.1 values here. ++ ++// These values are in common. ++c_static_assert(EVP_PKEY_CTRL_MD == 1); ++c_static_assert(EVP_PKEY_CTRL_RSA_KEYGEN_BITS == 0x1003); ++c_static_assert(EVP_PKEY_CTRL_RSA_OAEP_MD == 0x1009); ++c_static_assert(EVP_PKEY_CTRL_RSA_PADDING == 0x1001); ++c_static_assert(EVP_PKEY_CTRL_RSA_PSS_SALTLEN == 0x1002); ++c_static_assert(EVP_PKEY_OP_KEYGEN == (1 << 2)); ++c_static_assert(EVP_PKEY_RSA == 6); ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++ ++c_static_assert(EVP_PKEY_OP_SIGN == (1 << 3)); ++c_static_assert(EVP_PKEY_OP_VERIFY == (1 << 4)); ++c_static_assert(EVP_PKEY_OP_TYPE_CRYPT == ((1 << 8) | (1 << 9))); ++c_static_assert(EVP_PKEY_OP_TYPE_SIG == 0xF8); ++ ++#else ++ ++#undef EVP_PKEY_OP_SIGN ++#define EVP_PKEY_OP_SIGN (1 << 3) ++#undef EVP_PKEY_OP_VERIFY ++#define EVP_PKEY_OP_VERIFY (1 << 4) ++#undef EVP_PKEY_OP_TYPE_CRYPT ++#define EVP_PKEY_OP_TYPE_CRYPT ((1 << 8) | (1 << 9)) ++#undef EVP_PKEY_OP_TYPE_SIG ++#define EVP_PKEY_OP_TYPE_SIG 0xF8 // OP_SIGN | OP_VERIFY | OP_VERIFYRECOVER | OP_SIGNCTX | OP_VERIFYCTX ++ ++#endif ++ ++int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits) ++{ ++ return RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL); ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md) ++{ ++ // set_rsa_oaep_md doesn't route through RSA_pkey_ctx_ctrl n 1.1, unlike the other set_rsa operations. ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void*)md); ++#pragma clang diagnostic pop ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode) ++{ ++ return RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad_mode, NULL); ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen) ++{ ++ return RSA_pkey_ctx_ctrl( ++ ctx, (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltlen, NULL); ++} ++ ++int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md) ++{ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void*)md); ++#pragma clang diagnostic pop ++} ++ ++#endif // defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1 ++ ++#ifdef NEED_OPENSSL_3_0 ++ ++#include "apibridge_30_rev.h" ++ ++void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line) ++{ ++ // In portable builds, ensure that we found the 3.0 error reporting functions. ++ // In non-portable builds, this is just assert(true), but then we call the functions, ++ // so the compiler ensures they're there anyways. ++ assert(API_EXISTS(ERR_new) && API_EXISTS(ERR_set_debug) && API_EXISTS(ERR_set_error)); ++ ERR_new(); ++ ++ // ERR_set_debug saves only the pointer, not the value, as it expects constants. ++ // So just ignore the legacy numeric code, and use the 3.0 "Uh, I don't know" ++ // function name. ++ (void)func; ++ ERR_set_debug(file, line, "(unknown function)"); ++ ++ ERR_set_error(lib, reason, NULL); ++} ++ ++#endif // defined NEED_OPENSSL_3_0 +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h +new file mode 100644 +index 0000000000..0f28900cb7 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h +@@ -0,0 +1,13 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Functions based on OpenSSL 3.0 API, used when building against/running with older versions. ++ ++#pragma once ++#include "pal_types.h" ++ ++int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits); ++int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); ++int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); ++int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen); ++int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h +new file mode 100644 +index 0000000000..657cc969d2 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h +@@ -0,0 +1,10 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Functions based on OpenSSL 3.0 API, used when building against/running with older versions. ++ ++#pragma once ++#include "pal_types.h" ++ ++// For 3.0 to behave like previous versions. ++void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +index 1a9ea04839..456741360d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +@@ -1256,7 +1256,7 @@ done: + } + #endif // NEED_OPENSSL_1_0 */ + +-#ifdef NEED_OPENSSL_1_1 ++#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0 + + // Only defined in OpenSSL 1.1.1+, has no effect on 1.1.0. + #ifndef OPENSSL_INIT_NO_ATEXIT +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c +index b085114a6b..edd7a6dd2d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c +@@ -13,7 +13,7 @@ + + // Define pointers to all the used OpenSSL functions + #define REQUIRED_FUNCTION(fn) __typeof(fn) fn##_ptr; +-#define NEW_REQUIRED_FUNCTION(fn) __typeof(fn) fn##_ptr; ++#define REQUIRED_FUNCTION_110(fn) __typeof(fn) fn##_ptr; + #define LIGHTUP_FUNCTION(fn) __typeof(fn) fn##_ptr; + #define FALLBACK_FUNCTION(fn) __typeof(fn) fn##_ptr; + #define RENAMED_FUNCTION(fn,oldfn) __typeof(fn) fn##_ptr; +@@ -23,7 +23,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION + + // x.x.x, considering the max number of decimal digits for each component +@@ -73,7 +73,12 @@ static bool OpenLibrary() + + if (libssl == NULL) + { +- // Prefer OpenSSL 1.1.x ++ // Prefer OpenSSL 3.x ++ DlOpen(MAKELIB("3")); ++ } ++ ++ if (libssl == NULL) ++ { + DlOpen(MAKELIB("1.1")); + } + +@@ -117,7 +122,7 @@ static void InitializeOpenSSLShim() + #define REQUIRED_FUNCTION(fn) \ + if (!(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } + +-#define NEW_REQUIRED_FUNCTION(fn) \ ++#define REQUIRED_FUNCTION_110(fn) \ + if (!v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } + + #define LIGHTUP_FUNCTION(fn) \ +@@ -127,8 +132,8 @@ static void InitializeOpenSSLShim() + if (!(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fn##_ptr = (__typeof(fn))local_##fn; } + + #define RENAMED_FUNCTION(fn,oldfn) \ +- if (!v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } \ +- if (v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); } ++ fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn));\ ++ if (!fn##_ptr && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); } + + #define LEGACY_FUNCTION(fn) \ + if (v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } +@@ -138,8 +143,18 @@ static void InitializeOpenSSLShim() + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION ++ ++ // Sanity check that we have at least one functioning way of reporting errors. ++ if (ERR_put_error_ptr == &local_ERR_put_error) ++ { ++ if (ERR_new_ptr == NULL || ERR_set_debug_ptr == NULL || ERR_set_error_ptr == NULL) ++ { ++ fprintf(stderr, "Cannot determine the error reporting routine from libssl\n"); ++ abort(); ++ } ++ } + } + + __attribute__((destructor)) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 4c15914d25..1dc9a8c35c 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -36,6 +36,7 @@ + #include + + #include "pal_crypto_config.h" ++#define OPENSSL_VERSION_3_0_RTM 0x30000000L + #define OPENSSL_VERSION_1_1_1_RTM 0x10101000L + #define OPENSSL_VERSION_1_1_0_RTM 0x10100000L + #define OPENSSL_VERSION_1_0_2_RTM 0x10002000L +@@ -64,6 +65,22 @@ + #undef SSLv23_method + #endif + ++#ifdef ERR_put_error ++#undef ERR_put_error ++void ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line); ++#endif ++ ++// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. ++#ifndef RSA_PSS_SALTLEN_DIGEST ++#define RSA_PSS_SALTLEN_DIGEST -1 ++#endif ++ ++#if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include "apibridge_30_rev.h" ++#endif ++#if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++#include "apibridge_30.h" ++#endif + #if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM + #include "apibridge.h" + #endif +@@ -72,6 +89,7 @@ + + #define NEED_OPENSSL_1_0 true + #define NEED_OPENSSL_1_1 true ++#define NEED_OPENSSL_3_0 true + + #if !HAVE_OPENSSL_EC2M + // In portable build, we need to support the following functions even if they were not present +@@ -93,110 +111,16 @@ int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str); + const SSL_CIPHER* SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); + #endif + +-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM +-typedef struct stack_st _STACK; +-int CRYPTO_add_lock(int* pointer, int amount, int type, const char* file, int line); +-int CRYPTO_num_locks(void); +-void CRYPTO_set_locking_callback(void (*func)(int mode, int type, const char* file, int line)); +-void ERR_load_crypto_strings(void); +-int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX* a); +-int EVP_CIPHER_CTX_init(EVP_CIPHER_CTX* a); +-void HMAC_CTX_cleanup(HMAC_CTX* ctx); +-void HMAC_CTX_init(HMAC_CTX* ctx); +-void OPENSSL_add_all_algorithms_conf(void); +-int SSL_library_init(void); +-void SSL_load_error_strings(void); +-int SSL_state(const SSL* ssl); +-unsigned long SSLeay(void); ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include "osslcompat_102.h" ++#elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#include "osslcompat_30.h" ++#include "osslcompat_102.h" + #else +-typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; +-typedef struct stack_st OPENSSL_STACK; +- +-#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L +-#define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L +-#define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L +-#define OPENSSL_INIT_LOAD_CONFIG 0x00000040L +-#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L +- +-const BIGNUM* DSA_get0_key(const DSA* dsa, const BIGNUM** pubKey, const BIGNUM** privKey); +-void DSA_get0_pqg(const DSA* dsa, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g); +-const DSA_METHOD* DSA_get_method(const DSA* dsa); +-int32_t DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX); +-int32_t DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); +-void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); +-EVP_CIPHER_CTX* EVP_CIPHER_CTX_new(void); +-int32_t EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); +-void EVP_MD_CTX_free(EVP_MD_CTX* ctx); +-EVP_MD_CTX* EVP_MD_CTX_new(void); +-RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); +-int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); +-void HMAC_CTX_free(HMAC_CTX* ctx); +-HMAC_CTX* HMAC_CTX_new(void); +-int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS* settings); +-void OPENSSL_sk_free(OPENSSL_STACK*); +-OPENSSL_STACK* OPENSSL_sk_new_null(void); +-int OPENSSL_sk_num(const OPENSSL_STACK*); +-void* OPENSSL_sk_pop(OPENSSL_STACK* st); +-void OPENSSL_sk_pop_free(OPENSSL_STACK* st, void (*func)(void*)); +-int OPENSSL_sk_push(OPENSSL_STACK* st, const void* data); +-void* OPENSSL_sk_value(const OPENSSL_STACK*, int); +-long OpenSSL_version_num(void); +-void RSA_get0_crt_params(const RSA* rsa, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp); +-void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); +-void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); +-int32_t RSA_meth_get_flags(const RSA_METHOD* meth); +-const RSA_METHOD* RSA_PKCS1_OpenSSL(void); +-int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); +-int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); +-int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); +-int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); +-int32_t SSL_is_init_finished(SSL* ssl); +-#undef SSL_CTX_set_options +-unsigned long SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); +-void SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); +-#undef SSL_session_reused +-int SSL_session_reused(SSL* ssl); +-const SSL_METHOD* TLS_method(void); +-const ASN1_TIME* X509_CRL_get0_nextUpdate(const X509_CRL* crl); +-int32_t X509_NAME_get0_der(X509_NAME* x509Name, const uint8_t** pder, size_t* pderlen); +-int32_t X509_PUBKEY_get0_param( +- ASN1_OBJECT** palgOid, const uint8_t** pkeyBytes, int* pkeyBytesLen, X509_ALGOR** palg, X509_PUBKEY* pubkey); +-X509* X509_STORE_CTX_get0_cert(X509_STORE_CTX* ctx); +-STACK_OF(X509)* X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx); +-STACK_OF(X509)* X509_STORE_CTX_get0_untrusted(X509_STORE_CTX* ctx); +-X509_VERIFY_PARAM* X509_STORE_get0_param(X509_STORE* ctx); +-const ASN1_TIME* X509_get0_notAfter(const X509* x509); +-const ASN1_TIME* X509_get0_notBefore(const X509* x509); +-ASN1_BIT_STRING* X509_get0_pubkey_bitstr(const X509* x509); +-const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); +-X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); +-int32_t X509_get_version(const X509* x509); +-int32_t X509_up_ref(X509* x509); +- +-// Redefine EVP_PKEY_CTX_set_rsa operations to use (local_)RSA_pkey_ctx_ctrl so the path is the same +-// for 1.0-built on 1.1 as on 1.1-built on 1.1. +-#undef EVP_PKEY_CTX_set_rsa_keygen_bits +-#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ +- RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) +- +-// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. +- +-#undef EVP_PKEY_CTX_set_rsa_padding +-#define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ +- RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) +- +-#undef EVP_PKEY_CTX_set_rsa_pss_saltlen +-#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ +- RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) +- ++#include "osslcompat_30.h" ++#include "osslcompat_111.h" + #endif + +-#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +-X509_STORE* X509_STORE_CTX_get0_store(X509_STORE_CTX* ctx); +-int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername); +-#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 4 +- +-#endif + + #if !HAVE_OPENSSL_ALPN + #undef HAVE_OPENSSL_ALPN +@@ -213,11 +137,6 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, + void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsigned int* len); + #endif + +-// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. +-#ifndef RSA_PSS_SALTLEN_DIGEST +-#define RSA_PSS_SALTLEN_DIGEST -1 +-#endif +- + #define API_EXISTS(fn) (fn != NULL) + + // List of all functions from the libssl that are used in the System.Security.Cryptography.Native. +@@ -326,10 +245,13 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(ERR_error_string_n) \ + REQUIRED_FUNCTION(ERR_get_error) \ + LEGACY_FUNCTION(ERR_load_crypto_strings) \ +- REQUIRED_FUNCTION(ERR_put_error) \ ++ LIGHTUP_FUNCTION(ERR_new) \ + REQUIRED_FUNCTION(ERR_peek_error) \ + REQUIRED_FUNCTION(ERR_peek_last_error) \ ++ FALLBACK_FUNCTION(ERR_put_error) \ + REQUIRED_FUNCTION(ERR_reason_error_string) \ ++ LIGHTUP_FUNCTION(ERR_set_debug) \ ++ LIGHTUP_FUNCTION(ERR_set_error) \ + REQUIRED_FUNCTION(EVP_aes_128_cbc) \ + REQUIRED_FUNCTION(EVP_aes_128_ccm) \ + REQUIRED_FUNCTION(EVP_aes_128_ecb) \ +@@ -370,6 +292,11 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_keygen_bits) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_oaep_md) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_padding) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_pss_saltlen) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_signature_md) \ + REQUIRED_FUNCTION(EVP_PKEY_base_id) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ +@@ -438,7 +365,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(OCSP_RESPONSE_new) \ + LEGACY_FUNCTION(OPENSSL_add_all_algorithms_conf) \ + REQUIRED_FUNCTION(OPENSSL_cleanse) \ +- NEW_REQUIRED_FUNCTION(OPENSSL_init_ssl) \ ++ REQUIRED_FUNCTION_110(OPENSSL_init_ssl) \ + RENAMED_FUNCTION(OPENSSL_sk_free, sk_free) \ + RENAMED_FUNCTION(OPENSSL_sk_new_null, sk_new_null) \ + RENAMED_FUNCTION(OPENSSL_sk_num, sk_num) \ +@@ -510,11 +437,11 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(SSL_get_error) \ + REQUIRED_FUNCTION(SSL_get_finished) \ + REQUIRED_FUNCTION(SSL_get_peer_cert_chain) \ +- REQUIRED_FUNCTION(SSL_get_peer_certificate) \ + REQUIRED_FUNCTION(SSL_get_peer_finished) \ + REQUIRED_FUNCTION(SSL_get_SSL_CTX) \ + REQUIRED_FUNCTION(SSL_get_version) \ + LIGHTUP_FUNCTION(SSL_get0_alpn_selected) \ ++ RENAMED_FUNCTION(SSL_get1_peer_certificate, SSL_get_peer_certificate) \ + LEGACY_FUNCTION(SSL_library_init) \ + LEGACY_FUNCTION(SSL_load_error_strings) \ + REQUIRED_FUNCTION(SSL_new) \ +@@ -606,7 +533,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + + // Declare pointers to all the used OpenSSL functions + #define REQUIRED_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; +-#define NEW_REQUIRED_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; ++#define REQUIRED_FUNCTION_110(fn) extern __typeof(fn)* fn##_ptr; + #define LIGHTUP_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; + #define FALLBACK_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; + #define RENAMED_FUNCTION(fn,oldfn) extern __typeof(fn)* fn##_ptr; +@@ -616,7 +543,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION + + // Redefine all calls to OpenSSL functions as calls through pointers that are set +@@ -722,10 +649,13 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define ERR_error_string_n ERR_error_string_n_ptr + #define ERR_get_error ERR_get_error_ptr + #define ERR_load_crypto_strings ERR_load_crypto_strings_ptr ++#define ERR_new ERR_new_ptr + #define ERR_peek_error ERR_peek_error_ptr + #define ERR_peek_last_error ERR_peek_last_error_ptr + #define ERR_put_error ERR_put_error_ptr + #define ERR_reason_error_string ERR_reason_error_string_ptr ++#define ERR_set_debug ERR_set_debug_ptr ++#define ERR_set_error ERR_set_error_ptr + #define EVP_aes_128_cbc EVP_aes_128_cbc_ptr + #define EVP_aes_128_ecb EVP_aes_128_ecb_ptr + #define EVP_aes_128_gcm EVP_aes_128_gcm_ptr +@@ -766,6 +696,11 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr + #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr + #define EVP_PKEY_CTX_new_id EVP_PKEY_CTX_new_id_ptr ++#define EVP_PKEY_CTX_set_rsa_keygen_bits EVP_PKEY_CTX_set_rsa_keygen_bits_ptr ++#define EVP_PKEY_CTX_set_rsa_oaep_md EVP_PKEY_CTX_set_rsa_oaep_md_ptr ++#define EVP_PKEY_CTX_set_rsa_padding EVP_PKEY_CTX_set_rsa_padding_ptr ++#define EVP_PKEY_CTX_set_rsa_pss_saltlen EVP_PKEY_CTX_set_rsa_pss_saltlen_ptr ++#define EVP_PKEY_CTX_set_signature_md EVP_PKEY_CTX_set_signature_md_ptr + #define EVP_PKEY_base_id EVP_PKEY_base_id_ptr + #define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr + #define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr +@@ -875,13 +810,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_size RSA_size_ptr + #define RSA_up_ref RSA_up_ref_ptr + #define RSA_verify RSA_verify_ptr +-#define sk_free OPENSSL_sk_free_ptr +-#define sk_new_null OPENSSL_sk_new_null_ptr +-#define sk_num OPENSSL_sk_num_ptr +-#define sk_pop OPENSSL_sk_pop_ptr +-#define sk_pop_free OPENSSL_sk_pop_free_ptr +-#define sk_push OPENSSL_sk_push_ptr +-#define sk_value OPENSSL_sk_value_ptr + #define SSL_CIPHER_get_bits SSL_CIPHER_get_bits_ptr + #define SSL_CIPHER_find SSL_CIPHER_find_ptr + #define SSL_CIPHER_get_id SSL_CIPHER_get_id_ptr +@@ -912,11 +840,11 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define SSL_get_error SSL_get_error_ptr + #define SSL_get_finished SSL_get_finished_ptr + #define SSL_get_peer_cert_chain SSL_get_peer_cert_chain_ptr +-#define SSL_get_peer_certificate SSL_get_peer_certificate_ptr + #define SSL_get_peer_finished SSL_get_peer_finished_ptr + #define SSL_get_SSL_CTX SSL_get_SSL_CTX_ptr + #define SSL_get_version SSL_get_version_ptr + #define SSL_get0_alpn_selected SSL_get0_alpn_selected_ptr ++#define SSL_get1_peer_certificate SSL_get1_peer_certificate_ptr + #define SSL_is_init_finished SSL_is_init_finished_ptr + #define SSL_library_init SSL_library_init_ptr + #define SSL_load_error_strings SSL_load_error_strings_ptr +@@ -1011,7 +939,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + // STACK_OF types will have been declared with inline functions to handle the pointer casting. + // Since these inline functions are strongly bound to the OPENSSL_sk_* functions in 1.1 we need to + // rebind things here. +-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM + // type-safe OPENSSL_sk_free + #define sk_GENERAL_NAME_free(stack) OPENSSL_sk_free((OPENSSL_STACK*)(1 ? stack : (STACK_OF(GENERAL_NAME)*)0)) + #define sk_X509_free(stack) OPENSSL_sk_free((OPENSSL_STACK*)(1 ? stack : (STACK_OF(X509)*)0)) +@@ -1039,6 +967,17 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define sk_GENERAL_NAME_value(stack, idx) (GENERAL_NAME*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(GENERAL_NAME)*)0), idx) + #define sk_X509_NAME_value(stack, idx) (X509_NAME*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(X509_NAME)*)0), idx) + #define sk_X509_value(stack, idx) (X509*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(X509)*)0), idx) ++ ++#elif OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM ++ ++#define sk_free OPENSSL_sk_free_ptr ++#define sk_new_null OPENSSL_sk_new_null_ptr ++#define sk_num OPENSSL_sk_num_ptr ++#define sk_pop OPENSSL_sk_pop_ptr ++#define sk_pop_free OPENSSL_sk_pop_free_ptr ++#define sk_push OPENSSL_sk_push_ptr ++#define sk_value OPENSSL_sk_value_ptr ++ + #endif + + +@@ -1046,9 +985,26 @@ FOR_ALL_OPENSSL_FUNCTIONS + + #define API_EXISTS(fn) true + +-#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM +- ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#define NEED_OPENSSL_3_0 true ++#elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#define NEED_OPENSSL_1_1 true ++#else + #define NEED_OPENSSL_1_0 true ++#endif ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++ ++// Undo renames for renamed-in-3.0 ++#define SSL_get1_peer_certificate SSL_get_peer_certificate ++ ++#endif ++ ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++ ++#define ERR_put_error local_ERR_put_error ++ ++#elif OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM + + // Alias "future" API to the local_ version. + #define DSA_get0_key local_DSA_get0_key +@@ -1110,10 +1066,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define OPENSSL_sk_value sk_value + #define TLS_method SSLv23_method + +-#else // if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM +- +-#define NEED_OPENSSL_1_1 true +- + #endif + + #endif // FEATURE_DISTRO_AGNOSTIC_SSL +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h +new file mode 100644 +index 0000000000..2ee440c320 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h +@@ -0,0 +1,34 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++// ++ ++#pragma once ++ ++// Function prototypes unique to OpenSSL 1.0.2 ++ ++typedef struct stack_st _STACK; ++ ++#undef CRYPTO_num_locks ++#undef CRYPTO_set_locking_callback ++#undef ERR_load_crypto_strings ++#undef EVP_CIPHER_CTX_cleanup ++#undef EVP_CIPHER_CTX_init ++#undef OPENSSL_add_all_algorithms_conf ++#undef SSL_library_init ++#undef SSL_load_error_strings ++#undef SSL_state ++#undef SSLeay ++ ++int CRYPTO_add_lock(int* pointer, int amount, int type, const char* file, int line); ++int CRYPTO_num_locks(void); ++void CRYPTO_set_locking_callback(void (*func)(int mode, int type, const char* file, int line)); ++void ERR_load_crypto_strings(void); ++int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX* a); ++int EVP_CIPHER_CTX_init(EVP_CIPHER_CTX* a); ++void HMAC_CTX_cleanup(HMAC_CTX* ctx); ++void HMAC_CTX_init(HMAC_CTX* ctx); ++void OPENSSL_add_all_algorithms_conf(void); ++int SSL_library_init(void); ++void SSL_load_error_strings(void); ++int SSL_state(const SSL* ssl); ++unsigned long SSLeay(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +new file mode 100644 +index 0000000000..0a730cef89 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +@@ -0,0 +1,80 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Function prototypes unique to OpenSSL 1.1.x ++ ++#pragma once ++#include "pal_types.h" ++ ++#undef SSL_CTX_set_options ++#undef SSL_session_reused ++ ++typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; ++typedef struct stack_st OPENSSL_STACK; ++ ++#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L ++#define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L ++#define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L ++#define OPENSSL_INIT_LOAD_CONFIG 0x00000040L ++#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L ++ ++const BIGNUM* DSA_get0_key(const DSA* dsa, const BIGNUM** pubKey, const BIGNUM** privKey); ++void DSA_get0_pqg(const DSA* dsa, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g); ++const DSA_METHOD* DSA_get_method(const DSA* dsa); ++int32_t DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX); ++int32_t DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); ++void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); ++EVP_CIPHER_CTX* EVP_CIPHER_CTX_new(void); ++int32_t EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); ++void EVP_MD_CTX_free(EVP_MD_CTX* ctx); ++EVP_MD_CTX* EVP_MD_CTX_new(void); ++RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); ++int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); ++void HMAC_CTX_free(HMAC_CTX* ctx); ++HMAC_CTX* HMAC_CTX_new(void); ++int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS* settings); ++void OPENSSL_sk_free(OPENSSL_STACK*); ++OPENSSL_STACK* OPENSSL_sk_new_null(void); ++int OPENSSL_sk_num(const OPENSSL_STACK*); ++void* OPENSSL_sk_pop(OPENSSL_STACK* st); ++void OPENSSL_sk_pop_free(OPENSSL_STACK* st, void (*func)(void*)); ++int OPENSSL_sk_push(OPENSSL_STACK* st, const void* data); ++void* OPENSSL_sk_value(const OPENSSL_STACK*, int); ++long OpenSSL_version_num(void); ++const RSA_METHOD* RSA_PKCS1_OpenSSL(void); ++void RSA_get0_crt_params(const RSA* rsa, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp); ++void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); ++void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); ++int32_t RSA_meth_get_flags(const RSA_METHOD* meth); ++int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); ++int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); ++int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); ++int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); ++int SSL_CTX_config(SSL_CTX* ctx, const char* name); ++unsigned long SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); ++void SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); ++int32_t SSL_is_init_finished(SSL* ssl); ++int SSL_session_reused(SSL* ssl); ++const SSL_METHOD* TLS_method(void); ++const ASN1_TIME* X509_CRL_get0_nextUpdate(const X509_CRL* crl); ++int32_t X509_NAME_get0_der(X509_NAME* x509Name, const uint8_t** pder, size_t* pderlen); ++int32_t X509_PUBKEY_get0_param( ++ ASN1_OBJECT** palgOid, const uint8_t** pkeyBytes, int* pkeyBytesLen, X509_ALGOR** palg, X509_PUBKEY* pubkey); ++X509* X509_STORE_CTX_get0_cert(X509_STORE_CTX* ctx); ++STACK_OF(X509) * X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx); ++STACK_OF(X509) * X509_STORE_CTX_get0_untrusted(X509_STORE_CTX* ctx); ++X509_VERIFY_PARAM* X509_STORE_get0_param(X509_STORE* ctx); ++const ASN1_TIME* X509_get0_notAfter(const X509* x509); ++const ASN1_TIME* X509_get0_notBefore(const X509* x509); ++ASN1_BIT_STRING* X509_get0_pubkey_bitstr(const X509* x509); ++const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); ++X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); ++int32_t X509_get_version(const X509* x509); ++int32_t X509_up_ref(X509* x509); ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM ++int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername); ++X509_STORE* X509_STORE_CTX_get0_store(X509_STORE_CTX* ctx); ++#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 4 ++ ++#endif +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +new file mode 100644 +index 0000000000..0fe57c9132 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -0,0 +1,23 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Function prototypes unique to OpenSSL 3.0 ++ ++#pragma once ++#include "pal_types.h" ++ ++#undef EVP_PKEY_CTX_set_rsa_keygen_bits ++#undef EVP_PKEY_CTX_set_rsa_oaep_md ++#undef EVP_PKEY_CTX_set_rsa_padding ++#undef EVP_PKEY_CTX_set_rsa_pss_saltlen ++#undef EVP_PKEY_CTX_set_signature_md ++ ++void ERR_new(void); ++void ERR_set_debug(const char *file, int line, const char *func); ++void ERR_set_error(int lib, int reason, const char *fmt, ...); ++int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits); ++int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); ++int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); ++int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen); ++int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); ++X509* SSL_get1_peer_certificate(const SSL* ssl); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +index 7764464bc8..c2e3fb2028 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +@@ -285,7 +285,7 @@ int32_t CryptoNative_IsSslStateOK(SSL* ssl) + + X509* CryptoNative_SslGetPeerCertificate(SSL* ssl) + { +- return SSL_get_peer_certificate(ssl); ++ return SSL_get1_peer_certificate(ssl); + } + + X509Stack* CryptoNative_SslGetPeerCertChain(SSL* ssl) +-- +2.31.1 + diff --git a/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch b/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch new file mode 100644 index 0000000..f90abc6 --- /dev/null +++ b/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch @@ -0,0 +1,36 @@ +From 5848349f1e0df84949a01b41d41904036cc070f7 Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Fri, 4 Jun 2021 17:21:28 -0400 +Subject: [PATCH 6/9] Fix merge issues and make the build work + +--- + .../Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +index a7f777261e..d5ec28b1ae 100644 +--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs ++++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +@@ -370,8 +370,8 @@ internal void Finish(OidCollection applicationPolicy, OidCollection certificateP + // chain is just fine (unless it returned a negative code for an exception) + Debug.Assert(verify, "verify should have returned true"); + +- const Interop.Crypto.X509VerifyStatusCode NoCrl = +- Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL; ++ Interop.Crypto.X509VerifyStatusCode NoCrl = ++ X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL; + + ErrorCollection? errors = + workingChain.LastError > 0 ? (ErrorCollection?)workingChain[0] : null; +@@ -726,7 +726,7 @@ private static ArraySegment Base64UrlEncode(ReadOnlySpan input) + X509ChainStatus chainStatus = new X509ChainStatus + { + Status = statusFlag, +- StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode), ++ StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode.Code), + }; + + elementStatus.Add(chainStatus); +-- +2.31.1 + diff --git a/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch b/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch new file mode 100644 index 0000000..698a446 --- /dev/null +++ b/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch @@ -0,0 +1,179 @@ +From 7f171bb20e0816cd2d5af57437553f1a31a886af Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Thu, 15 Apr 2021 08:06:27 -0700 +Subject: [PATCH 7/9] OpenSSL3: Register legacy algorithms when needed + +--- + .../Interop.LegacyAlgorithms.cs | 31 +++++++++++++++++++ + .../openssl.c | 10 ++++++ + .../openssl.h | 2 ++ + .../opensslshim.h | 6 ++++ + .../osslcompat_30.h | 4 +++ + .../Cryptography/DesImplementation.Unix.cs | 2 ++ + .../Cryptography/RC2Implementation.Unix.cs | 2 ++ + ...em.Security.Cryptography.Algorithms.csproj | 3 ++ + 8 files changed, 60 insertions(+) + create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs +new file mode 100644 +index 0000000000..800b14b788 +--- /dev/null ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs +@@ -0,0 +1,31 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++using System.Runtime.InteropServices; ++ ++internal static partial class Interop ++{ ++ internal static partial class Crypto ++ { ++ private static volatile bool s_loadedLegacy; ++ private static readonly object s_legacyLoadLock = new object(); ++ ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RegisterLegacyAlgorithms")] ++ private static extern void CryptoNative_RegisterLegacyAlgorithms(); ++ ++ internal static void EnsureLegacyAlgorithmsRegistered() ++ { ++ if (!s_loadedLegacy) ++ { ++ lock (s_legacyLoadLock) ++ { ++ if (!s_loadedLegacy) ++ { ++ CryptoNative_RegisterLegacyAlgorithms(); ++ s_loadedLegacy = true; ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +index 456741360d..6792bdb1a1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +@@ -1117,6 +1117,16 @@ int64_t CryptoNative_OpenSslVersionNumber() + return (int64_t)OpenSSL_version_num(); + } + ++void CryptoNative_RegisterLegacyAlgorithms() ++{ ++#if NEED_OPENSSL_3_0 ++ if (API_EXISTS(OSSL_PROVIDER_try_load)) ++ { ++ OSSL_PROVIDER_try_load(NULL, "legacy", 1); ++ } ++#endif ++} ++ + #ifdef NEED_OPENSSL_1_0 + // Lock used to make sure EnsureopenSslInitialized itself is thread safe + static pthread_mutex_t g_initLock = PTHREAD_MUTEX_INITIALIZER; +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.h b/src/Native/Unix/System.Security.Cryptography.Native/openssl.h +index 1b4604024e..7bf0da2426 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.h +@@ -73,3 +73,5 @@ DLLEXPORT int32_t CryptoNative_LookupFriendlyNameByOid(const char* oidValue, con + DLLEXPORT int32_t CryptoNative_EnsureOpenSslInitialized(void); + + DLLEXPORT int64_t CryptoNative_OpenSslVersionNumber(void); ++ ++DLLEXPORT void CryptoNative_RegisterLegacyAlgorithms(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 1dc9a8c35c..957860cae4 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -41,6 +41,10 @@ + #define OPENSSL_VERSION_1_1_0_RTM 0x10100000L + #define OPENSSL_VERSION_1_0_2_RTM 0x10002000L + ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_1_RTM + #define HAVE_OPENSSL_SET_CIPHERSUITES 1 + #else +@@ -374,6 +378,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + RENAMED_FUNCTION(OPENSSL_sk_push, sk_push) \ + RENAMED_FUNCTION(OPENSSL_sk_value, sk_value) \ + FALLBACK_FUNCTION(OpenSSL_version_num) \ ++ LIGHTUP_FUNCTION(OSSL_PROVIDER_try_load) \ + REQUIRED_FUNCTION(PEM_read_bio_PKCS7) \ + REQUIRED_FUNCTION(PEM_read_bio_X509) \ + REQUIRED_FUNCTION(PEM_read_bio_X509_AUX) \ +@@ -778,6 +783,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define OPENSSL_sk_push OPENSSL_sk_push_ptr + #define OPENSSL_sk_value OPENSSL_sk_value_ptr + #define OpenSSL_version_num OpenSSL_version_num_ptr ++#define OSSL_PROVIDER_try_load OSSL_PROVIDER_try_load_ptr + #define PEM_read_bio_PKCS7 PEM_read_bio_PKCS7_ptr + #define PEM_read_bio_X509 PEM_read_bio_X509_ptr + #define PEM_read_bio_X509_AUX PEM_read_bio_X509_AUX_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +index 0fe57c9132..b87b4e7250 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -12,6 +12,9 @@ + #undef EVP_PKEY_CTX_set_rsa_pss_saltlen + #undef EVP_PKEY_CTX_set_signature_md + ++typedef struct ossl_provider_st OSSL_PROVIDER; ++typedef struct ossl_lib_ctx_st OSSL_LIB_CTX; ++ + void ERR_new(void); + void ERR_set_debug(const char *file, int line, const char *func); + void ERR_set_error(int lib, int reason, const char *fmt, ...); +@@ -20,4 +23,5 @@ int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); + int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); + int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen); + int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); ++OSSL_PROVIDER* OSSL_PROVIDER_try_load(OSSL_LIB_CTX* , const char* name, int retain_fallbacks); + X509* SSL_get1_peer_certificate(const SSL* ssl); +diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs +index 721efeec6c..0416a86577 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs +@@ -31,6 +31,8 @@ partial class DesImplementation + throw new NotSupportedException(); + } + ++ Interop.Crypto.EnsureLegacyAlgorithmsRegistered(); ++ + BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, 0, iv, encrypting); + return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting); + } +diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs +index 0c06cdbcf7..93e5e9a713 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs +@@ -33,6 +33,8 @@ partial class RC2Implementation + throw new NotSupportedException(); + } + ++ Interop.Crypto.EnsureLegacyAlgorithmsRegistered(); ++ + BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, effectiveKeyLength, iv, encrypting); + return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting); + } +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index c6e8b5b69a..cf5c6731c2 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -519,6 +519,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.LegacyAlgorithms.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.RAND.cs + +-- +2.31.1 + diff --git a/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch b/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch new file mode 100644 index 0000000..2858cc6 --- /dev/null +++ b/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch @@ -0,0 +1,79 @@ +From 30e2e4cbb11a4fbdb7102133b19bfc990a2ba939 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 16 Apr 2021 09:38:47 -0700 +Subject: [PATCH 8/9] Work around OpenSSL 3.0 ciphers not restoring original IV + on reset. + +--- + .../opensslshim.h | 2 ++ + .../osslcompat_30.h | 1 + + .../pal_evp_cipher.c | 20 ++++++++++++++++++- + 3 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 957860cae4..c5052c1ba5 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -271,6 +271,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + LEGACY_FUNCTION(EVP_CIPHER_CTX_cleanup) \ + REQUIRED_FUNCTION(EVP_CIPHER_CTX_ctrl) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_free) \ ++ LIGHTUP_FUNCTION(EVP_CIPHER_CTX_get_original_iv) \ + LEGACY_FUNCTION(EVP_CIPHER_CTX_init) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_new) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_reset) \ +@@ -676,6 +677,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_CIPHER_CTX_cleanup EVP_CIPHER_CTX_cleanup_ptr + #define EVP_CIPHER_CTX_ctrl EVP_CIPHER_CTX_ctrl_ptr + #define EVP_CIPHER_CTX_free EVP_CIPHER_CTX_free_ptr ++#define EVP_CIPHER_CTX_get_original_iv EVP_CIPHER_CTX_get_original_iv_ptr + #define EVP_CIPHER_CTX_init EVP_CIPHER_CTX_init_ptr + #define EVP_CIPHER_CTX_new EVP_CIPHER_CTX_new_ptr + #define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_reset_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +index b87b4e7250..bb529df51e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -18,6 +18,7 @@ typedef struct ossl_lib_ctx_st OSSL_LIB_CTX; + void ERR_new(void); + void ERR_set_debug(const char *file, int line, const char *func); + void ERR_set_error(int lib, int reason, const char *fmt, ...); ++int EVP_CIPHER_CTX_get_original_iv(EVP_CIPHER_CTX *ctx, void *buf, size_t len); + int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits); + int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); + int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c +index af2483fa0c..4d21294fa1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c +@@ -127,8 +127,26 @@ int32_t CryptoNative_EvpCipherReset(EVP_CIPHER_CTX* ctx) + // + // But since we have a different object returned for CreateEncryptor + // and CreateDecryptor we don't need to worry about that. ++ uint8_t* iv = NULL; + +- return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, KEEP_CURRENT_DIRECTION); ++#ifdef NEED_OPENSSL_3_0 ++ // OpenSSL 3.0 alpha 13 does not properly reset the IV. Work around that by ++ // asking for the original IV, and giving it back. ++ uint8_t tmpIV[EVP_MAX_IV_LENGTH]; ++ ++ // If we're direct against 3.0, or we're portable and found 3.0 ++ if (API_EXISTS(EVP_CIPHER_CTX_get_original_iv)) ++ { ++ if (EVP_CIPHER_CTX_get_original_iv(ctx, tmpIV, sizeof(tmpIV)) != 1) ++ { ++ return 0; ++ } ++ ++ iv = tmpIV; ++ } ++#endif ++ ++ return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, KEEP_CURRENT_DIRECTION); + } + + int32_t CryptoNative_EvpCipherCtxSetPadding(EVP_CIPHER_CTX* x, int32_t padding) +-- +2.31.1 + diff --git a/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch b/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch new file mode 100644 index 0000000..7b21c0f --- /dev/null +++ b/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch @@ -0,0 +1,48 @@ +From b7700862a9a85e5bab302c158d5aa6ac1af7c5c1 Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Mon, 7 Jun 2021 11:37:48 -0400 +Subject: [PATCH 9/9] Use `1` instead of `true` for more portable code + +--- + .../opensslshim.h | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index c5052c1ba5..b0d1a71671 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -91,9 +91,9 @@ void ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, + + #ifdef FEATURE_DISTRO_AGNOSTIC_SSL + +-#define NEED_OPENSSL_1_0 true +-#define NEED_OPENSSL_1_1 true +-#define NEED_OPENSSL_3_0 true ++#define NEED_OPENSSL_1_0 1 ++#define NEED_OPENSSL_1_1 1 ++#define NEED_OPENSSL_3_0 1 + + #if !HAVE_OPENSSL_EC2M + // In portable build, we need to support the following functions even if they were not present +@@ -991,14 +991,14 @@ FOR_ALL_OPENSSL_FUNCTIONS + + #else // FEATURE_DISTRO_AGNOSTIC_SSL + +-#define API_EXISTS(fn) true ++#define API_EXISTS(fn) 1 + + #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM +-#define NEED_OPENSSL_3_0 true ++#define NEED_OPENSSL_3_0 1 + #elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM +-#define NEED_OPENSSL_1_1 true ++#define NEED_OPENSSL_1_1 1 + #else +-#define NEED_OPENSSL_1_0 true ++#define NEED_OPENSSL_1_0 1 + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM +-- +2.31.1 + diff --git a/dotnet3.1.spec b/dotnet3.1.spec index b4b5af5..8a9c5d3 100644 --- a/dotnet3.1.spec +++ b/dotnet3.1.spec @@ -55,7 +55,7 @@ Name: dotnet3.1 Version: %{sdk_rpm_version} -Release: 1%{?dist} +Release: 2%{?dist} Summary: .NET Core Runtime and SDK License: MIT and ASL 2.0 and BSD and LGPLv2+ and CC-BY and CC0 and MS-PL and EPL-1.0 and GPL+ and GPLv2 and ISC and OFL and zlib URL: https://github.com/dotnet/ @@ -81,6 +81,17 @@ Patch103: corefx-39633-cgroupv2-mountpoints.patch # https://github.com/dotnet/corefx/pull/43068 Patch105: corefx-43068-centos-9-rid.patch +# https://github.com/dotnet/corefx/pull/43078 +Patch106: corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch +Patch107: corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch +Patch108: corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch +Patch109: corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch +Patch110: corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch +Patch111: corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch +Patch112: corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch +Patch113: corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch +Patch114: corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch + # Build with with hardening flags, including -pie Patch200: coreclr-hardening-flags.patch # Fix build with clang 10; Already applied at tarball-build time @@ -365,6 +376,15 @@ pushd src/corefx.* %patch102 -p1 %patch103 -p1 %patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 +%patch112 -p1 +%patch113 -p1 +%patch114 -p1 popd pushd src/coreclr.* @@ -560,6 +580,10 @@ echo "Testing build results for debug symbols..." %changelog +* Mon Jun 07 2021 Omair Majid - 3.1.115-2 +- Support building against OpenSSL 3.0 +- Resolves: RHBZ#1965045 + * Tue May 18 2021 Omair Majid - 3.1.115-1 - Update to .NET SDK 3.1.115 and Runtime 3.1.15 - Resolves: RHBZ#1961848