CR50: Add initial elliptic curve crypto implementation.

This change adds support for NIST-P256 curve operations.

BRANCH=none
BUG=chrome-os-partner:43025,chrome-os-partner:47524
TEST=new tests under test/tpm2/ pass.

Change-Id: I03a35ff3ab8af3c52282d882937880bfa2bdcd32
Signed-off-by: nagendra modadugu <ngm@google.com>
Reviewed-on: https://chromium-review.googlesource.com/324540
Commit-Ready: Nagendra Modadugu <ngm@google.com>
Tested-by: Nagendra Modadugu <ngm@google.com>
Reviewed-by: Marius Schilder <mschilder@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
This commit is contained in:
nagendra modadugu
2016-01-22 11:37:48 -08:00
committed by chrome-bot
parent 89424bfbed
commit 7ac69e594b
15 changed files with 2729 additions and 81 deletions

View File

@@ -31,6 +31,7 @@ dirs-y += $(BDIR)/tpm2
board-y = board.o
board-y += tpm2/NVMem.o
board-y += tpm2/aes.o
board-y += tpm2/ecc.o
board-y += tpm2/hash.o
board-y += tpm2/hash_data.o
board-y += tpm2/platform.o

View File

@@ -19,6 +19,6 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(BLOB, blob_task, NULL, TASK_STACK_SIZE) \
TASK_NOTEST(TPM, tpm_task, NULL, 4096) \
TASK_NOTEST(TPM, tpm_task, NULL, 8192) \
TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)

464
board/cr50/tpm2/ecc.c Normal file
View File

