Blob Blame History Raw
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);