blob: 4fabb370e5b7d9ec23ff81e161d6292a8113c741 [file] [log] [blame]
// Copyright 2020 The Chromium OS 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 "cryptohome/challenge_credentials/fido_utils.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/logging.h>
#include <brillo/secure_blob.h>
#include "cryptohome/crypto/sha.h"
#include "cryptohome/fido.pb.h"
namespace cryptohome {
constexpr char kCrosLoginPrefix[] = "chromeos:login:";
constexpr char kIconUrl[] = "http://www.noicon.google.com";
// Default FIDO request timeout 30s.
constexpr base::TimeDelta kRequestTimeOut = base::TimeDelta::FromSeconds(30);
// MakeCredential only uses ES256 algorithms.
constexpr int kCOSEAlgorithmIdentifierES256 = -7;
std::vector<uint8_t> GetFidoUserId(const std::string& account_id) {
auto digest = Sha256ToSecureBlob(brillo::BlobFromString(account_id));
return std::vector<uint8_t>(digest.begin(), digest.end());
}
std::unique_ptr<cryptohome::fido::PublicKeyCredentialRpEntity>
GetPublicKeyCredentialRpEntity(const std::string& id, const std::string& name) {
auto rp = std::make_unique<cryptohome::fido::PublicKeyCredentialRpEntity>();
rp->set_id(id);
rp->set_name(name);
return rp;
}
// Create User entity. Note the id is a 32-byte unique identifier derived from
// AccountIdentifier.account_id.
std::unique_ptr<cryptohome::fido::PublicKeyCredentialUserEntity>
GetPublicKeyCredentialUserEntity(const std::string& name,
const std::vector<uint8_t>& id,
const std::string& url_str,
const std::string& display_name) {
auto user =
std::make_unique<cryptohome::fido::PublicKeyCredentialUserEntity>();
user->set_name(name);
user->set_id(std::string(id.begin(), id.end()));
auto url = new cryptohome::fido::Url();
url->set_url(url_str);
user->set_allocated_icon(url);
user->set_display_name(display_name);
return user;
}
FidoPKCredCreationOptionsPtr BuildFidoMakeCredentialOptions(
std::unique_ptr<cryptohome::fido::PublicKeyCredentialUserEntity> user,
std::unique_ptr<cryptohome::fido::PublicKeyCredentialRpEntity> rp,
std::vector<uint8_t> challenge,
std::vector<cryptohome::fido::PublicKeyCredentialDescriptor>
exclude_credentials,
base::TimeDelta adjusted_timeout,
std::unique_ptr<cryptohome::fido::CableRegistration>
cable_registration_data,
cryptohome::fido::ProtectionPolicy protection_policy,
bool use_hmac_secret,
bool enforce_protection_policy,
std::string appid_exclude) {
auto options =
std::make_unique<cryptohome::fido::PublicKeyCredentialCreationOptions>();
// Owned by |options| and lifecycle managed by |options|.
options->set_allocated_relying_party(rp.release());
options->set_allocated_user(user.release());
auto param = options->add_public_key_parameters();
param->set_type(cryptohome::fido::PUBLIC_KEY);
param->set_algorithm_identifier(kCOSEAlgorithmIdentifierES256);
options->set_adjusted_timeout(adjusted_timeout.InMilliseconds());
options->set_challenge({challenge.begin(), challenge.end()});
// TODO(xzhou): need to implement attestation signature checking.
options->set_attestation(cryptohome::fido::NONE_ATTESTATION_PREFERENCE);
// Specify the RP's authenticator attributes requirements.
auto authenticator_selection =
std::make_unique<cryptohome::fido::AuthenticatorSelectionCriteria>();
authenticator_selection->set_authenticator_attachment(
cryptohome::fido::NO_PREFERENCE /* equivalent to any or unset */);
authenticator_selection->set_require_resident_key(false);
// TODO(xzhou): If security key supports user verification, we may allow
// security key as single factor authentication.
authenticator_selection->set_user_verification(cryptohome::fido::DISCOURAGED);
options->set_allocated_authenticator_selection(
authenticator_selection.release());
// A list of credentials RP knows about. If an authenticator has one of these
// credentials, it should not create a new one.
for (auto credential : exclude_credentials) {
auto next = options->add_exclude_credentials();
// Deep copy.
next->CopyFrom(credential);
}
if (cable_registration_data) {
options->set_allocated_cable_registration_data(
cable_registration_data.release());
}
options->set_hmac_create_secret(use_hmac_secret);
if (protection_policy != cryptohome::fido::ProtectionPolicy::UNSPECIFIED)
options->set_protection_policy(protection_policy);
options->set_enforce_protection_policy(enforce_protection_policy);
if (!appid_exclude.empty()) {
options->set_appid_exclude(appid_exclude);
}
return options;
}
FidoPKCredCreationOptionsPtr BuildFidoMakeCredentialOptions(
const cryptohome::AccountIdentifier& account,
const std::vector<uint8_t>& challenge,
bool create_hmac_secret) {
if (account.account_id() == "")
return nullptr;
std::vector<uint8_t> fido_account_id = GetFidoUserId(account.account_id());
auto user = GetPublicKeyCredentialUserEntity(
account.email(), /* name */
fido_account_id, /* id */
kIconUrl, account.email() /* display name */);
auto rp = GetPublicKeyCredentialRpEntity(
kCrosLoginPrefix + account.account_id(), /* the relying party id */
"Chrome OS Login" /* relying party name */);
return BuildFidoMakeCredentialOptions(
std::move(user), std::move(rp), challenge, {}, /* exclude credentials */
kRequestTimeOut, nullptr, /* cable registration data */
cryptohome::fido::ProtectionPolicy::UNSPECIFIED, create_hmac_secret,
false, /* enforce protection policy */
"" /* appid exclude */);
}
FidoPKCredRequestOptionsPtr BuildFidoGetAssertionOptions(
std::vector<uint8_t> challenge,
int64_t adjusted_timeout,
std::string relying_party_id,
std::vector<cryptohome::fido::PublicKeyCredentialDescriptor>
allow_credentials,
std::string appid,
std::vector<cryptohome::fido::CableAuthentication>
cable_authentication_data) {
auto options =
std::make_unique<cryptohome::fido::PublicKeyCredentialRequestOptions>();
std::string str_challenge(challenge.begin(), challenge.end());
options->set_challenge(str_challenge);
options->set_adjusted_timeout(adjusted_timeout);
options->set_relying_party_id(relying_party_id);
for (auto& credential : allow_credentials) {
auto next = options->add_allow_credentials();
next->CopyFrom(credential);
}
options->set_appid(appid);
for (const auto& cable_authentication : cable_authentication_data) {
auto next = options->add_cable_authentication_data();
next->CopyFrom(cable_authentication);
}
return options;
}
FidoPKCredRequestOptionsPtr BuildFidoGetAssertionOptions(
std::vector<uint8_t> challenge,
std::string relying_party_id,
std::string appid) {
return BuildFidoGetAssertionOptions(
challenge, kRequestTimeOut.InMilliseconds(), relying_party_id,
{}, /* allow credentials */
appid, {} /* Cloud Assisted BLE authentication data */);
}
} // namespace cryptohome