Commit 877a199e authored by Martin Kreichgauer's avatar Martin Kreichgauer Committed by Commit Bot

Fill in makeCredential implementation gaps in caBLEv2 authenticator

When handling makeCredential requests in the caBLEv2 authenticator, pass
request arguments from the native side where they are unmarshaled over
to the Java side, so they can be used to construct the GMSCore FIDO API
request. When receiving a response from the FIDO API, pass response
parameters back to native code where they are converted into a CTAP
response. Both sides were previously using hard-coded fake data.

Move CtapMakeCredentialRequest and CtapGetAssertionRequest parsing code
out of VirtualCtap2Device so that caBLEv2 authenticator native code can
reuse them. Add a Parse() factory method to AttestationObject because
the native code needs to parse the CBOR Java response from Java in order
to convert it into a CTAP message.

Also switch native code to make use of //base/android JNI type
conversion helpers throughout.

Bug: 1002262
Change-Id: Ie24adec8c2b8f64e4330aa1fc4b3bf8a273617e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2109037
Commit-Queue: Martin Kreichgauer <martinkr@google.com>
Reviewed-by: default avatarAdam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#751907}
parent 563b5207
...@@ -505,17 +505,21 @@ class BLEHandler extends BluetoothGattServerCallback implements Closeable { ...@@ -505,17 +505,21 @@ class BLEHandler extends BluetoothGattServerCallback implements Closeable {
* Called by native code to process a makeCredential request. * Called by native code to process a makeCredential request.
*/ */
@CalledByNative @CalledByNative
void makeCredential(long client) { void makeCredential(long client, byte[] clientDataHash, String rpId, byte[] userId,
mAuthenticator.makeCredential(client); int[] algorithms, byte[][] excludedCredentialIds, boolean residentKeyRequired) {
mAuthenticator.makeCredential(client, clientDataHash, rpId, userId, algorithms,
excludedCredentialIds, residentKeyRequired);
} }
/** /**
* Called by CableAuthenticator to notify native code of an attestation response to a * Called by CableAuthenticator to notify native code of an attestation response to a
* makeCredential request. * makeCredential request.
*/ */
public void onAuthenticatorAttestationResponse(long client, int ctapStatus) { public void onAuthenticatorAttestationResponse(
mTaskRunner.postTask( long client, int ctapStatus, byte[] attestationObject) {
() -> BLEHandlerJni.get().onAuthenticatorAttestationResponse(client, ctapStatus)); mTaskRunner.postTask(()
-> BLEHandlerJni.get().onAuthenticatorAttestationResponse(
client, ctapStatus, attestationObject));
} }
@NativeMethods @NativeMethods
...@@ -544,6 +548,7 @@ class BLEHandler extends BluetoothGattServerCallback implements Closeable { ...@@ -544,6 +548,7 @@ class BLEHandler extends BluetoothGattServerCallback implements Closeable {
/** /**
* Called to alert native code of a response to a makeCredential request. * Called to alert native code of a response to a makeCredential request.
*/ */
void onAuthenticatorAttestationResponse(long client, int ctapStatus); void onAuthenticatorAttestationResponse(
long client, int ctapStatus, byte[] attestationObject);
} }
} }
...@@ -9,10 +9,48 @@ ...@@ -9,10 +9,48 @@
#include "components/cbor/values.h" #include "components/cbor/values.h"
#include "components/cbor/writer.h" #include "components/cbor/writer.h"
#include "device/fido/attestation_statement.h" #include "device/fido/attestation_statement.h"
#include "device/fido/authenticator_data.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/opaque_attestation_statement.h"
namespace device { namespace device {
// static
base::Optional<AttestationObject> AttestationObject::Parse(
const cbor::Value& value) {
if (!value.is_map()) {
return base::nullopt;
}
const cbor::Value::MapValue& map = value.GetMap();
const auto& format_it = map.find(cbor::Value(kFormatKey));
if (format_it == map.end() || !format_it->second.is_string()) {
return base::nullopt;
}
const std::string& fmt = format_it->second.GetString();
const auto& att_stmt_it = map.find(cbor::Value(kAttestationStatementKey));
if (att_stmt_it == map.end() || !att_stmt_it->second.is_map()) {
return base::nullopt;
}
std::unique_ptr<AttestationStatement> attestation_statement =
std::make_unique<OpaqueAttestationStatement>(
fmt, cbor::Value(att_stmt_it->second.GetMap()));
const auto& auth_data_it = map.find(cbor::Value(kAuthDataKey));
if (auth_data_it == map.end() || !auth_data_it->second.is_bytestring()) {
return base::nullopt;
}
base::Optional<AuthenticatorData> authenticator_data =
AuthenticatorData::DecodeAuthenticatorData(
auth_data_it->second.GetBytestring());
if (!authenticator_data) {
return base::nullopt;
}
return AttestationObject(std::move(*authenticator_data),
std::move(attestation_statement));
}
AttestationObject::AttestationObject( AttestationObject::AttestationObject(
AuthenticatorData data, AuthenticatorData data,
std::unique_ptr<AttestationStatement> statement) std::unique_ptr<AttestationStatement> statement)
......
...@@ -25,13 +25,12 @@ class AttestationStatement; ...@@ -25,13 +25,12 @@ class AttestationStatement;
// https://www.w3.org/TR/2017/WD-webauthn-20170505/#cred-attestation. // https://www.w3.org/TR/2017/WD-webauthn-20170505/#cred-attestation.
class COMPONENT_EXPORT(DEVICE_FIDO) AttestationObject { class COMPONENT_EXPORT(DEVICE_FIDO) AttestationObject {
public: public:
static base::Optional<AttestationObject> Parse(const cbor::Value& value);
AttestationObject(AuthenticatorData data, AttestationObject(AuthenticatorData data,
std::unique_ptr<AttestationStatement> statement); std::unique_ptr<AttestationStatement> statement);
// Moveable.
AttestationObject(AttestationObject&& other); AttestationObject(AttestationObject&& other);
AttestationObject& operator=(AttestationObject&& other); AttestationObject& operator=(AttestationObject&& other);
~AttestationObject(); ~AttestationObject();
std::vector<uint8_t> GetCredentialId() const; std::vector<uint8_t> GetCredentialId() const;
......
...@@ -15,6 +15,121 @@ ...@@ -15,6 +15,121 @@
namespace device { namespace device {
namespace {
bool IsGetAssertionOptionMapFormatCorrect(
const cbor::Value::MapValue& option_map) {
return std::all_of(
option_map.begin(), option_map.end(), [](const auto& param) {
return param.first.is_string() &&
(param.first.GetString() == kUserPresenceMapKey ||
param.first.GetString() == kUserVerificationMapKey) &&
param.second.is_bool();
});
}
bool AreGetAssertionRequestMapKeysCorrect(
const cbor::Value::MapValue& request_map) {
return std::all_of(
request_map.begin(), request_map.end(), [](const auto& param) {
return (param.first.is_integer() && 1u <= param.first.GetInteger() &&
param.first.GetInteger() <= 7u);
});
}
} // namespace
// static
base::Optional<CtapGetAssertionRequest> CtapGetAssertionRequest::Parse(
const cbor::Value::MapValue& request_map) {
if (!AreGetAssertionRequestMapKeysCorrect(request_map))
return base::nullopt;
const auto rp_id_it = request_map.find(cbor::Value(1));
if (rp_id_it == request_map.end() || !rp_id_it->second.is_string())
return base::nullopt;
const auto client_data_hash_it = request_map.find(cbor::Value(2));
if (client_data_hash_it == request_map.end() ||
!client_data_hash_it->second.is_bytestring() ||
client_data_hash_it->second.GetBytestring().size() !=
kClientDataHashLength) {
return base::nullopt;
}
base::span<const uint8_t, kClientDataHashLength> client_data_hash(
client_data_hash_it->second.GetBytestring().data(),
kClientDataHashLength);
CtapGetAssertionRequest request(rp_id_it->second.GetString(),
/*client_data_json=*/std::string());
request.client_data_hash = fido_parsing_utils::Materialize(client_data_hash);
const auto allow_list_it = request_map.find(cbor::Value(3));
if (allow_list_it != request_map.end()) {
if (!allow_list_it->second.is_array())
return base::nullopt;
const auto& credential_descriptors = allow_list_it->second.GetArray();
if (credential_descriptors.empty())
return base::nullopt;
std::vector<PublicKeyCredentialDescriptor> allow_list;
for (const auto& credential_descriptor : credential_descriptors) {
auto allowed_credential =
PublicKeyCredentialDescriptor::CreateFromCBORValue(
credential_descriptor);
if (!allowed_credential)
return base::nullopt;
allow_list.push_back(std::move(*allowed_credential));
}
request.allow_list = std::move(allow_list);
}
const auto option_it = request_map.find(cbor::Value(5));
if (option_it != request_map.end()) {
if (!option_it->second.is_map())
return base::nullopt;
const auto& option_map = option_it->second.GetMap();
if (!IsGetAssertionOptionMapFormatCorrect(option_map))
return base::nullopt;
const auto user_presence_option =
option_map.find(cbor::Value(kUserPresenceMapKey));
if (user_presence_option != option_map.end()) {
request.user_presence_required = user_presence_option->second.GetBool();
}
const auto uv_option =
option_map.find(cbor::Value(kUserVerificationMapKey));
if (uv_option != option_map.end()) {
request.user_verification =
uv_option->second.GetBool()
? UserVerificationRequirement::kRequired
: UserVerificationRequirement::kDiscouraged;
}
}
const auto pin_auth_it = request_map.find(cbor::Value(6));
if (pin_auth_it != request_map.end()) {
if (!pin_auth_it->second.is_bytestring())
return base::nullopt;
request.pin_auth = pin_auth_it->second.GetBytestring();
}
const auto pin_protocol_it = request_map.find(cbor::Value(7));
if (pin_protocol_it != request_map.end()) {
if (!pin_protocol_it->second.is_unsigned() ||
pin_protocol_it->second.GetUnsigned() >
std::numeric_limits<uint8_t>::max()) {
return base::nullopt;
}
request.pin_protocol = pin_protocol_it->second.GetUnsigned();
}
return request;
}
CtapGetAssertionRequest::CtapGetAssertionRequest( CtapGetAssertionRequest::CtapGetAssertionRequest(
std::string in_rp_id, std::string in_rp_id,
std::string in_client_data_json) std::string in_client_data_json)
......
...@@ -33,6 +33,13 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest { ...@@ -33,6 +33,13 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
public: public:
using ClientDataHash = std::array<uint8_t, kClientDataHashLength>; using ClientDataHash = std::array<uint8_t, kClientDataHashLength>;
// Decodes a CTAP2 authenticatorGetAssertion request message. The request's
// |client_data_json| will be empty and |client_data_hash| will be set.
//
// A |uv| bit of 0 is mapped to UserVerificationRequirement::kDiscouraged.
static base::Optional<CtapGetAssertionRequest> Parse(
const cbor::Value::MapValue& request_map);
CtapGetAssertionRequest(std::string rp_id, std::string client_data_json); CtapGetAssertionRequest(std::string rp_id, std::string client_data_json);
CtapGetAssertionRequest(const CtapGetAssertionRequest& that); CtapGetAssertionRequest(const CtapGetAssertionRequest& that);
CtapGetAssertionRequest(CtapGetAssertionRequest&& that); CtapGetAssertionRequest(CtapGetAssertionRequest&& that);
...@@ -59,8 +66,7 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest { ...@@ -59,8 +66,7 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
bool is_u2f_only = false; bool is_u2f_only = false;
}; };
struct CtapGetNextAssertionRequest { struct CtapGetNextAssertionRequest {};
};
// Serializes GetAssertion request parameter into CBOR encoded map with // Serializes GetAssertion request parameter into CBOR encoded map with
// integer keys and CBOR encoded values as defined by the CTAP spec. // integer keys and CBOR encoded values as defined by the CTAP spec.
......
...@@ -15,6 +15,183 @@ ...@@ -15,6 +15,183 @@
namespace device { namespace device {
namespace {
bool IsMakeCredentialOptionMapFormatCorrect(
const cbor::Value::MapValue& option_map) {
return std::all_of(
option_map.begin(), option_map.end(), [](const auto& param) {
return param.first.is_string() &&
(param.first.GetString() == kResidentKeyMapKey ||
param.first.GetString() == kUserVerificationMapKey) &&
param.second.is_bool();
});
}
bool AreMakeCredentialRequestMapKeysCorrect(
const cbor::Value::MapValue& request_map) {
return std::all_of(
request_map.begin(), request_map.end(), [](const auto& param) {
return (param.first.is_integer() && 1u <= param.first.GetInteger() &&
param.first.GetInteger() <= 9u);
});
}
} // namespace
// static
base::Optional<CtapMakeCredentialRequest> CtapMakeCredentialRequest::Parse(
const cbor::Value::MapValue& request_map) {
if (!AreMakeCredentialRequestMapKeysCorrect(request_map))
return base::nullopt;
const auto client_data_hash_it = request_map.find(cbor::Value(1));
if (client_data_hash_it == request_map.end() ||
!client_data_hash_it->second.is_bytestring() ||
client_data_hash_it->second.GetBytestring().size() !=
kClientDataHashLength) {
return base::nullopt;
}
base::span<const uint8_t, kClientDataHashLength> client_data_hash(
client_data_hash_it->second.GetBytestring().data(),
kClientDataHashLength);
const auto rp_entity_it = request_map.find(cbor::Value(2));
if (rp_entity_it == request_map.end() || !rp_entity_it->second.is_map())
return base::nullopt;
auto rp_entity =
PublicKeyCredentialRpEntity::CreateFromCBORValue(rp_entity_it->second);
if (!rp_entity)
return base::nullopt;
const auto user_entity_it = request_map.find(cbor::Value(3));
if (user_entity_it == request_map.end() || !user_entity_it->second.is_map())
return base::nullopt;
auto user_entity = PublicKeyCredentialUserEntity::CreateFromCBORValue(
user_entity_it->second);
if (!user_entity)
return base::nullopt;
const auto credential_params_it = request_map.find(cbor::Value(4));
if (credential_params_it == request_map.end())
return base::nullopt;
auto credential_params = PublicKeyCredentialParams::CreateFromCBORValue(
credential_params_it->second);
if (!credential_params)
return base::nullopt;
CtapMakeCredentialRequest request(
/*client_data_json=*/std::string(), std::move(*rp_entity),
std::move(*user_entity), std::move(*credential_params));
request.client_data_hash = fido_parsing_utils::Materialize(client_data_hash);
const auto exclude_list_it = request_map.find(cbor::Value(5));
if (exclude_list_it != request_map.end()) {
if (!exclude_list_it->second.is_array())
return base::nullopt;
const auto& credential_descriptors = exclude_list_it->second.GetArray();
std::vector<PublicKeyCredentialDescriptor> exclude_list;
for (const auto& credential_descriptor : credential_descriptors) {
auto excluded_credential =
PublicKeyCredentialDescriptor::CreateFromCBORValue(
credential_descriptor);
if (!excluded_credential)
return base::nullopt;
exclude_list.push_back(std::move(*excluded_credential));
}
request.exclude_list = std::move(exclude_list);
}
const auto extensions_it = request_map.find(cbor::Value(6));
if (extensions_it != request_map.end()) {
if (!extensions_it->second.is_map()) {
return base::nullopt;
}
const auto& extensions = extensions_it->second.GetMap();
const auto hmac_secret_it =
extensions.find(cbor::Value(kExtensionHmacSecret));
if (hmac_secret_it != extensions.end()) {
if (!hmac_secret_it->second.is_bool()) {
return base::nullopt;
}
request.hmac_secret = hmac_secret_it->second.GetBool();
}
const auto cred_protect_it =
extensions.find(cbor::Value(device::kExtensionCredProtect));
if (cred_protect_it != extensions.end()) {
if (!cred_protect_it->second.is_unsigned()) {
return base::nullopt;
}
switch (cred_protect_it->second.GetUnsigned()) {
case 1:
// Default behaviour.
break;
case 2:
request.cred_protect =
std::make_pair(device::CredProtect::kUVOrCredIDRequired, false);
break;
case 3:
request.cred_protect =
std::make_pair(device::CredProtect::kUVRequired, false);
break;
default:
return base::nullopt;
}
}
}
const auto option_it = request_map.find(cbor::Value(7));
if (option_it != request_map.end()) {
if (!option_it->second.is_map())
return base::nullopt;
const auto& option_map = option_it->second.GetMap();
if (!IsMakeCredentialOptionMapFormatCorrect(option_map))
return base::nullopt;
const auto resident_key_option =
option_map.find(cbor::Value(kResidentKeyMapKey));
if (resident_key_option != option_map.end()) {
request.resident_key_required = resident_key_option->second.GetBool();
}
const auto uv_option =
option_map.find(cbor::Value(kUserVerificationMapKey));
if (uv_option != option_map.end()) {
request.user_verification =
uv_option->second.GetBool()
? UserVerificationRequirement::kRequired
: UserVerificationRequirement::kDiscouraged;
}
}
const auto pin_auth_it = request_map.find(cbor::Value(8));
if (pin_auth_it != request_map.end()) {
if (!pin_auth_it->second.is_bytestring())
return base::nullopt;
request.pin_auth = pin_auth_it->second.GetBytestring();
}
const auto pin_protocol_it = request_map.find(cbor::Value(9));
if (pin_protocol_it != request_map.end()) {
if (!pin_protocol_it->second.is_unsigned() ||
pin_protocol_it->second.GetUnsigned() >
std::numeric_limits<uint8_t>::max()) {
return base::nullopt;
}
request.pin_protocol = pin_protocol_it->second.GetUnsigned();
}
return request;
}
CtapMakeCredentialRequest::CtapMakeCredentialRequest( CtapMakeCredentialRequest::CtapMakeCredentialRequest(
std::string in_client_data_json, std::string in_client_data_json,
PublicKeyCredentialRpEntity in_rp, PublicKeyCredentialRpEntity in_rp,
......
...@@ -34,6 +34,11 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest { ...@@ -34,6 +34,11 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
public: public:
using ClientDataHash = std::array<uint8_t, kClientDataHashLength>; using ClientDataHash = std::array<uint8_t, kClientDataHashLength>;
// Decodes a CTAP2 authenticatorMakeCredential request message. The request's
// |client_data_json| will be empty and |client_data_hash| will be set.
static base::Optional<CtapMakeCredentialRequest> Parse(
const cbor::Value::MapValue& request_map);
CtapMakeCredentialRequest( CtapMakeCredentialRequest(
std::string client_data_json, std::string client_data_json,
PublicKeyCredentialRpEntity rp, PublicKeyCredentialRpEntity rp,
......
This diff is collapsed.
...@@ -177,22 +177,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device ...@@ -177,22 +177,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
DISALLOW_COPY_AND_ASSIGN(VirtualCtap2Device); DISALLOW_COPY_AND_ASSIGN(VirtualCtap2Device);
}; };
// Decodes a CBOR-encoded CTAP2 authenticatorMakeCredential request message. The
// request's client_data_json() value will be empty, and the hashed client data
// is returned separately.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::pair<CtapMakeCredentialRequest,
CtapMakeCredentialRequest::ClientDataHash>>
ParseCtapMakeCredentialRequest(const cbor::Value::MapValue& request_map);
// Decodes a CBOR-encoded CTAP2 authenticatorGetAssertion request message. The
// request's client_data_json() value will be empty, and the hashed client data
// is returned separately.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<
std::pair<CtapGetAssertionRequest, CtapGetAssertionRequest::ClientDataHash>>
ParseCtapGetAssertionRequest(const cbor::Value::MapValue& request_map);
} // namespace device } // namespace device
#endif // DEVICE_FIDO_VIRTUAL_CTAP2_DEVICE_H_ #endif // DEVICE_FIDO_VIRTUAL_CTAP2_DEVICE_H_
...@@ -58,36 +58,35 @@ TEST_F(VirtualCtap2DeviceTest, ParseMakeCredentialRequestForVirtualCtapKey) { ...@@ -58,36 +58,35 @@ TEST_F(VirtualCtap2DeviceTest, ParseMakeCredentialRequestForVirtualCtapKey) {
base::make_span(test_data::kCtapMakeCredentialRequest).subspan(1)); base::make_span(test_data::kCtapMakeCredentialRequest).subspan(1));
ASSERT_TRUE(cbor_request); ASSERT_TRUE(cbor_request);
ASSERT_TRUE(cbor_request->is_map()); ASSERT_TRUE(cbor_request->is_map());
const auto request_and_hash = const base::Optional<CtapMakeCredentialRequest> request =
ParseCtapMakeCredentialRequest(cbor_request->GetMap()); CtapMakeCredentialRequest::Parse(cbor_request->GetMap());
ASSERT_TRUE(request_and_hash); ASSERT_TRUE(request);
auto request = std::get<0>(*request_and_hash); EXPECT_THAT(request->client_data_hash,
auto client_data_hash = std::get<1>(*request_and_hash);
EXPECT_THAT(client_data_hash,
::testing::ElementsAreArray(test_data::kClientDataHash)); ::testing::ElementsAreArray(test_data::kClientDataHash));
EXPECT_EQ(test_data::kRelyingPartyId, request.rp.id); EXPECT_EQ(test_data::kRelyingPartyId, request->rp.id);
EXPECT_EQ("Acme", request.rp.name); EXPECT_EQ("Acme", request->rp.name);
EXPECT_THAT(request.user.id, ::testing::ElementsAreArray(test_data::kUserId)); EXPECT_THAT(request->user.id,
ASSERT_TRUE(request.user.name); ::testing::ElementsAreArray(test_data::kUserId));
EXPECT_EQ("johnpsmith@example.com", *request.user.name); ASSERT_TRUE(request->user.name);
ASSERT_TRUE(request.user.display_name); EXPECT_EQ("johnpsmith@example.com", *request->user.name);
EXPECT_EQ("John P. Smith", *request.user.display_name); ASSERT_TRUE(request->user.display_name);
ASSERT_TRUE(request.user.icon_url); EXPECT_EQ("John P. Smith", *request->user.display_name);
ASSERT_TRUE(request->user.icon_url);
EXPECT_EQ("https://pics.acme.com/00/p/aBjjjpqPb.png", EXPECT_EQ("https://pics.acme.com/00/p/aBjjjpqPb.png",
request.user.icon_url->spec()); request->user.icon_url->spec());
ASSERT_EQ(2u, ASSERT_EQ(2u,
request.public_key_credential_params.public_key_credential_params() request->public_key_credential_params.public_key_credential_params()
.size()); .size());
EXPECT_EQ(-7, EXPECT_EQ(-7,
request.public_key_credential_params.public_key_credential_params() request->public_key_credential_params.public_key_credential_params()
.at(0) .at(0)
.algorithm); .algorithm);
EXPECT_EQ(257, EXPECT_EQ(257,
request.public_key_credential_params.public_key_credential_params() request->public_key_credential_params.public_key_credential_params()
.at(1) .at(1)
.algorithm); .algorithm);
EXPECT_EQ(UserVerificationRequirement::kRequired, request.user_verification); EXPECT_EQ(UserVerificationRequirement::kRequired, request->user_verification);
EXPECT_TRUE(request.resident_key_required); EXPECT_TRUE(request->resident_key_required);
} }
TEST_F(VirtualCtap2DeviceTest, ParseGetAssertionRequestForVirtualCtapKey) { TEST_F(VirtualCtap2DeviceTest, ParseGetAssertionRequestForVirtualCtapKey) {
...@@ -111,20 +110,18 @@ TEST_F(VirtualCtap2DeviceTest, ParseGetAssertionRequestForVirtualCtapKey) { ...@@ -111,20 +110,18 @@ TEST_F(VirtualCtap2DeviceTest, ParseGetAssertionRequestForVirtualCtapKey) {
ASSERT_TRUE(cbor_request); ASSERT_TRUE(cbor_request);
ASSERT_TRUE(cbor_request->is_map()); ASSERT_TRUE(cbor_request->is_map());
auto request_and_hash = ParseCtapGetAssertionRequest(cbor_request->GetMap()); const base::Optional<CtapGetAssertionRequest> request =
ASSERT_TRUE(request_and_hash); CtapGetAssertionRequest::Parse(cbor_request->GetMap());
auto request = std::get<0>(*request_and_hash); EXPECT_THAT(request->client_data_hash,
auto client_data_hash = std::get<1>(*request_and_hash);
EXPECT_THAT(client_data_hash,
::testing::ElementsAreArray(test_data::kClientDataHash)); ::testing::ElementsAreArray(test_data::kClientDataHash));
EXPECT_EQ(test_data::kRelyingPartyId, request.rp_id); EXPECT_EQ(test_data::kRelyingPartyId, request->rp_id);
EXPECT_EQ(UserVerificationRequirement::kRequired, request.user_verification); EXPECT_EQ(UserVerificationRequirement::kRequired, request->user_verification);
EXPECT_FALSE(request.user_presence_required); EXPECT_FALSE(request->user_presence_required);
ASSERT_EQ(2u, request.allow_list.size()); ASSERT_EQ(2u, request->allow_list.size());
EXPECT_THAT(request.allow_list.at(0).id(), EXPECT_THAT(request->allow_list.at(0).id(),
::testing::ElementsAreArray(kAllowedCredentialOne)); ::testing::ElementsAreArray(kAllowedCredentialOne));
EXPECT_THAT(request.allow_list.at(1).id(), EXPECT_THAT(request->allow_list.at(1).id(),
::testing::ElementsAreArray(kAllowedCredentialTwo)); ::testing::ElementsAreArray(kAllowedCredentialTwo));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment