summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2019-11-12 11:20:12 -0800
committerCommit Bot <commit-bot@chromium.org>2019-11-21 19:24:22 +0000
commit3bc0a6b273fdd8bdc5ad34e5a0c1ecc88754cfa1 (patch)
tree16808c89fb37dd2b5206edde0d2eba6aeccd4c98 /test
parent052ed9c30e9fca104ac151920de92f8a8f76fc07 (diff)
downloadchrome-ec-3bc0a6b273fdd8bdc5ad34e5a0c1ecc88754cfa1.tar.gz
cr50: Add support for ACVP tests of HMAC SHA-256 DRBG
HMAC DRBG is used for U2F key generation, and as such is subject for ACVP tests. Expose DRBG Init, Generate and Seed commands for automated testing with externally provided test vectors. BUG=b:138578319 BRANCH=cr50 TEST=make CRYPTO_TEST=1 BOARD=cr50 -j && test/tpm_test/tpmtest.py Change-Id: I50a6750864d3cd9a304a9b8a8524ef29cec04410 Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1912662 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org> Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Diffstat (limited to 'test')
-rw-r--r--test/tpm_test/drbg_test.py108
-rw-r--r--test/tpm_test/subcmd.py4
-rwxr-xr-xtest/tpm_test/tpmtest.py11
3 files changed, 117 insertions, 6 deletions
diff --git a/test/tpm_test/drbg_test.py b/test/tpm_test/drbg_test.py
new file mode 100644
index 0000000000..097a222923
--- /dev/null
+++ b/test/tpm_test/drbg_test.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python2
+# Copyright 2019 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 hash functions using extended commands."""
+
+from __future__ import print_function
+
+from binascii import a2b_hex as a2b
+from struct import pack
+
+import subcmd
+import utils
+
+
+# A standard empty response to DRBG extended commands.
+EMPTY_DRBG_RESPONSE = ''.join('%c' % x for x in (0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, subcmd.DRBG_TEST))
+
+DRBG_INIT = 0
+DRBG_RESEED = 1
+DRBG_GENERATE = 2
+
+test_inputs = (
+ (DRBG_INIT,
+ ('C40894D0C37712140924115BF8A3110C7258532365BB598F81B127A5E4CB8EB0',
+ 'FBB1EDAF92D0C2699F5C0A7418D308B09AC679FFBB0D8918C8E62D35091DD2B9',
+ '2B18535D739F7E75AF4FF0C0C713DD4C9B0A6803D2E0DB2BDE3C4F3650ABF750')),
+ (DRBG_RESEED,
+ ('4D58A621857706450338CCA8A1AF5CD2BD9305F3475CF1A8752518DD8E8267B6',
+ '0153A0A1D7487E2EE9915E2CAA8488F97239C67595F418D9503D0B11CC07044E', '')),
+ (DRBG_GENERATE,
+ ('39AE66C2939D1D73EF21AE22988B04CC7E8EA2D790C75E1FC6ACC7FEEEF90F98',
+ '')),
+ (DRBG_GENERATE,
+ ('B8031829E07B09EEEADEBA149D0AC9F08B110197CD8BBDDC32744BCD66FCF3C4',
+ 'A1307377F6B472661BC3C6D44C035FB20A13CCB04D6601B2425FC4DDA3B6D7DF')),
+ (DRBG_INIT,
+ ('3A2D261884010CCB4C2C4D7B323CCB7BD4515089BEB749C565A7492710922164',
+ '9E4D22471A4546F516099DD4D737967562D1BB77D774B67B7FE4ED893AE336CF',
+ '5837CAA74345CC2D316555EF820E9F3B0FD454D8C5B7BDE68E4A176D52EE7D1C')),
+ (DRBG_GENERATE,
+ ('4D87985505D779F1AD98455E04199FE8F2FE8E550E6FEB1D26177A2C5B744B9F',
+ '')),
+ (DRBG_GENERATE,
+ ('85D011A3B36AC6B25A792F213A1C22C80BFD1C5B47BCA04CD0D9834BB466447B',
+ 'B03863C42C9396B4936D83A551871A424C5A8EDBDC9D1E0E8E89710D58B5CA1E')),
+
+)
+
+_DRBG_INIT_FORMAT = '{op:c}{p0l:s}{p0}{p1l:s}{p1}{p2l:s}{p2}'
+def _drbg_init_cmd(op, entropy, nonce, perso):
+ return _DRBG_INIT_FORMAT.format(op=op,
+ p0l=pack('>H', len(entropy)), p0=entropy,
+ p1l=pack('>H', len(nonce)), p1=nonce,
+ p2l=pack('>H', len(perso)), p2=perso)
+
+_DRBG_GEN_FORMAT = '{op:c}{p0l:s}{p0}{p1l:s}'
+
+def _drbg_gen_cmd(inp, out):
+ outlen = len(out)
+ if outlen == 0:
+ outlen = 32 # if we don't care about output value, still need to have it
+ return _DRBG_GEN_FORMAT.format(op=DRBG_GENERATE,
+ p0l=pack('>H', len(inp)), p0=inp,
+ p1l=pack('>H', outlen))
+
+
+def drbg_test(tpm):
+ """Runs DRBG test case.
+
+ Args:
+ tpm: a tpm object used to communicate with the device
+
+ Raises:
+ subcmd.TpmTestError: on unexpected target responses
+ """
+
+ for test in test_inputs:
+ drbg_op, drbg_params = test
+ if drbg_op == DRBG_INIT:
+ entropy, nonce, perso = drbg_params
+ cmd = _drbg_init_cmd(drbg_op, a2b(entropy), a2b(nonce), a2b(perso))
+ response = tpm.command(tpm.wrap_ext_command(subcmd.DRBG_TEST, cmd))
+ if response != EMPTY_DRBG_RESPONSE:
+ raise subcmd.TpmTestError("Unexpected response to DRBG_INIT: %s" %
+ (utils.hex_dump(wrapped_response)))
+ elif drbg_op == DRBG_RESEED:
+ entropy, inp1, inp2 = drbg_params
+ cmd = _drbg_init_cmd(drbg_op, a2b(entropy), a2b(inp1), a2b(inp2))
+ response = tpm.command(tpm.wrap_ext_command(subcmd.DRBG_TEST, cmd))
+ if response != EMPTY_DRBG_RESPONSE:
+ raise subcmd.TpmTestError("Unexpected response to DRBG_RESEED: %s" %
+ (utils.hex_dump(wrapped_response)))
+ elif drbg_op == DRBG_GENERATE:
+ inp, expected = drbg_params
+ cmd = _drbg_gen_cmd(a2b(inp), a2b(expected))
+ response = tpm.command(tpm.wrap_ext_command(subcmd.DRBG_TEST, cmd))
+ if expected != '':
+ result = response[12:]
+ if a2b(expected) != result:
+ raise subcmd.TpmTestError('error:\nexpected %s\nreceived %s' %
+ (utils.hex_dump(a2b(expected)),
+ utils.hex_dump(result)))
+ print('%sSUCCESS: %s' % (utils.cursor_back(), 'DRBG test'))
diff --git a/test/tpm_test/subcmd.py b/test/tpm_test/subcmd.py
index d6aeb6722f..7260df0dd5 100644
--- a/test/tpm_test/subcmd.py
+++ b/test/tpm_test/subcmd.py
@@ -5,7 +5,7 @@
"""Subcommand codes that specify the crypto module."""
-# Keep these codes in sync with include/extension.h.
+# Keep these codes in sync with include/tpm_vendor_cmds.h
AES = 0
HASH = 1
RSA = 2
@@ -13,7 +13,7 @@ ECC = 3
FW_UPGRADE = 4
HKDF = 5
ECIES = 6
-
+DRBG_TEST = 50
# The same exception class used by all tpmtest modules.
class TpmTestError(Exception):
pass
diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py
index 4a8e442265..11218cbcc6 100755
--- a/test/tpm_test/tpmtest.py
+++ b/test/tpm_test/tpmtest.py
@@ -20,6 +20,7 @@ root_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
sys.path.append(os.path.join(root_dir, '..', '..', 'build', 'tpm_test'))
import crypto_test
+import drbg_test
import ecc_test
import ecies_test
import ftdi_spi_tpm
@@ -71,17 +72,18 @@ class TPM(object):
if size > 4096:
raise subcmd.TpmTestError(prefix + 'invalid size %d' % size)
if response_mode:
- # Startup response code or extension command response code
- if cmd_code == 0x100 or cmd_code == 0:
+ # Startup response code, extension or vendor command response code
+ if cmd_code == 0x100 or cmd_code == 0 or cmd_code == 0x500:
return
else:
raise subcmd.TpmTestError(
- prefix + 'invalid command code 0x%x' % cmd_code)
+ prefix + 'invalid response code 0x%x' % cmd_code)
if cmd_code >= 0x11f and cmd_code <= 0x18f:
return # This is a valid command
if cmd_code == EXT_CMD:
return # This is an extension command
-
+ if cmd_code >= 0x20000000 and cmd_code <= 0x200001ff:
+ return # this is vendor command
raise subcmd.TpmTestError(prefix + 'invalid command code 0x%x' % cmd_code)
def command(self, cmd_data):
@@ -162,6 +164,7 @@ if __name__ == '__main__':
trng_test.trng_test(t)
sys.exit(1)
crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml'))
+ drbg_test.drbg_test(t)
ecc_test.ecc_test(t)
ecies_test.ecies_test(t)
hash_test.hash_test(t)