Browse Source

Allow non-FIPS MD5 to be used with TLS PRF even in FIPS mode

This is allowed per FIPS1402IG.pdf since the TLS PRF depends fully on
both MD5 and SHA-1.
Jouni Malinen 15 years ago
parent
commit
ff916b9df7
6 changed files with 163 additions and 8 deletions
  1. 16 0
      src/crypto/crypto.h
  2. 17 5
      src/crypto/crypto_openssl.c
  3. 113 0
      src/crypto/md5-non-fips.c
  4. 10 0
      src/crypto/md5.h
  5. 6 3
      src/crypto/sha1-tlsprf.c
  6. 1 0
      wpa_supplicant/Makefile

+ 16 - 0
src/crypto/crypto.h

@@ -47,6 +47,22 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
  */
 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
 
+#ifdef CONFIG_FIPS
+/**
+ * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
+			      const size_t *len, u8 *mac);
+#else /* CONFIG_FIPS */
+#define md5_vector_non_fips_allow md5_vector
+#endif /* CONFIG_FIPS */
+
+
 /**
  * sha1_vector - SHA-1 hash for data vector
  * @num_elem: Number of elements in the data vector

+ 17 - 5
src/crypto/crypto_openssl.c

@@ -32,7 +32,7 @@
 #endif /* openssl < 0.9.7 */
 
 
-int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+int openssl_digest_vector(const EVP_MD *type, int non_fips, size_t num_elem,
 			  const u8 *addr[], const size_t *len, u8 *mac)
 {
 	EVP_MD_CTX ctx;
@@ -40,6 +40,8 @@ int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
 	unsigned int mac_len;
 
 	EVP_MD_CTX_init(&ctx);
+	if (non_fips)
+		EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
 	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
 		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
 			   ERR_error_string(ERR_get_error(), NULL));
@@ -65,7 +67,7 @@ int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
 
 int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
+	return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
 }
 
 
@@ -92,20 +94,30 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
 
 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
+	return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
 }
 
 
+#ifdef CONFIG_FIPS
+int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
+			      const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
+}
+#endif /* CONFIG_FIPS */
+
+
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
-	return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
+	return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
 }
 
 
 int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 		  u8 *mac)
 {
-	return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
+	return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
+				     mac);
 }
 
 

+ 113 - 0
src/crypto/md5-non-fips.c

@@ -0,0 +1,113 @@
+/*
+ * MD5 hash implementation and interface functions (non-FIPS allowed cases)
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
+				   size_t num_elem, const u8 *addr[],
+				   const size_t *len, u8 *mac)
+{
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
+	size_t i, _len[6];
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = MD5(key) */
+        if (key_len > 64) {
+		if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 16;
+        }
+
+	/* the HMAC_MD5 transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = MD5_MAC_LEN;
+	return md5_vector_non_fips_allow(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
+			    size_t data_len, u8 *mac)
+{
+	return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
+					      &data_len, mac);
+}

+ 10 - 0
src/crypto/md5.h

@@ -21,5 +21,15 @@ int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
 		    const u8 *addr[], const size_t *len, u8 *mac);
 int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 	     u8 *mac);
+#ifdef CONFIG_FIPS
+int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
+				   size_t num_elem, const u8 *addr[],
+				   const size_t *len, u8 *mac);
+int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
+			    size_t data_len, u8 *mac);
+#else /* CONFIG_FIPS */
+#define hmac_md5_vector_non_fips_allow hmac_md5_vector
+#define hmac_md5_non_fips_allow hmac_md5
+#endif /* CONFIG_FIPS */
 
 #endif /* MD5_H */

+ 6 - 3
src/crypto/sha1-tlsprf.c

@@ -78,16 +78,19 @@ int tls_prf(const u8 *secret, size_t secret_len, const char *label,
 		S2--;
 	}
 
-	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
+	hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
+				       A_MD5);
 	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
 
 	MD5_pos = MD5_MAC_LEN;
 	SHA1_pos = SHA1_MAC_LEN;
 	for (i = 0; i < outlen; i++) {
 		if (MD5_pos == MD5_MAC_LEN) {
-			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
+			hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
+						       MD5_len, P_MD5);
 			MD5_pos = 0;
-			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
+			hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
+						A_MD5);
 		}
 		if (SHA1_pos == SHA1_MAC_LEN) {
 			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,

+ 1 - 0
wpa_supplicant/Makefile

@@ -1068,6 +1068,7 @@ endif
 
 ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
+MD5OBJS += ../src/crypto/md5-non-fips.o
 endif
 
 ifdef CONFIG_NDIS_EVENTS_INTEGRATED