@@ -0,0 +1,464 @@
/* Copyright 2015 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.
*/
/*
* TODO(ngm): only the NIST-P256 curve is currently supported.
*/
#include "CryptoEngine.h"
#include "TPMB.h"
#include "trng.h"
#include "dcrypto.h"
TPM2B_BYTE_VALUE(4);
static int check_p256_param(const TPM2B_ECC_PARAMETER *a)
{
return a->b.size == sizeof(p256_int);
}
static int check_p256_point(const TPMS_ECC_POINT *a)
{
return check_p256_param(&a->x) &&
check_p256_param(&a->y);
}
BOOL _cpri__EccIsPointOnCurve(TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q)
{
switch (curve_id) {
case TPM_ECC_NIST_P256:
if (!check_p256_point(q))
return FALSE;
if (DCRYPTO_p256_valid_point((p256_int *) q->x.b.buffer,
(p256_int *) q->y.b.buffer))
return TRUE;
else
return FALSE;
default:
return FALSE;
}
}
/* out = n1*G + n2*in */
CRYPT_RESULT _cpri__EccPointMultiply(
TPMS_ECC_POINT *out, TPM_ECC_CURVE curve_id,
TPM2B_ECC_PARAMETER *n1, TPMS_ECC_POINT *in, TPM2B_ECC_PARAMETER *n2)
{
int result;
switch (curve_id) {
case TPM_ECC_NIST_P256:
if (!check_p256_param(n1))
return CRYPT_PARAMETER;
if (in != NULL && !check_p256_point(in))
return CRYPT_PARAMETER;
if (n2 != NULL && !check_p256_param(n2))
return CRYPT_PARAMETER;
if (in == NULL || n2 == NULL)
result = DCRYPTO_p256_base_point_mul(
(p256_int *) out->x.b.buffer,
(p256_int *) out->y.b.buffer,
(p256_int *) n1->b.buffer);
else
result = DCRYPTO_p256_points_mul(
(p256_int *) out->x.b.buffer,
(p256_int *) out->y.b.buffer,
(p256_int *) n1->b.buffer,
(p256_int *) n2->b.buffer,
(p256_int *) in->x.b.buffer,
(p256_int *) in->y.b.buffer);
if (result) {
out->x.b.size = sizeof(p256_int);
out->y.b.size = sizeof(p256_int);
return CRYPT_SUCCESS;
} else {
return CRYPT_NO_RESULT;
}
default:
return CRYPT_FAIL;
}
}
/* Key generation based on FIPS-186.4 section B.1.2 (Key Generation by
* Testing Candidates) */
CRYPT_RESULT _cpri__GenerateKeyEcc(
TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
TPM_ECC_CURVE curve_id, TPM_ALG_ID hash_alg,
TPM2B *seed, const char *label, TPM2B *extra, UINT32 *counter)
{
TPM2B_4_BYTE_VALUE marshaled_counter = { .t = {4} };
uint32_t count = 0;
uint8_t key_bytes[P256_NBYTES];
if (curve_id != TPM_ECC_NIST_P256)
return CRYPT_PARAMETER;
/* extra may be empty, but seed must be specified. */
if (seed == NULL || seed->size < PRIMARY_SEED_SIZE)
return CRYPT_PARAMETER;
if (counter != NULL)
count = *counter;
if (count == 0)
count++;
for (; count != 0; count++) {
memcpy(marshaled_counter.t.buffer, &count, sizeof(count));
_cpri__KDFa(hash_alg, seed, label, extra, &marshaled_counter.b,
sizeof(key_bytes) * 8, key_bytes, NULL, FALSE);
if (DCRYPTO_p256_key_from_bytes(
(p256_int *) q->x.b.buffer,
(p256_int *) q->y.b.buffer,
(p256_int *) d->b.buffer, key_bytes))
break;
}
if (count == 0)
FAIL(FATAL_ERROR_INTERNAL);
if (counter != NULL)
*counter = count;
return CRYPT_SUCCESS;
}
CRYPT_RESULT _cpri__SignEcc(
TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
TPM_ALG_ID scheme, TPM_ALG_ID hash_alg, TPM_ECC_CURVE curve_id,
TPM2B_ECC_PARAMETER *d, TPM2B *digest, TPM2B_ECC_PARAMETER *k)
{
uint8_t digest_local[sizeof(p256_int)];
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
p256_int p256_digest;
if (curve_id != TPM_ECC_NIST_P256)
return CRYPT_PARAMETER;
switch (scheme) {
case TPM_ALG_ECDSA:
if (!check_p256_param(d))
return CRYPT_PARAMETER;
/* Trucate / 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);
DCRYPTO_p256_ecdsa_sign((p256_int *) d->b.buffer,
&p256_digest,
(p256_int *) r->b.buffer,
(p256_int *) s->b.buffer);
r->b.size = sizeof(p256_int);
s->b.size = sizeof(p256_int);
return CRYPT_SUCCESS;
default:
return CRYPT_PARAMETER;
}
}
CRYPT_RESULT _cpri__ValidateSignatureEcc(
TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
TPM_ALG_ID scheme, TPM_ALG_ID hash_alg,
TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q, TPM2B *digest)
{
uint8_t digest_local[sizeof(p256_int)];
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
p256_int p256_digest;
if (curve_id != TPM_ECC_NIST_P256)
return CRYPT_PARAMETER;
switch (scheme) {
case TPM_ALG_ECDSA:
/* Trucate / 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);
if (DCRYPTO_p256_ecdsa_verify(
(p256_int *) q->x.b.buffer,
(p256_int *) q->y.b.buffer,
&p256_digest,
(p256_int *) r->b.buffer,
(p256_int *) s->b.buffer))
return CRYPT_SUCCESS;
else
return CRYPT_FAIL;
default:
return CRYPT_PARAMETER;
}
}
CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
TPM_ECC_CURVE curve_id)
{
uint8_t key_bytes[P256_NBYTES] __aligned(4);
if (curve_id != TPM_ECC_NIST_P256)
return CRYPT_PARAMETER;
rand_bytes(key_bytes, sizeof(key_bytes));
if (DCRYPTO_p256_key_from_bytes((p256_int *) q->x.b.buffer,
(p256_int *) q->y.b.buffer,
(p256_int *) d->b.buffer,
key_bytes))
return CRYPT_SUCCESS;
else
return CRYPT_FAIL;
}
#ifdef CRYPTO_TEST_SETUP
#include "extension.h"
enum {
TEST_SIGN = 0,
TEST_VERIFY = 1,
TEST_KEYGEN = 2,
TEST_KEYDERIVE = 3
};
struct TPM2B_ECC_PARAMETER_aligned {
uint16_t pad;
TPM2B_ECC_PARAMETER d;
} __packed __aligned(4);
struct TPM2B_MAX_BUFFER_aligned {
uint16_t pad;
TPM2B_MAX_BUFFER d;
} __packed __aligned(4);
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_d = {
.d = {
.t = {32, {
0x0a, 0xd2, 0xa0, 0xfe, 0x89, 0xb2, 0x91, 0x09,
0x87, 0xd4, 0x7f, 0xa2, 0x1f, 0xc9, 0x3e, 0x7e,
0x7b, 0x2f, 0x48, 0x29, 0x6b, 0xe6, 0xb7, 0x09,
0xf1, 0x48, 0x4e, 0x74, 0x07, 0x1e, 0x44, 0xfc
}
}
}
};
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qx = {
.d = {
.t = {32, {
0xde, 0x81, 0x07, 0xe1, 0xe9, 0xb3, 0x6a, 0xa3,
0xb2, 0x02, 0xac, 0xb0, 0x04, 0x7a, 0x57, 0xb4,
0xbc, 0xd5, 0x4e, 0x20, 0x7f, 0x92, 0x4d, 0x3c,
0xee, 0xa8, 0x9c, 0x67, 0xa2, 0xd6, 0xc3, 0x12
}
}
}
};
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qy = {
.d = {
.t = {32, {
0x1d, 0x52, 0x65, 0x86, 0xb5, 0xa4, 0xcc, 0xc6,
0x9b, 0x68, 0x6d, 0x62, 0x8a, 0xfd, 0x9f, 0xc5,
0x7b, 0x0e, 0x9d, 0xee, 0x8f, 0x73, 0xa5, 0xfc,
0x72, 0x11, 0x97, 0x13, 0x74, 0xad, 0x85, 0x5c
}
}
}
};
#define MAX_MSG_BYTES MAX_DIGEST_BUFFER
static int point_equals(const TPMS_ECC_POINT *a, const TPMS_ECC_POINT *b)
{
return a->x.b.size == b->x.b.size &&
a->y.b.size == b->y.b.size &&
memcmp(a->x.b.buffer, b->x.b.buffer, a->x.b.size) == 0 &&
memcmp(a->y.b.buffer, b->y.b.buffer, a->y.b.size) == 0;
}
static void ec_command_handler(void *cmd_body, size_t cmd_size,
size_t *response_size_out)
{
uint8_t *cmd;
uint8_t op;
uint8_t curve_id;
uint8_t sign_mode;
uint8_t hashing;
uint16_t in_len;
uint8_t in[MAX_MSG_BYTES];
uint16_t digest_len;
struct TPM2B_MAX_BUFFER_aligned digest;
uint8_t *out = (uint8_t *) cmd_body;
uint32_t *response_size = (uint32_t *) response_size_out;
TPMS_ECC_POINT q;
TPM2B_ECC_PARAMETER *d;
TPM2B_ECC_PARAMETER *qx;
TPM2B_ECC_PARAMETER *qy;
struct TPM2B_ECC_PARAMETER_aligned r;
struct TPM2B_ECC_PARAMETER_aligned s;
/* Command format.
*
* OFFSET FIELD
* 0 OP
* 1 CURVE_ID
* 2 SIGN_MODE
* 3 HASHING
* 4 MSB IN LEN
* 5 LSB IN LEN
* 6 IN
* 6 + IN_LEN MSB DIGEST LEN
* 7 + IN_LEN LSB DIGEST LEN
* 8 + IN_LEN DIGEST
*/
cmd = (uint8_t *) cmd_body;
op = *cmd++;
curve_id = *cmd++;
sign_mode = *cmd++;
hashing = *cmd++;
in_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
cmd += 2;
if (in_len > sizeof(in)) {
*response_size = 0;
return;
}
memcpy(in, cmd, in_len);
cmd += in_len;
digest_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
cmd += 2;
if (digest_len > sizeof(digest.d.t.buffer)) {
*response_size = 0;
return;
}
digest.d.t.size = digest_len;
memcpy(digest.d.t.buffer, cmd, digest_len);
cmd += digest_len;
switch (curve_id) {
case TPM_ECC_NIST_P256:
d = (TPM2B_ECC_PARAMETER *) &NIST_P256_d.d;
qx = (TPM2B_ECC_PARAMETER *) &NIST_P256_qx.d;
qy = (TPM2B_ECC_PARAMETER *) &NIST_P256_qy.d;
q.x = *qx;
q.y = *qy;
break;
default:
*response_size = 0;
return;
}
switch (op) {
case TEST_SIGN:
if (_cpri__SignEcc(&r.d, &s.d, sign_mode, hashing,
curve_id, d, &digest.d.b, NULL)
!= CRYPT_SUCCESS) {
*response_size = 0;
return;
}
memcpy(out, r.d.b.buffer, r.d.b.size);
out += r.d.b.size;
memcpy(out, s.d.b.buffer, s.d.b.size);
*response_size = r.d.b.size + s.d.b.size;
break;
case TEST_VERIFY:
r.d.b.size = in_len / 2;
memcpy(r.d.b.buffer, in, r.d.b.size);
s.d.b.size = in_len / 2;
memcpy(s.d.b.buffer, in + r.d.b.size, s.d.b.size);
if (_cpri__ValidateSignatureEcc(
&r.d, &s.d, sign_mode, hashing, curve_id,
&q, &digest.d.b) != CRYPT_SUCCESS) {
*response_size = 0;
} else {
*out = 1;
*response_size = 1;
}
return;
case TEST_KEYGEN:
{
struct TPM2B_ECC_PARAMETER_aligned d_local;
TPMS_ECC_POINT q_local;
if (_cpri__GetEphemeralEcc(&q, &d_local.d, curve_id)
!= CRYPT_SUCCESS) {
*response_size = 0;
return;
}
if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
*response_size = 0;
return;
}
/* Verify correspondence of secret with the public point. */
if (_cpri__EccPointMultiply(
&q_local, curve_id, &d_local.d,
NULL, NULL) != CRYPT_SUCCESS) {
*response_size = 0;
return;
}
if (!point_equals(&q, &q_local)) {
*response_size = 0;
return;
}
*out = 1;
*response_size = 1;
return;
}
case TEST_KEYDERIVE:
{
/* Random seed. */
TPM2B_SEED seed;
struct TPM2B_ECC_PARAMETER_aligned d_local;
TPMS_ECC_POINT q_local;
const char *label = "ec_test";
if (in_len > PRIMARY_SEED_SIZE) {
*response_size = 0;
return;
}
seed.t.size = in_len;
memcpy(seed.t.buffer, in, in_len);
if (_cpri__GenerateKeyEcc(
&q, &d_local.d, curve_id, hashing,
&seed.b, label, NULL, NULL) != CRYPT_SUCCESS) {
*response_size = 0;
return;
}
if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
*response_size = 0;
return;
}
/* Verify correspondence of secret with the public point. */
if (_cpri__EccPointMultiply(
&q_local, curve_id, &d_local.d,
NULL, NULL) != CRYPT_SUCCESS) {
*response_size = 0;
return;
}
if (!point_equals(&q, &q_local)) {
*response_size = 0;
return;
}
*out = 1;
*response_size = 1;
return;
}
default:
*response_size = 0;
return;
}
}
DECLARE_EXTENSION_COMMAND(EXTENSION_EC, ec_command_handler);
#endif /* CRYPTO_TEST_SETUP */

