]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Allow non-FIPS MD5 to be used with TLS PRF even in FIPS mode
authorJouni Malinen <j@w1.fi>
Sun, 16 Aug 2009 15:56:48 +0000 (18:56 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 16 Aug 2009 15:56:48 +0000 (18:56 +0300)
This is allowed per FIPS1402IG.pdf since the TLS PRF depends fully on
both MD5 and SHA-1.

src/crypto/crypto.h
src/crypto/crypto_openssl.c
src/crypto/md5-non-fips.c [new file with mode: 0644]
src/crypto/md5.h
src/crypto/sha1-tlsprf.c
wpa_supplicant/Makefile

index e2d2112b8892480ff81a9559833be554697263b5..be3609e3424306fccbcaf8fb6e37976caaf58791 100644 (file)
@@ -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
index fceefb12c520d1233e1b1c641a44eeda165a9c89..4287e3efd0efb1217c58ef8e26b61864235154d4 100644 (file)
@@ -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);
 }
 
 
diff --git a/src/crypto/md5-non-fips.c b/src/crypto/md5-non-fips.c
new file mode 100644 (file)
index 0000000..6f29201
--- /dev/null
@@ -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);
+}
index 40ab6304fbdc1f31bd25fa38511127b0c654fc72..8952590782a3f771603dbb1ba721b6b4f714ac17 100644 (file)
@@ -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 */
index 3e2ae496553a15a710ce62769cb89c9dcce850ac..2c8c029ecf49584cecfa421ca230172743349839 100644 (file)
@@ -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,
index 381dfa9523ac7dc9263a9f55361016ddfe28604b..e10f299cd21ec4bc8173a02341163e270c136972 100644 (file)
@@ -1068,6 +1068,7 @@ endif
 
 ifdef CONFIG_FIPS
 CFLAGS += -DCONFIG_FIPS
+MD5OBJS += ../src/crypto/md5-non-fips.o
 endif
 
 ifdef CONFIG_NDIS_EVENTS_INTEGRATED