Support building against OpenSSL 3.0

Resolves: RHBZ#1965045
This commit is contained in:
Omair Majid 2021-06-08 10:58:25 -04:00
parent c0725fa2c5
commit b9eb75e9ea
10 changed files with 3765 additions and 1 deletions

View File

@ -0,0 +1,349 @@
From 2b6b45878b1be4d77eec34ab5bc80b626995a8c5 Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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<byte> m, int m_len, Span<byte> 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<SafeRsaHandle> _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 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs</Link>
</Compile>
--
2.31.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,538 @@
From 7111a92546253d6fc857f7cad8b0bff425df0798 Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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<byte> hash,
+ Span<byte> 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<byte> from,
- Span<byte> 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<byte> from,
Span<byte> 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<byte> m, int m_len, Span<byte> 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<byte> m, ReadOnlySpan<byte> 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<byte> pssBytes = new Span<byte>(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

View File

@ -0,0 +1,648 @@
From 49dc6e515d9ec0db1841e5d2d86f52916d35f667 Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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<X509VerifyStatusCode>
+ {
+ 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 <assert.h>
-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<X509ChainStatus> 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

View File

@ -0,0 +1,828 @@
From 07c2b5773e994e8922a24757605a5eff05073167 Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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 <assert.h>
+
+#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 <openssl/x509v3.h>
#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

View File

@ -0,0 +1,36 @@
From 5848349f1e0df84949a01b41d41904036cc070f7 Mon Sep 17 00:00:00 2001
From: Omair Majid <omajid@redhat.com>
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<char> Base64UrlEncode(ReadOnlySpan<byte> input)
X509ChainStatus chainStatus = new X509ChainStatus
{
Status = statusFlag,
- StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode),
+ StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode.Code),
};
elementStatus.Add(chainStatus);
--
2.31.1

View File

@ -0,0 +1,179 @@
From 7f171bb20e0816cd2d5af57437553f1a31a886af Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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 <openssl/provider.h>
+#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 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.LegacyAlgorithms.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.LegacyAlgorithms.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.RAND.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.RAND.cs</Link>
</Compile>
--
2.31.1

View File

@ -0,0 +1,79 @@
From 30e2e4cbb11a4fbdb7102133b19bfc990a2ba939 Mon Sep 17 00:00:00 2001
From: Jeremy Barton <jbarton@microsoft.com>
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

View File

@ -0,0 +1,48 @@
From b7700862a9a85e5bab302c158d5aa6ac1af7c5c1 Mon Sep 17 00:00:00 2001
From: Omair Majid <omajid@redhat.com>
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

View File

@ -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 <omajid@redhat.com> - 3.1.115-2
- Support building against OpenSSL 3.0
- Resolves: RHBZ#1965045
* Tue May 18 2021 Omair Majid <omajid@redhat.com> - 3.1.115-1
- Update to .NET SDK 3.1.115 and Runtime 3.1.15
- Resolves: RHBZ#1961848