Move HKDF into the FIPS module.

Change-Id: I7c5b0a24c26b83779cf889d890e2c18ae13187c3
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58725
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index b45256c..cdb5ddc 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -168,7 +168,6 @@
   evp/scrypt.c
   evp/sign.c
   ex_data.c
-  hkdf/hkdf.c
   hpke/hpke.c
   hrss/hrss.c
   kyber/keccak.c
@@ -390,13 +389,13 @@
   fipsmodule/ec/ec_test.cc
   fipsmodule/ec/p256-nistz_test.cc
   fipsmodule/ecdsa/ecdsa_test.cc
+  fipsmodule/hkdf/hkdf_test.cc
   fipsmodule/md5/md5_test.cc
   fipsmodule/modes/gcm_test.cc
   fipsmodule/rand/ctrdrbg_test.cc
   fipsmodule/rand/fork_detect_test.cc
   fipsmodule/service_indicator/service_indicator_test.cc
   fipsmodule/sha/sha_test.cc
-  hkdf/hkdf_test.cc
   hpke/hpke_test.cc
   hmac_extra/hmac_test.cc
   hrss/hrss_test.cc
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index e2e4d90..8231eee 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -80,6 +80,7 @@
 #include "ec/simple_mul.c"
 #include "ec/util.c"
 #include "ec/wnaf.c"
+#include "hkdf/hkdf.c"
 #include "hmac/hmac.c"
 #include "md4/md4.c"
 #include "md5/md5.c"
diff --git a/crypto/hkdf/hkdf.c b/crypto/fipsmodule/hkdf/hkdf.c
similarity index 98%
rename from crypto/hkdf/hkdf.c
rename to crypto/fipsmodule/hkdf/hkdf.c
index 23b60af..fa1cc72 100644
--- a/crypto/hkdf/hkdf.c
+++ b/crypto/fipsmodule/hkdf/hkdf.c
@@ -20,7 +20,7 @@
 #include <openssl/err.h>
 #include <openssl/hmac.h>
 
-#include "../internal.h"
+#include "../../internal.h"
 
 
 int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
diff --git a/crypto/hkdf/hkdf_test.cc b/crypto/fipsmodule/hkdf/hkdf_test.cc
similarity index 98%
rename from crypto/hkdf/hkdf_test.cc
rename to crypto/fipsmodule/hkdf/hkdf_test.cc
index 8aad6c8..dd7dd58 100644
--- a/crypto/hkdf/hkdf_test.cc
+++ b/crypto/fipsmodule/hkdf/hkdf_test.cc
@@ -20,9 +20,9 @@
 
 #include <gtest/gtest.h>
 
-#include "../test/file_test.h"
-#include "../test/test_util.h"
-#include "../test/wycheproof_util.h"
+#include "../../test/file_test.h"
+#include "../../test/test_util.h"
+#include "../../test/wycheproof_util.h"
 
 
 struct HKDFTestVector {
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c
index 08500e5..8dcc415 100644
--- a/crypto/fipsmodule/self_check/self_check.c
+++ b/crypto/fipsmodule/self_check/self_check.c
@@ -946,6 +946,36 @@
     goto err;
   }
 
