|
|
d1ad9f |
From b8e3a859f8904d395ea0e1a7d6c49a791029711c Mon Sep 17 00:00:00 2001
|
|
|
d1ad9f |
From: Robbie Harwood <rharwood@redhat.com>
|
|
|
d1ad9f |
Date: Fri, 9 Nov 2018 15:12:21 -0500
|
|
|
a53771 |
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4
|
|
|
a53771 |
|
|
|
a53771 |
NB: Use openssl's PRNG in FIPS mode and taint within krad.
|
|
|
a53771 |
|
|
|
a53771 |
A lot of the FIPS error conditions from OpenSSL are incredibly
|
|
|
a53771 |
mysterious (at best, things return NULL unexpectedly; at worst,
|
|
|
a53771 |
internal assertions are tripped; most of the time, you just get
|
|
|
a53771 |
ENOMEM). In order to cope with this, we need to have some level of
|
|
|
a53771 |
awareness of what we can and can't safely call.
|
|
|
a53771 |
|
|
|
a53771 |
This will slow down some calls slightly (FIPS_mode() takes multiple
|
|
|
a53771 |
locks), but not for any ciphers we care about - which is to say that
|
|
|
a53771 |
AES is fine. Shame about SPAKE though.
|
|
|
a53771 |
|
|
|
a53771 |
post6 restores MD4 (and therefore keygen-only RC4).
|
|
|
a53771 |
|
|
|
a53771 |
post7 restores MD5 and adds radius_md5_fips_override.
|
|
|
a53771 |
|
|
|
d1ad9f |
post8 silences a static analyzer warning.
|
|
|
a53771 |
|
|
|
d1ad9f |
post9 add missing includes for FIPS_mode() macro
|
|
|
a53771 |
|
|
|
d1ad9f |
Last-updated: krb5-1.20.1
|
|
|
a53771 |
---
|
|
|
d1ad9f |
doc/admin/conf_files/krb5_conf.rst | 6 +++
|
|
|
d1ad9f |
src/lib/crypto/krb/prng.c | 17 ++++++-
|
|
|
d1ad9f |
.../crypto/openssl/enc_provider/camellia.c | 7 +++
|
|
|
d1ad9f |
src/lib/crypto/openssl/enc_provider/rc4.c | 17 ++++++-
|
|
|
d1ad9f |
.../crypto/openssl/hash_provider/hash_evp.c | 12 +++++
|
|
|
d1ad9f |
src/lib/crypto/openssl/hmac.c | 7 ++-
|
|
|
d1ad9f |
src/lib/krad/attr.c | 46 ++++++++++++++-----
|
|
|
a53771 |
src/lib/krad/attrset.c | 5 +-
|
|
|
d1ad9f |
src/lib/krad/internal.h | 32 ++++++++++++-
|
|
|
d1ad9f |
src/lib/krad/packet.c | 22 +++++----
|
|
|
d1ad9f |
src/lib/krad/remote.c | 10 +++-
|
|
|
a53771 |
src/lib/krad/t_attr.c | 3 +-
|
|
|
a53771 |
src/lib/krad/t_attrset.c | 4 +-
|
|
|
d1ad9f |
src/plugins/preauth/spake/spake_client.c | 10 ++++
|
|
|
d1ad9f |
src/plugins/preauth/spake/spake_kdc.c | 10 ++++
|
|
|
d1ad9f |
15 files changed, 175 insertions(+), 33 deletions(-)
|
|
|
a53771 |
|
|
|
a53771 |
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
|
|
|
d1ad9f |
index d5d6e06ebb..2a4962069f 100644
|
|
|
a53771 |
--- a/doc/admin/conf_files/krb5_conf.rst
|
|
|
a53771 |
+++ b/doc/admin/conf_files/krb5_conf.rst
|
|
|
a53771 |
@@ -330,6 +330,12 @@ The libdefaults section may contain any of the following relations:
|
|
|
a53771 |
qualification of shortnames, set this relation to the empty string
|
|
|
a53771 |
with ``qualify_shortname = ""``. (New in release 1.18.)
|
|
|
a53771 |
|
|
|
a53771 |
+**radius_md5_fips_override**
|
|
|
a53771 |
+ Downstream-only option to enable use of MD5 in RADIUS
|
|
|
a53771 |
+ communication (libkrad). This allows for local (or protected
|
|
|
a53771 |
+ tunnel) communication with a RADIUS server that doesn't use krad
|
|
|
a53771 |
+ (e.g., freeradius) while in FIPS mode.
|
|
|
a53771 |
+
|
|
|
a53771 |
**rdns**
|
|
|
a53771 |
If this flag is true, reverse name lookup will be used in addition
|
|
|
a53771 |
to forward name lookup to canonicalizing hostnames for use in
|
|
|
a53771 |
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
|
|
|
d1ad9f |
index d6b79e2dea..ae37c77518 100644
|
|
|
a53771 |
--- a/src/lib/crypto/krb/prng.c
|
|
|
a53771 |
+++ b/src/lib/crypto/krb/prng.c
|
|
|
d1ad9f |
@@ -26,6 +26,14 @@
|
|
|
a53771 |
|
|
|
a53771 |
#include "crypto_int.h"
|
|
|
a53771 |
|
|
|
a53771 |
+#include <openssl/rand.h>
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
+#else
|
|
|
d1ad9f |
+#include <openssl/crypto.h>
|
|
|
d1ad9f |
+#endif
|
|
|
d1ad9f |
+
|
|
|
a53771 |
krb5_error_code KRB5_CALLCONV
|
|
|
a53771 |
krb5_c_random_seed(krb5_context context, krb5_data *data)
|
|
|
a53771 |
{
|
|
|
d1ad9f |
@@ -96,9 +104,16 @@ cleanup:
|
|
|
d1ad9f |
static krb5_boolean
|
|
|
d1ad9f |
get_os_entropy(unsigned char *buf, size_t len)
|
|
|
a53771 |
{
|
|
|
a53771 |
-#if defined(__linux__) && defined(SYS_getrandom)
|
|
|
a53771 |
int r;
|
|
|
a53771 |
|
|
|
a53771 |
+ /* A wild FIPS mode appeared! */
|
|
|
a53771 |
+ if (FIPS_mode()) {
|
|
|
a53771 |
+ /* The return codes on this API are not good */
|
|
|
a53771 |
+ r = RAND_bytes(buf, len);
|
|
|
a53771 |
+ return r == 1;
|
|
|
a53771 |
+ }
|
|
|
a53771 |
+
|
|
|
a53771 |
+#if defined(__linux__) && defined(SYS_getrandom)
|
|
|
a53771 |
while (len > 0) {
|
|
|
a53771 |
/*
|
|
|
a53771 |
* Pull from the /dev/urandom pool, but require it to have been seeded.
|
|
|
a53771 |
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
|
d1ad9f |
index 01920e6ce1..3dd3b0624f 100644
|
|
|
a53771 |
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
|
a53771 |
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
|
|
|
d1ad9f |
@@ -32,6 +32,7 @@
|
|
|
d1ad9f |
#include <openssl/camellia.h>
|
|
|
d1ad9f |
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
#include <openssl/core_names.h>
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
#else
|
|
|
d1ad9f |
#include <openssl/modes.h>
|
|
|
d1ad9f |
#endif
|
|
|
d1ad9f |
@@ -387,6 +388,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
|
|
|
a53771 |
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
|
|
|
a53771 |
struct iov_cursor cursor;
|
|
|
a53771 |
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
if (output->length < CAMELLIA_BLOCK_SIZE)
|
|
|
a53771 |
return KRB5_BAD_MSIZE;
|
|
|
a53771 |
|
|
|
d1ad9f |
@@ -418,6 +422,9 @@ static krb5_error_code
|
|
|
a53771 |
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
|
|
|
a53771 |
krb5_data *state)
|
|
|
a53771 |
{
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
state->length = 16;
|
|
|
a53771 |
state->data = (void *) malloc(16);
|
|
|
a53771 |
if (state->data == NULL)
|
|
|
a53771 |
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
|
d1ad9f |
index 448d563348..6a83f10d27 100644
|
|
|
a53771 |
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
|
a53771 |
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
|
|
|
d1ad9f |
@@ -38,6 +38,10 @@
|
|
|
d1ad9f |
|
|
|
d1ad9f |
#include <openssl/evp.h>
|
|
|
d1ad9f |
|
|
|
d1ad9f |
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
+#endif
|
|
|
d1ad9f |
+
|
|
|
d1ad9f |
/*
|
|
|
d1ad9f |
* The loopback field is a pointer to the structure. If the application copies
|
|
|
d1ad9f |
* the state (not a valid operation, but one which happens to works with some
|
|
|
d1ad9f |
@@ -69,6 +73,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
|
|
a53771 |
EVP_CIPHER_CTX *ctx = NULL;
|
|
|
a53771 |
struct arcfour_state *arcstate;
|
|
|
a53771 |
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
arcstate = (state != NULL) ? (void *)state->data : NULL;
|
|
|
a53771 |
if (arcstate != NULL) {
|
|
|
a53771 |
ctx = arcstate->ctx;
|
|
|
d1ad9f |
@@ -116,7 +123,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
|
|
a53771 |
static void
|
|
|
a53771 |
k5_arcfour_free_state(krb5_data *state)
|
|
|
a53771 |
{
|
|
|
a53771 |
- struct arcfour_state *arcstate = (void *)state->data;
|
|
|
a53771 |
+ struct arcfour_state *arcstate;
|
|
|
a53771 |
+
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return;
|
|
|
a53771 |
+
|
|
|
a53771 |
+ arcstate = (void *) state->data;
|
|
|
a53771 |
|
|
|
a53771 |
EVP_CIPHER_CTX_free(arcstate->ctx);
|
|
|
a53771 |
free(arcstate);
|
|
|
d1ad9f |
@@ -128,6 +140,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
|
|
|
a53771 |
{
|
|
|
a53771 |
struct arcfour_state *arcstate;
|
|
|
a53771 |
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
/*
|
|
|
a53771 |
* The cipher state here is a saved pointer to a struct arcfour_state
|
|
|
a53771 |
* object, rather than a flat byte array as in most enc providers. The
|
|
|
a53771 |
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
|
d1ad9f |
index f2fbffdb29..11659908bb 100644
|
|
|
a53771 |
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
|
a53771 |
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
|
|
d1ad9f |
@@ -60,6 +60,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
|
|
d1ad9f |
if (ctx == NULL)
|
|
|
d1ad9f |
return ENOMEM;
|
|
|
a53771 |
|
|
|
d1ad9f |
+ if (type == EVP_md4() || type == EVP_md5()) {
|
|
|
d1ad9f |
+ /* See comments below in hash_md4() and hash_md5(). */
|
|
|
d1ad9f |
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
|
|
|
38a7f7 |
+ }
|
|
|
38a7f7 |
+
|
|
|
d1ad9f |
ok = EVP_DigestInit_ex(ctx, type, NULL);
|
|
|
d1ad9f |
for (i = 0; i < num_data; i++) {
|
|
|
d1ad9f |
if (!SIGN_IOV(&data[i]))
|
|
|
d1ad9f |
@@ -78,6 +83,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
|
|
a53771 |
{
|
|
|
a53771 |
+ /*
|
|
|
a53771 |
+ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
|
|
|
a53771 |
+ * by IPA. These keys are only used along a (separately) secured channel
|
|
|
a53771 |
+ * for legacy reasons when performing trusts to Active Directory.
|
|
|
a53771 |
+ */
|
|
|
d1ad9f |
return hash_evp(EVP_md4(), data, num_data, output);
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
d1ad9f |
@@ -90,6 +100,8 @@ const struct krb5_hash_provider krb5int_hash_md4 = {
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
|
|
a53771 |
{
|
|
|
d1ad9f |
+ /* MD5 is needed in FIPS mode for communication with RADIUS servers. This
|
|
|
d1ad9f |
+ * is gated in libkrad by libdefaults->radius_md5_fips_override. */
|
|
|
d1ad9f |
return hash_evp(EVP_md5(), data, num_data, output);
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
|
|
|
d1ad9f |
index bf12b8d6a0..25a419d73a 100644
|
|
|
a53771 |
--- a/src/lib/crypto/openssl/hmac.c
|
|
|
a53771 |
+++ b/src/lib/crypto/openssl/hmac.c
|
|
|
d1ad9f |
@@ -59,6 +59,7 @@
|
|
|
d1ad9f |
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
#include <openssl/params.h>
|
|
|
d1ad9f |
#include <openssl/core_names.h>
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
#else
|
|
|
d1ad9f |
#include <openssl/hmac.h>
|
|
|
d1ad9f |
#endif
|
|
|
d1ad9f |
@@ -111,7 +112,11 @@ map_digest(const struct krb5_hash_provider *hash)
|
|
|
a53771 |
return EVP_sha256();
|
|
|
d1ad9f |
else if (hash == &krb5int_hash_sha384)
|
|
|
a53771 |
return EVP_sha384();
|
|
|
d1ad9f |
- else if (hash == &krb5int_hash_md5)
|
|
|
a53771 |
+
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return NULL;
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+ if (hash == &krb5int_hash_md5)
|
|
|
a53771 |
return EVP_md5();
|
|
|
d1ad9f |
else if (hash == &krb5int_hash_md4)
|
|
|
a53771 |
return EVP_md4();
|
|
|
a53771 |
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
|
|
|
d1ad9f |
index 9c13d9d755..42d354a3b5 100644
|
|
|
a53771 |
--- a/src/lib/krad/attr.c
|
|
|
a53771 |
+++ b/src/lib/krad/attr.c
|
|
|
a53771 |
@@ -38,7 +38,8 @@
|
|
|
a53771 |
typedef krb5_error_code
|
|
|
a53771 |
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips);
|
|
|
a53771 |
|
|
|
a53771 |
typedef struct {
|
|
|
a53771 |
const char *name;
|
|
|
a53771 |
@@ -51,12 +52,14 @@ typedef struct {
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
user_password_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips);
|
|
|
a53771 |
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
user_password_decode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *ignored);
|
|
|
a53771 |
|
|
|
a53771 |
static const attribute_record attributes[UCHAR_MAX] = {
|
|
|
a53771 |
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
|
|
|
a53771 |
@@ -128,7 +131,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
user_password_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips)
|
|
|
a53771 |
{
|
|
|
a53771 |
const unsigned char *indx;
|
|
|
a53771 |
krb5_error_code retval;
|
|
|
a53771 |
@@ -154,8 +158,15 @@ user_password_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
|
|
|
a53771 |
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
|
|
a53771 |
|
|
|
a53771 |
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
|
|
a53771 |
- &sum);
|
|
|
a53771 |
+ if (kr_use_fips(ctx)) {
|
|
|
a53771 |
+ /* Skip encryption here. Taint so that we won't pass it out of
|
|
|
a53771 |
+ * the machine by accident. */
|
|
|
a53771 |
+ *is_fips = TRUE;
|
|
|
a53771 |
+ sum.contents = calloc(1, BLOCKSIZE);
|
|
|
a53771 |
+ } else {
|
|
|
a53771 |
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
|
|
a53771 |
+ &sum);
|
|
|
a53771 |
+ }
|
|
|
a53771 |
if (retval != 0) {
|
|
|
a53771 |
zap(tmp.data, tmp.length);
|
|
|
a53771 |
zap(outbuf, len);
|
|
|
a53771 |
@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
static krb5_error_code
|
|
|
a53771 |
user_password_decode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips)
|
|
|
a53771 |
{
|
|
|
a53771 |
const unsigned char *indx;
|
|
|
a53771 |
krb5_error_code retval;
|
|
|
a53771 |
@@ -204,8 +216,15 @@ user_password_decode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
|
|
|
a53771 |
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
|
|
a53771 |
|
|
|
a53771 |
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
|
|
a53771 |
- &tmp, &sum);
|
|
|
a53771 |
+ if (kr_use_fips(ctx)) {
|
|
|
a53771 |
+ /* Skip encryption here. Taint so that we won't pass it out of
|
|
|
a53771 |
+ * the machine by accident. */
|
|
|
a53771 |
+ *is_fips = TRUE;
|
|
|
a53771 |
+ sum.contents = calloc(1, BLOCKSIZE);
|
|
|
a53771 |
+ } else {
|
|
|
a53771 |
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
|
|
a53771 |
+ &tmp, &sum);
|
|
|
a53771 |
+ }
|
|
|
a53771 |
if (retval != 0) {
|
|
|
a53771 |
zap(tmp.data, tmp.length);
|
|
|
a53771 |
zap(outbuf, in->length);
|
|
|
a53771 |
@@ -248,7 +267,7 @@ krb5_error_code
|
|
|
a53771 |
kr_attr_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const unsigned char *auth, krad_attr type,
|
|
|
a53771 |
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
|
|
|
a53771 |
- size_t *outlen)
|
|
|
a53771 |
+ size_t *outlen, krb5_boolean *is_fips)
|
|
|
a53771 |
{
|
|
|
a53771 |
krb5_error_code retval;
|
|
|
a53771 |
|
|
|
a53771 |
@@ -265,7 +284,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
|
|
|
a53771 |
return 0;
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
|
|
|
a53771 |
+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
|
|
|
a53771 |
+ is_fips);
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
krb5_error_code
|
|
|
a53771 |
@@ -274,6 +294,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
|
a53771 |
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
|
|
a53771 |
{
|
|
|
a53771 |
krb5_error_code retval;
|
|
|
a53771 |
+ krb5_boolean ignored;
|
|
|
a53771 |
|
|
|
a53771 |
retval = kr_attr_valid(type, in);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
@@ -288,7 +309,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
|
a53771 |
return 0;
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
|
|
|
a53771 |
+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
|
|
|
a53771 |
+ &ignored);
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
krad_attr
|
|
|
a53771 |
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
|
|
|
d1ad9f |
index f309f1581c..6ec031e320 100644
|
|
|
a53771 |
--- a/src/lib/krad/attrset.c
|
|
|
a53771 |
+++ b/src/lib/krad/attrset.c
|
|
|
a53771 |
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
|
|
|
a53771 |
krb5_error_code
|
|
|
a53771 |
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
|
a53771 |
const unsigned char *auth,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips)
|
|
|
a53771 |
{
|
|
|
a53771 |
unsigned char buffer[MAX_ATTRSIZE];
|
|
|
a53771 |
krb5_error_code retval;
|
|
|
a53771 |
@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
|
a53771 |
|
|
|
a53771 |
K5_TAILQ_FOREACH(a, &set->list, list) {
|
|
|
a53771 |
retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
|
|
|
a53771 |
- buffer, &attrlen);
|
|
|
a53771 |
+ buffer, &attrlen, is_fips);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
return retval;
|
|
|
a53771 |
|
|
|
a53771 |
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
|
|
|
d1ad9f |
index 7619563fc5..a17b6f39b1 100644
|
|
|
a53771 |
--- a/src/lib/krad/internal.h
|
|
|
a53771 |
+++ b/src/lib/krad/internal.h
|
|
|
d1ad9f |
@@ -39,6 +39,12 @@
|
|
|
a53771 |
#include <sys/socket.h>
|
|
|
a53771 |
#include <netdb.h>
|
|
|
a53771 |
|
|
|
a53771 |
+#include <openssl/crypto.h>
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
+#endif
|
|
|
d1ad9f |
+
|
|
|
a53771 |
#ifndef UCHAR_MAX
|
|
|
a53771 |
#define UCHAR_MAX 255
|
|
|
a53771 |
#endif
|
|
|
d1ad9f |
@@ -49,6 +55,13 @@
|
|
|
a53771 |
|
|
|
a53771 |
typedef struct krad_remote_st krad_remote;
|
|
|
a53771 |
|
|
|
a53771 |
+struct krad_packet_st {
|
|
|
a53771 |
+ char buffer[KRAD_PACKET_SIZE_MAX];
|
|
|
a53771 |
+ krad_attrset *attrset;
|
|
|
a53771 |
+ krb5_data pkt;
|
|
|
a53771 |
+ krb5_boolean is_fips;
|
|
|
a53771 |
+};
|
|
|
a53771 |
+
|
|
|
a53771 |
/* Validate constraints of an attribute. */
|
|
|
a53771 |
krb5_error_code
|
|
|
a53771 |
kr_attr_valid(krad_attr type, const krb5_data *data);
|
|
|
d1ad9f |
@@ -57,7 +70,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
|
|
|
a53771 |
krb5_error_code
|
|
|
a53771 |
kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
|
a53771 |
krad_attr type, const krb5_data *in,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips);
|
|
|
a53771 |
|
|
|
a53771 |
/* Decode an attribute. */
|
|
|
a53771 |
krb5_error_code
|
|
|
d1ad9f |
@@ -69,7 +83,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
|
|
a53771 |
krb5_error_code
|
|
|
a53771 |
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
|
|
a53771 |
const unsigned char *auth,
|
|
|
a53771 |
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
|
|
|
a53771 |
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
|
|
a53771 |
+ krb5_boolean *is_fips);
|
|
|
a53771 |
|
|
|
a53771 |
/* Decode attributes from a buffer. */
|
|
|
a53771 |
krb5_error_code
|
|
|
d1ad9f |
@@ -156,4 +171,17 @@ gai_error_code(int err)
|
|
|
a53771 |
}
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
+static inline krb5_boolean
|
|
|
a53771 |
+kr_use_fips(krb5_context ctx)
|
|
|
a53771 |
+{
|
|
|
a53771 |
+ int val = 0;
|
|
|
a53771 |
+
|
|
|
a53771 |
+ if (!FIPS_mode())
|
|
|
a53771 |
+ return 0;
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+ (void)profile_get_boolean(ctx->profile, "libdefaults",
|
|
|
d1ad9f |
+ "radius_md5_fips_override", NULL, 0, &val;;
|
|
|
a53771 |
+ return !val;
|
|
|
a53771 |
+}
|
|
|
a53771 |
+
|
|
|
a53771 |
#endif /* INTERNAL_H_ */
|
|
|
a53771 |
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
|
|
|
d1ad9f |
index c597174b65..fc2d248001 100644
|
|
|
a53771 |
--- a/src/lib/krad/packet.c
|
|
|
a53771 |
+++ b/src/lib/krad/packet.c
|
|
|
a53771 |
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
|
|
|
a53771 |
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
|
|
|
a53771 |
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
|
|
|
a53771 |
|
|
|
a53771 |
-struct krad_packet_st {
|
|
|
a53771 |
- char buffer[KRAD_PACKET_SIZE_MAX];
|
|
|
a53771 |
- krad_attrset *attrset;
|
|
|
a53771 |
- krb5_data pkt;
|
|
|
a53771 |
-};
|
|
|
a53771 |
-
|
|
|
a53771 |
typedef struct {
|
|
|
a53771 |
uchar x[(UCHAR_MAX + 1) / 8];
|
|
|
a53771 |
} idmap;
|
|
|
a53771 |
@@ -187,8 +181,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
|
|
|
a53771 |
memcpy(data.data + response->pkt.length, secret, strlen(secret));
|
|
|
a53771 |
|
|
|
a53771 |
/* Hash it. */
|
|
|
a53771 |
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
|
|
a53771 |
- &hash);
|
|
|
a53771 |
+ if (kr_use_fips(ctx)) {
|
|
|
a53771 |
+ /* This checksum does very little security-wise anyway, so don't
|
|
|
a53771 |
+ * taint. */
|
|
|
a53771 |
+ hash.contents = calloc(1, AUTH_FIELD_SIZE);
|
|
|
a53771 |
+ } else {
|
|
|
a53771 |
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
|
|
a53771 |
+ &hash);
|
|
|
a53771 |
+ }
|
|
|
a53771 |
free(data.data);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
return retval;
|
|
|
a53771 |
@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
|
|
|
a53771 |
|
|
|
a53771 |
/* Encode the attributes. */
|
|
|
a53771 |
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
|
|
|
a53771 |
- &attrset_len);
|
|
|
a53771 |
+ &attrset_len, &pkt->is_fips);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
goto error;
|
|
|
a53771 |
|
|
|
a53771 |
@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
|
|
|
a53771 |
|
|
|
a53771 |
/* Encode the attributes. */
|
|
|
a53771 |
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
|
|
|
a53771 |
- &attrset_len);
|
|
|
a53771 |
+ &attrset_len, &pkt->is_fips);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
goto error;
|
|
|
a53771 |
|
|
|
a53771 |
@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
|
|
|
a53771 |
const krb5_data *
|
|
|
a53771 |
krad_packet_encode(const krad_packet *pkt)
|
|
|
a53771 |
{
|
|
|
a53771 |
+ if (pkt->is_fips)
|
|
|
a53771 |
+ return NULL;
|
|
|
a53771 |
return &pkt->pkt;
|
|
|
a53771 |
}
|
|
|
a53771 |
|
|
|
a53771 |
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
|
|
|
d1ad9f |
index 06ae751bc8..929f1cef67 100644
|
|
|
a53771 |
--- a/src/lib/krad/remote.c
|
|
|
a53771 |
+++ b/src/lib/krad/remote.c
|
|
|
a53771 |
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
|
|
|
a53771 |
request *r;
|
|
|
a53771 |
|
|
|
a53771 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
|
a53771 |
- tmp = krad_packet_encode(r->request);
|
|
|
a53771 |
+ tmp = &r->request->pkt;
|
|
|
a53771 |
|
|
|
a53771 |
/* If the packet has already been sent, do nothing. */
|
|
|
a53771 |
if (r->sent == tmp->length)
|
|
|
a53771 |
@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr)
|
|
|
a53771 |
if (req != NULL) {
|
|
|
a53771 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
|
a53771 |
if (r->request == req &&
|
|
|
a53771 |
- r->sent == krad_packet_encode(req)->length) {
|
|
|
a53771 |
+ r->sent == req->pkt.length) {
|
|
|
a53771 |
request_finish(r, 0, rsp);
|
|
|
a53771 |
break;
|
|
|
a53771 |
}
|
|
|
d1ad9f |
@@ -460,6 +460,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
|
|
a53771 |
(krad_packet_iter_cb)iterator, &r, &tmp);
|
|
|
a53771 |
if (retval != 0)
|
|
|
a53771 |
goto error;
|
|
|
a53771 |
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
|
|
|
a53771 |
+ rr->info->ai_family != AF_UNIX) {
|
|
|
a53771 |
+ /* This would expose cleartext passwords, so abort. */
|
|
|
a53771 |
+ retval = ESOCKTNOSUPPORT;
|
|
|
a53771 |
+ goto error;
|
|
|
a53771 |
+ }
|
|
|
a53771 |
|
|
|
a53771 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
|
a53771 |
if (r->request == tmp) {
|
|
|
a53771 |
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
|
|
|
d1ad9f |
index eb2a780c89..4d285ad9de 100644
|
|
|
a53771 |
--- a/src/lib/krad/t_attr.c
|
|
|
a53771 |
+++ b/src/lib/krad/t_attr.c
|
|
|
a53771 |
@@ -50,6 +50,7 @@ main()
|
|
|
a53771 |
const char *tmp;
|
|
|
a53771 |
krb5_data in;
|
|
|
a53771 |
size_t len;
|
|
|
a53771 |
+ krb5_boolean is_fips = FALSE;
|
|
|
a53771 |
|
|
|
a53771 |
noerror(krb5_init_context(&ctx));
|
|
|
a53771 |
|
|
|
a53771 |
@@ -73,7 +74,7 @@ main()
|
|
|
a53771 |
in = string2data((char *)decoded);
|
|
|
a53771 |
retval = kr_attr_encode(ctx, secret, auth,
|
|
|
a53771 |
krad_attr_name2num("User-Password"),
|
|
|
a53771 |
- &in, outbuf, &len;;
|
|
|
a53771 |
+ &in, outbuf, &len, &is_fips);
|
|
|
a53771 |
insist(retval == 0);
|
|
|
a53771 |
insist(len == sizeof(encoded));
|
|
|
a53771 |
insist(memcmp(outbuf, encoded, len) == 0);
|
|
|
a53771 |
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
|
|
|
d1ad9f |
index 7928335ca4..0f95762534 100644
|
|
|
a53771 |
--- a/src/lib/krad/t_attrset.c
|
|
|
a53771 |
+++ b/src/lib/krad/t_attrset.c
|
|
|
a53771 |
@@ -49,6 +49,7 @@ main()
|
|
|
a53771 |
krb5_context ctx;
|
|
|
a53771 |
size_t len = 0, encode_len;
|
|
|
a53771 |
krb5_data tmp;
|
|
|
a53771 |
+ krb5_boolean is_fips = FALSE;
|
|
|
a53771 |
|
|
|
a53771 |
noerror(krb5_init_context(&ctx));
|
|
|
a53771 |
noerror(krad_attrset_new(ctx, &set);;
|
|
|
a53771 |
@@ -62,7 +63,8 @@ main()
|
|
|
a53771 |
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
|
|
|
a53771 |
|
|
|
a53771 |
/* Encode attrset. */
|
|
|
a53771 |
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
|
|
|
a53771 |
+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
|
|
|
a53771 |
+ &is_fips));
|
|
|
a53771 |
krad_attrset_free(set);
|
|
|
a53771 |
|
|
|
a53771 |
/* Manually encode User-Name. */
|
|
|
a53771 |
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
|
|
|
d1ad9f |
index 00734a13b5..13c699071f 100644
|
|
|
a53771 |
--- a/src/plugins/preauth/spake/spake_client.c
|
|
|
a53771 |
+++ b/src/plugins/preauth/spake/spake_client.c
|
|
|
d1ad9f |
@@ -38,6 +38,12 @@
|
|
|
a53771 |
#include "groups.h"
|
|
|
a53771 |
#include <krb5/clpreauth_plugin.h>
|
|
|
a53771 |
|
|
|
a53771 |
+#include <openssl/crypto.h>
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
+#endif
|
|
|
d1ad9f |
+
|
|
|
a53771 |
typedef struct reqstate_st {
|
|
|
a53771 |
krb5_pa_spake *msg; /* set in prep_questions, used in process */
|
|
|
a53771 |
krb5_keyblock *initial_key;
|
|
|
d1ad9f |
@@ -375,6 +381,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
|
|
a53771 |
|
|
|
a53771 |
if (maj_ver != 1)
|
|
|
a53771 |
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
|
a53771 |
+
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
vt = (krb5_clpreauth_vtable)vtable;
|
|
|
a53771 |
vt->name = "spake";
|
|
|
a53771 |
vt->pa_type_list = pa_types;
|
|
|
a53771 |
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
|
|
|
d1ad9f |
index 1a772d450f..3394f8a58e 100644
|
|
|
a53771 |
--- a/src/plugins/preauth/spake/spake_kdc.c
|
|
|
a53771 |
+++ b/src/plugins/preauth/spake/spake_kdc.c
|
|
|
d1ad9f |
@@ -41,6 +41,12 @@
|
|
|
a53771 |
|
|
|
a53771 |
#include <krb5/kdcpreauth_plugin.h>
|
|
|
a53771 |
|
|
|
a53771 |
+#include <openssl/crypto.h>
|
|
|
a53771 |
+
|
|
|
d1ad9f |
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
|
d1ad9f |
+#include <openssl/fips.h>
|
|
|
d1ad9f |
+#endif
|
|
|
d1ad9f |
+
|
|
|
a53771 |
/*
|
|
|
a53771 |
* The SPAKE kdcpreauth module uses a secure cookie containing the following
|
|
|
a53771 |
* concatenated fields (all integer fields are big-endian):
|
|
|
d1ad9f |
@@ -551,6 +557,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
|
|
a53771 |
|
|
|
a53771 |
if (maj_ver != 1)
|
|
|
a53771 |
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
|
a53771 |
+
|
|
|
a53771 |
+ if (FIPS_mode())
|
|
|
a53771 |
+ return KRB5_CRYPTO_INTERNAL;
|
|
|
a53771 |
+
|
|
|
a53771 |
vt = (krb5_kdcpreauth_vtable)vtable;
|
|
|
a53771 |
vt->name = "spake";
|
|
|
a53771 |
vt->pa_type_list = pa_types;
|
|
|
38a7f7 |
--
|
|
|
d1ad9f |
2.38.1
|
|
|
38a7f7 |
|