From 2b6b45878b1be4d77eec34ab5bc80b626995a8c5 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Fri, 19 Mar 2021 15:05:41 -0700 Subject: [PATCH 01/11] Use EVP_PKEY for RSA key generation --- .../Interop.EvpPkey.Rsa.cs | 16 ++++++++ .../Interop.Rsa.cs | 3 -- .../Security/Cryptography/RSAOpenSsl.cs | 37 ++++--------------- .../apibridge.c | 8 ++++ .../apibridge.h | 1 + .../opensslshim.h | 23 ++++++++++++ .../pal_evp_pkey_rsa.c | 29 +++++++++++++++ .../pal_evp_pkey_rsa.h | 5 +++ .../pal_rsa.c | 5 --- .../pal_rsa.h | 7 ---- ...em.Security.Cryptography.Algorithms.csproj | 3 ++ 11 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs index 1f61a826a9..c28522784b 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs @@ -10,6 +10,22 @@ internal static partial class Interop { internal static partial class Crypto { + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKey")] + private static extern SafeEvpPKeyHandle CryptoNative_RsaGenerateKey(int keySize); + + internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) + { + SafeEvpPKeyHandle pkey = CryptoNative_RsaGenerateKey(keySize); + + if (pkey.IsInvalid) + { + pkey.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return pkey; + } + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs index a7b85ae011..a05f020ada 100644 --- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs @@ -89,9 +89,6 @@ internal static partial class Crypto [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] internal static extern int RsaSize(SafeRsaHandle rsa); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKeyEx")] - internal static extern int RsaGenerateKeyEx(SafeRsaHandle rsa, int bits, SafeBignumHandle e); - internal static bool RsaSign(int type, ReadOnlySpan m, int m_len, Span sigret, out int siglen, SafeRsaHandle rsa) => RsaSign(type, ref MemoryMarshal.GetReference(m), m_len, ref MemoryMarshal.GetReference(sigret), out siglen, rsa); diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 6741d28bba..4d4a8414b3 100644 --- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -25,9 +25,6 @@ public sealed partial class RSAOpenSsl : RSA { private const int BitsPerByte = 8; - // 65537 (0x10001) in big-endian form - private static readonly byte[] s_defaultExponent = { 0x01, 0x00, 0x01 }; - private Lazy _key; public RSAOpenSsl() @@ -585,36 +582,18 @@ private static void CheckBoolReturn(int returnValue) private SafeRsaHandle GenerateKey() { - SafeRsaHandle key = Interop.Crypto.RsaCreate(); - bool generated = false; - - Interop.Crypto.CheckValidOpenSslHandle(key); - - try + using (SafeEvpPKeyHandle pkey = Interop.Crypto.RsaGenerateKey(KeySize)) { - using (SafeBignumHandle exponent = Interop.Crypto.CreateBignum(s_defaultExponent)) - { - // The documentation for RSA_generate_key_ex does not say that it returns only - // 0 or 1, so the call marshals it back as a full Int32 and checks for a value - // of 1 explicitly. - int response = Interop.Crypto.RsaGenerateKeyEx( - key, - KeySize, - exponent); - - CheckBoolReturn(response); - generated = true; - } - } - finally - { - if (!generated) + SafeRsaHandle rsa = Interop.Crypto.EvpPkeyGetRsa(pkey); + + if (rsa.IsInvalid) { - key.Dispose(); + rsa.Dispose(); + throw Interop.Crypto.CreateOpenSslCryptographicException(); } - } - return key; + return rsa; + } } protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c index 167de7fd8e..def7198deb 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c @@ -728,4 +728,12 @@ void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level) (void)ctx; (void)level; } + +int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2) +{ + // On OpenSSL 1.0.2 there aren't two different identifiers for RSA, + // so just pass the request on th EVP_PKEY_CTX_ctrl with the only identifier defined. + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, optype, cmd, p1, p2); +} + #endif diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h index 5f62864b24..b58611ae73 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h @@ -26,6 +26,7 @@ int32_t local_RSA_meth_get_flags(const RSA_METHOD* meth); int32_t local_RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); int32_t local_RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); int32_t local_RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); +int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); int32_t local_SSL_is_init_finished(const SSL* ssl); unsigned long local_SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index ed3994926d..dff6091e9e 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -145,6 +145,7 @@ void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); int32_t RSA_meth_get_flags(const RSA_METHOD* meth); const RSA_METHOD* RSA_PKCS1_OpenSSL(void); +int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); @@ -170,6 +171,13 @@ const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); int32_t X509_get_version(const X509* x509); int32_t X509_up_ref(X509* x509); + +// Redefine EVP_PKEY_CTX_set_rsa operations to use (local_)RSA_pkey_ctx_ctrl so the path is the same +// for 1.0-built on 1.1 as on 1.1-built on 1.1. +#undef EVP_PKEY_CTX_set_rsa_keygen_bits +#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + #endif #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM @@ -341,8 +349,12 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi RENAMED_FUNCTION(EVP_MD_CTX_free, EVP_MD_CTX_destroy) \ RENAMED_FUNCTION(EVP_MD_CTX_new, EVP_MD_CTX_create) \ REQUIRED_FUNCTION(EVP_MD_size) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ + REQUIRED_FUNCTION(EVP_PKEY_base_id) \ REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ REQUIRED_FUNCTION(EVP_PKEY_derive) \ @@ -350,6 +362,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ REQUIRED_FUNCTION(EVP_PKEY_get1_RSA) \ + REQUIRED_FUNCTION(EVP_PKEY_keygen) \ + REQUIRED_FUNCTION(EVP_PKEY_keygen_init) \ REQUIRED_FUNCTION(EVP_PKEY_new) \ REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ @@ -432,6 +446,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi FALLBACK_FUNCTION(RSA_get0_key) \ FALLBACK_FUNCTION(RSA_meth_get_flags) \ REQUIRED_FUNCTION(RSA_new) \ + FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ REQUIRED_FUNCTION(RSA_private_decrypt) \ REQUIRED_FUNCTION(RSA_private_encrypt) \ @@ -727,8 +742,12 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_MD_CTX_free EVP_MD_CTX_free_ptr #define EVP_MD_CTX_new EVP_MD_CTX_new_ptr #define EVP_MD_size EVP_MD_size_ptr +#define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr +#define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr +#define EVP_PKEY_CTX_new_id EVP_PKEY_CTX_new_id_ptr +#define EVP_PKEY_base_id EVP_PKEY_base_id_ptr #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr #define EVP_PKEY_derive EVP_PKEY_derive_ptr @@ -736,6 +755,8 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr #define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr #define EVP_PKEY_get1_RSA EVP_PKEY_get1_RSA_ptr +#define EVP_PKEY_keygen EVP_PKEY_keygen_ptr +#define EVP_PKEY_keygen_init EVP_PKEY_keygen_init_ptr #define EVP_PKEY_new EVP_PKEY_new_ptr #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr @@ -818,6 +839,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define RSA_get_method RSA_get_method_ptr #define RSA_meth_get_flags RSA_meth_get_flags_ptr #define RSA_new RSA_new_ptr +#define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr #define RSA_private_decrypt RSA_private_decrypt_ptr #define RSA_private_encrypt RSA_private_encrypt_ptr @@ -1026,6 +1048,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define RSA_set0_crt_params local_RSA_set0_crt_params #define RSA_set0_factors local_RSA_set0_factors #define RSA_set0_key local_RSA_set0_key +#define RSA_pkey_ctx_ctrl local_RSA_pkey_ctx_ctrl #define SSL_CTX_set_security_level local_SSL_CTX_set_security_level #define SSL_is_init_finished local_SSL_is_init_finished #define X509_CRL_get0_nextUpdate local_X509_CRL_get0_nextUpdate diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c index e8d961dbd2..29f9238ce9 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c @@ -4,6 +4,35 @@ #include "pal_evp_pkey_rsa.h" +EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) +{ + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + + if (ctx == NULL) + { + return NULL; + } + + EVP_PKEY* pkey = NULL; + EVP_PKEY* ret = NULL; + + if (EVP_PKEY_keygen_init(ctx) == 1 && + EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && + EVP_PKEY_keygen(ctx, &pkey) == 1) + { + ret = pkey; + pkey = NULL; + } + + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + + EVP_PKEY_CTX_free(ctx); + return ret; +} + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) { return EVP_PKEY_get1_RSA(pkey); diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h index d8ff369670..1fda149414 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h @@ -6,6 +6,11 @@ #include "pal_compiler.h" #include "opensslshim.h" +/* +Creates an RSA key of the requested size. +*/ +DLLEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); + /* Shims the EVP_PKEY_get1_RSA method. diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c index f764815a04..080027de0e 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c @@ -143,11 +143,6 @@ int32_t CryptoNative_RsaSize(RSA* rsa) return RSA_size(rsa); } -int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e) -{ - return RSA_generate_key_ex(rsa, bits, e, NULL); -} - int32_t CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa) { diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h index b85fed627f..1c0bc2df47 100644 --- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h @@ -86,13 +86,6 @@ Returns the RSA modulus size in bytes. */ DLLEXPORT int32_t CryptoNative_RsaSize(RSA* rsa); -/* -Shims the RSA_generate_key_ex method. - -Returns 1 upon success, otherwise 0. -*/ -DLLEXPORT int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e); - /* Shims the RSA_sign method. diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index fa63b6e2fe..6ad2b78e01 100644 --- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -507,6 +507,9 @@ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs -- 2.31.1