619 lines
14 KiB
C
619 lines
14 KiB
C
|
/* 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 "util.h"
|
||
|
#include "dcrypto.h"
|
||
|
|
||
|
#include "cryptoc/p256.h"
|
||
|
#include "cryptoc/p256_ecdsa.h"
|
||
|
#include "cryptoc/util.h"
|
||
|
|
||
|
static void reverse_tpm2b(TPM2B *b)
|
||
|
{
|
||
|
reverse(b->buffer, b->size);
|
||
|
}
|
||
|
|
||
|
TPM2B_BYTE_VALUE(4);
|
||
|
TPM2B_BYTE_VALUE(32);
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
switch (curve_id) {
|
||
|
case TPM_ECC_NIST_P256:
|
||
|
if (!check_p256_point(q))
|
||
|
return FALSE;
|
||
|
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
result = dcrypto_p256_is_valid_point((p256_int *) q->x.b.buffer,
|
||
|
(p256_int *) q->y.b.buffer);
|
||
|
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
if (result)
|
||
|
return TRUE;
|
||
|
else
|
||
|
return FALSE;
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* out = n1*G, or out = 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 ((n1 != NULL && n2 != NULL) ||
|
||
|
(n1 == NULL && n2 == NULL))
|
||
|
/* Only one of n1 or n2 must be specified. */
|
||
|
return CRYPT_PARAMETER;
|
||
|
if ((n2 != NULL && in == NULL) ||
|
||
|
(n2 == NULL && in != NULL))
|
||
|
return CRYPT_PARAMETER;
|
||
|
if (n1 != NULL && !check_p256_param(n1))
|
||
|
return CRYPT_PARAMETER;
|
||
|
if (in != NULL &&
|
||
|
(!check_p256_point(in) ||
|
||
|
!_cpri__EccIsPointOnCurve(curve_id, in)))
|
||
|
return CRYPT_POINT;
|
||
|
if (n2 != NULL && !check_p256_param(n2))
|
||
|
return CRYPT_PARAMETER;
|
||
|
|
||
|
if (n1 != NULL) {
|
||
|
reverse_tpm2b(&n1->b);
|
||
|
|
||
|
result = DCRYPTO_p256_base_point_mul(
|
||
|
(p256_int *) out->x.b.buffer,
|
||
|
(p256_int *) out->y.b.buffer,
|
||
|
(p256_int *) n1->b.buffer);
|
||
|
|
||
|
reverse_tpm2b(&n1->b);
|
||
|
} else {
|
||
|
reverse_tpm2b(&n2->b);
|
||
|
reverse_tpm2b(&in->x.b);
|
||
|
reverse_tpm2b(&in->y.b);
|
||
|
|
||
|
result = DCRYPTO_p256_point_mul(
|
||
|
(p256_int *) out->x.b.buffer,
|
||
|
(p256_int *) out->y.b.buffer,
|
||
|
(p256_int *) n2->b.buffer,
|
||
|
(p256_int *) in->x.b.buffer,
|
||
|
(p256_int *) in->y.b.buffer);
|
||
|
|
||
|
reverse_tpm2b(&n2->b);
|
||
|
reverse_tpm2b(&in->x.b);
|
||
|
reverse_tpm2b(&in->y.b);
|
||
|
}
|
||
|
|
||
|
if (result) {
|
||
|
out->x.b.size = sizeof(p256_int);
|
||
|
out->y.b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&out->x.b);
|
||
|
reverse_tpm2b(&out->y.b);
|
||
|
|
||
|
return CRYPT_SUCCESS;
|
||
|
} else {
|
||
|
return CRYPT_NO_RESULT;
|
||
|
}
|
||
|
default:
|
||
|
return CRYPT_PARAMETER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* The name field of TPM2B_NAME is a TPMT_HA */
|
||
|
static const uint8_t TPM2_ECC_EK_NAME_TEMPLATE[] = {
|
||
|
/* TPM_ALG_SHA256 in big endian. */
|
||
|
0x00, 0x0b,
|
||
|
/* SHA256 digest of the default template TPMT_PUBLIC. */
|
||
|
0x0f, 0x12, 0x77, 0xa2, 0xf3, 0xf3, 0x82, 0xe7,
|
||
|
0xf7, 0x5d, 0xb4, 0x66, 0xfa, 0xc2, 0x34, 0x18,
|
||
|
0x2a, 0x8d, 0x62, 0xf9, 0x7d, 0xfb, 0xaa, 0xe7,
|
||
|
0xb0, 0x6f, 0xdf, 0x52, 0xbd, 0xa5, 0x14, 0x67
|
||
|
};
|
||
|
BUILD_ASSERT(sizeof(TPM2_ECC_EK_NAME_TEMPLATE) == 2 + SHA256_DIGEST_SIZE);
|
||
|
|
||
|
/* The first 4 bytes of the wrong template used in factory
|
||
|
* c2e0319340fb48f102539ea98363f81e2d306e918dd778abf05473a2a60dae09
|
||
|
*/
|
||
|
static const TPM2B_4_BYTE_VALUE TPM2_ECC_EK_NAME_CR50 = {
|
||
|
.t = {
|
||
|
.size = 4,
|
||
|
.buffer = {
|
||
|
0xc2, 0xe0, 0x31, 0x93
|
||
|
},
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* 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} };
|
||
|
TPM2B_32_BYTE_VALUE local_seed = { .t = {32} };
|
||
|
TPM2B *local_extra;
|
||
|
uint32_t count = 0;
|
||
|
uint8_t key_bytes[P256_NBYTES];
|
||
|
LITE_HMAC_CTX hmac;
|
||
|
|
||
|
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++;
|
||
|
|
||
|
/* Hash down the primary seed for ECC key generation, so that
|
||
|
* the derivation tree is distinct from RSA key derivation. */
|
||
|
DCRYPTO_HMAC_SHA256_init(&hmac, seed->buffer, seed->size);
|
||
|
HASH_update(&hmac.hash, "ECC", 4);
|
||
|
memcpy(local_seed.t.buffer, DCRYPTO_HMAC_final(&hmac),
|
||
|
local_seed.t.size);
|
||
|
always_memset(&hmac, 0, sizeof(hmac));
|
||
|
/* b/35576109: the personalize code uses only the first 4 bytes
|
||
|
* of extra.
|
||
|
*/
|
||
|
if (extra && extra->size == sizeof(TPM2_ECC_EK_NAME_TEMPLATE) &&
|
||
|
memcmp(extra->buffer,
|
||
|
TPM2_ECC_EK_NAME_TEMPLATE,
|
||
|
sizeof(TPM2_ECC_EK_NAME_TEMPLATE)) == 0) {
|
||
|
local_extra = (TPM2B *) &TPM2_ECC_EK_NAME_CR50.b;
|
||
|
} else {
|
||
|
local_extra = extra;
|
||
|
}
|
||
|
|
||
|
for (; count != 0; count++) {
|
||
|
memcpy(marshaled_counter.t.buffer, &count, sizeof(count));
|
||
|
_cpri__KDFa(hash_alg, &local_seed.b, label, local_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)) {
|
||
|
q->x.b.size = sizeof(p256_int);
|
||
|
q->y.b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
d->b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&d->b);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
always_memset(local_seed.t.buffer, 0, local_seed.t.size);
|
||
|
always_memset(key_bytes, 0, sizeof(key_bytes));
|
||
|
|
||
|
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;
|
||
|
int result;
|
||
|
struct drbg_ctx drbg;
|
||
|
|
||
|
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);
|
||
|
|
||
|
reverse_tpm2b(&d->b);
|
||
|
|
||
|
hmac_drbg_init_rand(&drbg, 512);
|
||
|
result = dcrypto_p256_ecdsa_sign(&drbg,
|
||
|
(p256_int *) d->b.buffer,
|
||
|
&p256_digest,
|
||
|
(p256_int *) r->b.buffer,
|
||
|
(p256_int *) s->b.buffer);
|
||
|
reverse_tpm2b(&d->b);
|
||
|
|
||
|
r->b.size = sizeof(p256_int);
|
||
|
s->b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&r->b);
|
||
|
reverse_tpm2b(&s->b);
|
||
|
|
||
|
if (result)
|
||
|
return CRYPT_SUCCESS;
|
||
|
else
|
||
|
return CRYPT_FAIL;
|
||
|
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;
|
||
|
int result;
|
||
|
|
||
|
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);
|
||
|
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
reverse_tpm2b(&r->b);
|
||
|
reverse_tpm2b(&s->b);
|
||
|
|
||
|
result = 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);
|
||
|
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
reverse_tpm2b(&r->b);
|
||
|
reverse_tpm2b(&s->b);
|
||
|
|
||
|
if (result)
|
||
|
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)
|
||
|
{
|
||
|
int result;
|
||
|
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));
|
||
|
|
||
|
result = DCRYPTO_p256_key_from_bytes((p256_int *) q->x.b.buffer,
|
||
|
(p256_int *) q->y.b.buffer,
|
||
|
(p256_int *) d->b.buffer,
|
||
|
key_bytes);
|
||
|
always_memset(key_bytes, 0, sizeof(key_bytes));
|
||
|
|
||
|
if (result) {
|
||
|
q->x.b.size = sizeof(p256_int);
|
||
|
q->y.b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&q->x.b);
|
||
|
reverse_tpm2b(&q->y.b);
|
||
|
|
||
|
d->b.size = sizeof(p256_int);
|
||
|
reverse_tpm2b(&d->b);
|
||
|
|
||
|
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, {
|
||
|
0xfc, 0x44, 0x1e, 0x07, 0x74, 0x4e, 0x48, 0xf1,
|
||
|
0x09, 0xb7, 0xe6, 0x6b, 0x29, 0x48, 0x2f, 0x7b,
|
||
|
0x7e, 0x3e, 0xc9, 0x1f, 0xa2, 0x7f, 0xd4, 0x87,
|
||
|
0x09, 0x91, 0xb2, 0x89, 0xfe, 0xa0, 0xd2, 0x0a
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qx = {
|
||
|
.d = {
|
||
|
.t = {32, {
|
||
|
0x12, 0xc3, 0xd6, 0xa2, 0x67, 0x9c, 0xa8, 0xee,
|
||
|
0x3c, 0x4d, 0x92, 0x7f, 0x20, 0x4e, 0xd5, 0xbc,
|
||
|
0xb4, 0x57, 0x7a, 0x04, 0xb0, 0xac, 0x02, 0xb2,
|
||
|
0xa3, 0x6a, 0xb3, 0xe9, 0xe1, 0x07, 0x81, 0xde
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qy = {
|
||
|
.d = {
|
||
|
.t = {32, {
|
||
|
0x5c, 0x85, 0xad, 0x74, 0x13, 0x97, 0x11, 0x72,
|
||
|
0xfc, 0xa5, 0x73, 0x8f, 0xee, 0x9d, 0x0e, 0x7b,
|
||
|
0xc5, 0x9f, 0xfd, 0x8a, 0x62, 0x6d, 0x68, 0x9b,
|
||
|
0xc6, 0xcc, 0xa4, 0xb5, 0x86, 0x65, 0x52, 0x1d
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#define MAX_MSG_BYTES MAX_DIGEST_BUFFER
|
||
|
|
||
|
static int point_equals(const TPMS_ECC_POINT *a, const TPMS_ECC_POINT *b)
|
||
|
{
|
||
|
int diff = 0;
|
||
|
|
||
|
diff = a->x.b.size != b->x.b.size;
|
||
|
diff |= a->y.b.size != b->y.b.size;
|
||
|
if (!diff) {
|
||
|
diff |= !DCRYPTO_equals(
|
||
|
a->x.b.buffer, b->x.b.buffer, a->x.b.size);
|
||
|
diff |= !DCRYPTO_equals(
|
||
|
a->y.b.buffer, b->y.b.buffer, a->y.b.size);
|
||
|
}
|
||
|
|
||
|
return !diff;
|
||
|
}
|
||
|
|
||
|
static void ecc_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;
|
||
|
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;
|
||
|
|
||
|
/* Make copies of d, and q, as const data is immutable. */
|
||
|
switch (curve_id) {
|
||
|
case TPM_ECC_NIST_P256:
|
||
|
d = NIST_P256_d.d;
|
||
|
q.x = NIST_P256_qx.d;
|
||
|
q.y = NIST_P256_qy.d;
|
||
|
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 = "ecc_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_ECC, ecc_command_handler);
|
||
|
|
||
|
#endif /* CRYPTO_TEST_SETUP */
|