summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/dcrypto/hmac_drbg.c117
-rw-r--r--include/tpm_vendor_cmds.h5
-rw-r--r--test/tpm_test/drbg_test.py108
-rw-r--r--test/tpm_test/subcmd.py4
-rwxr-xr-xtest/tpm_test/tpmtest.py11
5 files changed, 239 insertions, 6 deletions
diff --git a/chip/g/dcrypto/hmac_drbg.c b/chip/g/dcrypto/hmac_drbg.c
index bf49103e93..0643c9bf84 100644
--- a/chip/g/dcrypto/hmac_drbg.c
+++ b/chip/g/dcrypto/hmac_drbg.c
@@ -6,6 +6,7 @@
#include "console.h"
#include "cryptoc/util.h"
#include "dcrypto.h"
+#include "extension.h"
#include "internal.h"
#include "trng.h"
@@ -356,4 +357,120 @@ static int cmd_hmac_drbg_rand(int argc, char **argv)
return 0;
}
DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg_rand, cmd_hmac_drbg_rand, NULL, NULL);
+
+enum drbg_command {
+ DRBG_INIT = 0,
+ DRBG_RESEED = 1,
+ DRBG_GENERATE = 2
+};
+
+/*
+ * DRBG_TEST command structure:
+ *
+ * field | size | note
+ * ==========================================================================
+ * mode | 1 | 0 - DRBG_INIT, 1 - DRBG_RESEED, 2 - DRBG_GENERATE
+ * p0_len | 2 | size of first input in bytes
+ * p0 | p0_len | entropy for INIT & SEED, input for GENERATE
+ * p1_len | 2 | size of second input in bytes (for INIT & RESEED)
+ * | | or size of expected output for GENERATE
+ * p1 | p1_len | nonce for INIT & SEED
+ * p2_len | 2 | size of third input in bytes for DRBG_INIT
+ * p2 | p2_len | personalization for INIT & SEED
+ *
+ * DRBG_INIT (entropy, nonce, perso)
+ * DRBG_RESEED (entropy, additional input 1, additional input 2)
+ * DRBG_INIT and DRBG_RESEED returns empty response
+ * DRBG_GENERATE (p0_len, p0 - additional input 1, p1_len - size of output)
+ * DRBG_GENERATE returns p1_len bytes of generated data
+ * (up to a maximum of 128 bytes)
+ */
+static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf,
+ size_t input_size, size_t *response_size)
+{
+ static struct drbg_ctx drbg_ctx;
+ static uint8_t output[128];
+ uint8_t *p0 = NULL, *p1 = NULL, *p2 = NULL;
+ uint16_t p0_len = 0, p1_len = 0, p2_len = 0;
+ uint8_t *cmd = (uint8_t *)buf;
+ size_t max_out_len = *response_size;
+ enum drbg_command drbg_op;
+
+ *response_size = 0;
+ /* there is always op + first parameter, even if zero length */
+ if (input_size < sizeof(p0_len) + 1)
+ return VENDOR_RC_BOGUS_ARGS;
+ drbg_op = *cmd++;
+ p0_len = *cmd++;
+ p0_len = p0_len * 256 + *cmd++;
+ input_size -= 3;
+ if (p0_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ input_size -= p0_len;
+ if (p0_len)
+ p0 = cmd;
+ cmd += p0_len;
+
+ /* there should be enough space for p1_len */
+ if (input_size && input_size < sizeof(p1_len))
+ return VENDOR_RC_BOGUS_ARGS;
+
+ /* DRBG_GENERATE should just have p1_len defined */
+ if (drbg_op == DRBG_GENERATE && input_size != sizeof(p1_len))
+ return VENDOR_RC_BOGUS_ARGS;
+
+ if (input_size) {
+ p1_len = *cmd++;
+ p1_len = p1_len * 256 + *cmd++;
+ input_size -= 2;
+
+ if (drbg_op != DRBG_GENERATE) {
+ if (p1_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ input_size -= p1_len;
+ if (p1_len)
+ p1 = cmd;
+ cmd += p1_len;
+ }
+ }
+
+ if (input_size) {
+ if (drbg_op == DRBG_GENERATE)
+ return VENDOR_RC_BOGUS_ARGS;
+ p2_len = *cmd++;
+ p2_len = p2_len * 256 + *cmd++;
+ input_size -= 2;
+ if (p2_len > input_size)
+ return VENDOR_RC_BOGUS_ARGS;
+ if (p2_len)
+ p2 = cmd;
+ }
+
+ switch (drbg_op) {
+ case DRBG_INIT: {
+ hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ break;
+ }
+ case DRBG_RESEED: {
+ hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len);
+ break;
+ }
+ case DRBG_GENERATE: {
+ if (p1_len > sizeof(output) || max_out_len < p1_len)
+ return VENDOR_RC_BOGUS_ARGS;
+
+ hmac_drbg_generate(&drbg_ctx, output, p1_len, p0, p0_len);
+
+ memcpy(buf, output, p1_len);
+ *response_size = p1_len;
+ break;
+ }
+ default:
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_DRBG_TEST, drbg_test);
+
#endif /* CRYPTO_TEST_SETUP */
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index 7244b47a4f..5afd1fc84b 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -136,6 +136,11 @@ enum vendor_cmd_cc {
VENDOR_CC_U2F_MODE = 49,
+ /*
+ * HMAC-SHA256 DRBG invocation for ACVP tests
+ */
+ VENDOR_CC_DRBG_TEST = 50,
+
VENDOR_CC_TRNG_TEST = 51,
LAST_VENDOR_COMMAND = 65535,
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)