diff options
Diffstat (limited to 'chromium/device/fido/attested_credential_data.cc')
-rw-r--r-- | chromium/device/fido/attested_credential_data.cc | 111 |
1 files changed, 68 insertions, 43 deletions
diff --git a/chromium/device/fido/attested_credential_data.cc b/chromium/device/fido/attested_credential_data.cc index e1c4f9e6789..1365828d755 100644 --- a/chromium/device/fido/attested_credential_data.cc +++ b/chromium/device/fido/attested_credential_data.cc @@ -10,12 +10,19 @@ #include "base/numerics/safe_math.h" #include "components/cbor/reader.h" #include "components/device_event_log/device_event_log.h" +#include "device/fido/cbor_extract.h" +#include "device/fido/ed25519_public_key.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/p256_public_key.h" #include "device/fido/public_key.h" #include "device/fido/rsa_public_key.h" +using device::cbor_extract::IntKey; +using device::cbor_extract::Is; +using device::cbor_extract::StepOrByte; +using device::cbor_extract::Stop; + namespace device { // static @@ -57,70 +64,88 @@ AttestedCredentialData::ConsumeFromCtapResponse( const cbor::Value::MapValue& public_key_map = public_key_cbor->GetMap(); - // kAlg is required to be present. See - // https://www.w3.org/TR/webauthn/#credentialpublickey - // COSE allows it to be a string or an integer. However, WebAuthn defines - // COSEAlgorithmIdentifier to be a long[1], thus only integer-based algorithms - // can be negotiated. - // - // [1] https://www.w3.org/TR/webauthn/#alg-identifier - const auto it = - public_key_map.find(cbor::Value(static_cast<int64_t>(CoseKeyKey::kAlg))); - if (it == public_key_map.end() || !it->second.is_integer()) { - FIDO_LOG(ERROR) << "Public key is missing algorithm identifier"; + struct COSEKey { + const int64_t* alg; + const int64_t* kty; + } cose_key; + + static constexpr cbor_extract::StepOrByte<COSEKey> kSteps[] = { + // clang-format off + + // kAlg is required to be present. See + // https://www.w3.org/TR/webauthn/#credentialpublickey + // COSE allows it to be a string or an integer. However, WebAuthn defines + // COSEAlgorithmIdentifier to be a long[1], thus only integer-based + // algorithms can be negotiated. + // + // [1] https://www.w3.org/TR/webauthn/#alg-identifier + ELEMENT(Is::kRequired, COSEKey, alg), + IntKey<COSEKey>(static_cast<int>(CoseKeyKey::kAlg)), + + // kKty is required in COSE keys: + // https://tools.ietf.org/html/rfc8152#section-7 + ELEMENT(Is::kRequired, COSEKey, kty), + IntKey<COSEKey>(static_cast<int>(CoseKeyKey::kKty)), + + Stop<COSEKey>(), + // clang-format on + }; + + if (!cbor_extract::Extract<COSEKey>(&cose_key, kSteps, public_key_map)) { + FIDO_LOG(ERROR) << "Failed to parse COSE key"; return base::nullopt; } // In WebIDL, a |long| is an |int32_t|[1]. // // [1] https://heycam.github.io/webidl/#idl-long - const int64_t algorithm64 = it->second.GetInteger(); + const int64_t algorithm64 = *cose_key.alg; if (algorithm64 > std::numeric_limits<int32_t>::max() || algorithm64 < std::numeric_limits<int32_t>::min()) { FIDO_LOG(ERROR) << "COSE algorithm in public key is out of range"; return base::nullopt; } const int32_t algorithm = static_cast<int32_t>(algorithm64); + const int64_t key_type = *cose_key.kty; std::unique_ptr<PublicKey> public_key; - // kKty is required in COSE keys: - // https://tools.ietf.org/html/rfc8152#section-7 - auto public_key_type = - public_key_map.find(cbor::Value(static_cast<int64_t>(CoseKeyKey::kKty))); - if (public_key_type == public_key_map.end()) { - FIDO_LOG(ERROR) << "COSE key missing kty"; - return base::nullopt; - } + if (key_type == static_cast<int64_t>(CoseKeyTypes::kEC2) || + key_type == static_cast<int64_t>(CoseKeyTypes::kOKP)) { + auto curve = public_key_map.find( + cbor::Value(static_cast<int64_t>(CoseKeyKey::kEllipticCurve))); + if (curve == public_key_map.end() || !curve->second.is_integer()) { + return base::nullopt; + } + const int64_t curve_id = curve->second.GetInteger(); - if (public_key_type->second.is_unsigned()) { - const int64_t key_type = public_key_type->second.GetUnsigned(); - if (key_type == static_cast<int64_t>(CoseKeyTypes::kEC2)) { - auto curve = public_key_map.find( - cbor::Value(static_cast<int64_t>(CoseKeyKey::kEllipticCurve))); - if (curve == public_key_map.end() || !curve->second.is_integer()) { + if (key_type == static_cast<int64_t>(CoseKeyTypes::kEC2) && + curve_id == static_cast<int64_t>(CoseCurves::kP256)) { + auto p256_key = P256PublicKey::ExtractFromCOSEKey( + algorithm, public_key_cbor_bytes, public_key_map); + if (!p256_key) { + FIDO_LOG(ERROR) << "Invalid P-256 public key"; return base::nullopt; } - - if (curve->second.GetInteger() == - static_cast<int64_t>(CoseCurves::kP256)) { - auto p256_key = P256PublicKey::ExtractFromCOSEKey( - algorithm, public_key_cbor_bytes, public_key_map); - if (!p256_key) { - FIDO_LOG(ERROR) << "Invalid P-256 public key"; - return base::nullopt; - } - public_key = std::move(p256_key); - } - } else if (key_type == static_cast<int64_t>(CoseKeyTypes::kRSA)) { - auto rsa_key = RSAPublicKey::ExtractFromCOSEKey( + public_key = std::move(p256_key); + } else if (key_type == static_cast<int64_t>(CoseKeyTypes::kOKP) && + curve_id == static_cast<int64_t>(CoseCurves::kEd25519)) { + auto ed25519_key = Ed25519PublicKey::ExtractFromCOSEKey( algorithm, public_key_cbor_bytes, public_key_map); - if (!rsa_key) { - FIDO_LOG(ERROR) << "Invalid RSA public key"; + if (!ed25519_key) { + FIDO_LOG(ERROR) << "Invalid Ed25519 public key"; return base::nullopt; } - public_key = std::move(rsa_key); + public_key = std::move(ed25519_key); + } + } else if (key_type == static_cast<int64_t>(CoseKeyTypes::kRSA)) { + auto rsa_key = RSAPublicKey::ExtractFromCOSEKey( + algorithm, public_key_cbor_bytes, public_key_map); + if (!rsa_key) { + FIDO_LOG(ERROR) << "Invalid RSA public key"; + return base::nullopt; } + public_key = std::move(rsa_key); } if (!public_key) { @@ -204,7 +229,7 @@ std::vector<uint8_t> AttestedCredentialData::SerializeAsBytes() const { fido_parsing_utils::Append(&attestation_data, aaguid_); fido_parsing_utils::Append(&attestation_data, credential_id_length_); fido_parsing_utils::Append(&attestation_data, credential_id_); - fido_parsing_utils::Append(&attestation_data, public_key_->cose_key_bytes()); + fido_parsing_utils::Append(&attestation_data, public_key_->cose_key_bytes); return attestation_data; } |