diff options
author | Vadim Sukhomlinov <sukhomlinov@google.com> | 2020-06-24 18:47:02 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-25 23:22:15 +0000 |
commit | c8e570f49157412f058bd272c0e3cdf5324a634d (patch) | |
tree | 7b1d16dd3989c9b25fd7fb4793d47ebab837d570 | |
parent | a33e33844859f5e3b2949cd085fce50acad29f86 (diff) | |
download | chrome-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.c | 31 | ||||
-rw-r--r-- | test/tpm_test/ecc_test.py | 106 |
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)) |