diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2019-11-11 16:39:14 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-05 07:25:19 +0000 |
commit | 65e147217ad968743b5f6e3d94db6b5dcefb11ad (patch) | |
tree | e52229ecfe021c36fa4f4cc52fbb52643084673c /test | |
parent | f9cca4269a124019f56980471d152b68177837f0 (diff) | |
download | chrome-ec-65e147217ad968743b5f6e3d94db6b5dcefb11ad.tar.gz |
cr50: add functionality for ACVP tests of elliptic curve implementationstabilize-lazor-13278.B-cr50_stab
NIST ACVP test expects access to test point is on curve and verification
of signature with arbitrary public key. Current implementation supported
only fixed public key. ACVP tests to be submitted separately.
Added two new test commands to support ACVP:
- TEST_POINT - test that given point is on selected curve
- TEST_VERIFY_ANY - same as TEST_VERIFY, but use provided Q
- TEST_SIGN_ANY - same as TEST_SIGN, but use provided d (private key)
BUG=b:138578319
TEST=make CRYPTO_TEST=1 BOARD=cr50 -j && test/tpm_test/tpmtest.py
Change-Id: Ibeabede935f5bbac918b3043072e05f8a6417aa4
Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2227077
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/ecc_test.py | 188 |
1 files changed, 156 insertions, 32 deletions
diff --git a/test/tpm_test/ecc_test.py b/test/tpm_test/ecc_test.py index 155a497b98..9ec34c2f21 100644 --- a/test/tpm_test/ecc_test.py +++ b/test/tpm_test/ecc_test.py @@ -4,7 +4,7 @@ # found in the LICENSE file. """Module for testing ecc functions using extended commands.""" -import binascii +from binascii import a2b_hex as a2b import hashlib import os import struct @@ -17,6 +17,9 @@ _ECC_OPCODES = { 'VERIFY': 0x01, 'KEYGEN': 0x02, 'KEYDERIVE': 0x03, + 'TEST_POINT': 0x04, + 'VERIFY_ANY': 0x05, + 'SIGN_ANY': 0x06, } _ECC_CURVES = { @@ -42,54 +45,134 @@ _HASH_FUNC = { 'NIST-P256': hashlib.sha256 } -# Command format. +NIST_P256_QX = ('12c3d6a2679ca8ee3c4d927f204ed5bc' + 'b4577a04b0ac02b2a36ab3e9e10781de') +NIST_P256_QY = ('5c85ad7413971172fca5738fee9d0e7b' + 'c59ffd8a626d689bc6cca4b58665521d') + +PKEY = ('fc441e07744e48f109b7e66b29482f7b' + '7e3ec91fa27fd4870991b289fea0d20a') + +## +# Field size: +# FIELD LENGTH +# OP 1 +# CURVE_ID 1 +# SIGN_MODE 1 +# HASHING 1 +# MSG_LEN 2 (big endian) +# MSG MSG_LEN +# R_LEN 2 (big endian) +# R R_LEN +# S_LEN 2 (big endian) +# S S_LEN +# DIGEST_LEN 2 (big endian) +# DIGEST DIGEST_LEN +# D_LEN 2 (big endian) +# D D_LEN +# QX_LEN 2 (big endian) +# QX QX_LEN +# QY_LEN 2 (big endian) +# QY QX_LEN # -# 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 +# Command formats: # -_ECC_CMD_FORMAT = '{o:c}{c:c}{s:c}{h:c}{ml:s}{msg}{dl:s}{dig}' +# TEST_SIGN: +# OP | CURVE_ID | SIGN_MODE | HASHING | DIGEST_LEN | DIGEST +# @returns 0/1 | R_LEN | R | S_LEN | S +_TEST_SIGN = '{o:c}{c:c}{s:c}{h:c}{dl:s}{dig}' +# TEST_SIGN_ANY: +# OP | CURVE_ID | SIGN_MODE | HASHING | DIGEST_LEN | DIGEST | D_LEN | D +# @returns 0/1 | R_LEN | R | S_LEN | S +_TEST_SIGN_ANY = '{o:c}{c:c}{s:c}{h:c}{dl:s}{dig}{pl:s}{pk}' + +# +# TEST_VERIFY: +# OP | CURVE_ID | SIGN_MODE | HASHING | R_LEN | R | S_LEN | S +# DIGEST_LEN | DIGEST +# @returns 1 if successful +_TEST_VERIFY = '{o:c}{c:c}{sm:c}{h:c}{rs}{dl:s}{dig}' + +# TEST_VERIFY_ANY: +# OP | CURVE_ID | SIGN_MODE | HASHING | R_LEN | R | S_LEN | S | +# DIGEST_LEN | DIGEST | QX_LEN | QX | QY_LEN | QY +# @returns 1 if successful +_TEST_VERIFY_ANY = _TEST_VERIFY + '{qxl:s}{qx}{qyl:s}{qy}' + +# TEST_KEYDERIVE: +# OP | CURVE_ID | SEED_LEN | SEED +# @returns 1 if successful +# +_TEST_KEYDERIVE = '{o:c}{c:c}{ml:s}{msg}' + +# TEST_POINT: +# OP | CURVE_ID | QX_LEN | QX | QY_LEN | QY +# @returns 1 if point is on curve + +_TEST_POINT = '{o:c}{c:c}{qxl:s}{qx}{qyl:s}{qy}' + +# +# TEST_KEYGEN: +# OP | CURVE_ID +# @returns 0/1 | D_LEN | D | QX_LEN | QX | QY_LEN | QY +# +_TEST_KEYGEN = '{o:c}{c:c}' def _sign_cmd(curve_id, hash_func, sign_mode, msg): op = _ECC_OPCODES['SIGN'] digest = hash_func(msg).digest() digest_len = len(digest) - return _ECC_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) + return _TEST_SIGN.format(o=op, c=curve_id, s=sign_mode, h=_HASH['SHA256'], + dl=struct.pack('>H', digest_len), dig=digest) + +def _sign_any_cmd(curve_id, hash_func, sign_mode, msg, pkey): + op = _ECC_OPCODES['SIGN_ANY'] + digest = hash_func(msg).digest() + digest_len = len(digest) + return _TEST_SIGN_ANY.format(o=op, c=curve_id, s=sign_mode, + h=_HASH['SHA256'], + dl=struct.pack('>H', digest_len), dig=digest, + pl=struct.pack('>H', len(pkey)), pk=pkey) def _verify_cmd(curve_id, hash_func, sign_mode, msg, sig): op = _ECC_OPCODES['VERIFY'] - sig_len = len(sig) digest = hash_func(msg).digest() digest_len = len(digest) - return _ECC_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) + return _TEST_VERIFY.format(o=op, c=curve_id, sm=sign_mode, h=_HASH['SHA256'], + rs=sig, + dl=struct.pack('>H', digest_len), + dig=digest) + +def _verify_any_cmd(curve_id, hash_func, sign_mode, msg, sig, qx, qy): + op = _ECC_OPCODES['VERIFY_ANY'] + digest = hash_func(msg).digest() + digest_len = len(digest) + return _TEST_VERIFY_ANY.format(o=op, c=curve_id, sm=sign_mode, + h=_HASH['SHA256'], + rs=sig, + dl=struct.pack('>H', digest_len), dig=digest, + qxl=struct.pack('>H', len(qx)), qx=qx, + qyl=struct.pack('>H', len(qy)), qy=qy) + +def _test_point_cmd(curve_id, qx, qy): + op = _ECC_OPCODES['TEST_POINT'] + return _TEST_POINT.format(o=op, c=curve_id, + qxl=struct.pack('>H', len(qx)), qx=qx, + qyl=struct.pack('>H', len(qy)), qy=qy) def _keygen_cmd(curve_id): op = _ECC_OPCODES['KEYGEN'] - return _ECC_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='') + return _TEST_KEYGEN.format(o=op, c=curve_id) def _keyderive_cmd(curve_id, seed): op = _ECC_OPCODES['KEYDERIVE'] seed_len = len(seed) - return _ECC_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='') + return _TEST_KEYDERIVE.format(o=op, c=curve_id, + ml=struct.pack('>H', seed_len), msg=seed) _SIGN_INPUTS = ( @@ -117,18 +200,57 @@ def _sign_test(tpm): cmd = _sign_cmd(_ECC_CURVES[curve_id], _HASH_FUNC[curve_id], _SIGN_MODE[sign_mode], msg) wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) + expected = '\x01' signature = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) - + if signature[:1] != expected: + raise subcmd.TpmTestError('%s error:%s:%s' % ( + test_name, utils.hex_dump(signature[:1]), utils.hex_dump(expected))) cmd = _verify_cmd(_ECC_CURVES[curve_id], _HASH_FUNC[curve_id], - _SIGN_MODE[sign_mode], msg, signature) + _SIGN_MODE[sign_mode], msg, signature[1:]) wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) verified = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) + + if verified[:1] != expected: + raise subcmd.TpmTestError('%s error:%s:%s' % ( + test_name, utils.hex_dump(verified[:1]), utils.hex_dump(expected))) + print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) + +def _sign_test_any(tpm): + msg = 'Hello CR50' + + for data in _SIGN_INPUTS: + curve_id, sign_mode = data + test_name = 'ECC-SIGN, Q:%s:%s' % data + cmd = _sign_any_cmd(_ECC_CURVES[curve_id], _HASH_FUNC[curve_id], + _SIGN_MODE[sign_mode], msg, a2b(PKEY)) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) expected = '\x01' - if verified != expected: + signature = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) + if signature[:1] != expected: + raise subcmd.TpmTestError('%s error:%s:%s' % ( + test_name, utils.hex_dump(signature[:1]), utils.hex_dump(expected))) + # make sure properly supplied Q.x, Q.y works + cmd = _verify_any_cmd(_ECC_CURVES[curve_id], _HASH_FUNC[curve_id], + _SIGN_MODE[sign_mode], msg, signature[1:], + a2b(NIST_P256_QX), a2b(NIST_P256_QY)) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) + verified = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) + if verified[:1] != expected: raise subcmd.TpmTestError('%s error:%s:%s' % ( - test_name, utils.hex_dump(verified), utils.hex_dump(expected))) + test_name, utils.hex_dump(verified[:1]), utils.hex_dump(expected))) print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) +def _point_test(tpm): + test_name = 'POINT-TEST: NIST-P256' + cmd = _test_point_cmd(_ECC_CURVES['NIST-P256'], + a2b(NIST_P256_QX), a2b(NIST_P256_QY)) + wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) + verified = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) + expected = '\x01' + if verified != expected: + raise subcmd.TpmTestError('%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: @@ -138,9 +260,9 @@ def _keygen_test(tpm): wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd)) valid = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response) expected = '\x01' - if valid != expected: + if valid[:1] != expected: raise subcmd.TpmTestError('%s error:%s:%s' % ( - test_name, utils.hex_dump(valid), utils.hex_dump(expected))) + test_name, utils.hex_dump(valid[:1]), utils.hex_dump(expected))) print('%sSUCCESS: %s' % (utils.cursor_back(), test_name)) @@ -161,5 +283,7 @@ def _keyderive_test(tpm): def ecc_test(tpm): _sign_test(tpm) + _sign_test_any(tpm) + _point_test(tpm) _keygen_test(tpm) _keyderive_test(tpm) |