summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2016-03-29 20:49:43 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-04-14 17:28:21 -0700
commit533a536140c13bb853e51a62af36bd56c6d85b0d (patch)
tree1e6e4936caaf3f35259c7c0d7f99de6ddd1ea030
parent9ab5ffaef0b98e797ee6d1e09687c1fa7b4b79fe (diff)
downloadchrome-ec-533a536140c13bb853e51a62af36bd56c6d85b0d.tar.gz
CR50: add support for HKDF (RFC 5869)
Add support for SHA256 based HKDF key derivation as specified in RFC 5869. This change includes test vectors from the RFC. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 TEST=tests under test/tpm2 pass Change-Id: I7d0e4e92775b74c41643f45587fc08f56d8916aa Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/336091 Commit-Ready: Nagendra Modadugu <ngm@google.com> Tested-by: Nagendra Modadugu <ngm@google.com> Reviewed-by: Marius Schilder <mschilder@chromium.org>
-rw-r--r--board/cr50/build.mk1
-rw-r--r--board/cr50/tpm2/hkdf.c93
-rw-r--r--chip/g/build.mk1
-rw-r--r--chip/g/dcrypto/dcrypto.h8
-rw-r--r--chip/g/dcrypto/hkdf.c79
-rw-r--r--include/extension.h1
-rw-r--r--test/tpm_test/hkdf_test.py112
-rw-r--r--test/tpm_test/subcmd.py1
-rwxr-xr-xtest/tpm_test/tpmtest.py2
9 files changed, 298 insertions, 0 deletions
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index 3a1c734afc..09dd749239 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -35,6 +35,7 @@ board-y += tpm2/aes.o
board-y += tpm2/ecc.o
board-y += tpm2/hash.o
board-y += tpm2/hash_data.o
+board-y += tpm2/hkdf.o
board-y += tpm2/platform.o
board-y += tpm2/rsa.o
board-y += tpm2/stubs.o
diff --git a/board/cr50/tpm2/hkdf.c b/board/cr50/tpm2/hkdf.c
new file mode 100644
index 0000000000..dcc494af16
--- /dev/null
+++ b/board/cr50/tpm2/hkdf.c
@@ -0,0 +1,93 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+
+#ifdef CRYPTO_TEST_SETUP
+
+#include "extension.h"
+
+enum {
+ TEST_RFC = 0,
+};
+
+#define MAX_OKM_BYTES 1024
+
+static void hkdf_command_handler(void *cmd_body,
+ size_t cmd_size,
+ size_t *response_size)
+{
+ uint8_t *cmd;
+ uint8_t *out;
+ uint8_t op;
+ size_t salt_len;
+ const uint8_t *salt;
+ size_t IKM_len;
+ const uint8_t *IKM;
+ size_t info_len;
+ const uint8_t *info;
+ size_t OKM_len;
+ uint8_t OKM[MAX_OKM_BYTES];
+
+ /* Command format.
+ *
+ * WIDTH FIELD
+ * 1 OP
+ * 1 MSB SALT LEN
+ * 1 LSB SALT LEN
+ * SALT_LEN SALT
+ * 1 MSB IKM LEN
+ * 1 LSB IKM LEN
+ * IKM_LEN IKM
+ * 1 MSB INFO LEN
+ * 1 LSB INFO LEN
+ * INFO_LEN INFO
+ * 1 MSB OKM LEN
+ * 1 LSB OKM LEN
+ */
+ cmd = (uint8_t *) cmd_body;
+ out = (uint8_t *) cmd_body;
+ op = *cmd++;
+
+ salt_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+ cmd += 2;
+ salt = cmd;
+ cmd += salt_len;
+
+ IKM_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+ cmd += 2;
+ IKM = cmd;
+ cmd += IKM_len;
+
+ info_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+ cmd += 2;
+ info = cmd;
+ cmd += info_len;
+
+ OKM_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
+
+ if (OKM_len > MAX_OKM_BYTES) {
+ *response_size = 0;
+ return;
+ }
+
+ switch (op) {
+ case TEST_RFC:
+ if (DCRYPTO_hkdf(OKM, OKM_len, salt, salt_len,
+ IKM, IKM_len, info, info_len)) {
+ memcpy(out, OKM, OKM_len);
+ *response_size = OKM_len;
+ } else {
+ *response_size = 0;
+ }
+ break;
+ default:
+ *response_size = 0;
+ }
+}
+
+DECLARE_EXTENSION_COMMAND(EXTENSION_HKDF, hkdf_command_handler);
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 6a279417a8..97589c7fd6 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -29,6 +29,7 @@ endif
chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/bn.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/hmac.o
+chip-$(CONFIG_DCRYPTO)+= dcrypto/hkdf.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ec.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ecdsa.o
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
index a412adee5a..c333d93fee 100644
--- a/chip/g/dcrypto/dcrypto.h
+++ b/chip/g/dcrypto/dcrypto.h
@@ -141,4 +141,12 @@ int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
const p256_int *digest, const p256_int *r,
const p256_int *s);
+/*
+ * HKDF.
+ */
+int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len,
+ const uint8_t *info, size_t info_len);
+
#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */
diff --git a/chip/g/dcrypto/hkdf.c b/chip/g/dcrypto/hkdf.c
new file mode 100644
index 0000000000..db861ec318
--- /dev/null
+++ b/chip/g/dcrypto/hkdf.c
@@ -0,0 +1,79 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* An implementation of HKDF as per RFC 5869. */
+
+#include "dcrypto.h"
+#include "internal.h"
+
+static int hkdf_extract(uint8_t *PRK, const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len)
+{
+ struct HMAC_CTX ctx;
+
+ if (PRK == NULL)
+ return 0;
+ if (salt == NULL && salt_len > 0)
+ return 0;
+ if (IKM == NULL && IKM_len > 0)
+ return 0;
+
+ dcrypto_HMAC_SHA256_init(&ctx, salt, salt_len);
+ dcrypto_HMAC_update(&ctx, IKM, IKM_len);
+ memcpy(PRK, dcrypto_HMAC_final(&ctx), SHA256_DIGEST_BYTES);
+ return 1;
+}
+
+static int hkdf_expand(uint8_t *OKM, size_t OKM_len, const uint8_t *PRK,
+ const uint8_t *info, size_t info_len)
+{
+ uint8_t count = 1;
+ const uint8_t *T = OKM;
+ size_t T_len = 0;
+ uint32_t num_blocks = (OKM_len / SHA256_DIGEST_BYTES) +
+ (OKM_len % SHA256_DIGEST_BYTES ? 1 : 0);
+
+ if (OKM == NULL || OKM_len == 0)
+ return 0;
+ if (PRK == NULL)
+ return 0;
+ if (info == NULL && info_len > 0)
+ return 0;
+ if (num_blocks > 255)
+ return 0;
+
+ while (OKM_len > 0) {
+ struct HMAC_CTX ctx;
+ const size_t block_size = MIN(OKM_len, SHA256_DIGEST_BYTES);
+
+ dcrypto_HMAC_SHA256_init(&ctx, PRK, SHA256_DIGEST_BYTES);
+ dcrypto_HMAC_update(&ctx, T, T_len);
+ dcrypto_HMAC_update(&ctx, info, info_len);
+ dcrypto_HMAC_update(&ctx, &count, sizeof(count));
+ memcpy(OKM, dcrypto_HMAC_final(&ctx), block_size);
+
+ T += T_len;
+ T_len = SHA256_DIGEST_BYTES;
+ count += 1;
+ OKM += block_size;
+ OKM_len -= block_size;
+ }
+ return 1;
+}
+
+int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len,
+ const uint8_t *salt, size_t salt_len,
+ const uint8_t *IKM, size_t IKM_len,
+ const uint8_t *info, size_t info_len)
+{
+ int result;
+ uint8_t PRK[SHA256_DIGEST_BYTES];
+
+ if (!hkdf_extract(PRK, salt, salt_len, IKM, IKM_len))
+ return 0;
+
+ result = hkdf_expand(OKM, OKM_len, PRK, info, info_len);
+ memset(PRK, 0, sizeof(PRK));
+ return result;
+}
diff --git a/include/extension.h b/include/extension.h
index 4e7b66558c..868fae370d 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -51,6 +51,7 @@ enum {
EXTENSION_RSA = 2,
EXTENSION_EC = 3,
EXTENSION_FW_UPGRADE = 4,
+ EXTENSION_HKDF = 5,
};
diff --git a/test/tpm_test/hkdf_test.py b/test/tpm_test/hkdf_test.py
new file mode 100644
index 0000000000..5de0b3879a
--- /dev/null
+++ b/test/tpm_test/hkdf_test.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+# Copyright 2016 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Module for testing HKDF using extended commands."""
+
+from binascii import a2b_hex as a2b
+from struct import pack
+
+import subcmd
+import utils
+
+
+_HKDF_OPCODES = {
+ 'TEST_RFC': 0x00,
+}
+
+
+# Command format.
+#
+# WIDTH FIELD
+# 1 OP
+# 1 MSB SALT LEN
+# 1 LSB SALT LEN
+# SALT_LEN SALT
+# 1 MSB IKM LEN
+# 1 LSB IKM LEN
+# IKM_LEN IKM
+# 1 MSB INFO LEN
+# 1 LSB INFO LEN
+# INFO_LEN INFO
+# 1 MSB OKM LEN
+# 1 LSB OKM LEN
+#
+_HKDF_CMD_FORMAT = '{op:c}{sl:s}{salt}{ikml:s}{ikm}{infol:s}{info}{okml:s}'
+
+
+def _rfc_test_cmd(salt, ikm, info, okml):
+ op = _HKDF_OPCODES['TEST_RFC']
+ return _HKDF_CMD_FORMAT.format(op=op,
+ sl=pack('>H', len(salt)), salt=salt,
+ ikml=pack('>H', len(ikm)), ikm=ikm,
+ infol=pack('>H', len(info)), info=info,
+ okml=pack('>H', okml))
+
+
+#
+# Test vectors for HKDF-SHA256 from RFC 5869.
+#
+_RFC_TEST_INPUTS = (
+ (
+ '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b',
+ '000102030405060708090a0b0c',
+ 'f0f1f2f3f4f5f6f7f8f9',
+ ('3cb25f25faacd57a90434f64d0362f2a'
+ '2d2d0a90cf1a5a4c5db02d56ecc4c5bf'
+ '34007208d5b887185865'),
+ 'BASIC',
+ ),
+ (
+ ('000102030405060708090a0b0c0d0e0f'
+ '101112131415161718191a1b1c1d1e1f'
+ '202122232425262728292a2b2c2d2e2f'
+ '303132333435363738393a3b3c3d3e3f'
+ '404142434445464748494a4b4c4d4e4f'),
+ ('606162636465666768696a6b6c6d6e6f'
+ '707172737475767778797a7b7c7d7e7f'
+ '808182838485868788898a8b8c8d8e8f'
+ '909192939495969798999a9b9c9d9e9f'
+ 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf'),
+ ('b0b1b2b3b4b5b6b7b8b9babbbcbdbebf'
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf'
+ 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'
+ 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef'
+ 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'),
+ ('b11e398dc80327a1c8e7f78c596a4934'
+ '4f012eda2d4efad8a050cc4c19afa97c'
+ '59045a99cac7827271cb41c65e590e09'
+ 'da3275600c2f09b8367793a9aca3db71'
+ 'cc30c58179ec3e87c14c01d5c1f3434f'
+ '1d87'),
+ 'LONG INPUTS',
+ ),
+ (
+ '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b',
+ '',
+ '',
+ ('8da4e775a563c18f715f802a063c5a31'
+ 'b8a11f5c5ee1879ec3454e5f3c738d2d'
+ '9d201395faa4b61a96c8'),
+ 'ZERO SALT/INFO',
+ )
+)
+
+
+def _rfc_tests(tpm):
+ for data in _RFC_TEST_INPUTS:
+ IKM, salt, info, OKM = map(a2b, data[:-1])
+ test_name = 'HKDF:SHA256:%s' % data[-1]
+ cmd = _rfc_test_cmd(salt, IKM, info, len(OKM))
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.HKDF, cmd))
+ result = tpm.unwrap_ext_response(subcmd.HKDF, wrapped_response)
+
+ if result != OKM:
+ raise subcmd.TpmTestError('%s error:%s%s' % (
+ test_name, utils.hex_dump(result), utils.hex_dump(OKM)))
+ print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+
+
+def hkdf_test(tpm):
+ _rfc_tests(tpm)
diff --git a/test/tpm_test/subcmd.py b/test/tpm_test/subcmd.py
index 33a4ab21d7..e0de4af9f5 100644
--- a/test/tpm_test/subcmd.py
+++ b/test/tpm_test/subcmd.py
@@ -11,6 +11,7 @@ HASH = 1
RSA = 2
EC = 3
FW_UPGRADE = 4
+HKDF = 5
# The same exception class used by all tpmtest modules.
class TpmTestError(Exception):
diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py
index 4b92ea3ce9..9f08a2d99c 100755
--- a/test/tpm_test/tpmtest.py
+++ b/test/tpm_test/tpmtest.py
@@ -22,6 +22,7 @@ import crypto_test
import ecc_test
import ftdi_spi_tpm
import hash_test
+import hkdf_test
import rsa_test
import subcmd
import upgrade_test
@@ -136,6 +137,7 @@ if __name__ == '__main__':
crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml'))
ecc_test.ecc_test(t)
hash_test.hash_test(t)
+ hkdf_test.hkdf_test(t)
rsa_test.rsa_test(t)
upgrade_test.upgrade(t)
except subcmd.TpmTestError as e: