0

[webauthn] Send permissions list with UVToken

When sending getPinUvAuthTokenUsingUvWithPermissions, the permissions
list is required [1]. Since we are only using UVToken for make
credential and get assertion, and sometimes making a credential involves
getting assertions, request those two permissions with every UVToken
request.

[1] https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#permissions-list

Fixed: 1086558
Change-Id: I572850efafb02ab9d292465379d385751adac101
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2220258
Commit-Queue: Nina Satragno <nsatragno@chromium.org>
Commit-Queue: Martin Kreichgauer <martinkr@google.com>
Auto-Submit: Nina Satragno <nsatragno@chromium.org>
Reviewed-by: Martin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#774189}
This commit is contained in:
Nina Satragno
2020-06-02 17:03:22 +00:00
committed by Commit Bot
parent c5df6fa134
commit 4f6b4c4e67
4 changed files with 51 additions and 7 deletions

@ -521,6 +521,9 @@ AsCTAPRequestValuePair(const UvTokenRequest& request) {
Subcommand::kGetUvToken, [&request](cbor::Value::MapValue* map) {
map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
std::move(request.cose_key_));
map->emplace(static_cast<int>(RequestKey::kPermissions),
static_cast<uint8_t>(Permissions::kMakeCredential) |
static_cast<uint8_t>(Permissions::kGetAssertion));
});
}

@ -35,12 +35,26 @@ enum class Subcommand : uint8_t {
// RequestKey enumerates the keys in the top-level CBOR map for all PIN
// commands.
enum class RequestKey : int {
kProtocol = 1,
kSubcommand = 2,
kKeyAgreement = 3,
kPINAuth = 4,
kNewPINEnc = 5,
kPINHashEnc = 6,
kProtocol = 0x01,
kSubcommand = 0x02,
kKeyAgreement = 0x03,
kPINAuth = 0x04,
kNewPINEnc = 0x05,
kPINHashEnc = 0x06,
kMinPINLength = 0x07,
kMinPINLengthRPIDs = 0x08,
kPermissions = 0x09,
kPermissionsRPID = 0x0A,
};
// Permission list flags. See
// https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#permissions
enum class Permissions : uint8_t {
kMakeCredential = 0x01,
kGetAssertion = 0x02,
kCredentialManagement = 0x04,
kBioEnrollment = 0x08,
kPlatformConfiguration = 0x10,
};
// ResponseKey enumerates the keys in the top-level CBOR map for all PIN

@ -683,7 +683,12 @@ VirtualCtap2Device::CheckUserVerification(
kSupportedAndPinSet ||
options.supports_uv_token)) {
DCHECK(pin_protocol && *pin_protocol == 1);
if (CheckPINToken(pin_token, *pin_auth, client_data_hash)) {
auto permission = is_make_credential ? pin::Permissions::kMakeCredential
: pin::Permissions::kGetAssertion;
if (mutable_state()->pin_uv_token_permissions &
static_cast<uint8_t>(permission) &&
CheckPINToken(pin_token, *pin_auth, client_data_hash)) {
uv = true;
} else {
return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
@ -1331,6 +1336,13 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnPINCommand(
return err;
};
mutable_state()->pin_retries = kMaxPinRetries;
// Set default PinUvAuthToken permissions.
mutable_state()->pin_uv_token_permissions =
static_cast<uint8_t>(pin::Permissions::kMakeCredential) |
static_cast<uint8_t>(pin::Permissions::kGetAssertion);
response_map.emplace(
static_cast<int>(pin::ResponseKey::kPINToken),
GenerateAndEncryptToken(shared_key, mutable_state()->pin_token));
@ -1344,6 +1356,17 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnPINCommand(
return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
}
const auto permissions_it = request_map.find(
cbor::Value(static_cast<int>(pin::RequestKey::kPermissions)));
if (permissions_it == request_map.end() ||
!permissions_it->second.is_unsigned()) {
return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
}
uint8_t permissions = permissions_it->second.GetUnsigned();
if (permissions == 0) {
return CtapDeviceResponseCode::kCtap1ErrInvalidParameter;
}
if (device_info_->options.user_verification_availability ==
AuthenticatorSupportedOptions::UserVerificationAvailability::
kSupportedButNotConfigured) {
@ -1375,6 +1398,7 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnPINCommand(
mutable_state()->pin_retries = kMaxPinRetries;
mutable_state()->uv_retries = kMaxUvRetries;
mutable_state()->pin_uv_token_permissions = permissions;
response_map.emplace(
static_cast<int>(pin::ResponseKey::kPINToken),

@ -165,6 +165,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
// The random PIN token that is returned as a placeholder for the PIN
// itself.
uint8_t pin_token[32];
// The permissions parameter for |pin_token|.
// TODO(nsatragno): implement permissions RPID.
uint8_t pin_uv_token_permissions = 0;
// Number of internal UV retries remaining.
int uv_retries = kMaxUvRetries;