diff -Naur libreswan-3.20-orig/lib/libswan/ike_info.c libreswan-3.20/lib/libswan/ike_info.c
--- libreswan-3.20-orig/lib/libswan/ike_info.c 2017-03-14 11:53:11.000000000 -0400
+++ libreswan-3.20/lib/libswan/ike_info.c 2017-04-22 19:02:37.667000000 -0400
@@ -64,6 +64,11 @@
char *ptr = buf;
const char *sep = "";
+ if (alg_info == NULL) {
+ PEXPECT_LOG("%s", "parameter alg_info unexpectedly NULL");
+ return;
+ }
+
FOR_EACH_IKE_INFO(alg_info, ike_info) {
if (ike_info->ike_encrypt != NULL &&
ike_info->ike_prf != NULL &&
@@ -95,6 +100,12 @@
char *ptr = buf;
char *be = buf + buflen;
+ if (alg_info_ike == NULL) {
+ PEXPECT_LOG("%s", "parameter alg_info_ike unexpectedly NULL");
+ return;
+ }
+
+
passert(buflen > 0);
const char *sep = "";
diff -Naur libreswan-3.20-orig/programs/pluto/crypt_prf.c libreswan-3.20/programs/pluto/crypt_prf.c
--- libreswan-3.20-orig/programs/pluto/crypt_prf.c 2017-03-14 11:53:11.000000000 -0400
+++ libreswan-3.20/programs/pluto/crypt_prf.c 2017-04-22 19:02:37.668000000 -0400
@@ -35,6 +35,36 @@
#include "crypt_symkey.h"
#include "crypto.h"
+size_t crypt_prf_fips_key_size_min(const struct prf_desc *prf)
+{
+ /*
+ * FIPS 198 Section 3 CRYPTOGRAPHIC KEYS requires keys to be
+ * >= "L/2" (where L is the block-size in bytes of the hash
+ * function).
+ *
+ * FIPS 198-1 Section 3 instead cites SP 800-107. Good luck
+ * reading the latter.
+ */
+ return prf->prf_key_size / 2;
+}
+
+size_t crypt_prf_fips_key_size_floor(void)
+{
+ static size_t key_size_floor;
+ if (!key_size_floor) {
+ key_size_floor = SIZE_MAX;
+ for (const struct prf_desc **prfp = next_prf_desc(NULL);
+ prfp != NULL; prfp = next_prf_desc(prfp)) {
+ if (!(*prfp)->common.fips) {
+ continue;
+ }
+ key_size_floor = min(key_size_floor,
+ crypt_prf_fips_key_size_min(*prfp));
+ }
+ }
+ return key_size_floor;
+}
+
struct crypt_prf {
struct prf_context *context;
lset_t debug;
@@ -46,13 +76,19 @@
const char *name,
struct prf_context *context)
{
- struct crypt_prf *prf = alloc_thing(struct crypt_prf, name);
- *prf = (struct crypt_prf) {
- .context = context,
- .debug = debug,
- .name = name,
- .desc = prf_desc,
- };
+ struct crypt_prf *prf = NULL;
+
+ if (context != NULL) {
+ prf = alloc_thing(struct crypt_prf, name);
+ *prf = (struct crypt_prf) {
+ .context = context,
+ .debug = debug,
+ .name = name,
+ .desc = prf_desc,
+ };
+ }
+ DBG(debug, DBG_log("%s PRF %s crypt-prf@%p",
+ name, prf_desc->common.name, prf));
return prf;
}
diff -Naur libreswan-3.20-orig/programs/pluto/crypt_prf.h libreswan-3.20/programs/pluto/crypt_prf.h
--- libreswan-3.20-orig/programs/pluto/crypt_prf.h 2017-03-14 11:53:11.000000000 -0400
+++ libreswan-3.20/programs/pluto/crypt_prf.h 2017-04-22 19:02:37.668000000 -0400
@@ -26,6 +26,14 @@
struct crypt_prf;
/*
+ * FIPS requires a minimum key size. In FIPS mode, when the key is
+ * less than this, the init will fail. Here the "floor" is the
+ * minimum of all the fips algorithms so failing this is really bad.
+ */
+size_t crypt_prf_fips_key_size_min(const struct prf_desc *prf_desc);
+size_t crypt_prf_fips_key_size_floor(void);
+
+/*
* Primitives implementing IKE PRFs.
*
* Some PRFs are implemented using the HMAC algorithm (described in
diff -Naur libreswan-3.20-orig/programs/pluto/ikev1_spdb_struct.c libreswan-3.20/programs/pluto/ikev1_spdb_struct.c
--- libreswan-3.20-orig/programs/pluto/ikev1_spdb_struct.c 2017-03-14 11:53:11.000000000 -0400
+++ libreswan-3.20/programs/pluto/ikev1_spdb_struct.c 2017-04-22 19:05:18.395000000 -0400
@@ -52,6 +52,7 @@
#include "ike_alg.h"
#include "db_ops.h"
#include "lswfips.h" /* for libreswan_fipsmode */
+#include "crypt_prf.h"
#include "nat_traversal.h"
@@ -901,6 +902,7 @@
bool xauth_init = FALSE,
xauth_resp = FALSE;
const char *const role = selection ? "initiator" : "responder";
+ const chunk_t *pss = &empty_chunk;
passert(c != NULL);
@@ -1190,9 +1192,10 @@
if ((iap & POLICY_PSK) == LEMPTY) {
ugh = "policy does not allow OAKLEY_PRESHARED_KEY authentication";
} else {
- /* check that we can find a preshared secret */
- if (get_preshared_secret(c)
- == NULL)
+ /* check that we can find a proper preshared secret */
+ pss = get_preshared_secret(c);
+
+ if (pss == NULL)
{
char mid[IDTOA_BUF],
hid[IDTOA_BUF];
@@ -1212,6 +1215,8 @@
ugh = builddiag(
"Can't authenticate: no preshared key found for `%s' and `%s'",
mid, hid);
+ } else {
+ DBG(DBG_PRIVATE, DBG_dump_chunk("User PSK:", *pss));
}
ta.auth = OAKLEY_PRESHARED_KEY;
}
@@ -1398,6 +1403,31 @@
}
}
+ {
+
+ if ((st->st_policy & POLICY_PSK) && pss != &empty_chunk && pss != NULL) {
+ const size_t key_size_min = crypt_prf_fips_key_size_min(ta.prf);
+
+ if (pss->len < key_size_min) {
+ if (libreswan_fipsmode()) {
+ ugh = builddiag("FIPS: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)",
+ st->st_connection->name,
+ pss->len,
+ ta.prf->common.name,
+ key_size_min);
+ } else {
+ libreswan_log("WARNING: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)",
+ st->st_connection->name,
+ pss->len,
+ ta.prf->common.name,
+ key_size_min);
+ }
+ }
+
+ }
+
+ }
+
/*
* ML: at last check for allowed transforms in alg_info_ike
*/
diff -Naur libreswan-3.20-orig/programs/pluto/ikev2_psk.c libreswan-3.20/programs/pluto/ikev2_psk.c
--- libreswan-3.20-orig/programs/pluto/ikev2_psk.c 2017-03-14 11:53:11.000000000 -0400
+++ libreswan-3.20/programs/pluto/ikev2_psk.c 2017-04-22 19:02:37.669000000 -0400
@@ -57,6 +57,7 @@
#include "keys.h"
#include "crypt_prf.h"
#include "crypt_symkey.h"
+#include "lswfips.h"
#include <nss.h>
#include <pk11pub.h>
@@ -91,6 +92,24 @@
return FALSE; /* failure: no PSK to use */
}
DBG(DBG_PRIVATE, DBG_dump_chunk("User PSK:", *pss));
+ const size_t key_size_min = crypt_prf_fips_key_size_min(st->st_oakley.prf);
+ if (pss->len < key_size_min) {
+ if (libreswan_fipsmode()) {
+ loglog(RC_LOG_SERIOUS,
+ "FIPS: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)",
+ st->st_connection->name,
+ pss->len,
+ st->st_oakley.prf->common.name,
+ key_size_min);
+ return FALSE;
+ } else {
+ libreswan_log("WARNING: connection %s PSK length of %zu bytes is too short for %s PRF in FIPS mode (%zu bytes required)",
+ st->st_connection->name,
+ pss->len,
+ st->st_oakley.prf->common.name,
+ key_size_min);
+ }
+ }
} else {
/*
* RFC-7619
@@ -137,9 +156,19 @@
{
struct crypt_prf *prf =
crypt_prf_init_chunk("<prf-psk> = prf(<psk>,\"Key Pad for IKEv2\")",
- DBG_CRYPT,
- st->st_oakley.prf,
- "shared secret", *pss);
+ DBG_CRYPT,
+ st->st_oakley.prf,
+ "shared secret", *pss);
+ if (prf == NULL) {
+ if (libreswan_fipsmode()) {
+ PASSERT_FAIL("FIPS: failure creating %s PRF context for digesting PSK",
+ st->st_oakley.prf->common.name);
+ }
+ loglog(RC_LOG_SERIOUS,
+ "failure creating %s PRF context for digesting PSK",
+ st->st_oakley.prf->common.name);
+ return FALSE;
+ }
crypt_prf_update_bytes(psk_key_pad_str/*name*/, prf,
psk_key_pad_str, psk_key_pad_str_len);
prf_psk = crypt_prf_final_symkey(&prf);