blob: 0f6d75dd34138ef56d7c702de3b53fd39ce060f1 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/credentialmanager/CredentialManagerTypeConverters.h"
#include <algorithm>
#include <utility>
#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "modules/credentialmanager/Credential.h"
#include "modules/credentialmanager/FederatedCredential.h"
#include "modules/credentialmanager/MakePublicKeyCredentialOptions.h"
#include "modules/credentialmanager/PasswordCredential.h"
#include "modules/credentialmanager/PublicKeyCredential.h"
#include "modules/credentialmanager/PublicKeyCredentialDescriptor.h"
#include "modules/credentialmanager/PublicKeyCredentialParameters.h"
#include "modules/credentialmanager/PublicKeyCredentialRequestOptions.h"
#include "modules/credentialmanager/PublicKeyCredentialRpEntity.h"
#include "modules/credentialmanager/PublicKeyCredentialUserEntity.h"
#include "platform/wtf/Time.h"
namespace {
// Time to wait for an authenticator to successfully complete an operation.
constexpr TimeDelta kAdjustedTimeoutLower = TimeDelta::FromMinutes(1);
constexpr TimeDelta kAdjustedTimeoutUpper = TimeDelta::FromMinutes(2);
WTF::TimeDelta AdjustTimeout(uint32_t timeout) {
WTF::TimeDelta adjusted_timeout;
adjusted_timeout = WTF::TimeDelta::FromMilliseconds(timeout);
return std::max(kAdjustedTimeoutLower,
std::min(kAdjustedTimeoutUpper, adjusted_timeout));
}
} // namespace
namespace mojo {
using password_manager::mojom::blink::CredentialInfo;
using password_manager::mojom::blink::CredentialInfoPtr;
using password_manager::mojom::blink::CredentialType;
using password_manager::mojom::blink::CredentialManagerError;
using webauth::mojom::blink::AuthenticatorStatus;
using webauth::mojom::blink::MakePublicKeyCredentialOptionsPtr;
using webauth::mojom::blink::PublicKeyCredentialDescriptor;
using webauth::mojom::blink::PublicKeyCredentialDescriptorPtr;
using webauth::mojom::blink::PublicKeyCredentialRpEntity;
using webauth::mojom::blink::PublicKeyCredentialRpEntityPtr;
using webauth::mojom::blink::PublicKeyCredentialUserEntity;
using webauth::mojom::blink::PublicKeyCredentialUserEntityPtr;
using webauth::mojom::blink::PublicKeyCredentialParameters;
using webauth::mojom::blink::PublicKeyCredentialParametersPtr;
using webauth::mojom::blink::PublicKeyCredentialRequestOptionsPtr;
using webauth::mojom::blink::PublicKeyCredentialType;
using webauth::mojom::blink::AuthenticatorTransport;
// static
CredentialInfoPtr TypeConverter<CredentialInfoPtr, blink::Credential*>::Convert(
blink::Credential* credential) {
auto info = CredentialInfo::New();
info->id = credential->id();
if (credential->IsPasswordCredential()) {
::blink::PasswordCredential* password_credential =
static_cast<::blink::PasswordCredential*>(credential);
info->type = CredentialType::PASSWORD;
info->password = password_credential->password();
info->name = password_credential->name();
info->icon = password_credential->iconURL();
info->federation = blink::SecurityOrigin::CreateUnique();
} else {
DCHECK(credential->IsFederatedCredential());
::blink::FederatedCredential* federated_credential =
static_cast<::blink::FederatedCredential*>(credential);
info->type = CredentialType::FEDERATED;
info->password = g_empty_string;
info->federation = federated_credential->GetProviderAsOrigin();
info->name = federated_credential->name();
info->icon = federated_credential->iconURL();
}
return info;
}
// static
blink::Credential*
TypeConverter<blink::Credential*, CredentialInfoPtr>::Convert(
const CredentialInfoPtr& info) {
switch (info->type) {
case CredentialType::FEDERATED:
return blink::FederatedCredential::Create(info->id, info->federation,
info->name, info->icon);
case CredentialType::PASSWORD:
return blink::PasswordCredential::Create(info->id, info->password,
info->name, info->icon);
case CredentialType::EMPTY:
return nullptr;
}
NOTREACHED();
return nullptr;
}
// static
CredentialManagerError
TypeConverter<CredentialManagerError, AuthenticatorStatus>::Convert(
const AuthenticatorStatus& status) {
switch (status) {
case webauth::mojom::blink::AuthenticatorStatus::NOT_SUPPORTED_ERROR:
return CredentialManagerError::NOT_SUPPORTED;
case webauth::mojom::blink::AuthenticatorStatus::NOT_ALLOWED_ERROR:
return CredentialManagerError::NOT_ALLOWED;
case webauth::mojom::blink::AuthenticatorStatus::UNKNOWN_ERROR:
return CredentialManagerError::UNKNOWN;
case webauth::mojom::blink::AuthenticatorStatus::PENDING_REQUEST:
return CredentialManagerError::PENDING_REQUEST;
case webauth::mojom::blink::AuthenticatorStatus::INVALID_DOMAIN:
return CredentialManagerError::INVALID_DOMAIN;
case webauth::mojom::blink::AuthenticatorStatus::TIMED_OUT:
return CredentialManagerError::TIMED_OUT;
case webauth::mojom::blink::AuthenticatorStatus::NOT_IMPLEMENTED:
return CredentialManagerError::NOT_IMPLEMENTED;
case webauth::mojom::blink::AuthenticatorStatus::SUCCESS:
NOTREACHED();
break;
}
NOTREACHED();
return CredentialManagerError::UNKNOWN;
}
// static
Vector<uint8_t>
TypeConverter<Vector<uint8_t>, blink::ArrayBufferOrArrayBufferView>::Convert(
const blink::ArrayBufferOrArrayBufferView& buffer) {
DCHECK(!buffer.IsNull());
Vector<uint8_t> vector;
if (buffer.IsArrayBuffer()) {
vector.Append(static_cast<uint8_t*>(buffer.GetAsArrayBuffer()->Data()),
buffer.GetAsArrayBuffer()->ByteLength());
} else {
DCHECK(buffer.IsArrayBufferView());
vector.Append(static_cast<uint8_t*>(
buffer.GetAsArrayBufferView().View()->BaseAddress()),
buffer.GetAsArrayBufferView().View()->byteLength());
}
return vector;
}
// static
PublicKeyCredentialType TypeConverter<PublicKeyCredentialType, String>::Convert(
const String& type) {
if (type == "public-key")
return PublicKeyCredentialType::PUBLIC_KEY;
NOTREACHED();
return PublicKeyCredentialType::PUBLIC_KEY;
}
// static
AuthenticatorTransport TypeConverter<AuthenticatorTransport, String>::Convert(
const String& transport) {
if (transport == "usb")
return AuthenticatorTransport::USB;
if (transport == "nfc")
return AuthenticatorTransport::NFC;
if (transport == "ble")
return AuthenticatorTransport::BLE;
NOTREACHED();
return AuthenticatorTransport::USB;
}
// static
PublicKeyCredentialUserEntityPtr
TypeConverter<PublicKeyCredentialUserEntityPtr,
blink::PublicKeyCredentialUserEntity>::
Convert(const blink::PublicKeyCredentialUserEntity& user) {
auto entity = webauth::mojom::blink::PublicKeyCredentialUserEntity::New();
entity->id = ConvertTo<Vector<uint8_t>>(user.id());
entity->name = user.name();
if (user.hasIcon()) {
entity->icon = blink::KURL(blink::KURL(), user.icon());
}
entity->display_name = user.displayName();
return entity;
}
// static
PublicKeyCredentialRpEntityPtr
TypeConverter<PublicKeyCredentialRpEntityPtr,
blink::PublicKeyCredentialRpEntity>::
Convert(const blink::PublicKeyCredentialRpEntity& rp) {
auto entity = webauth::mojom::blink::PublicKeyCredentialRpEntity::New();
if (rp.hasId()) {
entity->id = rp.id();
}
entity->name = rp.name();
if (rp.hasIcon()) {
entity->icon = blink::KURL(blink::KURL(), rp.icon());
}
return entity;
}
// static
PublicKeyCredentialDescriptorPtr
TypeConverter<PublicKeyCredentialDescriptorPtr,
blink::PublicKeyCredentialDescriptor>::
Convert(const blink::PublicKeyCredentialDescriptor& descriptor) {
auto mojo_descriptor =
webauth::mojom::blink::PublicKeyCredentialDescriptor::New();
mojo_descriptor->type = ConvertTo<PublicKeyCredentialType>(descriptor.type());
mojo_descriptor->id = ConvertTo<Vector<uint8_t>>(descriptor.id());
if (descriptor.hasTransports()) {
for (const auto& transport : descriptor.transports()) {
mojo_descriptor->transports.push_back(
ConvertTo<AuthenticatorTransport>(transport));
}
}
return mojo_descriptor;
}
// static
PublicKeyCredentialParametersPtr
TypeConverter<PublicKeyCredentialParametersPtr,
blink::PublicKeyCredentialParameters>::
Convert(const blink::PublicKeyCredentialParameters& parameter) {
auto mojo_parameter =
webauth::mojom::blink::PublicKeyCredentialParameters::New();
mojo_parameter->type = ConvertTo<PublicKeyCredentialType>(parameter.type());
// A COSEAlgorithmIdentifier's value is a number identifying a cryptographic
// algorithm. Values are registered in the IANA COSE Algorithms registry.
// https://www.iana.org/assignments/cose/cose.xhtml#algorithms
mojo_parameter->algorithm_identifier = parameter.alg();
return mojo_parameter;
}
// static
MakePublicKeyCredentialOptionsPtr
TypeConverter<MakePublicKeyCredentialOptionsPtr,
blink::MakePublicKeyCredentialOptions>::
Convert(const blink::MakePublicKeyCredentialOptions& options) {
auto mojo_options =
webauth::mojom::blink::MakePublicKeyCredentialOptions::New();
mojo_options->relying_party = PublicKeyCredentialRpEntity::From(options.rp());
mojo_options->user = PublicKeyCredentialUserEntity::From(options.user());
if (!mojo_options->relying_party | !mojo_options->user) {
return nullptr;
}
mojo_options->challenge = ConvertTo<Vector<uint8_t>>(options.challenge());
// Step 4 of https://w3c.github.io/webauthn/#createCredential
if (options.hasTimeout()) {
mojo_options->adjusted_timeout = AdjustTimeout(options.timeout());
} else {
mojo_options->adjusted_timeout = kAdjustedTimeoutLower;
}
// Steps 8 and 9 of
// https://www.w3.org/TR/2017/WD-webauthn-20170505/#createCredential
Vector<PublicKeyCredentialParametersPtr> parameters;
for (const auto& parameter : options.pubKeyCredParams()) {
PublicKeyCredentialParametersPtr normalized_parameter =
PublicKeyCredentialParameters::From(parameter);
if (normalized_parameter) {
parameters.push_back(std::move(normalized_parameter));
}
}
if (parameters.IsEmpty() && options.hasPubKeyCredParams()) {
return nullptr;
}
mojo_options->public_key_parameters = std::move(parameters);
if (options.hasExcludeCredentials()) {
// Adds the excludeCredentials members
for (const auto descriptor : options.excludeCredentials()) {
PublicKeyCredentialDescriptorPtr mojo_descriptor =
PublicKeyCredentialDescriptor::From(descriptor);
if (mojo_descriptor) {
mojo_options->exclude_credentials.push_back(std::move(mojo_descriptor));
}
}
}
return mojo_options;
}
// static
PublicKeyCredentialRequestOptionsPtr
TypeConverter<PublicKeyCredentialRequestOptionsPtr,
blink::PublicKeyCredentialRequestOptions>::
Convert(const blink::PublicKeyCredentialRequestOptions& options) {
auto mojo_options =
webauth::mojom::blink::PublicKeyCredentialRequestOptions::New();
mojo_options->challenge = ConvertTo<Vector<uint8_t>>(options.challenge());
if (options.hasTimeout()) {
mojo_options->adjusted_timeout = AdjustTimeout(options.timeout());
} else {
mojo_options->adjusted_timeout = kAdjustedTimeoutLower;
}
mojo_options->relying_party_id = options.rpId();
if (options.hasAllowCredentials()) {
// Adds the allowList members
for (auto descriptor : options.allowCredentials()) {
PublicKeyCredentialDescriptorPtr mojo_descriptor =
PublicKeyCredentialDescriptor::From(descriptor);
if (mojo_descriptor) {
mojo_options->allow_credentials.push_back(std::move(mojo_descriptor));
}
}
}
return mojo_options;
}
} // namespace mojo