diff options
author | Louis Collard <louiscollard@chromium.org> | 2019-04-22 15:04:06 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-25 11:27:17 -0700 |
commit | 04c85f7968a45f3f25504b8169d2a3751e588785 (patch) | |
tree | fd138a29dee39ef95013ebd0828fa7da8263f312 | |
parent | 351984635c163a8b2a8c623fb4ad8b3bc1c65477 (diff) | |
download | chrome-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.c | 53 | ||||
-rw-r--r-- | include/u2f.h | 6 |
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 |