From 64a276e3485b7066a3c630d018ca44dabeb7b6c7 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Sat, 15 May 2021 21:18:06 -0400 Subject: [PATCH] Handle OpenSSL 3's providers OpenSSL 3 compartmentalizes what algorithms it uses, which for us means another hoop to jump through to use dubious cryptography. Right now, we need to load "legacy" in order to access MD4 and RC4. (cherry picked from commit faac961a0d02c7818aad87c765eb344b87e668fa) [rharwood@redhat.com: des3 removal, rc4 FIPSification] --- src/configure.ac | 1 + src/lib/crypto/openssl/enc_provider/aes.c | 16 +++++++ .../crypto/openssl/enc_provider/camellia.c | 16 +++++++ src/lib/crypto/openssl/enc_provider/rc4.c | 4 ++ .../crypto/openssl/hash_provider/hash_evp.c | 5 ++ src/lib/crypto/openssl/init.c | 47 +++++++++++++++++++ .../preauth/pkinit/pkinit_crypto_openssl.c | 25 ++++++++-- 7 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/configure.ac b/src/configure.ac index 9c2e816fe..20066918b 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -284,6 +284,7 @@ AC_SUBST(CRYPTO_IMPL_LIBS) if test "$CRYPTO_IMPL" = openssl; then AC_CHECK_FUNCS(EVP_KDF_fetch) + AC_CHECK_FUNCS(OSSL_PROVIDER_load) fi AC_ARG_WITH([prng-alg], diff --git a/src/lib/crypto/openssl/enc_provider/aes.c b/src/lib/crypto/openssl/enc_provider/aes.c index 6b4622fe9..31c90a69d 100644 --- a/src/lib/crypto/openssl/enc_provider/aes.c +++ b/src/lib/crypto/openssl/enc_provider/aes.c @@ -68,6 +68,10 @@ cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, EVP_CIPHER_CTX *ctx; struct iov_cursor cursor; + ret = krb5int_crypto_init(); + if (ret) + return ret; + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; @@ -102,6 +106,10 @@ cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, EVP_CIPHER_CTX *ctx; struct iov_cursor cursor; + ret = krb5int_crypto_init(); + if (ret) + return ret; + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; @@ -137,6 +145,10 @@ cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, struct iov_cursor cursor; AES_KEY enck; + ret = krb5int_crypto_init(); + if (ret) + return ret; + memset(iv_cts,0,sizeof(iv_cts)); if (ivec && ivec->data){ if (ivec->length != sizeof(iv_cts)) @@ -190,6 +202,10 @@ cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, struct iov_cursor cursor; AES_KEY deck; + ret = krb5int_crypto_init(); + if (ret) + return ret; + memset(iv_cts,0,sizeof(iv_cts)); if (ivec && ivec->data){ if (ivec->length != sizeof(iv_cts)) diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c index f79679a0b..7cc7fc6fb 100644 --- a/src/lib/crypto/openssl/enc_provider/camellia.c +++ b/src/lib/crypto/openssl/enc_provider/camellia.c @@ -92,6 +92,10 @@ cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, EVP_CIPHER_CTX *ctx; struct iov_cursor cursor; + ret = krb5int_crypto_init(); + if (ret) + return ret; + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; @@ -126,6 +130,10 @@ cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, EVP_CIPHER_CTX *ctx; struct iov_cursor cursor; + ret = krb5int_crypto_init(); + if (ret) + return ret; + ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; @@ -161,6 +169,10 @@ cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, struct iov_cursor cursor; CAMELLIA_KEY enck; + ret = krb5int_crypto_init(); + if (ret) + return ret; + memset(iv_cts,0,sizeof(iv_cts)); if (ivec && ivec->data){ if (ivec->length != sizeof(iv_cts)) @@ -214,6 +226,10 @@ cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, struct iov_cursor cursor; CAMELLIA_KEY deck; + ret = krb5int_crypto_init(); + if (ret) + return ret; + memset(iv_cts,0,sizeof(iv_cts)); if (ivec && ivec->data){ if (ivec->length != sizeof(iv_cts)) diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c index 9bf407899..4e7af3555 100644 --- a/src/lib/crypto/openssl/enc_provider/rc4.c +++ b/src/lib/crypto/openssl/enc_provider/rc4.c @@ -69,6 +69,10 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data, if (FIPS_mode()) return KRB5_CRYPTO_INTERNAL; + ret = krb5int_crypto_init(); + if (ret) + return ret; + arcstate = (state != NULL) ? (void *)state->data : NULL; if (arcstate != NULL) { ctx = arcstate->ctx; diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c index 2eb5139c0..09d7b3896 100644 --- a/src/lib/crypto/openssl/hash_provider/hash_evp.c +++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c @@ -41,6 +41,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data, const krb5_data *d; size_t i; int ok; + krb5_error_code ret; + + ret = krb5int_crypto_init(); + if (ret) + return ret; if (output->length != (unsigned int)EVP_MD_size(type)) return KRB5_CRYPTO_INTERNAL; diff --git a/src/lib/crypto/openssl/init.c b/src/lib/crypto/openssl/init.c index 1139bce53..8342dece1 100644 --- a/src/lib/crypto/openssl/init.c +++ b/src/lib/crypto/openssl/init.c @@ -26,6 +26,51 @@ #include "crypto_int.h" +#ifdef HAVE_OSSL_PROVIDER_LOAD + +/* + * Starting in OpenSSL 3, algorithms are grouped into containers called + * "providers", not all of which are loaded by default. At time of writing, + * we need MD4 and RC4 from the legacy provider. Oddly, 3DES is not in + * legacy. + */ + +#include + +OSSL_PROVIDER *legacy_provider = NULL; +OSSL_PROVIDER *default_provider = NULL; + +int +krb5int_crypto_impl_init(void) +{ + legacy_provider = OSSL_PROVIDER_load(NULL, "legacy"); + default_provider = OSSL_PROVIDER_load(NULL, "default"); + + /* + * Someone might build openssl without the legacy provider. They will + * have a bad time, but some things will still work. I don't know think + * this configuration is worth supporting. + */ + if (legacy_provider == NULL || default_provider == NULL) + abort(); + + return 0; +} + +void +krb5int_crypto_impl_cleanup(void) +{ + if (legacy_provider != NULL) + OSSL_PROVIDER_unload(legacy_provider); + if (default_provider != NULL) + OSSL_PROVIDER_unload(default_provider); + + legacy_provider = NULL; + default_provider = NULL; +} + +#else /* !HAVE_OSSL_PROVIDER_LOAD */ + int krb5int_crypto_impl_init(void) { @@ -36,3 +81,5 @@ void krb5int_crypto_impl_cleanup(void) { } + +#endif diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index 350c2118a..284702432 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -44,6 +44,14 @@ #include #endif +#ifdef HAVE_OSSL_PROVIDER_LOAD +#include + +/* TODO these leak - where to release them? */ +OSSL_PROVIDER *legacy_provider = NULL; +OSSL_PROVIDER *default_provider = NULL; +#endif + static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context ); static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ); @@ -2937,12 +2945,23 @@ cleanup: return retval; } +/* Initialize OpenSSL. */ int pkinit_openssl_init() { - /* Initialize OpenSSL. */ - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); +#ifdef HAVE_OSSL_PROVIDER_LOAD + legacy_provider = OSSL_PROVIDER_load(NULL, "legacy"); + default_provider = OSSL_PROVIDER_load(NULL, "default"); + + /* + * Someone might build openssl without the legacy provider. They will + * have a bad time, but some things will still work. I don't know think + * this configuration is worth supporting. + */ + if (legacy_provider == NULL || default_provider == NULL) + abort(); +#endif + return 0; }