6ea8af6747
MD4 cipher requires OpenSSL3's "legacy" provider, while MD5 fetched from the "default" one. Both ciphers are unavailable in FIPS mode, however MD5 is tolerated for RADIUS requests on local host. The OpenSSL3 library context was missing the "default" provider, causing MD5 encryption to fail in FIPS mode. Resolves: rhbz#2068458 Signed-off-by: Julien Rische <jrische@redhat.com>
700 lines
24 KiB
Diff
700 lines
24 KiB
Diff
From 4f8cba1780bc167c52de2a791cad6a1817508bbe Mon Sep 17 00:00:00 2001
|
|
From: Julien Rische <jrische@redhat.com>
|
|
Date: Wed, 23 Feb 2022 17:34:33 +0100
|
|
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4
|
|
|
|
NB: Use openssl's PRNG in FIPS mode and taint within krad.
|
|
|
|
A lot of the FIPS error conditions from OpenSSL are incredibly
|
|
mysterious (at best, things return NULL unexpectedly; at worst,
|
|
internal assertions are tripped; most of the time, you just get
|
|
ENOMEM). In order to cope with this, we need to have some level of
|
|
awareness of what we can and can't safely call.
|
|
|
|
This will slow down some calls slightly (FIPS_mode() takes multiple
|
|
locks), but not for any ciphers we care about - which is to say that
|
|
AES is fine. Shame about SPAKE though.
|
|
|
|
post6 restores MD4 (and therefore keygen-only RC4).
|
|
|
|
post7 restores MD5 and adds radius_md5_fips_override.
|
|
|
|
post8 restores MD4/MD5 for OpenSSL 3.0
|
|
|
|
Use OpenSSL 3.0 library context to access MD4 and MD5 lazily from
|
|
legacy provider if RC4 encryption type is enabled, without affecting
|
|
global context.
|
|
|
|
Remove EVP_MD_CTX_FLAG_NON_FIPS_ALLOW flag since does not have any
|
|
effect anymore.
|
|
|
|
post9 load both default and legacy provider into library context
|
|
|
|
Last-updated: krb5-1.19
|
|
---
|
|
doc/admin/conf_files/krb5_conf.rst | 6 ++
|
|
src/lib/crypto/krb/prng.c | 11 ++-
|
|
.../crypto/openssl/enc_provider/camellia.c | 6 ++
|
|
src/lib/crypto/openssl/enc_provider/rc4.c | 13 ++-
|
|
.../crypto/openssl/hash_provider/hash_evp.c | 93 ++++++++++++++++++-
|
|
src/lib/crypto/openssl/hmac.c | 6 +-
|
|
src/lib/krad/attr.c | 46 ++++++---
|
|
src/lib/krad/attrset.c | 5 +-
|
|
src/lib/krad/internal.h | 28 +++++-
|
|
src/lib/krad/packet.c | 22 +++--
|
|
src/lib/krad/remote.c | 10 +-
|
|
src/lib/krad/t_attr.c | 3 +-
|
|
src/lib/krad/t_attrset.c | 4 +-
|
|
src/plugins/preauth/spake/spake_client.c | 6 ++
|
|
src/plugins/preauth/spake/spake_kdc.c | 6 ++
|
|
15 files changed, 230 insertions(+), 35 deletions(-)
|
|
|
|
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
|
|
index 675175955..adba8238d 100644
|
|
--- a/doc/admin/conf_files/krb5_conf.rst
|
|
+++ b/doc/admin/conf_files/krb5_conf.rst
|
|
@@ -330,6 +330,12 @@ The libdefaults section may contain any of the following relations:
|
|
qualification of shortnames, set this relation to the empty string
|
|
with ``qualify_shortname = ""``. (New in release 1.18.)
|
|
|
|
+**radius_md5_fips_override**
|
|
+ Downstream-only option to enable use of MD5 in RADIUS
|
|
+ communication (libkrad). This allows for local (or protected
|
|
+ tunnel) communication with a RADIUS server that doesn't use krad
|
|
+ (e.g., freeradius) while in FIPS mode.
|
|
+
|
|
**rdns**
|
|
If this flag is true, reverse name lookup will be used in addition
|
|
to forward name lookup to canonicalizing hostnames for use in
|
|
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
|
|
index cb9ca9b98..f0e9984ca 100644
|
|
--- a/src/lib/crypto/krb/prng.c
|
|
+++ b/src/lib/crypto/krb/prng.c
|
|
@@ -26,6 +26,8 @@
|
|
|
|
#include "crypto_int.h"
|
|
|
|
+#include <openssl/rand.h>
|
|
+
|
|
krb5_error_code KRB5_CALLCONV
|
|
krb5_c_random_seed(krb5_context context, krb5_data *data)
|
|
{
|
|
@@ -99,9 +101,16 @@ krb5_boolean
|
|
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
|
|
{
|
|
const char *device;
|
|
-#if defined(__linux__) && defined(SYS_getrandom)
|
|
int r;
|
|
|
|
+ /* A wild FIPS mode appeared! */
|
|
+ if (FIPS_mode()) {
|
|
+ /* The return codes on this API are not good */
|
|
+ r = RAND_bytes(buf, len);
|
|
+ return r == 1;
|
|
+ }
|
|
+
|
|
+#if defined(__linux__) && defined(SYS_getrandom)
|
|
while (len > 0) {
|
|
/*
|
|
* Pull from the /dev/urandom pool, but require it to have been seeded.
|
|
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
index 2da691329..f79679a0b 100644
|
|
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
|
|
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
|
|
struct iov_cursor cursor;
|
|
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
if (output->length < CAMELLIA_BLOCK_SIZE)
|
|
return KRB5_BAD_MSIZE;
|
|
|
|
@@ -331,6 +334,9 @@ static krb5_error_code
|
|
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
|
|
krb5_data *state)
|
|
{
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
state->length = 16;
|
|
state->data = (void *) malloc(16);
|
|
if (state->data == NULL)
|
|
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
index bc87c6f42..9bf407899 100644
|
|
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
|
EVP_CIPHER_CTX *ctx = NULL;
|
|
struct arcfour_state *arcstate;
|
|
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
arcstate = (state != NULL) ? (void *)state->data : NULL;
|
|
if (arcstate != NULL) {
|
|
ctx = arcstate->ctx;
|
|
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
|
static void
|
|
k5_arcfour_free_state(krb5_data *state)
|
|
{
|
|
- struct arcfour_state *arcstate = (void *)state->data;
|
|
+ struct arcfour_state *arcstate;
|
|
+
|
|
+ if (FIPS_mode())
|
|
+ return;
|
|
+
|
|
+ arcstate = (void *) state->data;
|
|
|
|
EVP_CIPHER_CTX_free(arcstate->ctx);
|
|
free(arcstate);
|
|
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
|
|
{
|
|
struct arcfour_state *arcstate;
|
|
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
/*
|
|
* The cipher state here is a saved pointer to a struct arcfour_state
|
|
* object, rather than a flat byte array as in most enc providers. The
|
|
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
index 1e0fb8fc3..57bca3fec 100644
|
|
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
@@ -32,6 +32,46 @@
|
|
|
|
#include "crypto_int.h"
|
|
#include <openssl/evp.h>
|
|
+#include <openssl/provider.h>
|
|
+#include <threads.h>
|
|
+
|
|
+typedef struct ossl_lib_md_context {
|
|
+ OSSL_LIB_CTX *libctx;
|
|
+ OSSL_PROVIDER *default_provider;
|
|
+ OSSL_PROVIDER *legacy_provider;
|
|
+} ossl_md_context_t;
|
|
+
|
|
+static thread_local ossl_md_context_t *ossl_md_ctx = NULL;
|
|
+
|
|
+static krb5_error_code
|
|
+init_ossl_md_ctx(ossl_md_context_t *ctx, const char *algo)
|
|
+{
|
|
+ ctx->libctx = OSSL_LIB_CTX_new();
|
|
+ if (!ctx->libctx)
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
+ /* Load both legacy and default provider as both may be needed. */
|
|
+ ctx->default_provider = OSSL_PROVIDER_load(ctx->libctx, "default");
|
|
+ ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy");
|
|
+
|
|
+ if (!(ctx->default_provider && ctx->legacy_provider))
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+deinit_ossl_ctx(ossl_md_context_t *ctx)
|
|
+{
|
|
+ if (ctx->legacy_provider)
|
|
+ OSSL_PROVIDER_unload(ctx->legacy_provider);
|
|
+
|
|
+ if (ctx->default_provider)
|
|
+ OSSL_PROVIDER_unload(ctx->default_provider);
|
|
+
|
|
+ if (ctx->libctx)
|
|
+ OSSL_LIB_CTX_free(ctx->libctx);
|
|
+}
|
|
|
|
static krb5_error_code
|
|
hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
|
@@ -61,16 +101,65 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
|
return ok ? 0 : KRB5_CRYPTO_INTERNAL;
|
|
}
|
|
|
|
+static krb5_error_code
|
|
+hash_legacy_evp(const char *algo, const krb5_crypto_iov *data, size_t num_data,
|
|
+ krb5_data *output)
|
|
+{
|
|
+ krb5_error_code err;
|
|
+ EVP_MD *md = NULL;
|
|
+
|
|
+ if (!ossl_md_ctx) {
|
|
+ ossl_md_ctx = malloc(sizeof(ossl_md_context_t));
|
|
+ if (!ossl_md_ctx) {
|
|
+ err = ENOMEM;
|
|
+ goto end;
|
|
+ }
|
|
+
|
|
+ err = init_ossl_md_ctx(ossl_md_ctx, algo);
|
|
+ if (err) {
|
|
+ deinit_ossl_ctx(ossl_md_ctx);
|
|
+ free(ossl_md_ctx);
|
|
+ ossl_md_ctx = NULL;
|
|
+ goto end;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ md = EVP_MD_fetch(ossl_md_ctx->libctx, algo, NULL);
|
|
+ if (!md) {
|
|
+ err = KRB5_CRYPTO_INTERNAL;
|
|
+ goto end;
|
|
+ }
|
|
+
|
|
+ err = hash_evp(md, data, num_data, output);
|
|
+
|
|
+end:
|
|
+ if (md)
|
|
+ EVP_MD_free(md);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
static krb5_error_code
|
|
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
|
{
|
|
- return hash_evp(EVP_md4(), data, num_data, output);
|
|
+ /*
|
|
+ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
|
|
+ * by IPA. These keys are only used along a (separately) secured channel
|
|
+ * for legacy reasons when performing trusts to Active Directory.
|
|
+ */
|
|
+ return FIPS_mode() ? hash_legacy_evp("MD4", data, num_data, output)
|
|
+ : hash_evp(EVP_md4(), data, num_data, output);
|
|
}
|
|
|
|
static krb5_error_code
|
|
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
|
{
|
|
- return hash_evp(EVP_md5(), data, num_data, output);
|
|
+ /*
|
|
+ * MD5 is needed in FIPS mode for communication with RADIUS servers. This
|
|
+ * is gated in libkrad by libdefaults->radius_md5_fips_override.
|
|
+ */
|
|
+ return FIPS_mode() ? hash_legacy_evp("MD5", data, num_data, output)
|
|
+ : hash_evp(EVP_md5(), data, num_data, output);
|
|
}
|
|
|
|
static krb5_error_code
|
|
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
|
|
index 7dc59dcc0..769a50c00 100644
|
|
--- a/src/lib/crypto/openssl/hmac.c
|
|
+++ b/src/lib/crypto/openssl/hmac.c
|
|
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
|
|
return EVP_sha256();
|
|
else if (!strncmp(hash->hash_name, "SHA-384",7))
|
|
return EVP_sha384();
|
|
- else if (!strncmp(hash->hash_name, "MD5", 3))
|
|
+
|
|
+ if (FIPS_mode())
|
|
+ return NULL;
|
|
+
|
|
+ if (!strncmp(hash->hash_name, "MD5", 3))
|
|
return EVP_md5();
|
|
else if (!strncmp(hash->hash_name, "MD4", 3))
|
|
return EVP_md4();
|
|
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
|
|
index 9c13d9d75..42d354a3b 100644
|
|
--- a/src/lib/krad/attr.c
|
|
+++ b/src/lib/krad/attr.c
|
|
@@ -38,7 +38,8 @@
|
|
typedef krb5_error_code
|
|
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips);
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
@@ -51,12 +52,14 @@ typedef struct {
|
|
static krb5_error_code
|
|
user_password_encode(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips);
|
|
|
|
static krb5_error_code
|
|
user_password_decode(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *ignored);
|
|
|
|
static const attribute_record attributes[UCHAR_MAX] = {
|
|
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
|
|
@@ -128,7 +131,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
|
|
static krb5_error_code
|
|
user_password_encode(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips)
|
|
{
|
|
const unsigned char *indx;
|
|
krb5_error_code retval;
|
|
@@ -154,8 +158,15 @@ user_password_encode(krb5_context ctx, const char *secret,
|
|
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
|
|
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
|
|
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
|
- &sum);
|
|
+ if (kr_use_fips(ctx)) {
|
|
+ /* Skip encryption here. Taint so that we won't pass it out of
|
|
+ * the machine by accident. */
|
|
+ *is_fips = TRUE;
|
|
+ sum.contents = calloc(1, BLOCKSIZE);
|
|
+ } else {
|
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
|
+ &sum);
|
|
+ }
|
|
if (retval != 0) {
|
|
zap(tmp.data, tmp.length);
|
|
zap(outbuf, len);
|
|
@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret,
|
|
static krb5_error_code
|
|
user_password_decode(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips)
|
|
{
|
|
const unsigned char *indx;
|
|
krb5_error_code retval;
|
|
@@ -204,8 +216,15 @@ user_password_decode(krb5_context ctx, const char *secret,
|
|
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
|
|
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
|
|
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
|
- &tmp, &sum);
|
|
+ if (kr_use_fips(ctx)) {
|
|
+ /* Skip encryption here. Taint so that we won't pass it out of
|
|
+ * the machine by accident. */
|
|
+ *is_fips = TRUE;
|
|
+ sum.contents = calloc(1, BLOCKSIZE);
|
|
+ } else {
|
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
|
+ &tmp, &sum);
|
|
+ }
|
|
if (retval != 0) {
|
|
zap(tmp.data, tmp.length);
|
|
zap(outbuf, in->length);
|
|
@@ -248,7 +267,7 @@ krb5_error_code
|
|
kr_attr_encode(krb5_context ctx, const char *secret,
|
|
const unsigned char *auth, krad_attr type,
|
|
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
|
|
- size_t *outlen)
|
|
+ size_t *outlen, krb5_boolean *is_fips)
|
|
{
|
|
krb5_error_code retval;
|
|
|
|
@@ -265,7 +284,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
|
|
return 0;
|
|
}
|
|
|
|
- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
|
|
+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
|
|
+ is_fips);
|
|
}
|
|
|
|
krb5_error_code
|
|
@@ -274,6 +294,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
{
|
|
krb5_error_code retval;
|
|
+ krb5_boolean ignored;
|
|
|
|
retval = kr_attr_valid(type, in);
|
|
if (retval != 0)
|
|
@@ -288,7 +309,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
return 0;
|
|
}
|
|
|
|
- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
|
|
+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
|
|
+ &ignored);
|
|
}
|
|
|
|
krad_attr
|
|
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
|
|
index 03c613716..d89982a13 100644
|
|
--- a/src/lib/krad/attrset.c
|
|
+++ b/src/lib/krad/attrset.c
|
|
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
|
|
krb5_error_code
|
|
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
const unsigned char *auth,
|
|
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
|
|
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips)
|
|
{
|
|
unsigned char buffer[MAX_ATTRSIZE];
|
|
krb5_error_code retval;
|
|
@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
|
|
K5_TAILQ_FOREACH(a, &set->list, list) {
|
|
retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
|
|
- buffer, &attrlen);
|
|
+ buffer, &attrlen, is_fips);
|
|
if (retval != 0)
|
|
return retval;
|
|
|
|
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
|
|
index 0143d155a..223ffd730 100644
|
|
--- a/src/lib/krad/internal.h
|
|
+++ b/src/lib/krad/internal.h
|
|
@@ -39,6 +39,8 @@
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
|
|
+#include <openssl/crypto.h>
|
|
+
|
|
#ifndef UCHAR_MAX
|
|
#define UCHAR_MAX 255
|
|
#endif
|
|
@@ -49,6 +51,13 @@
|
|
|
|
typedef struct krad_remote_st krad_remote;
|
|
|
|
+struct krad_packet_st {
|
|
+ char buffer[KRAD_PACKET_SIZE_MAX];
|
|
+ krad_attrset *attrset;
|
|
+ krb5_data pkt;
|
|
+ krb5_boolean is_fips;
|
|
+};
|
|
+
|
|
/* Validate constraints of an attribute. */
|
|
krb5_error_code
|
|
kr_attr_valid(krad_attr type, const krb5_data *data);
|
|
@@ -57,7 +66,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
|
|
krb5_error_code
|
|
kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
krad_attr type, const krb5_data *in,
|
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips);
|
|
|
|
/* Decode an attribute. */
|
|
krb5_error_code
|
|
@@ -69,7 +79,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
krb5_error_code
|
|
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
const unsigned char *auth,
|
|
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
|
|
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
|
+ krb5_boolean *is_fips);
|
|
|
|
/* Decode attributes from a buffer. */
|
|
krb5_error_code
|
|
@@ -152,4 +163,17 @@ gai_error_code(int err)
|
|
}
|
|
}
|
|
|
|
+static inline krb5_boolean
|
|
+kr_use_fips(krb5_context ctx)
|
|
+{
|
|
+ int val = 0;
|
|
+
|
|
+ if (!FIPS_mode())
|
|
+ return 0;
|
|
+
|
|
+ profile_get_boolean(ctx->profile, "libdefaults",
|
|
+ "radius_md5_fips_override", NULL, 0, &val);
|
|
+ return !val;
|
|
+}
|
|
+
|
|
#endif /* INTERNAL_H_ */
|
|
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
|
|
index c597174b6..fc2d24800 100644
|
|
--- a/src/lib/krad/packet.c
|
|
+++ b/src/lib/krad/packet.c
|
|
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
|
|
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
|
|
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
|
|
|
|
-struct krad_packet_st {
|
|
- char buffer[KRAD_PACKET_SIZE_MAX];
|
|
- krad_attrset *attrset;
|
|
- krb5_data pkt;
|
|
-};
|
|
-
|
|
typedef struct {
|
|
uchar x[(UCHAR_MAX + 1) / 8];
|
|
} idmap;
|
|
@@ -187,8 +181,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
|
|
memcpy(data.data + response->pkt.length, secret, strlen(secret));
|
|
|
|
/* Hash it. */
|
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
|
- &hash);
|
|
+ if (kr_use_fips(ctx)) {
|
|
+ /* This checksum does very little security-wise anyway, so don't
|
|
+ * taint. */
|
|
+ hash.contents = calloc(1, AUTH_FIELD_SIZE);
|
|
+ } else {
|
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
|
+ &hash);
|
|
+ }
|
|
free(data.data);
|
|
if (retval != 0)
|
|
return retval;
|
|
@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
|
|
|
|
/* Encode the attributes. */
|
|
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
|
|
- &attrset_len);
|
|
+ &attrset_len, &pkt->is_fips);
|
|
if (retval != 0)
|
|
goto error;
|
|
|
|
@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
|
|
|
|
/* Encode the attributes. */
|
|
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
|
|
- &attrset_len);
|
|
+ &attrset_len, &pkt->is_fips);
|
|
if (retval != 0)
|
|
goto error;
|
|
|
|
@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
|
|
const krb5_data *
|
|
krad_packet_encode(const krad_packet *pkt)
|
|
{
|
|
+ if (pkt->is_fips)
|
|
+ return NULL;
|
|
return &pkt->pkt;
|
|
}
|
|
|
|
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
|
|
index c96a9b4ee..eca432424 100644
|
|
--- a/src/lib/krad/remote.c
|
|
+++ b/src/lib/krad/remote.c
|
|
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
|
|
request *r;
|
|
|
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
- tmp = krad_packet_encode(r->request);
|
|
+ tmp = &r->request->pkt;
|
|
|
|
/* If the packet has already been sent, do nothing. */
|
|
if (r->sent == tmp->length)
|
|
@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr)
|
|
if (req != NULL) {
|
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
if (r->request == req &&
|
|
- r->sent == krad_packet_encode(req)->length) {
|
|
+ r->sent == req->pkt.length) {
|
|
request_finish(r, 0, rsp);
|
|
break;
|
|
}
|
|
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
|
(krad_packet_iter_cb)iterator, &r, &tmp);
|
|
if (retval != 0)
|
|
goto error;
|
|
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
|
|
+ rr->info->ai_family != AF_UNIX) {
|
|
+ /* This would expose cleartext passwords, so abort. */
|
|
+ retval = ESOCKTNOSUPPORT;
|
|
+ goto error;
|
|
+ }
|
|
|
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
if (r->request == tmp) {
|
|
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
|
|
index eb2a780c8..4d285ad9d 100644
|
|
--- a/src/lib/krad/t_attr.c
|
|
+++ b/src/lib/krad/t_attr.c
|
|
@@ -50,6 +50,7 @@ main()
|
|
const char *tmp;
|
|
krb5_data in;
|
|
size_t len;
|
|
+ krb5_boolean is_fips = FALSE;
|
|
|
|
noerror(krb5_init_context(&ctx));
|
|
|
|
@@ -73,7 +74,7 @@ main()
|
|
in = string2data((char *)decoded);
|
|
retval = kr_attr_encode(ctx, secret, auth,
|
|
krad_attr_name2num("User-Password"),
|
|
- &in, outbuf, &len);
|
|
+ &in, outbuf, &len, &is_fips);
|
|
insist(retval == 0);
|
|
insist(len == sizeof(encoded));
|
|
insist(memcmp(outbuf, encoded, len) == 0);
|
|
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
|
|
index 7928335ca..0f9576253 100644
|
|
--- a/src/lib/krad/t_attrset.c
|
|
+++ b/src/lib/krad/t_attrset.c
|
|
@@ -49,6 +49,7 @@ main()
|
|
krb5_context ctx;
|
|
size_t len = 0, encode_len;
|
|
krb5_data tmp;
|
|
+ krb5_boolean is_fips = FALSE;
|
|
|
|
noerror(krb5_init_context(&ctx));
|
|
noerror(krad_attrset_new(ctx, &set));
|
|
@@ -62,7 +63,8 @@ main()
|
|
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
|
|
|
|
/* Encode attrset. */
|
|
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
|
|
+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
|
|
+ &is_fips));
|
|
krad_attrset_free(set);
|
|
|
|
/* Manually encode User-Name. */
|
|
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
|
|
index 00734a13b..a3ce22b70 100644
|
|
--- a/src/plugins/preauth/spake/spake_client.c
|
|
+++ b/src/plugins/preauth/spake/spake_client.c
|
|
@@ -38,6 +38,8 @@
|
|
#include "groups.h"
|
|
#include <krb5/clpreauth_plugin.h>
|
|
|
|
+#include <openssl/crypto.h>
|
|
+
|
|
typedef struct reqstate_st {
|
|
krb5_pa_spake *msg; /* set in prep_questions, used in process */
|
|
krb5_keyblock *initial_key;
|
|
@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
|
|
|
if (maj_ver != 1)
|
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
+
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
vt = (krb5_clpreauth_vtable)vtable;
|
|
vt->name = "spake";
|
|
vt->pa_type_list = pa_types;
|
|
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
|
|
index 88c964ce1..c7df0392f 100644
|
|
--- a/src/plugins/preauth/spake/spake_kdc.c
|
|
+++ b/src/plugins/preauth/spake/spake_kdc.c
|
|
@@ -41,6 +41,8 @@
|
|
|
|
#include <krb5/kdcpreauth_plugin.h>
|
|
|
|
+#include <openssl/crypto.h>
|
|
+
|
|
/*
|
|
* The SPAKE kdcpreauth module uses a secure cookie containing the following
|
|
* concatenated fields (all integer fields are big-endian):
|
|
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
|
|
|
if (maj_ver != 1)
|
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
+
|
|
+ if (FIPS_mode())
|
|
+ return KRB5_CRYPTO_INTERNAL;
|
|
+
|
|
vt = (krb5_kdcpreauth_vtable)vtable;
|
|
vt->name = "spake";
|
|
vt->pa_type_list = pa_types;
|
|
--
|
|
2.35.1
|
|
|