summaryrefslogtreecommitdiff
path: root/board/cr50/tpm2/ecc.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/cr50/tpm2/ecc.c')
-rw-r--r--board/cr50/tpm2/ecc.c324
1 files changed, 212 insertions, 112 deletions
diff --git a/board/cr50/tpm2/ecc.c b/board/cr50/tpm2/ecc.c
index 3aea411487..95afd01ce9 100644
--- a/board/cr50/tpm2/ecc.c
+++ b/board/cr50/tpm2/ecc.c
@@ -361,13 +361,17 @@ CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
#ifdef CRYPTO_TEST_SETUP
+#include "console.h"
#include "extension.h"
enum {
TEST_SIGN = 0,
TEST_VERIFY = 1,
TEST_KEYGEN = 2,
- TEST_KEYDERIVE = 3
+ TEST_KEYDERIVE = 3,
+ TEST_POINT = 4,
+ TEST_VERIFY_ANY = 5,
+ TEST_SIGN_ANY = 6,
};
struct TPM2B_ECC_PARAMETER_aligned {
@@ -434,182 +438,278 @@ static int point_equals(const TPMS_ECC_POINT *a, const TPMS_ECC_POINT *b)
return !diff;
}
+/**
+ * Parse TPM_2B data, copy data to destination, update position
+ * @param ptr - pointer to current position, updated if parsed successfully
+ * @param cmd_size - remaining number of bytes, [in/out]
+ * @param len [out] - length of parsed data
+ * @param out [out] - destination buffer to copy data
+ * @param out_len - size of destination buffer
+ */
+static int parse_2b(uint8_t **ptr, size_t *cmd_size, uint16_t *len,
+ uint8_t *out, size_t out_len)
+{
+ uint16_t length;
+ uint8_t *local_ptr = *ptr;
+
+ *len = 0;
+ /* if there is no space for 2 bytes of length, exit */
+ if (*cmd_size < sizeof(length))
+ return 0;
+ length = local_ptr[0];
+ length = (length << 8) | local_ptr[1];
+ *cmd_size -= sizeof(length);
+ local_ptr += 2;
+ if (*cmd_size < length || length > out_len) {
+ ccprintf("%s: length = %d (0x%4x),"
+ " data available = %d, out_len = %d\n",
+ __func__, length, length, *cmd_size, out_len);
+ *cmd_size = 0;
+ return 0;
+ }
+ *len = length;
+ memcpy(out, local_ptr, length);
+ *ptr = local_ptr + length;
+ *cmd_size -= length;
+ return 1;
+}
+
+static void store_2b(uint8_t **ptr, size_t *rsp_size, TPM2B_ECC_PARAMETER *p)
+{
+ uint8_t *out = *ptr;
+
+ *out++ = p->t.size >> 8;
+ *out++ = p->t.size & 0xff;
+ memcpy(out, p->t.buffer, p->t.size);
+ *ptr = out + p->t.size;
+ *rsp_size += 2 + p->t.size;
+}
+
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;
+ uint8_t sign_mode = 0;
+ uint8_t hashing = 0;
+ TPM2B_SEED seed;
+
struct TPM2B_MAX_BUFFER_aligned digest;
uint8_t *out = (uint8_t *) cmd_body;
- uint32_t *response_size = (uint32_t *) response_size_out;
+ size_t *response_size = 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.
+ /**
+ * Command formats:
+ *
+ * TEST_SIGN:
+ * OP | CURVE_ID | SIGN_MODE | HASHING | DIGEST_LEN | DIGEST
+ * @returns 0/1 | R_LEN | R | S_LEN | S
+ *
+ * TEST_SIGN_ANY:
+ * OP | CURVE_ID | SIGN_MODE | HASHING | DIGEST_LEN | DIGEST |
+ * D_LEN | D
+ * @returns 0/1 | R_LEN | R | S_LEN | S
+ *
+ * TEST_VERIFY:
+ * OP | CURVE_ID | SIGN_MODE | HASHING | R_LEN | R | S_LEN | S
+ * DIGEST_LEN | DIGEST
+ * @returns 0/1 | if successful
+ *
+ * TEST_VERIFY_ANY:
+ * OP | CURVE_ID | SIGN_MODE | HASHING | R_LEN | R | S_LEN | S |
+ * DIGEST_LEN | DIGEST | QX_LEN | QX | QY_LEN | QY
+ * @returns 1 if successful
+ *
+ * TEST_KEYDERIVE :
+ * OP | CURVE_ID | SEED_LEN | SEED
+ * @returns 1 if successful
+ *
+ * TEST_POINT:
+ * OP | CURVE_ID | QX_LEN | QX | QY_LEN | QY
+ * @returns 1 if point is on curve
*
- * 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
+ * TEST_KEYGEN:
+ * OP | CURVE_ID
+ * @returns 0/1 | D_LEN | D | QX_LEN | QX | QY_LEN | QY
+ *
+ * Field size:
+ * FIELD LENGTH
+ * OP 1
+ * CURVE_ID 1
+ * SIGN_MODE 1
+ * HASHING 1
+ * MSG_LEN 2 (big endian)
+ * MSG MSG_LEN
+ * SEED_LEN 2 (big endian)
+ * SEED SEED_LEN
+ * R_LEN 2 (big endian)
+ * R R_LEN
+ * S_LEN 2 (big endian)
+ * S S_LEN
+ * DIGEST_LEN 2 (big endian)
+ * DIGEST DIGEST_LEN
+ * D_LEN 2 (big endian)
+ * D D_LEN
+ * QX_LEN 2 (big endian)
+ * QX QX_LEN
+ * QY_LEN 2 (big endian)
+ * QY QX_LEN
*/
+ *response_size = 0;
+ if (cmd_size < 2)
+ return;
- cmd = (uint8_t *) cmd_body;
+ 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;
+ cmd_size -= 2;
+
+ if (op == TEST_SIGN || op == TEST_VERIFY || op == TEST_VERIFY_ANY ||
+ op == TEST_SIGN_ANY) {
+ if (cmd_size >= 2) {
+ sign_mode = *cmd++;
+ hashing = *cmd++;
+ cmd_size -= 2;
+ } else
+ return;
+ }
+
+ if (op == TEST_SIGN || op == TEST_SIGN_ANY) {
+ if (!parse_2b(&cmd, &cmd_size, &digest.d.t.size,
+ digest.d.t.buffer, sizeof(digest.d.t.buffer)))
+ return;
+ if (op == TEST_SIGN_ANY &&
+ !parse_2b(&cmd, &cmd_size, &d.t.size, d.t.buffer,
+ sizeof(d.t.buffer)))
+ return;
+ if (op == TEST_SIGN) {
+ if (curve_id == TPM_ECC_NIST_P256)
+ d = NIST_P256_d.d;
+ else
+ 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;
+ if (op == TEST_KEYDERIVE &&
+ !parse_2b(&cmd, &cmd_size, &seed.t.size, seed.t.buffer,
+ sizeof(seed.t.buffer)))
return;
+
+ if (op == TEST_VERIFY || op == TEST_VERIFY_ANY) {
+ if (!parse_2b(&cmd, &cmd_size, &r.d.t.size, r.d.t.buffer,
+ sizeof(r.d.t.buffer)))
+ return;
+ if (!parse_2b(&cmd, &cmd_size, &s.d.t.size, s.d.t.buffer,
+ sizeof(s.d.t.buffer)))
+ return;
+ if (!parse_2b(&cmd, &cmd_size, &digest.d.t.size,
+ digest.d.t.buffer, sizeof(digest.d.t.buffer)))
+ 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;
+ if (op == TEST_VERIFY_ANY || op == TEST_POINT) {
+ if (!parse_2b(&cmd, &cmd_size, &q.x.t.size, q.x.t.buffer,
+ sizeof(q.x.t.buffer)))
+ return;
+ if (!parse_2b(&cmd, &cmd_size, &q.y.t.size, q.y.t.buffer,
+ sizeof(q.y.t.buffer)))
+ return;
+ } else {
+ /* use fixed signature */
q.x = NIST_P256_qx.d;
q.y = NIST_P256_qy.d;
- break;
- default:
- *response_size = 0;
- return;
}
+ /* there should be no other data as command is parsed */
+ if (cmd_size != 0)
+ return;
+
+ *out = 0;
+ *response_size = 1;
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;
+ case TEST_SIGN_ANY:
+ if (hashing != TPM_ALG_SHA256 && hashing != TPM_ALG_NULL)
+ return;
+ if (_cpri__SignEcc(&r.d, &s.d, sign_mode, hashing, curve_id, &d,
+ &digest.d.b, NULL) != CRYPT_SUCCESS) {
+ ccprintf("test_sign: error signing\n");
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;
+ *out++ = 1;
+ store_2b(&out, response_size, &r.d);
+ store_2b(&out, response_size, &s.d);
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 {
+ case TEST_VERIFY_ANY:
+ if (_cpri__ValidateSignatureEcc(&r.d, &s.d, sign_mode, hashing,
+ curve_id, &q,
+ &digest.d.b) != CRYPT_SUCCESS) {
+ ccprintf("test_verify: verification failed\n");
+ } else
*out = 1;
- *response_size = 1;
- }
return;
- case TEST_KEYGEN:
- {
+ 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;
+ != CRYPT_SUCCESS)
return;
- }
- if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
- *response_size = 0;
+
+ if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE)
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;
+ NULL, NULL) != CRYPT_SUCCESS)
return;
- }
- if (!point_equals(&q, &q_local)) {
- *response_size = 0;
+ if (!point_equals(&q, &q_local))
return;
- }
- *out = 1;
- *response_size = 1;
+
+ *out++ = 1;
+ store_2b(&out, response_size, &d_local.d);
+ store_2b(&out, response_size, &q.x);
+ store_2b(&out, response_size, &q.y);
return;
}
- case TEST_KEYDERIVE:
- {
- /* Random seed. */
- TPM2B_SEED seed;
+ case TEST_KEYDERIVE: {
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;
+ if (_cpri__GenerateKeyEcc(&q, &d_local.d, curve_id, hashing,
+ &seed.b, label, NULL,
+ NULL) != CRYPT_SUCCESS)
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;
+ if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE)
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;
+ if (_cpri__EccPointMultiply(&q_local, curve_id, &d_local.d,
+ NULL, NULL) != CRYPT_SUCCESS)
return;
- }
- if (!point_equals(&q, &q_local)) {
- *response_size = 0;
+
+ if (!point_equals(&q, &q_local))
return;
- }
*out = 1;
- *response_size = 1;
- return;
+ break;
}
+ case TEST_POINT:
+ *out = _cpri__EccIsPointOnCurve(curve_id, &q);
+ break;
+
default:
- *response_size = 0;
- return;
+ break;
}
}