summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2019-11-11 16:39:14 -0800
committerCommit Bot <commit-bot@chromium.org>2020-06-05 07:25:19 +0000
commit65e147217ad968743b5f6e3d94db6b5dcefb11ad (patch)
treee52229ecfe021c36fa4f4cc52fbb52643084673c /test
parentf9cca4269a124019f56980471d152b68177837f0 (diff)
downloadchrome-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.py188
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)