+  // HKDF
+  static const uint8_t kHKDFSecret[32] = {
+      0x68, 0x67, 0x85, 0x04, 0xb9, 0xb3, 0xad, 0xd1, 0x7d, 0x59, 0x67,
+      0xa1, 0xa7, 0xbd, 0x37, 0x99, 0x3f, 0xd8, 0xa3, 0x3c, 0xe7, 0x30,
+      0x30, 0x71, 0xf3, 0x9c, 0x09, 0x6d, 0x16, 0x35, 0xb3, 0xc9,
+  };
+  static const uint8_t kHKDFSalt[32] = {
+      0x8a, 0xab, 0x18, 0xb4, 0x9b, 0x0a, 0x17, 0xf9, 0xe8, 0xe6, 0x97,
+      0x1a, 0x3d, 0xff, 0xda, 0x9b, 0x26, 0x8b, 0x3d, 0x17, 0x78, 0x0a,
+      0xb3, 0xea, 0x65, 0xdb, 0x2a, 0xc0, 0x29, 0x9c, 0xfa, 0x72,
+  };
+  static const uint8_t kHKDFInfo[32] = {
+      0xe5, 0x6f, 0xf9, 0xe1, 0x18, 0x5e, 0x64, 0x8c, 0x6c, 0x8f, 0xee,
+      0xc6, 0x93, 0x5a, 0xc5, 0x14, 0x8c, 0xf3, 0xd9, 0x78, 0xd2, 0x3a,
+      0x86, 0xdd, 0x01, 0xdf, 0xb9, 0xe9, 0x5e, 0xe5, 0x1a, 0x56,
+  };
+  static const uint8_t kHKDFOutput[32] = {
+      0xa6, 0x29, 0xb4, 0xd7, 0xf4, 0xc1, 0x16, 0x64, 0x71, 0x5e, 0xa4,
+      0xa8, 0xe6, 0x60, 0x8c, 0xf3, 0xc1, 0xa5, 0x03, 0xe2, 0x22, 0xf9,
+      0x89, 0xe2, 0x12, 0x18, 0xbe, 0xef, 0x16, 0x86, 0xe0, 0xec,
+  };
+  uint8_t hkdf_output[sizeof(kHKDFOutput)];
+  if (!HKDF(hkdf_output, sizeof(hkdf_output), EVP_sha256(), kHKDFSecret,
+            sizeof(kHKDFSecret), kHKDFSalt, sizeof(kHKDFSalt), kHKDFInfo,
+            sizeof(kHKDFInfo)) ||
+      !check_test(kHKDFOutput, hkdf_output, sizeof(kHKDFOutput), "HKDF")) {
+    fprintf(stderr, "HKDF failed.\n");
+    goto err;
+  }
+
   ret = 1;
 
 err:
diff --git a/util/fipstools/acvp/acvptool/subprocess/hkdf.go b/util/fipstools/acvp/acvptool/subprocess/hkdf.go
index 3cd4c32..b124d79 100644
--- a/util/fipstools/acvp/acvptool/subprocess/hkdf.go
+++ b/util/fipstools/acvp/acvptool/subprocess/hkdf.go
@@ -173,6 +173,9 @@
 			if err != nil {
 				return nil, fmt.Errorf("HKDF operation failed: %s", err)
 			}
