Commit ce160596 authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

webauthn: add test for oversized credential IDs.

I thought that this would trigger a hairpin callback, but it doesn't
because device discovery goes via the MessageLoop in both the virtual
and real-world cases.

Change-Id: I2c44793294189d9171221d1cb9cdb5a706c3869e
Reviewed-on: https://chromium-review.googlesource.com/982634
Commit-Queue: Adam Langley <agl@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548499}
parent acbb420a
......@@ -45,12 +45,14 @@ using webauth::mojom::GetAssertionAuthenticatorResponsePtr;
using webauth::mojom::MakeCredentialAuthenticatorResponsePtr;
using webauth::mojom::PublicKeyCredentialCreationOptions;
using webauth::mojom::PublicKeyCredentialCreationOptionsPtr;
using webauth::mojom::PublicKeyCredentialDescriptor;
using webauth::mojom::PublicKeyCredentialParameters;
using webauth::mojom::PublicKeyCredentialParametersPtr;
using webauth::mojom::PublicKeyCredentialRequestOptions;
using webauth::mojom::PublicKeyCredentialRequestOptionsPtr;
using webauth::mojom::PublicKeyCredentialRpEntity;
using webauth::mojom::PublicKeyCredentialRpEntityPtr;
using webauth::mojom::PublicKeyCredentialType;
using webauth::mojom::PublicKeyCredentialUserEntity;
using webauth::mojom::PublicKeyCredentialUserEntityPtr;
......@@ -653,6 +655,44 @@ TEST_F(AuthenticatorImplTest, TestGetAssertionTimeout) {
EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.status());
}
TEST_F(AuthenticatorImplTest, OversizedCredentialId) {
device::test::ScopedVirtualFidoDevice virtual_device_;
TestServiceManagerContext smc_;
// 255 is the maximum size of a U2F credential ID. We also test one greater
// (256) to ensure that nothing untoward happens.
const std::vector<size_t> kSizes = {255, 256};
for (size_t size : kSizes) {
SCOPED_TRACE(size);
SimulateNavigation(GURL(kTestOrigin1));
AuthenticatorPtr authenticator = ConnectToAuthenticator();
PublicKeyCredentialRequestOptionsPtr options =
GetTestPublicKeyCredentialRequestOptions();
auto credential = PublicKeyCredentialDescriptor::New();
credential->type = PublicKeyCredentialType::PUBLIC_KEY;
credential->id.resize(size);
const bool should_be_valid = size < 256;
if (should_be_valid) {
ASSERT_TRUE(virtual_device_.mutable_state()->InjectRegistration(
credential->id, kTestRelyingPartyId));
}
options->allow_credentials.emplace_back(std::move(credential));
TestGetAssertionCallback cb;
authenticator->GetAssertion(std::move(options), cb.callback());
cb.WaitForCallback();
if (should_be_valid) {
EXPECT_EQ(AuthenticatorStatus::SUCCESS, cb.status());
} else {
EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, cb.status());
}
}
}
enum class IndividualAttestation {
REQUESTED,
NOT_REQUESTED,
......
......@@ -92,6 +92,28 @@ VirtualFidoDevice::State::State()
: attestation_cert_common_name("Batch Certificate"),
individual_attestation_cert_common_name("Individual Certificate") {}
VirtualFidoDevice::State::~State() = default;
bool VirtualFidoDevice::State::InjectRegistration(
const std::vector<uint8_t>& credential_id,
const std::string& relying_party_id) {
std::vector<uint8_t> application_parameter(crypto::kSHA256Length);
crypto::SHA256HashString(relying_party_id, application_parameter.data(),
application_parameter.size());
auto private_key = crypto::ECPrivateKey::Create();
if (!private_key) {
return false;
}
RegistrationData registration(std::move(private_key),
std::move(application_parameter),
0 /* signature counter */);
bool was_inserted;
std::tie(std::ignore, was_inserted) =
registrations.emplace(credential_id, std::move(registration));
return was_inserted;
}
VirtualFidoDevice::VirtualFidoDevice()
: state_(new State), weak_factory_(this) {}
......
......@@ -64,6 +64,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
// Registered keys. Keyed on key handle (a.k.a. "credential ID").
std::map<std::vector<uint8_t>, RegistrationData> registrations;
// Adds a registration for the specified credential ID with the application
// parameter set to be valid for the given relying party ID (which would
// typically be a domain, e.g. "example.com").
//
// Returns true on success. Will fail if there already exists a credential
// with the given ID.
bool InjectRegistration(const std::vector<uint8_t>& credential_id,
const std::string& relying_party_id);
private:
friend class base::RefCounted<State>;
~State();
......
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