diff options
author | nagendra modadugu <ngm@google.com> | 2016-03-29 20:49:43 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-04-14 17:28:21 -0700 |
commit | 533a536140c13bb853e51a62af36bd56c6d85b0d (patch) | |
tree | 1e6e4936caaf3f35259c7c0d7f99de6ddd1ea030 | |
parent | 9ab5ffaef0b98e797ee6d1e09687c1fa7b4b79fe (diff) | |
download | chrome-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.mk | 1 | ||||
-rw-r--r-- | board/cr50/tpm2/hkdf.c | 93 | ||||
-rw-r--r-- | chip/g/build.mk | 1 | ||||
-rw-r--r-- | chip/g/dcrypto/dcrypto.h | 8 | ||||
-rw-r--r-- | chip/g/dcrypto/hkdf.c | 79 | ||||
-rw-r--r-- | include/extension.h | 1 | ||||
-rw-r--r-- | test/tpm_test/hkdf_test.py | 112 | ||||
-rw-r--r-- | test/tpm_test/subcmd.py | 1 | ||||
-rwxr-xr-x | test/tpm_test/tpmtest.py | 2 |
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: |