summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/build.mk6
-rw-r--r--board/cr50/dcrypto/internal.h10
-rw-r--r--board/cr50/dcrypto/p256.c95
-rw-r--r--board/cr50/dcrypto/u2f.c7
-rw-r--r--board/cr50/dcrypto/u2f_impl.h2
-rw-r--r--board/cr50/tpm2/ecc.c208
-rw-r--r--common/u2f.c17
7 files changed, 186 insertions, 159 deletions
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index 4576e30c0e..b221c4f050 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -19,7 +19,7 @@ ifeq ($(BOARD_MK_INCLUDED_ONCE),)
# List of variables which can be defined in the environment or set in the make
# command line.
ENV_VARS := CR50_DEV CRYPTO_TEST H1_RED_BOARD U2F_TEST RND_TEST DRBG_TEST\
- ECDSA_TEST DCRYPTO_TEST
+ ECDSA_TEST DCRYPTO_TEST P256_BIN_TEST
ifneq ($(CRYPTO_TEST),)
CPPFLAGS += -DCRYPTO_TEST_SETUP
@@ -44,6 +44,10 @@ ifneq ($(DCRYPTO_TEST),)
CPPFLAGS += -DCRYPTO_TEST_CMD_DCRYPTO_TEST=1
endif
+ifneq ($(P256_BIN_TEST),)
+CPPFLAGS += -DP256_BIN_TEST=1
+endif
+
endif
diff --git a/board/cr50/dcrypto/internal.h b/board/cr50/dcrypto/internal.h
index 6df2df3ef9..b88d0a1d25 100644
--- a/board/cr50/dcrypto/internal.h
+++ b/board/cr50/dcrypto/internal.h
@@ -180,7 +180,7 @@ typedef struct p256_int {
p256_digit a[P256_NDIGITS];
uint8_t b8[P256_NBYTES];
};
-} __packed p256_int;
+} p256_int;
extern const p256_int SECP256r1_nMin2;
@@ -211,6 +211,14 @@ void p256_to_bin(const p256_int *src, uint8_t dst[P256_NBYTES]);
*/
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst);
+/**
+ * Reads from big-endian binary form of given size, add padding with
+ * zeros if short. Check that leading digits beyond P256_NBYTES are zeroes.
+ *
+ * @return true if provided big-endian fits into p256.
+ */
+bool p256_from_be_bin_size(const uint8_t *src, size_t len, p256_int *dst);
+
int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
const p256_int *message, p256_int *r, p256_int *s)
__attribute__((warn_unused_result));
diff --git a/board/cr50/dcrypto/p256.c b/board/cr50/dcrypto/p256.c
index 6c923b4699..49c2fe4b2b 100644
--- a/board/cr50/dcrypto/p256.c
+++ b/board/cr50/dcrypto/p256.c
@@ -4,6 +4,7 @@
*/
#include "dcrypto.h"
+#include "endian.h"
const p256_int SECP256r1_nMin2 = /* P-256 curve order - 2 */
{ .a = { 0xfc632551 - 2, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0,
@@ -135,6 +136,34 @@ void p256_to_bin(const p256_int *src, uint8_t dst[P256_NBYTES])
#endif
}
+bool p256_from_be_bin_size(const uint8_t *src, size_t len, p256_int *dst)
+{
+ size_t i;
+
+ /**
+ * Skip zero padding if input length is larger than P-256 size.
+ * This may happen with TPM2 commands receiving big-endian number
+ * with leading zeroes from external sources.
+ */
+ while (len > P256_NBYTES) {
+ if (*src != 0)
+ return false;
+ len--;
+ src++;
+ }
+
+ i = len;
+ /* Now add zero padding little-endian p256 if length is smaller. */
+ while (i < P256_NBYTES) {
+ dst->b8[i] = 0;
+ i++;
+ }
+ reverse_bytes(dst->b8, src, len);
+
+ /* Note: this code is correct only for little-endian platform. */
+ return true;
+}
+
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst)
{
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
@@ -193,3 +222,69 @@ enum hmac_result p256_hmac_drbg_generate(struct drbg_ctx *ctx, p256_int *rnd)
return result;
}
+
+#ifndef P256_BIN_TEST
+#define P256_BIN_TEST 0
+#endif
+
+#ifdef CRYPTO_TEST_SETUP
+
+#if P256_BIN_TEST
+#include "console.h"
+
+static int cmd_p256_bin_test(int argc, char *argv[])
+{
+ static const uint8_t i1[] = {
+ 0, 0, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22,
+ 0x23, 0x30, 0x31, 0x32, 0x33, 0x40, 0x41, 0x42, 0x43,
+ 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63, 0x70,
+ 0x71, 0x72, 0x73, 0x80, 0x81, 0x82, 0x83, 0x84
+ };
+ p256_int e = { .a = { 0x80818283, 0x70717273, 0x60616263, 0x50515253,
+ 0x40414243, 0x30313233, 0x20212223,
+ 0x10111213 } };
+
+ p256_int r;
+ bool passed = true;
+ bool result;
+
+ /* zero padded */
+ result = p256_from_be_bin_size(i1, 34, &r);
+ passed = result && (p256_cmp(&r, &e) == 0);
+ ccprintf("in=%ph\nout=%ph\n", HEX_BUF(i1, 34), HEX_BUF(&r, sizeof(r)));
+
+ /* right sized. */
+ memset(&r, 0, sizeof(r));
+ result = p256_from_be_bin_size(i1 + 2, 32, &r);
+ passed = passed && (p256_cmp(&r, &e) == 0);
+ ccprintf("in=%ph\nout=%ph\n", HEX_BUF(i1 + 2, 32),
+ HEX_BUF(&r, sizeof(r)));
+
+ /**
+ * Smaller big num, where padding high byte(s) with zeroes is needed.
+ * we do this by loading 31 byte starting 1 byte higher.
+ * This will result in same value as in 'e' except that the
+ * highest byte will be 0 (e.a[7] == 0x00111213).
+ */
+ memset(&r, 0, sizeof(r));
+ result = p256_from_be_bin_size(i1 + 3, 31, &r);
+
+ /* Update expected result by clearing high byte */
+ e.b8[31] = 0x00;
+ passed = passed && (p256_cmp(&r, &e) == 0);
+ ccprintf("in=%ph\nout=%ph\n", HEX_BUF(i1 + 3, 31),
+ HEX_BUF(&r, sizeof(r)));
+
+ /* larger big num. */
+ result = p256_from_be_bin_size(i1 + 2, 33, &r);
+ passed = passed && !result;
+
+ ccprintf("p256_from_be_bin_size() test %s\n",
+ (passed) ? "PASSED" : "NOT PASSED");
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(p256_test, cmd_p256_bin_test, NULL, NULL);
+#endif /* P256_BIN_TEST */
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/board/cr50/dcrypto/u2f.c b/board/cr50/dcrypto/u2f.c
index 9f987fbd64..91c80577b6 100644
--- a/board/cr50/dcrypto/u2f.c
+++ b/board/cr50/dcrypto/u2f.c
@@ -433,7 +433,7 @@ static bool g2f_individual_key_pair(const struct u2f_state *state, p256_int *d,
#define G2F_CERT_NAME "CrO2"
size_t g2f_attestation_cert_serial(const struct u2f_state *state,
- const uint8_t *serial, uint8_t *buf)
+ const p256_int *serial, uint8_t *buf)
{
p256_int d, pk_x, pk_y;
@@ -441,9 +441,8 @@ size_t g2f_attestation_cert_serial(const struct u2f_state *state,
return 0;
/* Note that max length is not currently respected here. */
- return DCRYPTO_x509_gen_u2f_cert_name(&d, &pk_x, &pk_y,
- (p256_int *)serial, G2F_CERT_NAME,
- buf,
+ return DCRYPTO_x509_gen_u2f_cert_name(&d, &pk_x, &pk_y, serial,
+ G2F_CERT_NAME, buf,
G2F_ATTESTATION_CERT_MAX_LEN);
}
diff --git a/board/cr50/dcrypto/u2f_impl.h b/board/cr50/dcrypto/u2f_impl.h
index 7f0f10ef36..be3fbd6b76 100644
--- a/board/cr50/dcrypto/u2f_impl.h
+++ b/board/cr50/dcrypto/u2f_impl.h
@@ -145,7 +145,7 @@ enum ec_error_list u2f_authorize_keyhandle(const struct u2f_state *state,
* @return size of certificate written to buf, 0 on error.
*/
size_t g2f_attestation_cert_serial(const struct u2f_state *state,
- const uint8_t *serial, uint8_t *buf);
+ const p256_int *serial, uint8_t *buf);
/**
* Verify that provided key handle and public key match.
diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c
index 90a6dac08b..8f9392af28 100644
--- a/board/cr50/tpm2/ecc.c
+++ b/board/cr50/tpm2/ecc.c
@@ -14,66 +14,22 @@
#include "util.h"
#include "dcrypto.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_param_in_range(const TPM2B_ECC_PARAMETER *a)
-{
- return a->b.size <= sizeof(p256_int);
-}
-
-static int check_p256_point_in_range(const TPMS_ECC_POINT *a)
-{
- return check_p256_param_in_range(&a->x) &&
- check_p256_param_in_range(&a->y);
-}
-
-static void append_zeros_to_p256_param(TPM2B_ECC_PARAMETER *a)
-{
- while (a->b.size < sizeof(p256_int)) {
- a->b.buffer[a->b.size] = 0;
- a->b.size++;
- }
-}
-
-static void append_zeros_to_p256_point(TPMS_ECC_POINT *a)
-{
- append_zeros_to_p256_param(&a->x);
- append_zeros_to_p256_param(&a->y);
-}
-
BOOL _cpri__EccIsPointOnCurve(TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q)
{
int result;
- int x_size = q->x.b.size;
- int y_size = q->y.b.size;
+ p256_int x, y;
switch (curve_id) {
case TPM_ECC_NIST_P256:
- if (!check_p256_point_in_range(q))
- return FALSE;
-
- reverse_tpm2b(&q->x.b);
- reverse_tpm2b(&q->y.b);
- append_zeros_to_p256_point(q);
- result = dcrypto_p256_is_valid_point((p256_int *) q->x.b.buffer,
- (p256_int *) q->y.b.buffer);
+ if (!p256_from_be_bin_size(q->x.b.buffer, q->x.b.size, &x) ||
+ !p256_from_be_bin_size(q->y.b.buffer, q->y.b.size, &y))
+ return FALSE;
- q->x.b.size = x_size;
- q->y.b.size = y_size;
- reverse_tpm2b(&q->x.b);
- reverse_tpm2b(&q->y.b);
+ result = dcrypto_p256_is_valid_point(&x, &y);
if (result)
return TRUE;
@@ -90,61 +46,44 @@ CRYPT_RESULT _cpri__EccPointMultiply(
TPM2B_ECC_PARAMETER *n1, TPMS_ECC_POINT *in, TPM2B_ECC_PARAMETER *n2)
{
int result;
+ p256_int n, in_x, in_y, out_x, out_y;
switch (curve_id) {
case TPM_ECC_NIST_P256:
- if ((n1 != NULL && n2 != NULL) ||
- (n1 == NULL && n2 == NULL))
+ 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))
+ if ((n2 != NULL && in == NULL) || (n2 == NULL && in != NULL))
return CRYPT_PARAMETER;
- if (n1 != NULL && !check_p256_param(n1))
+ if (n1 != NULL &&
+ !p256_from_be_bin_size(n1->b.buffer, n1->b.size, &n))
return CRYPT_PARAMETER;
if (in != NULL && !_cpri__EccIsPointOnCurve(curve_id, in))
return CRYPT_POINT;
- if (n2 != NULL && !check_p256_param(n2))
+ if (n2 != NULL &&
+ !p256_from_be_bin_size(n2->b.buffer, n2->b.size, &n))
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);
+ result =
+ DCRYPTO_p256_base_point_mul(&out_x, &out_y, &n);
} else {
- const int x_size = in->x.b.size;
- const int y_size = in->y.b.size;
-
- reverse_tpm2b(&n2->b);
- reverse_tpm2b(&in->x.b);
- reverse_tpm2b(&in->y.b);
- append_zeros_to_p256_point(in);
-
- 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);
- in->x.b.size = x_size;
- in->y.b.size = y_size;
- reverse_tpm2b(&in->x.b);
- reverse_tpm2b(&in->y.b);
+ if (!p256_from_be_bin_size(in->x.b.buffer, in->x.b.size,
+ &in_x) ||
+ !p256_from_be_bin_size(in->y.b.buffer, in->y.b.size,
+ &in_y))
+ return CRYPT_PARAMETER;
+
+ result = DCRYPTO_p256_point_mul(&out_x, &out_y, &n,
+ &in_x, &in_y);
}
+ p256_clear(&n);
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);
-
+ p256_to_bin(&out_x, out->x.b.buffer);
+ p256_to_bin(&out_y, out->y.b.buffer);
return CRYPT_SUCCESS;
} else {
return CRYPT_NO_RESULT;
@@ -225,22 +164,22 @@ CRYPT_RESULT _cpri__GenerateKeyEcc(
}
for (; count != 0; count++) {
+ p256_int x, y, key;
+
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)) {
+ if (DCRYPTO_p256_key_from_bytes(&x, &y, &key, key_bytes)) {
q->x.b.size = sizeof(p256_int);
+ p256_to_bin(&x, q->x.b.buffer);
+
q->y.b.size = sizeof(p256_int);
- reverse_tpm2b(&q->x.b);
- reverse_tpm2b(&q->y.b);
+ p256_to_bin(&y, q->y.b.buffer);
d->b.size = sizeof(p256_int);
- reverse_tpm2b(&d->b);
-
+ p256_to_bin(&key, d->b.buffer);
+ p256_clear(&key);
break;
}
}
@@ -263,7 +202,7 @@ CRYPT_RESULT _cpri__SignEcc(
{
uint8_t digest_local[sizeof(p256_int)];
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
- p256_int p256_digest;
+ p256_int p256_digest, key, p256_r, p256_s;
int result;
if (curve_id != TPM_ECC_NIST_P256)
@@ -271,31 +210,23 @@ CRYPT_RESULT _cpri__SignEcc(
switch (scheme) {
case TPM_ALG_ECDSA: {
- const UINT16 d_size = d->b.size;
-
- if (!check_p256_param_in_range(d))
+ if (!p256_from_be_bin_size(d->b.buffer, d->b.size, &key))
return CRYPT_PARAMETER;
+
/* 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);
+ digest->buffer, digest_len);
p256_from_bin(digest_local, &p256_digest);
- reverse_tpm2b(&d->b);
- append_zeros_to_p256_param(d);
-
- result = fips_p256_ecdsa_sign(
- (p256_int *) d->b.buffer,
- &p256_digest,
- (p256_int *) r->b.buffer,
- (p256_int *) s->b.buffer);
- d->b.size = d_size;
- reverse_tpm2b(&d->b);
+ result = fips_p256_ecdsa_sign(&key, &p256_digest, &p256_r,
+ &p256_s);
+ p256_clear(&key);
r->b.size = sizeof(p256_int);
s->b.size = sizeof(p256_int);
- reverse_tpm2b(&r->b);
- reverse_tpm2b(&s->b);
+ p256_to_bin(&p256_r, r->b.buffer);
+ p256_to_bin(&p256_s, s->b.buffer);
if (result)
return CRYPT_SUCCESS;
@@ -314,7 +245,7 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc(
{
uint8_t digest_local[sizeof(p256_int)];
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
- p256_int p256_digest;
+ p256_int p256_digest, q_x, q_y, p256_r, p256_s;
int result;
if (curve_id != TPM_ECC_NIST_P256)
@@ -322,43 +253,20 @@ CRYPT_RESULT _cpri__ValidateSignatureEcc(
switch (scheme) {
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;
+ if (!p256_from_be_bin_size(q->x.b.buffer, q->x.b.size, &q_x) ||
+ !p256_from_be_bin_size(q->y.b.buffer, q->y.b.size, &q_y) ||
+ !p256_from_be_bin_size(r->b.buffer, r->b.size, &p256_r) ||
+ !p256_from_be_bin_size(s->b.buffer, s->b.size, &p256_s))
+ return CRYPT_PARAMETER;
/* 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);
+ digest->buffer, digest_len);
p256_from_bin(digest_local, &p256_digest);
- 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,
- (p256_int *) q->y.b.buffer,
- &p256_digest,
- (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);
+ result = dcrypto_p256_ecdsa_verify(&q_x, &q_y, &p256_digest,
+ &p256_r, &p256_s);
if (result)
return CRYPT_SUCCESS;
@@ -375,26 +283,26 @@ CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
{
int result;
uint8_t key_bytes[P256_NBYTES] __aligned(4);
+ p256_int x, y, key;
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);
+ result = DCRYPTO_p256_key_from_bytes(&x, &y, &key, 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);
+ p256_to_bin(&x, q->x.b.buffer);
+ p256_to_bin(&y, q->y.b.buffer);
d->b.size = sizeof(p256_int);
- reverse_tpm2b(&d->b);
+ p256_to_bin(&key, d->b.buffer);
+ p256_clear(&key);
return CRYPT_SUCCESS;
} else {
diff --git a/common/u2f.c b/common/u2f.c
index e5fe20371e..0795d88359 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -21,7 +21,6 @@
#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ##args)
-
size_t g2f_attestation_cert(uint8_t *buf)
{
uint8_t *serial;
@@ -34,7 +33,21 @@ size_t g2f_attestation_cert(uint8_t *buf)
if (system_get_chip_unique_id(&serial) != P256_NBYTES)
return 0;
- return g2f_attestation_cert_serial(state, serial, buf);
+#ifdef CHIP_G
+ /**
+ * chip/g implementation of system_get_chip_unique_id() always
+ * returns 32-bit aligned pointer, but host mock-ups do no guarantee
+ * that, so copy data to aligned location.
+ */
+ return g2f_attestation_cert_serial(state, (p256_int *)serial, buf);
+#else
+ {
+ p256_int p256_serial;
+
+ memcpy(&p256_serial, serial, sizeof(p256_serial));
+ return g2f_attestation_cert_serial(state, &p256_serial, buf);
+ }
+#endif
}
/* U2F GENERATE command */