From 30e2e4cbb11a4fbdb7102133b19bfc990a2ba939 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Fri, 16 Apr 2021 09:38:47 -0700 Subject: [PATCH 08/11] 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