View File

@@ -46,45 +46,6 @@ CRYPT_RESULT _cpri__EccCommitCompute(
return CRYPT_FAIL;
}
BOOL _cpri__EccIsPointOnCurve(
TPM_ECC_CURVE curveId, // IN: the curve selector
TPMS_ECC_POINT * Q // IN: the point.
)
{
ecprintf("%s called\n", __func__);
return 0;
}
CRYPT_RESULT _cpri__EccPointMultiply(
TPMS_ECC_POINT * Rout, // OUT: the product point R
TPM_ECC_CURVE curveId, // IN: the curve to use
TPM2B_ECC_PARAMETER * dIn, // IN: value to multiply against the
// curve generator
TPMS_ECC_POINT * Qin, // IN: point Q
TPM2B_ECC_PARAMETER * uIn // IN: scalar value for the multiplier of Q
)
{
ecprintf("%s called\n", __func__);
return CRYPT_FAIL;
}
CRYPT_RESULT _cpri__GenerateKeyEcc(
TPMS_ECC_POINT * Qout, // OUT: the public point
TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
TPM_ECC_CURVE curveId, // IN: the curve identifier
TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key
// generation process
TPM2B * seed, // IN: the seed to use
const char *label, // IN: A label for the generation process.
TPM2B * extra, // IN: Party 1 data for the KDF
UINT32 * counter // IN/OUT: Counter value to allow KDF
// iteration to be propagated across multiple functions
)
{
ecprintf("%s called\n", __func__);
return CRYPT_FAIL;
}
CRYPT_RESULT _cpri__GenerateKeyRSA(
TPM2B * n, // OUT: The public modulu
TPM2B * p, // OUT: One of the prime factors of n
@@ -102,31 +63,6 @@ CRYPT_RESULT _cpri__GenerateKeyRSA(
return CRYPT_FAIL;
}
CRYPT_RESULT _cpri__GetEphemeralEcc(
TPMS_ECC_POINT * Qout, // OUT: the public point
TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
TPM_ECC_CURVE curveId // IN: the curve for the key
)
{
ecprintf("%s called\n", __func__);
return CRYPT_FAIL;
}
CRYPT_RESULT _cpri__SignEcc(
TPM2B_ECC_PARAMETER * rOut, // OUT: r component of the signature
TPM2B_ECC_PARAMETER * sOut, // OUT: s component of the signature
TPM_ALG_ID scheme, // IN: the scheme selector
TPM_ALG_ID hashAlg, // IN: the hash algorithm if need
TPM_ECC_CURVE curveId, // IN: the curve used in the signature process
TPM2B_ECC_PARAMETER * dIn, // IN: the private key
TPM2B * digest, // IN: the digest to sign
TPM2B_ECC_PARAMETER * kIn // IN: k for input
)
{
ecprintf("%s called\n", __func__);
return CRYPT_FAIL;
}
BOOL _cpri__Startup(
void)
{
@@ -159,22 +95,6 @@ CRYPT_RESULT _cpri__TestKeyRSA(
return CRYPT_FAIL;
}
CRYPT_RESULT _cpri__ValidateSignatureEcc(
TPM2B_ECC_PARAMETER * rIn, // IN: r component of the signature
TPM2B_ECC_PARAMETER * sIn, // IN: s component of the signature
TPM_ALG_ID scheme, // IN: the scheme selector
TPM_ALG_ID hashAlg, // IN: the hash algorithm used (not used
// in all schemes)
TPM_ECC_CURVE curveId, // IN: the curve used in the
// signature process
TPMS_ECC_POINT * Qin, // IN: the public point of the key
TPM2B * digest // IN: the digest that was signed
)
{
ecprintf("%s called\n", __func__);
return CRYPT_FAIL;
}
int _math__Comp(
const UINT32 aSize, // IN: size of a
const BYTE * a, // IN: a buffer

View File

@@ -27,6 +27,10 @@ endif
chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/bn.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/hmac.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ec.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ecdsa.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/rsa.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha1.o
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha256.o

View File

@@ -119,4 +119,22 @@ int DCRYPTO_rsa_verify(struct RSA *rsa, const uint8_t *digest,
const uint32_t sig_len, enum padding_mode padding,
enum hashing_mode hashing);
/*
* EC.
*/
int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y);
int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
const p256_int *n);
int DCRYPTO_p256_points_mul(p256_int *out_x, p256_int *out_y,
const p256_int *n1, const p256_int *n2,
const p256_int *in_x, const p256_int *in_y);
int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
const uint8_t key_bytes[P256_NBYTES]);
void DCRYPTO_p256_ecdsa_sign(const p256_int *d, const p256_int *digest,
p256_int *r, p256_int *s);
int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
const p256_int *digest, const p256_int *r,
const p256_int *s);
#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */

