summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Collard <louiscollard@chromium.org>2019-04-22 15:04:06 +0800
committerchrome-bot <chrome-bot@chromium.org>2019-04-25 11:27:17 -0700
commit04c85f7968a45f3f25504b8169d2a3751e588785 (patch)
treefd138a29dee39ef95013ebd0828fa7da8263f312
parent351984635c163a8b2a8c623fb4ad8b3bc1c65477 (diff)
downloadchrome-ec-04c85f7968a45f3f25504b8169d2a3751e588785.tar.gz
cr50: Support legacy U2F key handles
The new U2F functions make use of a new key derivation scheme. This adds a flag clients can specify that allows the new functions to also sign requests using a legacy key handle. This will allow continued support of legacy key handles in Chrome OS whilst allowing the legacy code to be removed from cr50. BUG=b:112603199, b:123161715 TEST=with new cr50 and u2fd patched to send new param: - register legacy key handle with Google - restart u2fd with user keys and no fallback - check login fails - restart u2fd with user keys and fallback - check login succeeds Signed-off-by: Louis Collard <louiscollard@chromium.org> Change-Id: Ib3164e9c0856d51b958fa8db181153b5b2227850 Reviewed-on: https://chromium-review.googlesource.com/1580622 Reviewed-by: Andrey Pronin <apronin@chromium.org>
-rw-r--r--common/u2f.c53
-rw-r--r--include/u2f.h6
2 files changed, 54 insertions, 5 deletions
diff --git a/common/u2f.c b/common/u2f.c
index 8ae8402c8c..282d59808b 100644
--- a/common/u2f.c
+++ b/common/u2f.c
@@ -472,6 +472,27 @@ static int verify_kh_owned(const uint8_t *user_secret, const uint8_t *app_id,
return safe_memcmp(recreated_kh, key_handle, KH_LEN) == 0;
}
+static int verify_legacy_kh_owned(const uint8_t *app_id,
+ const uint8_t *key_handle,
+ uint8_t *origin_seed)
+{
+ uint8_t unwrapped_kh[KH_LEN];
+ uint8_t kh_app_id[U2F_APPID_SIZE];
+
+ p256_int app_id_p256;
+ p256_int kh_app_id_p256;
+
+ /* Unwrap key handle */
+ if (wrap_kh(app_id, key_handle, unwrapped_kh, DECRYPT_MODE))
+ return 0;
+ deinterleave64(unwrapped_kh, kh_app_id, origin_seed);
+
+ /* Return whether appId (i.e. origin) matches. */
+ p256_from_bin(app_id, &app_id_p256);
+ p256_from_bin(kh_app_id, &kh_app_id_p256);
+ return p256_cmp(&app_id_p256, &kh_app_id_p256) == 0;
+}
+
/* Below, we depend on the response not being larger than than the request. */
BUILD_ASSERT(sizeof(U2F_SIGN_RESP) <= sizeof(U2F_SIGN_REQ));
@@ -487,19 +508,36 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code,
struct drbg_ctx ctx;
/* Origin private key. */
+ uint8_t legacy_origin_seed[SHA256_DIGEST_SIZE];
p256_int origin_d;
/* Hash, and corresponding signature. */
p256_int h, r, s;
+ /* Whether the key handle uses the legacy key derivation scheme. */
+ int legacy_kh = 0;
+
/* Response is smaller than request, so no need to check this. */
*response_size = 0;
if (input_size != sizeof(U2F_SIGN_REQ))
return VENDOR_RC_BOGUS_ARGS;
- if (!verify_kh_owned(req->userSecret, req->appId, req->keyHandle))
- return VENDOR_RC_PASSWORD_REQUIRED;
+ if (!verify_kh_owned(req->userSecret, req->appId, req->keyHandle)) {
+ if ((req->flags & SIGN_LEGACY_KH) == 0)
+ return VENDOR_RC_PASSWORD_REQUIRED;
+
+ /*
+ * We have a key handle which is not valid for the new scheme,
+ * but may be a valid legacy key handle, and we have been asked
+ * to sign legacy key handles.
+ */
+ if (verify_legacy_kh_owned(req->appId, req->keyHandle,
+ legacy_origin_seed))
+ legacy_kh = 1;
+ else
+ return VENDOR_RC_PASSWORD_REQUIRED;
+ }
/* We might not actually need to sign anything. */
if (req->flags == U2F_AUTH_CHECK_ONLY)
@@ -510,9 +548,14 @@ static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code,
return VENDOR_RC_NOT_ALLOWED;
/* Re-create origin-specific key. */
- if (u2f_origin_user_keypair(
- req->keyHandle, &origin_d, NULL, NULL) != EC_SUCCESS)
- return VENDOR_RC_INTERNAL_ERROR;
+ if (legacy_kh) {
+ if (u2f_origin_key(legacy_origin_seed, &origin_d) != EC_SUCCESS)
+ return VENDOR_RC_INTERNAL_ERROR;
+ } else {
+ if (u2f_origin_user_keypair(req->keyHandle, &origin_d, NULL,
+ NULL) != EC_SUCCESS)
+ return VENDOR_RC_INTERNAL_ERROR;
+ }
/* Prepare hash to sign. */
p256_from_bin(req->hash, &h);
diff --git a/include/u2f.h b/include/u2f.h
index 003f047175..1a445f8f4a 100644
--- a/include/u2f.h
+++ b/include/u2f.h
@@ -151,6 +151,12 @@ typedef struct {
#define G2F_ATTEST 0x80 // Fixed attestation key
#define G2F_CONSUME 0x02 // Consume presence
+// The key handle format was changed when support for user secrets was added.
+// U2F_SIGN requests that specify this flag will first try to validate the
+// key handle as a new format key handle, and if that fails, will fall back
+// to treating it as a legacy key handle (without user secrets).
+#define SIGN_LEGACY_KH 0x40
+
// U2F Attest format for U2F Register Response.
#define U2F_ATTEST_FORMAT_REG_RESP 0