krb5/Handle-OpenSSL-3-s-provider...

269 lines
8.3 KiB
Diff

From c4b890e5b033fc7c5ed0faa1c66883368e29ec24 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
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 <openssl/provider.h>
+
+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 <openssl/params.h>
#endif
+#ifdef HAVE_OSSL_PROVIDER_LOAD
+#include <openssl/provider.h>
+
+/* 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;
}