56
chip/g/dcrypto/hmac.c Normal file
View File

@@ -0,0 +1,56 @@
/* Copyright 2015 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.
*/
#include <stdint.h>
#include "internal.h"
#include "dcrypto.h"
static void HMAC_init(struct HMAC_CTX *ctx, const void *key, unsigned int len)
{
unsigned int i;
memset(&ctx->opad[0], 0, sizeof(ctx->opad));
if (len > sizeof(ctx->opad)) {
DCRYPTO_SHA256_init(&ctx->hash, 0);
DCRYPTO_HASH_update(&ctx->hash, key, len);
memcpy(&ctx->opad[0], DCRYPTO_HASH_final(&ctx->hash),
DCRYPTO_HASH_size(&ctx->hash));
} else {
memcpy(&ctx->opad[0], key, len);
}
for (i = 0; i < sizeof(ctx->opad); ++i)
ctx->opad[i] ^= 0x36;
DCRYPTO_SHA256_init(&ctx->hash, 0);
/* hash ipad */
DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
for (i = 0; i < sizeof(ctx->opad); ++i)
ctx->opad[i] ^= (0x36 ^ 0x5c);
}
void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
unsigned int len)
{
DCRYPTO_SHA256_init(&ctx->hash, 0);
HMAC_init(ctx, key, len);
}
const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx)
{
uint8_t digest[SHA_DIGEST_MAX_BYTES]; /* upto SHA2 */
memcpy(digest, DCRYPTO_HASH_final(&ctx->hash),
(DCRYPTO_HASH_size(&ctx->hash) <= sizeof(digest) ?
DCRYPTO_HASH_size(&ctx->hash) : sizeof(digest)));
DCRYPTO_SHA256_init(&ctx->hash, 0);
DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
DCRYPTO_HASH_update(&ctx->hash, digest, DCRYPTO_HASH_size(&ctx->hash));
memset(&ctx->opad[0], 0, sizeof(ctx->opad)); /* wipe key */
return DCRYPTO_HASH_final(&ctx->hash);
}

