summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2020-06-24 18:47:02 -0700
committerCommit Bot <commit-bot@chromium.org>2020-06-25 23:22:15 +0000
commitc8e570f49157412f058bd272c0e3cdf5324a634d (patch)
tree7b1d16dd3989c9b25fd7fb4793d47ebab837d570
parenta33e33844859f5e3b2949cd085fce50acad29f86 (diff)
downloadchrome-ec-c8e570f49157412f058bd272c0e3cdf5324a634d.tar.gz
ecc: fix padding for ECDSA sign and verify, add more test vectors
https://crrev.com/c/2222386 added support for short EC keys to some functions. Extending this support to sign and verify. Added test vectors for regression testing in tpmtest.py BUG=b:157528390 TEST=tpmtest.py Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: I3db2c9eee9da995d45d534a2732130948548ead8 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2265605 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org> Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org>
-rw-r--r--board/cr50/tpm2/ecc.c31
-rw-r--r--test/tpm_test/ecc_test.py106
2 files changed, 101 insertions, 36 deletions
diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c
index cdef555fda..4a7cb6b6ff 100644
--- a/board/cr50/tpm2/ecc.c
+++ b/board/cr50/tpm2/ecc.c
@@ -273,16 +273,19 @@ CRYPT_RESULT _cpri__SignEcc(
return CRYPT_PARAMETER;
switch (scheme) {
- case TPM_ALG_ECDSA:
- if (!check_p256_param(d))
+ case TPM_ALG_ECDSA: {
+ const UINT16 d_size = d->b.size;
+
+ if (!check_p256_param_in_range(d))
return CRYPT_PARAMETER;
- /* Trucate / zero-pad the digest as appropriate. */
+ /* Truncate / zero-pad the digest as appropriate. */
memset(digest_local, 0, sizeof(digest_local));
memcpy(digest_local + sizeof(digest_local) - digest_len,
digest->buffer, digest_len);
p256_from_bin(digest_local, &p256_digest);
reverse_tpm2b(&d->b);
+ append_zeros_to_p256_param(d);
hmac_drbg_init_rand(&drbg, 512);
result = dcrypto_p256_ecdsa_sign(&drbg,
@@ -290,6 +293,7 @@ CRYPT_RESULT _cpri__SignEcc(
&p256_digest,
(p256_int *) r->b.buffer,
(p256_int *) s->b.buffer);
+ d->b.size = d_size;
reverse_tpm2b(&d->b);
r->b.size = sizeof(p256_int);
@@ -301,6 +305,7 @@ CRYPT_RESULT _cpri__SignEcc(
return CRYPT_SUCCESS;
else
return CRYPT_FAIL;
+ }
default:
return CRYPT_PARAMETER;
}
@@ -320,8 +325,13 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc(
return CRYPT_PARAMETER;
switch (scheme) {
- case TPM_ALG_ECDSA:
- /* Trucate / zero-pad the digest as appropriate. */
+ case TPM_ALG_ECDSA: {
+ const UINT16 qx_size = q->x.b.size;
+ const UINT16 qy_size = q->y.b.size;
+ const UINT16 r_size = r->b.size;
+ const UINT16 s_size = s->b.size;
+
+ /* Truncate / zero-pad the digest as appropriate. */
memset(digest_local, 0, sizeof(digest_local));
memcpy(digest_local + sizeof(digest_local) - digest_len,
digest->buffer, digest_len);
@@ -329,9 +339,13 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc(
reverse_tpm2b(&q->x.b);
reverse_tpm2b(&q->y.b);
+ append_zeros_to_p256_point(q);
reverse_tpm2b(&r->b);
+ append_zeros_to_p256_param(r);
+
reverse_tpm2b(&s->b);
+ append_zeros_to_p256_param(s);
result = dcrypto_p256_ecdsa_verify(
(p256_int *) q->x.b.buffer,
@@ -340,16 +354,21 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc(
(p256_int *) r->b.buffer,
(p256_int *) s->b.buffer);
+ /* restore original size */
+ q->x.b.size = qx_size;
+ q->y.b.size = qy_size;
reverse_tpm2b(&q->x.b);
reverse_tpm2b(&q->y.b);
-
+ r->b.size = r_size;
reverse_tpm2b(&r->b);
+ s->b.size = s_size;
reverse_tpm2b(&s->b);
if (result)
return CRYPT_SUCCESS;
else
return CRYPT_FAIL;
+ }
default:
return CRYPT_PARAMETER;
}
diff --git a/test/tpm_test/ecc_test.py b/test/tpm_test/ecc_test.py
index e0d5fb361a..ecc68dbdd5 100644
--- a/test/tpm_test/ecc_test.py
+++ b/test/tpm_test/ecc_test.py
@@ -43,14 +43,6 @@ _HASH_FUNC = {
'NIST-P256': hashlib.sha256
}
-NIST_P256_QX = ('12c3d6a2679ca8ee3c4d927f204ed5bc'
- 'b4577a04b0ac02b2a36ab3e9e10781de')
-NIST_P256_QY = ('5c85ad7413971172fca5738fee9d0e7b'
- 'c59ffd8a626d689bc6cca4b58665521d')
-
-PKEY = ('fc441e07744e48f109b7e66b29482f7b'
- '7e3ec91fa27fd4870991b289fea0d20a')
-
#
# Field size:
# FIELD LENGTH
@@ -180,14 +172,52 @@ def _sign_test(tpm):
utils.hex_dump(expected)))
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+
+# tuples of (d = pkey, x, y)
+P256_POINTS = (
+ ('fc441e07744e48f109b7e66b29482f7b7e3ec91fa27fd4870991b289fea0d20a',
+ '12c3d6a2679ca8ee3c4d927f204ed5bcb4577a04b0ac02b2a36ab3e9e10781de',
+ '5c85ad7413971172fca5738fee9d0e7bc59ffd8a626d689bc6cca4b58665521d'),
+ ('0d7841823ef146c3fc533397ce349e7423c9c0fc6d2bd5864cb8c3c4a28387b3',
+ '108072a654ffc96d948e4593d632055cd7dee6a1d9d9377c1a1a642565a51cb0',
+ '0716a5bbc736ffb97ef78d612055bb7187ed90bce82918ea07a4eb7ecd572ea7'),
+ ('00fda48d4e3e1fe4afa320bfed836b4cdccccecf6fdbdb05b986801a5654cc09',
+ '9a38b6ca7263068fe65ce570a6625263179223ab177f502f204c2c7ac4d8586e',
+ 'f1b1a398c21c02c7fe4a8252952005d0a7686ca3cfe05501f9879be160503562'),
+ ('b72d249ee3610c9119dfb4a2d6925172d4b162b70c3c850256e70565df384e2f',
+ '0011bf6d971e1c1f7d87056ca978e02cc860bb0ba05b86039f84d6902d04e66e',
+ '5077a07410161fb449009baf0c010077254543fceb062d02c72349dfebeedd48'),
+ ('b72d249ee3610c9119dfb4a2d6925172d4b162b70c3c850256e70565df384e2f',
+ '0011bf6d971e1c1f7d87056ca978e02cc860bb0ba05b86039f84d6902d04e66e',
+ '5077a07410161fb449009baf0c010077254543fceb062d02c72349dfebeedd48'),
+ ('15fcbfecee4c9f4a769d74226e8ffe86d4deb5e35d704d2bd465c02051c7d3d6',
+ '42b2006a77f9687c0a2ae6ba2ad114b27fb53cfdc1dd49ebcd9e398a3cd6e12b',
+ '0091ee137d5946416f7cab8f825f8537af38a57713f19e3555fd0e9a16935fad'),
+ ('27a1fc7e676ec9a598f75259c5030bcc95ad7bd2a91d4d8cffa5f390f33cef00',
+ 'ab99caa4908e426554e86f71086d14ac99ded8ed23cea72f9bece8062d2d3d8f',
+ 'ee5524ccb2872c58d6d22295efff9d091c5e52866e5c494df1d14509bcab1e00'),
+# points with zero bytes removed:
+ ('fda48d4e3e1fe4afa320bfed836b4cdccccecf6fdbdb05b986801a5654cc09',
+ '9a38b6ca7263068fe65ce570a6625263179223ab177f502f204c2c7ac4d8586e',
+ 'f1b1a398c21c02c7fe4a8252952005d0a7686ca3cfe05501f9879be160503562'),
+ ('b72d249ee3610c9119dfb4a2d6925172d4b162b70c3c850256e70565df384e2f',
+ '11bf6d971e1c1f7d87056ca978e02cc860bb0ba05b86039f84d6902d04e66e',
+ '5077a07410161fb449009baf0c010077254543fceb062d02c72349dfebeedd48'),
+ ('15fcbfecee4c9f4a769d74226e8ffe86d4deb5e35d704d2bd465c02051c7d3d6',
+ '42b2006a77f9687c0a2ae6ba2ad114b27fb53cfdc1dd49ebcd9e398a3cd6e12b',
+ '91ee137d5946416f7cab8f825f8537af38a57713f19e3555fd0e9a16935fad')
+ )
+
def _sign_test_any(tpm):
msg = b'Hello CR50'
-
- for data in _SIGN_INPUTS:
- curve_id, sign_mode = data
- test_name = 'ECC-SIGN, Q:%s:%s' % data
+ curve_id = 'NIST-P256'
+ sign_mode = 'ECDSA'
+ counter = 1
+ for data in P256_POINTS:
+ d, x, y = data
+ test_name = 'ECC-SIGN, Q:%s:%s %d' % (curve_id, sign_mode, counter)
cmd = _sign_any_cmd(_ECC_CURVES[curve_id], _HASH_FUNC[curve_id],
- _SIGN_MODE[sign_mode], msg, a2b(PKEY))
+ _SIGN_MODE[sign_mode], msg, a2b(d))
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd))
expected = b'\x01'
signature = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response)
@@ -198,7 +228,7 @@ def _sign_test_any(tpm):
# 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))
+ a2b(x), a2b(y))
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd))
verified = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response)
if verified[:1] != expected:
@@ -206,30 +236,46 @@ def _sign_test_any(tpm):
test_name, utils.hex_dump(verified[:1]),
utils.hex_dump(expected)))
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
+ counter += 1
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 = b'\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))
+ curve_id = 'NIST-P256'
+ counter = 1
+ for data in P256_POINTS:
+ test_name = 'POINT-TEST, Q:%s: %d' % (curve_id, counter)
+ _, x, y = data
+ cmd = _test_point_cmd(_ECC_CURVES[curve_id], a2b(x), a2b(y))
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd))
+ verified = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response)
+ expected = b'\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))
+ counter += 1
def _keygen_test(tpm):
for data in _KEYGEN_INPUTS:
curve_id, = data
test_name = 'ECC-KEYGEN:%s' % data
cmd = _keygen_cmd(_ECC_CURVES[curve_id])
- wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC, cmd))
- valid = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response)
- expected = b'\x01'
- if valid[:1] != expected:
- raise subcmd.TpmTestError('%s error:%s:%s' % (
- test_name, utils.hex_dump(valid[:1]), utils.hex_dump(expected)))
+ counter = 1
+ while counter < 100:
+ wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.ECC,
+ cmd))
+ valid = tpm.unwrap_ext_response(subcmd.ECC, wrapped_response)
+ expected = b'\x01'
+ if valid[:1] != expected:
+ raise subcmd.TpmTestError('%s error:%s:%s' % (
+ test_name, utils.hex_dump(valid[:1]),
+ utils.hex_dump(expected)))
+ counter += 1
+ # print keys where x or y starts with zero
+ if valid[37:38] == b'\x00' or valid[71:72] == b'\x00':
+ print('d=', valid[3:35].hex())
+ print('x=', valid[37:69].hex())
+ print('y=', valid[71:103].hex())
+
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))