+			if len(resp[0]) != int(outBytes) {
+				return nil, fmt.Errorf("HKDF operation resulted in %d bytes but wanted %d", len(resp[0]), outBytes)
+			}
 
 			if isValidationTest {
 				passed := bytes.Equal(expected, resp[0])
diff --git a/util/fipstools/acvp/acvptool/test/expected/HKDF.bz2 b/util/fipstools/acvp/acvptool/test/expected/HKDF.bz2
new file mode 100644
index 0000000..791fa7a
--- /dev/null
+++ b/util/fipstools/acvp/acvptool/test/expected/HKDF.bz2
Binary files differ
diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json
index d1e8eb5..36fdaad 100644
--- a/util/fipstools/acvp/acvptool/test/tests.json
+++ b/util/fipstools/acvp/acvptool/test/tests.json
@@ -18,6 +18,7 @@
 {"Wrapper": "modulewrapper", "In": "vectors/HMAC-SHA2-384.bz2", "Out": "expected/HMAC-SHA2-384.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/HMAC-SHA2-512.bz2", "Out": "expected/HMAC-SHA2-512.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/HMAC-SHA2-512-256.bz2", "Out": "expected/HMAC-SHA2-512-256.bz2"},
+{"Wrapper": "modulewrapper", "In": "vectors/HKDF.bz2", "Out": "expected/HKDF.bz2"},
 {"Wrapper": "testmodulewrapper", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"},
 {"Wrapper": "testmodulewrapper", "In": "vectors/KDA.bz2", "Out": "expected/KDA.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/KAS-ECC-SSC.bz2"},
diff --git a/util/fipstools/acvp/acvptool/test/vectors/HKDF.bz2 b/util/fipstools/acvp/acvptool/test/vectors/HKDF.bz2
new file mode 100644
index 0000000..f69a461
--- /dev/null
+++ b/util/fipstools/acvp/acvptool/test/vectors/HKDF.bz2
Binary files differ
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index 460a8e9..5c4f9b0 100644
--- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -37,6 +37,7 @@
 #include <openssl/ecdh.h>
 #include <openssl/ecdsa.h>
 #include <openssl/err.h>
+#include <openssl/hkdf.h>
 #include <openssl/hmac.h>
 #include <openssl/obj.h>
 #include <openssl/rsa.h>
@@ -885,6 +886,34 @@
           "FB",
           "FC"
         ]
+      },
+      {
+        "algorithm": "KDA",
+        "mode": "HKDF",
+        "revision": "Sp800-56Cr1",
+        "fixedInfoPattern": "uPartyInfo||vPartyInfo",
+        "encoding": [
+          "concatenation"
+        ],
+        "hmacAlg": [
+          "SHA2-224",
+          "SHA2-256",
+          "SHA2-384",
+          "SHA2-512",
+          "SHA2-512/256"
+        ],
+        "macSaltMethods": [
+          "default",
+          "random"
+        ],
+        "l": 2048,
+        "z": [
+          {
+            "min": 224,
+            "max": 65336,
+            "increment": 8
+          }
+        ]
       }
     ])";
   return write_reply({Span<const uint8_t>(
@@ -1431,6 +1460,30 @@
   return write_reply({Span<const uint8_t>(digest, digest_len)});
 }
 
+template <const EVP_MD *HashFunc()>
+static bool HKDF(const Span<const uint8_t> args[], ReplyCallback write_reply) {
+  const EVP_MD *const md = HashFunc();
+  const auto key = args[0];
+  const auto salt = args[1];
+  const auto info = args[2];
+  const auto out_len_bytes = args[3];
+
+  if (out_len_bytes.size() != sizeof(uint32_t)) {
+    return false;
+  }
+  const uint32_t out_len = CRYPTO_load_u32_le(out_len_bytes.data());
+  if (out_len > (1 << 24)) {
+    return false;
+  }
+
+  std::vector<uint8_t> out(out_len);
+  if (!::HKDF(out.data(), out_len, md, key.data(), key.size(), salt.data(),
+              salt.size(), info.data(), info.size())) {
+    return false;
+  }
+  return write_reply({out});
+}
+
 template <bool WithReseed>
 static bool DRBG(const Span<const uint8_t> args[], ReplyCallback write_reply) {
   const auto out_len_bytes = args[0];
@@ -1971,6 +2024,11 @@
     {"3DES-ECB/decrypt", 3, TDES<false>},
     {"3DES-CBC/encrypt", 4, TDES_CBC<true>},
     {"3DES-CBC/decrypt", 4, TDES_CBC<false>},
+    {"HKDF/SHA2-224", 4, HKDF<EVP_sha224>},
+    {"HKDF/SHA2-256", 4, HKDF<EVP_sha256>},
+    {"HKDF/SHA2-384", 4, HKDF<EVP_sha384>},
+    {"HKDF/SHA2-512", 4, HKDF<EVP_sha512>},
+    {"HKDF/SHA2-512/256", 4, HKDF<EVP_sha512_256>},
     {"HMAC-SHA-1", 2, HMAC<EVP_sha1>},
     {"HMAC-SHA2-224", 2, HMAC<EVP_sha224>},
     {"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},
diff --git a/util/fipstools/break-kat.go b/util/fipstools/break-kat.go
index 6eace5b..ed29bb3 100644
--- a/util/fipstools/break-kat.go
+++ b/util/fipstools/break-kat.go
@@ -21,6 +21,7 @@
 		"AES-GCM-decrypt": "35f3058f875760ff09d3120f70c4bc9ed7a86872e13452202176f7371ae04faae1dd391920f5d13953d896785994823c",
 		"DRBG":            "c4da0740d505f1ee280b95e58c4931ac6de846a0152fbb4a3f174cf4787a4f1a40c2b50babe14aae530be5886d910a27",
 		"DRBG-reseed":     "c7161ca36c2309b716e9859bb96c6d49bdc8352103a18cd24ef42ec97ef46bf446eb1a4576c186e9351803763a7912fe",
+		"HKDF":            "68678504b9b3add17d5967a1a7bd37993fd8a33ce7303071f39c096d1635b3c9",
 		"SHA-1":           "132fd9bad5c1826263bafbb699f707a5",
 		"SHA-256":         "ff3b857da7236a2baa0f396b51522217",
 		"SHA-512":         "212512f8d2ad8322781c6c4d69a9daa1",