View File

@@ -82,6 +82,21 @@ void dcrypto_sha_update(struct HASH_CTX *unused,
const uint8_t *data, uint32_t n);
void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest);
/*
* HMAC.
*/
struct HMAC_CTX {
struct HASH_CTX hash;
uint8_t opad[64];
};
#define HASH_update(ctx, data, len) \
((ctx)->vtab->update((ctx), (data), (len)))
void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
unsigned int len);
#define dcrypto_HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len)
const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx);
/*
* BIGNUM.
*/
@@ -101,6 +116,53 @@ int bn_check_topbit(const struct BIGNUM *N);
void bn_mont_modexp(struct BIGNUM *output, const struct BIGNUM *input,
const struct BIGNUM *exp, const struct BIGNUM *N);
/*
* EC.
*/
#define P256_BITSPERDIGIT 32
#define P256_NDIGITS 8
#define P256_NBYTES 32
typedef uint32_t p256_digit;
typedef int32_t p256_sdigit;
typedef uint64_t p256_ddigit;
typedef int64_t p256_sddigit;
/* Define p256_int as a struct to leverage struct assignment. */
typedef struct {
p256_digit a[P256_NDIGITS] __packed;
} p256_int;
#define P256_DIGITS(x) ((x)->a)
#define P256_DIGIT(x, y) ((x)->a[y])
#define P256_ZERO { {0} }
#define P256_ONE { {1} }
/* Curve constants. */
extern const p256_int SECP256r1_n;
extern const p256_int SECP256r1_p;
extern const p256_int SECP256r1_b;
void p256_init(p256_int *a);
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst);
#define p256_clear(a) p256_init((a))
int p256_is_zero(const p256_int *a);
int p256_cmp(const p256_int *a, const p256_int *b);
int p256_get_bit(const p256_int *scalar, int bit);
p256_digit p256_shl(const p256_int *a, int n, p256_int *b);
void p256_shr(const p256_int *a, int n, p256_int *b);
int p256_add(const p256_int *a, const p256_int *b, p256_int *c);
int p256_add_d(const p256_int *a, p256_digit d, p256_int *b);
void p256_points_mul_vartime(
const p256_int *n1, const p256_int *n2, const p256_int *in_x,
const p256_int *in_y, p256_int *out_x, p256_int *out_y);
void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out);
void p256_modmul(const p256_int *MOD, const p256_int *a,
const p256_digit top_b, const p256_int *b, p256_int *c);
void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b);
void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b);
/*
* Utility functions.
*/

444
chip/g/dcrypto/p256.c Normal file
View File

