summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/u2f.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/cr50/dcrypto/u2f.c')
-rw-r--r--board/cr50/dcrypto/u2f.c272
1 files changed, 197 insertions, 75 deletions
diff --git a/board/cr50/dcrypto/u2f.c b/board/cr50/dcrypto/u2f.c
index 76be43285d..4cd267ac61 100644
--- a/board/cr50/dcrypto/u2f.c
+++ b/board/cr50/dcrypto/u2f.c
@@ -53,7 +53,7 @@ static void u2f_origin_user_mac(const struct u2f_state *state,
HMAC_SHA256_update(&ctx, origin, U2F_APPID_SIZE);
HMAC_SHA256_update(&ctx, user, U2F_USER_SECRET_SIZE);
HMAC_SHA256_update(&ctx, origin_seed, U2F_ORIGIN_SEED_SIZE);
- if (kh_version != 0)
+ if (kh_version == U2F_KH_VERSION_1)
HMAC_SHA256_update(&ctx, &kh_version, sizeof(kh_version));
#ifdef CR50_DEV_U2F_VERBOSE
ccprintf("origin %ph\n", HEX_BUF(origin, U2F_APPID_SIZE));
@@ -71,7 +71,8 @@ static void u2f_origin_user_mac(const struct u2f_state *state,
static void u2f_authorization_mac(const struct u2f_state *state,
const union u2f_key_handle_variant *kh,
- uint8_t kh_version,
+ uint8_t kh_version, const uint8_t *user,
+ const uint8_t *origin,
const uint8_t *auth_time_secret_hash,
uint8_t *kh_auth_mac)
{
@@ -80,25 +81,39 @@ static void u2f_authorization_mac(const struct u2f_state *state,
const void *kh_header = NULL;
size_t kh_header_size = 0;
- if (kh_version == 0) {
- memset(kh_auth_mac, 0xff, SHA256_DIGEST_SIZE);
- return;
- }
- /* At some point we may have v2 key handle, so prepare for it. */
- if (kh_version == 1) {
+ switch (kh_version) {
+ case U2F_KH_VERSION_2:
+ auth_salt = kh->v2.authorization_salt;
+ kh_header = &kh->v2;
+ kh_header_size = U2F_V2_KH_HEADER_SIZE;
+ break;
+ case U2F_KH_VERSION_1:
auth_salt = kh->v1.authorization_salt;
kh_header = &kh->v1;
+ /* include kh_hmac, which depends on user and origin */
kh_header_size = U2F_V1_KH_HEADER_SIZE;
+ break;
+ default:
+ /**
+ * Version 0 doesn't contain authorization salt, so do
+ * nothing for it as well as for unknown versions.
+ */
+ memset(kh_auth_mac, 0xff, SHA256_DIGEST_SIZE);
+ return;
}
/**
* HMAC(u2f_hmac_key, auth_salt || key_handle_header
- * || authTimeSecret)
+ * [origin || user ] || authTimeSecret)
*/
HMAC_SHA256_hw_init(&ctx, state->hmac_key, SHA256_DIGEST_SIZE);
HMAC_SHA256_update(&ctx, auth_salt, U2F_AUTHORIZATION_SALT_SIZE);
HMAC_SHA256_update(&ctx, kh_header, kh_header_size);
+ if (kh_version == U2F_KH_VERSION_2) {
+ HMAC_SHA256_update(&ctx, origin, U2F_APPID_SIZE);
+ HMAC_SHA256_update(&ctx, user, U2F_USER_SECRET_SIZE);
+ }
HMAC_SHA256_update(&ctx, auth_time_secret_hash,
U2F_AUTH_TIME_SECRET_SIZE);
@@ -124,7 +139,7 @@ static int app_hw_device_id(enum dcrypto_appid appid, const uint32_t input[8],
/**
* Compute HMAC(HMAC(hw_device_id, SHA256(name[appid])), input)
- * It is not used as a key though, and treated as personalization
+ * It is not used as a key though, and treated as additional data
* string for DRBG.
*/
result = DCRYPTO_appkey_derive(appid, input, output);
@@ -141,7 +156,7 @@ static int app_hw_device_id(enum dcrypto_appid appid, const uint32_t input[8],
*
* @param state U2F state parameters
* @param kh key handle
- * @param kh_version key handle version (0 - legacy, 1 - versioned)
+ * @param kh_version key handle version
* @param d pointer to ECDSA private key
* @param pk_x pointer to public key point
* @param pk_y pointer to public key point
@@ -158,15 +173,29 @@ static enum ec_error_list u2f_origin_user_key_pair(
struct drbg_ctx drbg;
size_t key_handle_size = 0;
uint8_t *key_handle = NULL;
- enum dcrypto_result result;
-
- if (kh_version == 0) {
- key_handle_size = sizeof(struct u2f_key_handle_v0);
- key_handle = (uint8_t *)&kh->v0;
- } else if ((kh_version == 1) && (kh->v1.version == kh_version)) {
+ enum dcrypto_result result = DCRYPTO_FAIL;
+
+ p256_clear(d);
+ memset(key_seed, 0, sizeof(key_seed));
+
+ switch (kh_version) {
+ case U2F_KH_VERSION_2:
+ if (kh->v2.version != U2F_KH_VERSION_2)
+ return EC_ERROR_INVAL;
+ key_handle_size = U2F_V2_KH_HEADER_SIZE;
+ key_handle = (uint8_t *)&kh->v2;
+ break;
+ case U2F_KH_VERSION_1:
+ if (kh->v1.version != U2F_KH_VERSION_1)
+ return EC_ERROR_INVAL;
key_handle_size = U2F_V1_KH_HEADER_SIZE;
key_handle = (uint8_t *)&kh->v1;
- } else {
+ break;
+ case 0:
+ key_handle_size = sizeof(struct u2f_key_handle_v0);
+ key_handle = (uint8_t *)&kh->v0;
+ break;
+ default:
return EC_ERROR_INVAL;
}
@@ -184,10 +213,8 @@ static enum ec_error_list u2f_origin_user_key_pair(
hmac_drbg_init(&drbg, state->drbg_entropy,
state->drbg_entropy_size, dev_salt, P256_NBYTES,
NULL, 0, HMAC_DRBG_DO_NOT_AUTO_RESEED);
- if (hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
- key_handle,
- key_handle_size) != DCRYPTO_OK)
- return EC_ERROR_HW_INTERNAL;
+ result = hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
+ key_handle, key_handle_size);
} else {
/**
* FIPS-compliant path.
@@ -206,10 +233,13 @@ static enum ec_error_list u2f_origin_user_key_pair(
/**
* Additional data = Device_ID (constant coming from HW).
*/
- if (hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
- dev_salt, P256_NBYTES) != DCRYPTO_OK)
- return EC_ERROR_HW_INTERNAL;
+ result = hmac_drbg_generate(&drbg, key_seed, sizeof(key_seed),
+ dev_salt, P256_NBYTES);
}
+
+ if (result != DCRYPTO_OK)
+ return EC_ERROR_HW_INTERNAL;
+
result = DCRYPTO_p256_key_from_bytes(pk_x, pk_y, d, key_seed);
drbg_exit(&drbg);
@@ -237,28 +267,48 @@ enum ec_error_list u2f_generate(const struct u2f_state *state,
union u2f_key_handle_variant *kh,
uint8_t kh_version, struct u2f_ec_point *pubKey)
{
- uint8_t *kh_hmac, *kh_origin_seed;
- int generate_key_pair_rc;
+ uint8_t *kh_hmac = NULL;
+ uint8_t *kh_origin_seed = NULL;
+ uint8_t *auth_salt = NULL;
+ uint8_t *auth_hmac = NULL;
+ enum ec_error_list generate_key_pair_rc = EC_ERROR_HW_INTERNAL;
+
/* Generated public keys associated with key handle. */
p256_int opk_x, opk_y;
if (!fips_crypto_allowed())
return EC_ERROR_HW_INTERNAL;
- /* Compute constants for request key handler version. */
- if (kh_version == 0) {
- kh_hmac = kh->v0.hmac;
- kh_origin_seed = kh->v0.origin_seed;
- } else if (kh_version == 1) {
+ /* Compute constants for requested key handle version. */
+ switch (kh_version) {
+ case U2F_KH_VERSION_2:
+ /**
+ * This may overwrite input parameters if shared
+ * request/response buffer is used by caller.
+ */
+ kh_origin_seed = kh->v2.origin_seed;
+ auth_salt = kh->v2.authorization_salt;
+ auth_hmac = kh->v2.authorization_hmac;
+ kh->v2.version = U2F_KH_VERSION_2;
+ break;
+ case U2F_KH_VERSION_1:
kh_hmac = kh->v1.kh_hmac;
kh_origin_seed = kh->v1.origin_seed;
+ auth_salt = kh->v1.authorization_salt;
+ auth_hmac = kh->v1.authorization_hmac;
/**
* This may overwrite input parameters if shared
* request/response buffer is used by caller.
*/
kh->v1.version = kh_version;
- } else
+ break;
+ case 0:
+ kh_hmac = kh->v0.hmac;
+ kh_origin_seed = kh->v0.origin_seed;
+ break;
+ default:
return EC_ERROR_INVAL;
+ }
/* Generate key handle candidates and origin-specific key pair. */
do {
@@ -267,8 +317,9 @@ enum ec_error_list u2f_generate(const struct u2f_state *state,
if (!fips_rand_bytes(kh_origin_seed, U2F_ORIGIN_SEED_SIZE))
return EC_ERROR_HW_INTERNAL;
- u2f_origin_user_mac(state, user, origin, kh_origin_seed,
- kh_version, kh_hmac);
+ if (kh_hmac) /* Versions 0 & 1 only. */
+ u2f_origin_user_mac(state, user, origin, kh_origin_seed,
+ kh_version, kh_hmac);
/**
* Try to generate key pair using key handle. This may fail if
@@ -284,13 +335,12 @@ enum ec_error_list u2f_generate(const struct u2f_state *state,
if (generate_key_pair_rc != EC_SUCCESS)
return generate_key_pair_rc;
- if (kh_version == 1) {
- if (!fips_rand_bytes(kh->v1.authorization_salt,
- U2F_AUTHORIZATION_SALT_SIZE))
+ if (kh_version) {
+ if (!fips_rand_bytes(auth_salt, U2F_AUTHORIZATION_SALT_SIZE))
return EC_ERROR_HW_INTERNAL;
- u2f_authorization_mac(state, kh, kh_version, authTimeSecretHash,
- kh->v1.authorization_hmac);
+ u2f_authorization_mac(state, kh, kh_version, user, origin,
+ authTimeSecretHash, auth_hmac);
}
pubKey->pointFormat = U2F_POINT_UNCOMPRESSED;
@@ -307,8 +357,8 @@ enum ec_error_list u2f_authorize_keyhandle(
{
/* Re-created key handle. */
uint8_t recreated_hmac[SHA256_DIGEST_SIZE];
- const uint8_t *origin_seed, *kh_hmac;
- int result = 0;
+ const uint8_t *origin_seed = NULL, *kh_hmac = NULL, *auth_hmac = NULL;
+ enum dcrypto_result result = 0;
if (!fips_crypto_allowed())
return EC_ERROR_HW_INTERNAL;
@@ -318,36 +368,54 @@ enum ec_error_list u2f_authorize_keyhandle(
* was provided. This allows us to verify that the key handle
* is owned by this combination of device, current user and origin.
*/
- if (kh_version == 0) {
- origin_seed = kh->v0.origin_seed;
- kh_hmac = kh->v0.hmac;
- } else {
+ switch (kh_version) {
+ case U2F_KH_VERSION_2:
+ if (!authTimeSecretHash || kh->v2.version != U2F_KH_VERSION_2)
+ return EC_ERROR_ACCESS_DENIED;
+
+ origin_seed = kh->v2.origin_seed;
+ auth_hmac = kh->v2.authorization_hmac;
+ break;
+ case U2F_KH_VERSION_1:
+ if (kh->v1.version != U2F_KH_VERSION_1)
+ return EC_ERROR_ACCESS_DENIED;
origin_seed = kh->v1.origin_seed;
+ auth_hmac = kh->v1.authorization_hmac;
kh_hmac = kh->v1.kh_hmac;
+ break;
+ case 0:
+ origin_seed = kh->v0.origin_seed;
+ kh_hmac = kh->v0.hmac;
+ break;
+ default:
+ return EC_ERROR_INVAL;
}
- /* First, check inner part. */
- u2f_origin_user_mac(state, user, origin, origin_seed, kh_version,
- recreated_hmac);
- /**
- * DCRYPTO_equals return 1 if success, by subtracting 1 we make it
- * zero, and other results - zero or non-zero will be detected.
- */
- result |= DCRYPTO_equals(&recreated_hmac, kh_hmac,
- sizeof(recreated_hmac)) - DCRYPTO_OK;
+ if (kh_hmac) {
+ /* First, check inner part. */
+ u2f_origin_user_mac(state, user, origin, origin_seed,
+ kh_version, recreated_hmac);
+
+ /**
+ * DCRYPTO_equals return DCRYPTO_OK if success, by subtracting 1
+ * we make it zero, and other results - zero or non-zero will be
+ * detected.
+ */
+ result |= DCRYPTO_equals(&recreated_hmac, kh_hmac,
+ sizeof(recreated_hmac));
- always_memset(recreated_hmac, 0, sizeof(recreated_hmac));
+ always_memset(recreated_hmac, 0, sizeof(recreated_hmac));
+ }
- if ((kh_version != 0) && (authTimeSecretHash != NULL)) {
- u2f_authorization_mac(state, kh, kh_version, authTimeSecretHash,
- recreated_hmac);
- result |= DCRYPTO_equals(&recreated_hmac,
- kh->v1.authorization_hmac,
- sizeof(recreated_hmac)) - DCRYPTO_OK;
+ if (auth_hmac && authTimeSecretHash) {
+ u2f_authorization_mac(state, kh, kh_version, user, origin,
+ authTimeSecretHash, recreated_hmac);
+ result |= DCRYPTO_equals(&recreated_hmac, auth_hmac,
+ sizeof(recreated_hmac));
always_memset(recreated_hmac, 0, sizeof(recreated_hmac));
}
- return (result == 0) ? EC_SUCCESS : EC_ERROR_ACCESS_DENIED;
+ return (result == DCRYPTO_OK) ? EC_SUCCESS : EC_ERROR_ACCESS_DENIED;
}
static enum ec_error_list
@@ -411,14 +479,18 @@ enum ec_error_list u2f_sign(const struct u2f_state *state,
result = u2f_authorize_keyhandle(state, kh, kh_version, user, origin,
authTimeSecretHash);
- if (result != EC_SUCCESS)
+ if (result != EC_SUCCESS) {
+ memset(sig, 0, sizeof(*sig));
return result;
+ }
/* Re-create origin-specific key. */
result = u2f_origin_user_key_pair(state, kh, kh_version, &origin_d,
NULL, NULL);
- if (result != EC_SUCCESS)
+ if (result != EC_SUCCESS) {
+ memset(sig, 0, sizeof(*sig));
return result;
+ }
/* Prepare hash to sign. */
p256_from_bin(hash, &h);
@@ -581,6 +653,7 @@ enum ec_error_list u2f_attest(const struct u2f_state *state,
DCRYPTO_OK) ?
EC_SUCCESS :
EC_ERROR_HW_INTERNAL;
+ drbg_exit(&dr_ctx);
p256_clear(&d);
p256_to_bin(&r, sig->sig_r);
@@ -675,41 +748,90 @@ static int cmd_u2f_test(int argc, char **argv)
ccprintf("\nVersion 1 tests\n");
ccprintf("u2f_generate - %s\n",
expect_bool(u2f_generate(&state, user, origin, authTime, &kh,
- 1, &pubKey),
+ U2F_KH_VERSION_1, &pubKey),
EC_SUCCESS));
ccprintf("kh: %ph\n", HEX_BUF(&kh, sizeof(kh.v1)));
ccprintf("pubKey: %ph\n", HEX_BUF(&pubKey, sizeof(pubKey)));
ccprintf("u2f_authorize_keyhandle - %s\n",
- expect_bool(u2f_authorize_keyhandle(&state, &kh, 1, user,
+ expect_bool(u2f_authorize_keyhandle(&state, &kh,
+ U2F_KH_VERSION_1, user,
origin, authTime),
EC_SUCCESS));
kh.v1.authorization_salt[0] ^= 0x10;
ccprintf("u2f_authorize_keyhandle - %s\n",
- expect_bool(u2f_authorize_keyhandle(&state, &kh, 1, user,
+ expect_bool(u2f_authorize_keyhandle(&state, &kh,
+ U2F_KH_VERSION_1, user,
origin, authTime),
EC_ERROR_ACCESS_DENIED));
kh.v1.authorization_salt[0] ^= 0x10;
ccprintf("u2f_sign - %s\n",
- expect_bool(u2f_sign(&state, &kh, 1, user, origin, authTime,
- authTime, &sig),
+ expect_bool(u2f_sign(&state, &kh, U2F_KH_VERSION_1, user,
+ origin, authTime, authTime, &sig),
EC_SUCCESS));
ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));
ccprintf("u2f_attest - %s\n",
- expect_bool(u2f_attest(&state, &kh, 1, user, origin, authTime,
- &pubKey, authTime, sizeof(authTime),
- &sig),
+ expect_bool(u2f_attest(&state, &kh, U2F_KH_VERSION_1, user,
+ origin, authTime, &pubKey, authTime,
+ sizeof(authTime), &sig),
EC_SUCCESS));
ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));
/* Should fail with incorrect key handle. */
kh.v1.origin_seed[0] ^= 0x10;
ccprintf("u2f_sign - %s\n",
- expect_bool(u2f_sign(&state, &kh, 1, user, origin, authTime,
- authTime, &sig),
+ expect_bool(u2f_sign(&state, &kh, U2F_KH_VERSION_1, user,
+ origin, authTime, authTime, &sig),
+ EC_ERROR_ACCESS_DENIED));
+ ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));
+
+ cflush();
+
+ /* Version 2 key handle. */
+ memset(&kh, 0, sizeof(kh));
+ ccprintf("\nVersion 2 tests\n");
+ ccprintf("u2f_generate - %s\n",
+ expect_bool(u2f_generate(&state, user, origin, authTime, &kh,
+ U2F_KH_VERSION_2, &pubKey),
+ EC_SUCCESS));
+ ccprintf("kh: %ph\n", HEX_BUF(&kh, sizeof(kh.v2)));
+ ccprintf("pubKey: %ph\n", HEX_BUF(&pubKey, sizeof(pubKey)));
+
+ ccprintf("u2f_authorize_keyhandle - %s\n",
+ expect_bool(u2f_authorize_keyhandle(&state, &kh,
+ U2F_KH_VERSION_2, user,
+ origin, authTime),
+ EC_SUCCESS));
+
+ kh.v2.authorization_salt[0] ^= 0x10;
+ ccprintf("u2f_authorize_keyhandle - %s\n",
+ expect_bool(u2f_authorize_keyhandle(&state, &kh,
+ U2F_KH_VERSION_2, user,
+ origin, authTime),
+ EC_ERROR_ACCESS_DENIED));
+
+ kh.v2.authorization_salt[0] ^= 0x10;
+ ccprintf("u2f_sign - %s\n",
+ expect_bool(u2f_sign(&state, &kh, U2F_KH_VERSION_2, user,
+ origin, authTime, authTime, &sig),
+ EC_SUCCESS));
+ ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));
+
+ ccprintf("u2f_attest - %s\n",
+ expect_bool(u2f_attest(&state, &kh, U2F_KH_VERSION_2, user,
+ origin, authTime, &pubKey, authTime,
+ sizeof(authTime), &sig),
+ EC_SUCCESS));
+ ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));
+
+ /* Should fail with incorrect key handle. */
+ kh.v2.origin_seed[0] ^= 0x10;
+ ccprintf("u2f_sign - %s\n",
+ expect_bool(u2f_sign(&state, &kh, U2F_KH_VERSION_2, user,
+ origin, authTime, authTime, &sig),
EC_ERROR_ACCESS_DENIED));
ccprintf("sig: %ph\n", HEX_BUF(&sig, sizeof(sig)));