diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/tpm_test/ecc_test.py | 169 | ||||
-rw-r--r-- | test/tpm_test/subcmd.py | 1 | ||||
-rwxr-xr-x | test/tpm_test/tpmtest.py | 2 |
3 files changed, 172 insertions, 0 deletions
diff --git a/test/tpm_test/ecc_test.py b/test/tpm_test/ecc_test.py new file mode 100644 index 0000000000..cd4bb0a261 --- /dev/null +++ b/test/tpm_test/ecc_test.py @@ -0,0 +1,169 @@ +#!/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 ecc functions using extended commands.""" +import binascii +import hashlib +import os +import struct + +import subcmd +import utils + +_EC_OPCODES = { + 'SIGN': 0x00, + 'VERIFY': 0x01, + 'KEYGEN': 0x02, + 'KEYDERIVE': 0x03, +} + +_EC_CURVES = { + 'NIST-P256': 0x03, +} + +# TPM2 signature codes. +_SIGN_MODE = { + 'NONE': 0x00, + 'ECDSA': 0x18, + # TODO(ngm): add support for SCHNORR. + # 'SCHNORR': 0x1c +} + +# TPM2 ALG codes. +_HASH = { + 'NONE': 0x00, + 'SHA1': 0x04, + 'SHA256': 0x0B +} + +_HASH_FUNC = { + 'NIST-P256': hashlib.sha256 +} + +# Command format. +# +# 0x00 OP +# 0x00 CURVE_ID +# 0x00 SIGN_MODE +# 0x00 HASHING +# 0x00 MSB IN LEN +# 0x00 LSB IN LEN +# .... IN +# 0x00 MSB DIGEST LEN +# 0x00 LSB DIGEST LEN +# .... DIGEST +# +_EC_CMD_FORMAT = '{o:c}{c:c}{s:c}{h:c}{ml:s}{msg}{dl:s}{dig}' + + +def _sign_cmd(curve_id, hash_func, sign_mode, msg): + op = _EC_OPCODES['SIGN'] + digest = hash_func(msg).digest() + digest_len = len(digest) + return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'], + ml=struct.pack('>H', 0), msg='', + dl=struct.pack('>H', digest_len), dig=digest) + + +def _verify_cmd(curve_id, hash_func, sign_mode, msg, sig): + op = _EC_OPCODES['VERIFY'] + sig_len = len(sig) + digest = hash_func(msg).digest() + digest_len = len(digest) + return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'], + ml=struct.pack('>H', sig_len), msg=sig, + dl=struct.pack('>H', digest_len), dig=digest) + + +def _keygen_cmd(curve_id): + op = _EC_OPCODES['KEYGEN'] + return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'], + h=_HASH['NONE'], ml=struct.pack('>H', 0), msg='', + dl=struct.pack('>H', 0), dig='') + + +def _keyderive_cmd(curve_id, seed): + op = _EC_OPCODES['KEYDERIVE'] + seed_len = len(seed) + return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'], + h=_HASH['NONE'], ml=struct.pack('>H', seed_len), + msg=seed, dl=struct.pack('>H', 0), dig='') + + +_SIGN_INPUTS = ( + ('NIST-P256', 'ECDSA'), +) + + +_KEYGEN_INPUTS = ( + ('NIST-P256',), +) + + +_KEYDERIVE_INPUTS = ( + # Curve-id, random seed size. + ('NIST-P256', 32), +) + + +class ECError(Exception): + pass + + +def _sign_test(tpm): + msg = 'Hello CR50' + + for data in _SIGN_INPUTS: + curve_id, sign_mode = data + test_name = 'EC-SIGN:%s:%s' % data + cmd = _sign_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id], + _SIGN_MODE[sign_mode], msg) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd)) + signature = tpm.unwrap_ext_response(subcmd.EC, wrapped_response) + + cmd = _verify_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id], + _SIGN_MODE[sign_mode], msg, signature) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd)) + verified = tpm.unwrap_ext_response(subcmd.EC, wrapped_response) + expected = '\x01' + if verified != expected: + raise ECError('%s error:%s:%s' % ( + test_name, utils.hex_dump(verified), utils.hex_dump(expected))) + print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) + + +def _keygen_test(tpm): + for data in _KEYGEN_INPUTS: + curve_id, = data + test_name = 'EC-KEYGEN:%s' % data + cmd = _keygen_cmd(_EC_CURVES[curve_id]) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd)) + valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response) + expected = '\x01' + if valid != expected: + raise ECError('%s error:%s:%s' % ( + test_name, utils.hex_dump(valid), utils.hex_dump(expected))) + print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) + + +def _keyderive_test(tpm): + for data in _KEYDERIVE_INPUTS: + curve_id, seed_bytes = data + seed = os.urandom(seed_bytes) + test_name = 'EC-KEYDERIVE:%s' % data[0] + cmd = _keyderive_cmd(_EC_CURVES[curve_id], seed) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd)) + valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response) + expected = '\x01' + if valid != expected: + raise ECError('%s error:%s:%s' % ( + test_name, utils.hex_dump(valid), utils.hex_dump(expected))) + print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) + + +def ecc_test(tpm): + _sign_test(tpm) + _keygen_test(tpm) + _keyderive_test(tpm) diff --git a/test/tpm_test/subcmd.py b/test/tpm_test/subcmd.py index f7bd8090a0..d14c2e9b9c 100644 --- a/test/tpm_test/subcmd.py +++ b/test/tpm_test/subcmd.py @@ -9,3 +9,4 @@ AES = 0 HASH = 1 RSA = 2 +EC = 3 diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py index 52d7205022..173f0ec693 100755 --- a/test/tpm_test/tpmtest.py +++ b/test/tpm_test/tpmtest.py @@ -19,6 +19,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 ecc_test import ftdi_spi_tpm import hash_test import rsa_test @@ -135,6 +136,7 @@ if __name__ == '__main__': t = TPM(debug_mode=debug_needed) crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml')) + ecc_test.ecc_test(t) hash_test.hash_test(t) rsa_test.rsa_test(t) except (TpmError, crypto_test.CryptoError, hash_test.HashError, |