@@ -0,0 +1,444 @@
/* Copyright 2015 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.
*/
#include "dcrypto.h"
#include "internal.h"
#include <assert.h>
const p256_int SECP256r1_n = /* curve order */
{ {0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
static const p256_int SECP256r1_nMin2 = /* curve order - 2 */
{ {0xfc632551 - 2, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
const p256_int SECP256r1_p = /* curve field size */
{ {-1, -1, -1, 0, 0, 0, 1, -1 } };
const p256_int SECP256r1_b = /* curve b */
{ {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8} };
static const p256_int p256_one = P256_ONE;
void p256_init(p256_int *a)
{
memset(a, 0, sizeof(*a));
}
int p256_get_bit(const p256_int *scalar, int bit)
{
return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
>> (bit & (P256_BITSPERDIGIT - 1))) & 1;
}
p256_digit p256_shl(const p256_int *a, int n, p256_int *b)
{
int i;
p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
n %= P256_BITSPERDIGIT;
for (i = P256_NDIGITS - 1; i > 0; --i) {
p256_digit accu = (P256_DIGIT(a, i) << n);
accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
top >>= (P256_BITSPERDIGIT - n);
return top;
}
void p256_shr(const p256_int *a, int n, p256_int *b)
{
int i;
n %= P256_BITSPERDIGIT;
for (i = 0; i < P256_NDIGITS - 1; ++i) {
p256_digit accu = (P256_DIGIT(a, i) >> n);
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
}
int p256_is_zero(const p256_int *a)
{
int i, result = 0;
for (i = 0; i < P256_NDIGITS; ++i)
result |= P256_DIGIT(a, i);
return !result;
}
int p256_cmp(const p256_int *a, const p256_int *b)
{
int i;
p256_sddigit borrow = 0;
p256_digit notzero = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
/* Track whether any result digit is ever not zero.
* Relies on !!(non-zero) evaluating to 1, e.g., !!(-1)
* evaluating to 1. */
notzero |= !!((p256_digit) borrow);
borrow >>= P256_BITSPERDIGIT;
}
return (int) borrow | notzero;
}
/* c = a - b. Returns borrow: 0 or -1. */
int p256_sub(const p256_int *a, const p256_int *b, p256_int *c)
{
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
if (c)
P256_DIGIT(c, i) = (p256_digit) borrow;
borrow >>= P256_BITSPERDIGIT;
}
return (int) borrow;
}
/* c = a + b. Returns carry: 0 or 1. */
int p256_add(const p256_int *a, const p256_int *b, p256_int *c)
{
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += (p256_ddigit) P256_DIGIT(a, i) + P256_DIGIT(b, i);
if (c)
P256_DIGIT(c, i) = (p256_digit) carry;
carry >>= P256_BITSPERDIGIT;
}
return (int) carry;
}
/* b = a + d. Returns carry, 0 or 1. */
int p256_add_d(const p256_int *a, p256_digit d, p256_int *b)
{
int i;
p256_ddigit carry = d;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += (p256_ddigit) P256_DIGIT(a, i);
if (b)
P256_DIGIT(b, i) = (p256_digit) carry;
carry >>= P256_BITSPERDIGIT;
}
return (int) carry;
}
/* top, c[] += a[] * b */
/* Returns new top. */
static p256_digit p256_muladd(const p256_int *a, p256_digit b,
p256_digit top, p256_digit *c)
{
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += *c;
carry += (p256_ddigit) P256_DIGIT(a, i) * b;
*c++ = (p256_digit) carry;
carry >>= P256_BITSPERDIGIT;
}
return top + (p256_digit) carry;
}
/* top, c[] -= top_a, a[] */
static p256_digit p256_subtop(p256_digit top_a, const p256_digit *a,
p256_digit top_c, p256_digit *c)
{
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += *c;
borrow -= *a++;
*c++ = (p256_digit) borrow;
borrow >>= P256_BITSPERDIGIT;
}
borrow += top_c;
borrow -= top_a;
top_c = (p256_digit) borrow;
assert((borrow >> P256_BITSPERDIGIT) == 0);
return top_c;
}
/* top, c[] += MOD[] & mask (0 or -1) */
/* returns new top. */
static p256_digit p256_addM(const p256_int *MOD, p256_digit top,
p256_digit *c, p256_digit mask)
{
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += *c;
carry += P256_DIGIT(MOD, i) & mask;
*c++ = (p256_digit) carry;
carry >>= P256_BITSPERDIGIT;
}
return top + (p256_digit) carry;
}
/* top, c[] -= MOD[] & mask (0 or -1) */
/* returns new top. */
static p256_digit p256_subM(const p256_int *MOD, p256_digit top,
p256_digit *c, p256_digit mask)
{
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += *c;
borrow -= P256_DIGIT(MOD, i) & mask;
*c++ = (p256_digit) borrow;
borrow >>= P256_BITSPERDIGIT;
}
return top + (p256_digit) borrow;
}
/* Convert in. */
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst)
{
int i;
const uint8_t *p = &src[0];
for (i = P256_NDIGITS - 1; i >= 0; --i) {
P256_DIGIT(dst, i) =
(p[0] << 24) |
(p[1] << 16) |
(p[2] << 8) |
p[3];
p += 4;
}
}
void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out)
{
if (out != in)
*out = *in;
p256_addM(MOD, 0, P256_DIGITS(out),
p256_subM(MOD, 0, P256_DIGITS(out), -1));
}
void p256_modmul(const p256_int *MOD, const p256_int *a,
const p256_digit top_b, const p256_int *b, p256_int *c)
{
p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
p256_digit top = 0;
int i;
/* Multiply/add into tmp. */
for (i = 0; i < P256_NDIGITS; ++i) {
if (i)
tmp[i + P256_NDIGITS - 1] = top;
top = p256_muladd(a, P256_DIGIT(b, i), 0, tmp + i);
}
/* Multiply/add top digit. */
tmp[i + P256_NDIGITS - 1] = top;
top = p256_muladd(a, top_b, 0, tmp + i);
/* Reduce tmp, digit by digit. */
for (; i >= 0; --i) {
p256_digit reducer[P256_NDIGITS] = { 0 };
p256_digit top_reducer;
/* top can be any value at this point.
* Guestimate reducer as top * MOD, since msw of MOD is -1. */
top_reducer = p256_muladd(MOD, top, 0, reducer);
/* Subtract reducer from top | tmp. */
top = p256_subtop(top_reducer, reducer, top, tmp + i);
/* top is now either 0 or 1. Make it 0, fixed-timing. */
assert(top <= 1);
top = p256_subM(MOD, top, tmp + i, ~(top - 1));
assert(top == 0);
/* We have now reduced the top digit off tmp. Fetch
* new top digit. */
top = tmp[i + P256_NDIGITS - 1];
}
/* tmp might still be larger than MOD, yet same bit length.
* Make sure it is less, fixed-timing. */
p256_addM(MOD, 0, tmp, p256_subM(MOD, 0, tmp, -1));
memcpy(c, tmp, P256_NBYTES);
}
/* if (mask) dst = src, fixed-timing style. */
static void conditional_copy(const p256_int *src, p256_int *dst, int mask)
{
int i;
for (i = 0; i < P256_NDIGITS; ++i) {
p256_digit b = P256_DIGIT(src, i) & mask; /* 0 or src[i] */
b |= P256_DIGIT(dst, i) & ~mask; /* dst[i] or 0 */
P256_DIGIT(dst, i) = b;
}
}
/* -1 iff (x & 15) == 0, 0 otherwise. */
/* Relies on arithmetic shift right behavior. */
#define ZEROtoONES(x) (((int32_t)(((x) & 15) - 1)) >> 31)
/* tbl[0] = tbl[idx], fixed-timing style. */
static void set0ToIdx(p256_int tbl[16], int idx)
{
int32_t i;
tbl[0] = p256_one;
for (i = 1; i < 16; ++i)
conditional_copy(&tbl[i], &tbl[0], ZEROtoONES(i - idx));
}
/* b = 1/a mod MOD, fixed timing, Fermat's little theorem. */
void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b)
{
int i;
p256_int tbl[16];
/* tbl[i] = a**i, tbl[0] unused. */
tbl[1] = *a;
for (i = 2; i < 16; ++i)
p256_modmul(MOD, &tbl[i-1], 0, a, &tbl[i]);
*b = p256_one;
for (i = 256; i > 0; i -= 4) {
int32_t idx = 0;
p256_modmul(MOD, b, 0, b, b);
p256_modmul(MOD, b, 0, b, b);
p256_modmul(MOD, b, 0, b, b);
p256_modmul(MOD, b, 0, b, b);
idx |= p256_get_bit(&SECP256r1_nMin2, i - 1) << 3;
idx |= p256_get_bit(&SECP256r1_nMin2, i - 2) << 2;
idx |= p256_get_bit(&SECP256r1_nMin2, i - 3) << 1;
idx |= p256_get_bit(&SECP256r1_nMin2, i - 4) << 0;
set0ToIdx(tbl, idx); /* tbl[0] = tbl[idx] */
p256_modmul(MOD, b, 0, &tbl[0], &tbl[0]);
conditional_copy(&tbl[0], b, ~ZEROtoONES(idx));
}
}
static int p256_is_even(const p256_int *a)
{
return !(P256_DIGIT(a, 0) & 1);
}
static void p256_shr1(const p256_int *a, int highbit, p256_int *b)
{
int i;
for (i = 0; i < P256_NDIGITS - 1; ++i) {
p256_digit accu = (P256_DIGIT(a, i) >> 1);
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
(highbit << (P256_BITSPERDIGIT - 1));
}
/* b = 1/a mod MOD, binary euclid. */
void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b)
{
p256_int R = P256_ZERO;
p256_int S = P256_ONE;
p256_int U = *MOD;
p256_int V = *a;
for (;;) {
if (p256_is_even(&U)) {
p256_shr1(&U, 0, &U);
if (p256_is_even(&R)) {
p256_shr1(&R, 0, &R);
} else {
/* R = (R + MOD)/2 */
p256_shr1(&R, p256_add(&R, MOD, &R), &R);
}
} else if (p256_is_even(&V)) {
p256_shr1(&V, 0, &V);
if (p256_is_even(&S)) {
p256_shr1(&S, 0, &S);
} else {
/* S = (S + MOD)/2 */
p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
}
} else { /* U, V both odd. */
if (!p256_sub(&V, &U, NULL)) {
p256_sub(&V, &U, &V);
if (p256_sub(&S, &R, &S))
p256_add(&S, MOD, &S);
if (p256_is_zero(&V))
break; /* done. */
} else {
p256_sub(&U, &V, &U);
if (p256_sub(&R, &S, &R))
p256_add(&R, MOD, &R);
}
}
}
p256_mod(MOD, &R, b);
}
int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y)
{
p256_int y2, x3;
if (p256_cmp(&SECP256r1_p, x) <= 0 || p256_cmp(&SECP256r1_p, y) <= 0 ||
p256_is_zero(x) || p256_is_zero(y))
return 0;
p256_modmul(&SECP256r1_p, y, 0, y, &y2); /* y^2 */
p256_modmul(&SECP256r1_p, x, 0, x, &x3); /* x^2 */
p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); /* x^3 */
if (p256_sub(&x3, x, &x3))
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - x */
if (p256_sub(&x3, x, &x3))
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 2x */
if (p256_sub(&x3, x, &x3))
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 3x */
if (p256_add(&x3, &SECP256r1_b, &x3)) /* x^3 - 3x + b */
p256_sub(&x3, &SECP256r1_p, &x3);
if (p256_sub(&x3, &SECP256r1_p, &x3)) /* make sure 0 <= x3 < p */
p256_add(&x3, &SECP256r1_p, &x3);
return p256_cmp(&y2, &x3) == 0;
}
/*
* Key selection based on FIPS-186-4, section B.4.2 (Key Pair
* Generation by Testing Candidates).
*/
int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
const uint8_t key_bytes[P256_NBYTES])
{
int valid;
p256_int key;
p256_from_bin(key_bytes, &key);
if (p256_cmp(&SECP256r1_nMin2, &key) < 0)
return 0;
p256_add(&key, &p256_one, &key);
valid = DCRYPTO_p256_base_point_mul(x, y, &key);
if (valid)
*d = key;
return valid;
}

