diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2019-11-15 11:37:08 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-19 20:35:30 +0000 |
commit | 8190be1a6fef4203d743825d7afe74b5ec1fc083 (patch) | |
tree | ab821d6962572ea7c6476ac17d47f85f3de3919e | |
parent | e9bc15a9ac68e3b28e68c0191794e842927622ee (diff) | |
download | chrome-ec-8190be1a6fef4203d743825d7afe74b5ec1fc083.tar.gz |
cr50: Add TRNG_TEST command to download entropy samples for NIST tests
NIST 800-90B Entropy assesment tests requires 1M of 8-bit samples for
statistical tests. While it's possible to use TPM2_GetRandom command
to get entropy on cr50 (there is no software postprocessing), this
command is not available when compiled with CRYPTO_TEST=1 due to lack
of space in firmware. Adding vendor command which is available with
CRYPTO_TEST=1 to get raw entropy from TRNG. Added support script
to save entropy in file for further analysis. Since downloading
entropy takes a long time, new option'-t' added to tpmtest.py
which only invokes download of TRNG samples
BUG=b:138577834
BRANCH=cr50
TEST=make BOARD=cr50 CRYPTO_TEST=1 && test/tpm_test/tpmtest.py -t
To run NIST tests: nist_entropy.sh
Change-Id: I237a4581332a6e2c0332fe6ecf40731ab0be3355
Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1919640
Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Commit-Queue: Vadim Bendebury <vbendeb@chromium.org>
Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r-- | chip/g/trng.c | 36 | ||||
-rw-r--r-- | include/tpm_vendor_cmds.h | 2 | ||||
-rw-r--r-- | test/tpm_test/README.md | 49 | ||||
-rwxr-xr-x | test/tpm_test/nist_entropy.sh | 21 | ||||
-rwxr-xr-x | test/tpm_test/tpmtest.py | 29 | ||||
-rw-r--r-- | test/tpm_test/trng_test.py | 50 |
6 files changed, 185 insertions, 2 deletions
diff --git a/chip/g/trng.c b/chip/g/trng.c index 69e4ce1d87..afd9fa86e3 100644 --- a/chip/g/trng.c +++ b/chip/g/trng.c @@ -132,3 +132,39 @@ static int command_rand(int argc, char **argv) } DECLARE_CONSOLE_COMMAND(rand, command_rand, NULL, NULL); #endif /* !defined(SECTION_IS_RO) && defined(TEST_TRNG) */ + +#ifdef CRYPTO_TEST_SETUP +#include "extension.h" +/* + * This extension command is similar to TPM2_GetRandom, but made + * available for CRYPTO_TEST = 1 which disables TPM + * Command structure, shared out of band with the test driver running + * on the host: + * + * field | size | note + * =================================================================== + * text_len | 2 | size of the text to process, big endian + */ +static enum vendor_cmd_rc trng_test(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size) +{ + uint16_t text_len; + uint8_t *cmd; + size_t response_room = *response_size; + + if (input_size != sizeof(text_len)) { + *response_size = 0; + return VENDOR_RC_BOGUS_ARGS; + } + cmd = buf; + text_len = *cmd++; + text_len = text_len * 256 + *cmd++; + text_len = MIN(text_len, response_room); + rand_bytes(buf, text_len); + *response_size = text_len; + return VENDOR_RC_SUCCESS; +} + +DECLARE_VENDOR_COMMAND(VENDOR_CC_TRNG_TEST, trng_test); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h index c22079f490..7244b47a4f 100644 --- a/include/tpm_vendor_cmds.h +++ b/include/tpm_vendor_cmds.h @@ -136,6 +136,8 @@ enum vendor_cmd_cc { VENDOR_CC_U2F_MODE = 49, + VENDOR_CC_TRNG_TEST = 51, + LAST_VENDOR_COMMAND = 65535, }; diff --git a/test/tpm_test/README.md b/test/tpm_test/README.md new file mode 100644 index 0000000000..80aaa0a76f --- /dev/null +++ b/test/tpm_test/README.md @@ -0,0 +1,49 @@ +# TPM / Crypto unit tests +tpmtest.py runs set of tests to check correctness of cryptographic functions +implementation. These tests require a special firmware image built with +CRYPTO_TEST=1 flag to enable direct exposure of low-level cryptographic +functions via TPM extensions and vendor commands. TPM functionality itself +is disabled due to not enough enough flash/memory to fit both. +As such, these tests are expected to run over H1 Red board. + +Firmware image is expected to be built with: + +make BOARD=cr50 CRYPTO_TEST=1 -j + +Cryptographic tests are invoked when tpmtest.py is executed with no command-line +parameters: + + ./tpmtest.py + +Option *-d* can be used for debugging. It adds output of actual data +sent/received from H1, which is handy when adding new functionality: + + ./tpmtest.py -d + +# TRNG tests +Another functionality is statistical assessment of entropy from True Random +Number Generator (TRNG). These tests are prerequisite for FIPS 140-2/3 +certification and governed by NIST SP 800-90B. +tpmtest.py implements a mode to download raw data from TRNG: + + ./tpmtest.py -t + +Script nist_entropy.sh automated this testing by +1. Downloading latest NIST Entropy Assessment tool from + [https://github.com/usnistgov/SP800-90B_EntropyAssessment] and building it. +2. Gathering 1000000 of 8-bit samples from H1 TRNG and + storing it in /tmp/trng_output using tpmtest.py -t +3. Running NIST tool in non-IID (independent and identically distributed) mode + to estimate entropy. This specific mode is choosed as there is no formal + proof that TRNG data is independent and identically distributed. + It follows manual in + [https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90B.pdf] + +The successful result is being awarded entropy estimate for TRNG, which is +expected to be more than 7 (8 is theoretical max). +If test fails, no entropy assessment is awarded. + +This script is expected to run in platform/ec/test/tpm_test directory +(where ./tpmtest.py is located) + + diff --git a/test/tpm_test/nist_entropy.sh b/test/tpm_test/nist_entropy.sh new file mode 100755 index 0000000000..f69c5652cd --- /dev/null +++ b/test/tpm_test/nist_entropy.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# 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. + +# NIST toolset needs sudo emerge dev-libs/libdivsufsort +rm -rf /tmp/ea +git clone --depth 1 https://github.com/usnistgov/SP800-90B_EntropyAssessment.git /tmp/ea/ +make -C /tmp/ea/cpp/ non_iid +make -C /tmp/ea/cpp/ restart +TRNG_OUT=/tmp/trng_output +rm -f $TRNG_OUT +./tpmtest.py -t +if [ ! -f "$TRNG_OUT" ]; then + echo "$TRNG_OUT does not exist" + exit 1 +fi +/tmp/ea/cpp/ea_non_iid -a $TRNG_OUT | tee ea_non_iid.log +entropy=`grep min ea_non_iid.log | awk '{ print $5 }'` +echo "Minimal entropy" $entropy +/tmp/ea/cpp/ea_restart $TRNG_OUT $entropy | tee -a ea_non_iid.log diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py index 823c3013e7..4a8e442265 100755 --- a/test/tpm_test/tpmtest.py +++ b/test/tpm_test/tpmtest.py @@ -7,6 +7,7 @@ from __future__ import print_function +import getopt import os import struct import sys @@ -26,6 +27,7 @@ import hash_test import hkdf_test import rsa_test import subcmd +import trng_test import upgrade_test # Extension command for dcypto testing @@ -130,12 +132,35 @@ class TPM(object): def debug_enabled(self): return self._debug_enabled +def usage(): + print ('Syntax: tpmtest.py [-d | -t | -h ]\n' + ' -d - prints additional debug information during tests\n' + ' -t - dump raw output from TRNG to /tmp/trng_output\n' + ' -h - this help\n') + return if __name__ == '__main__': try: - debug_needed = len(sys.argv) == 2 and sys.argv[1] == '-d' + opts, args = getopt.getopt(sys.argv[1:], 'dth','help') + except getopt.GetoptError as err: + print(str(err)) + usage() + sys.exit(2) + debug_needed = False + trng_only = False + for o, a in opts: + if o == '-d': + debug_needed = True + elif o == '-t': + trng_only = True + elif o == '-h' or o == '--help': + usage() + sys.exit(0) + try: t = TPM(debug_mode=debug_needed) - + if trng_only: + trng_test.trng_test(t) + sys.exit(1) crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml')) ecc_test.ecc_test(t) ecies_test.ecies_test(t) diff --git a/test/tpm_test/trng_test.py b/test/tpm_test/trng_test.py new file mode 100644 index 0000000000..aac2803076 --- /dev/null +++ b/test/tpm_test/trng_test.py @@ -0,0 +1,50 @@ +#!/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. +"""Tests for trng.""" +from __future__ import print_function +import struct + +import subcmd +import utils + +TRNG_TEST_FMT = '>H' +TRNG_TEST_RSP_FMT = '>H2IH' +TRNG_TEST_CC = 0x33 +TRNG_SAMPLE_SIZE = 1000 # minimal recommended by NIST is 1000 bytes per sample +TRNG_SAMPLE_COUNT = 1000 # NIST require at least 1000000 of 8-bit samples + +def get_random_command(size): + return struct.pack(TRNG_TEST_FMT, size) + +def get_random_command_rsp(size): + return struct.pack(TRNG_TEST_RSP_FMT, 0x8001, + struct.calcsize(TRNG_TEST_RSP_FMT) + size, 0, TRNG_TEST_CC) + + +def trng_test(tpm): + """Download entropy samples from TRNG + + Command structure, shared out of band with the test running on the target: + + field | size | note + =================================================================== + text_len | 2 | size of the text to process, big endian + + Args: + tpm: a tpm object used to communicate with the device + + Raises: + subcmd.TpmTestError: on unexpected target responses + """ + with open('/tmp/trng_output', 'wb') as f: + for x in range(0, TRNG_SAMPLE_COUNT): + wrapped_response = tpm.command(tpm.wrap_ext_command(TRNG_TEST_CC, + get_random_command(TRNG_SAMPLE_SIZE))) + if wrapped_response[:12] != get_random_command_rsp(TRNG_SAMPLE_SIZE): + raise subcmd.TpmTestError("Unexpected response to '%s': %s" % + ("trng", utils.hex_dump(wrapped_response))) + f.write(wrapped_response[12:]) + print('%s %d%%\r' %( utils.cursor_back(), (x/10)), end=""), + print('%sSUCCESS: %s' % (utils.cursor_back(), 'trng')) |