From d1de97ec288a3b822ec8899f39395414617ac349 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Tue, 30 May 2023 01:21:48 -0400 Subject: [PATCH] Enable PKINIT if at least one group is available OpenSSL may no longer allow decoding of non-well-known Diffie-Hellman group parameters as EVP_PKEY objects in FIPS mode. However, OpenSSL does not know about MODP group 2 (1024-bit), which is considered as a custom group. As a consequence, the PKINIT kdcpreauth module fails to load in FIPS mode. Allow initialization of PKINIT plugin if at least one of the MODP well-known group parameters successfully decodes. [ghudson@mit.edu: minor commit message and code edits] ticket: 9096 (new) --- src/plugins/preauth/pkinit/pkinit_clnt.c | 2 +- src/plugins/preauth/pkinit/pkinit_crypto.h | 3 +- .../preauth/pkinit/pkinit_crypto_openssl.c | 76 +++++++++++-------- src/plugins/preauth/pkinit/pkinit_srv.c | 2 +- src/plugins/preauth/pkinit/pkinit_trace.h | 3 + 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c index 8c4d81bbc1..a9d9b98250 100644 --- a/src/plugins/preauth/pkinit/pkinit_clnt.c +++ b/src/plugins/preauth/pkinit/pkinit_clnt.c @@ -1378,7 +1378,7 @@ pkinit_client_plugin_init(krb5_context context, if (retval) goto errout; - retval = pkinit_init_plg_crypto(&ctx->cryptoctx); + retval = pkinit_init_plg_crypto(context, &ctx->cryptoctx); if (retval) goto errout; diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h index 64300da856..a87bae6df7 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto.h +++ b/src/plugins/preauth/pkinit/pkinit_crypto.h @@ -103,7 +103,8 @@ typedef struct _pkinit_cert_matching_data { /* * Functions to initialize and cleanup crypto contexts */ -krb5_error_code pkinit_init_plg_crypto(pkinit_plg_crypto_context *); +krb5_error_code pkinit_init_plg_crypto(krb5_context, + pkinit_plg_crypto_context *); void pkinit_fini_plg_crypto(pkinit_plg_crypto_context); krb5_error_code pkinit_init_req_crypto(pkinit_req_crypto_context *); diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index ca105d2421..2abc9dbbe1 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -47,7 +47,8 @@ static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context ); static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ); -static krb5_error_code pkinit_init_dh_params(pkinit_plg_crypto_context ); +static krb5_error_code pkinit_init_dh_params(krb5_context, + pkinit_plg_crypto_context); static void pkinit_fini_dh_params(pkinit_plg_crypto_context ); static krb5_error_code pkinit_init_certs(pkinit_identity_crypto_context ctx); @@ -988,7 +989,8 @@ oerr_cert(krb5_context context, krb5_error_code code, X509_STORE_CTX *certctx, } krb5_error_code -pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) +pkinit_init_plg_crypto(krb5_context context, + pkinit_plg_crypto_context *cryptoctx) { krb5_error_code retval = ENOMEM; pkinit_plg_crypto_context ctx = NULL; @@ -1006,7 +1008,7 @@ pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) if (retval) goto out; - retval = pkinit_init_dh_params(ctx); + retval = pkinit_init_dh_params(context, ctx); if (retval) goto out; @@ -1315,30 +1317,36 @@ pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx) ASN1_OBJECT_free(ctx->id_kp_serverAuth); } -static krb5_error_code -pkinit_init_dh_params(pkinit_plg_crypto_context plgctx) +static int +try_import_group(krb5_context context, const krb5_data *params, + const char *name, EVP_PKEY **pkey_out) { - krb5_error_code retval = ENOMEM; - - plgctx->dh_1024 = decode_dh_params(&oakley_1024); - if (plgctx->dh_1024 == NULL) - goto cleanup; - - plgctx->dh_2048 = decode_dh_params(&oakley_2048); - if (plgctx->dh_2048 == NULL) - goto cleanup; + *pkey_out = decode_dh_params(params); + if (*pkey_out == NULL) + TRACE_PKINIT_DH_GROUP_UNAVAILABLE(context, name); + return (*pkey_out != NULL) ? 1 : 0; +} - plgctx->dh_4096 = decode_dh_params(&oakley_4096); - if (plgctx->dh_4096 == NULL) - goto cleanup; +static krb5_error_code +pkinit_init_dh_params(krb5_context context, pkinit_plg_crypto_context plgctx) +{ + int n = 0; - retval = 0; + n += try_import_group(context, &oakley_1024, "MODP 2 (1024-bit)", + &plgctx->dh_1024); + n += try_import_group(context, &oakley_2048, "MODP 14 (2048-bit)", + &plgctx->dh_2048); + n += try_import_group(context, &oakley_4096, "MODP 16 (4096-bit)", + &plgctx->dh_4096); -cleanup: - if (retval) + if (n == 0) { pkinit_fini_dh_params(plgctx); + k5_setmsg(context, ENOMEM, + _("PKINIT cannot initialize any key exchange groups")); + return ENOMEM; + } - return retval; + return 0; } static void @@ -2961,11 +2969,11 @@ client_create_dh(krb5_context context, if (cryptoctx->received_params != NULL) params = cryptoctx->received_params; - else if (dh_size == 1024) + else if (plg_cryptoctx->dh_1024 != NULL && dh_size == 1024) params = plg_cryptoctx->dh_1024; - else if (dh_size == 2048) + else if (plg_cryptoctx->dh_2048 != NULL && dh_size == 2048) params = plg_cryptoctx->dh_2048; - else if (dh_size == 4096) + else if (plg_cryptoctx->dh_4096 != NULL && dh_size == 4096) params = plg_cryptoctx->dh_4096; else goto cleanup; @@ -3261,19 +3269,23 @@ pkinit_create_td_dh_parameters(krb5_context context, krb5_algorithm_identifier alg_4096 = { dh_oid, oakley_4096 }; krb5_algorithm_identifier *alglist[4]; - if (opts->dh_min_bits > 4096) { - ret = KRB5KRB_ERR_GENERIC; - goto cleanup; - } - i = 0; - if (opts->dh_min_bits <= 2048) + if (plg_cryptoctx->dh_2048 != NULL && opts->dh_min_bits <= 2048) alglist[i++] = &alg_2048; - alglist[i++] = &alg_4096; - if (opts->dh_min_bits <= 1024) + if (plg_cryptoctx->dh_4096 != NULL && opts->dh_min_bits <= 4096) + alglist[i++] = &alg_4096; + if (plg_cryptoctx->dh_1024 != NULL && opts->dh_min_bits <= 1024) alglist[i++] = &alg_1024; alglist[i] = NULL; + if (i == 0) { + ret = KRB5KRB_ERR_GENERIC; + k5_setmsg(context, ret, + _("OpenSSL has no supported key exchange groups for " + "pkinit_dh_min_bits=%d"), opts->dh_min_bits); + goto cleanup; + } + ret = k5int_encode_krb5_td_dh_parameters(alglist, &der_alglist); if (ret) goto cleanup; diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index 865c543c44..705e1f12ed 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -1222,7 +1222,7 @@ pkinit_server_plugin_init_realm(krb5_context context, const char *realmname, goto errout; plgctx->realmname_len = strlen(plgctx->realmname); - retval = pkinit_init_plg_crypto(&plgctx->cryptoctx); + retval = pkinit_init_plg_crypto(context, &plgctx->cryptoctx); if (retval) goto errout; diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h index 259e95c6c2..5ee39c085c 100644 --- a/src/plugins/preauth/pkinit/pkinit_trace.h +++ b/src/plugins/preauth/pkinit/pkinit_trace.h @@ -90,6 +90,9 @@ #define TRACE_PKINIT_CLIENT_TRYAGAIN(c) \ TRACE(c, "PKINIT client trying again with KDC-provided parameters") +#define TRACE_PKINIT_DH_GROUP_UNAVAILABLE(c, name) \ + TRACE(c, "PKINIT key exchange group {str} unsupported", name) + #define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \ TRACE(c, "PKINIT OpenSSL error: {str}", msg) -- 2.39.2