1403
chip/g/dcrypto/p256_ec.c Normal file

File diff suppressed because it is too large Load Diff

103
chip/g/dcrypto/p256_ecdsa.c Normal file
View File

@@ -0,0 +1,103 @@
/* Copyright 2015 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.
*/
#include <stdint.h>
#include "dcrypto.h"
/* Compute k based on a given {key, digest} pair, 0 < k < n. */
static void determine_k(const p256_int *key, const p256_int *digest,
char *tweak, p256_int *k)
{
do {
p256_int p1, p2;
struct HMAC_CTX hmac;
/* NOTE: taking the p256_int in-memory representation
* is not endian neutral. Signatures with an
* identical key on identical digests will differ per
* host endianness. This however does not jeopardize
* the key bits. */
dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
dcrypto_HMAC_update(&hmac, tweak, 1);
dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
++(*tweak);
p256_from_bin(dcrypto_HMAC_final(&hmac), &p1);
dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
dcrypto_HMAC_update(&hmac, tweak, 1);
dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
++(*tweak);
p256_from_bin(dcrypto_HMAC_final(&hmac), &p2);
/* Combine p1 and p2 into well distributed k. */
p256_modmul(&SECP256r1_n, &p1, 0, &p2, k);
/* (Attempt to) clear stack state. */
p256_clear(&p1);
p256_clear(&p2);
} while (p256_is_zero(k));
}
void DCRYPTO_p256_ecdsa_sign(const p256_int *key, const p256_int *digest,
p256_int *r, p256_int *s)
{
char tweak = 'A';
p256_digit top;
for (;;) {
p256_int k, kinv;
determine_k(key, digest, &tweak, &k);
DCRYPTO_p256_base_point_mul(r, s, &k);
p256_mod(&SECP256r1_n, r, r);
/* Make sure r != 0. */
if (p256_is_zero(r))
continue;
p256_modmul(&SECP256r1_n, r, 0, key, s);
top = p256_add(s, digest, s);
p256_modinv(&SECP256r1_n, &k, &kinv);
p256_modmul(&SECP256r1_n, &kinv, top, s, s);
/* (Attempt to) clear stack state. */
p256_clear(&k);
p256_clear(&kinv);
/* Make sure s != 0. */
if (p256_is_zero(s))
continue;
break;
}
}
int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
const p256_int *digest,
const p256_int *r, const p256_int *s)
{
p256_int u, v;
/* Check public key. */
if (!DCRYPTO_p256_valid_point(key_x, key_y))
return 0;
/* Check r and s are != 0 % n. */
p256_mod(&SECP256r1_n, r, &u);
p256_mod(&SECP256r1_n, s, &v);
if (p256_is_zero(&u) || p256_is_zero(&v))
return 0;
p256_modinv_vartime(&SECP256r1_n, s, &v);
p256_modmul(&SECP256r1_n, digest, 0, &v, &u); /* digest / s % n */
p256_modmul(&SECP256r1_n, r, 0, &v, &v); /* r / s % n */
p256_points_mul_vartime(&u, &v, key_x, key_y, &u, &v);
p256_mod(&SECP256r1_n, &u, &u); /* (x coord % p) % n */
return p256_cmp(r, &u) == 0;
}

View File

@@ -49,6 +49,7 @@ enum {
EXTENSION_AES = 0,
EXTENSION_HASH = 1,
EXTENSION_RSA = 2,
EXTENSION_EC = 3,
};

169
test/tpm_test/ecc_test.py Normal file
View File

@@ -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)

View File

@@ -9,3 +9,4 @@
AES = 0
HASH = 1
RSA = 2
EC = 3

View File

@@ -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,