summaryrefslogtreecommitdiff
path: root/chromium/device/fido/attested_credential_data.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/device/fido/attested_credential_data.cc')
-rw-r--r--chromium/device/fido/attested_credential_data.cc111
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;
}