// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ash/crosapi/keystore_service_ash.h"
#include <stdint.h>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/debug/dump_without_crashing.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
#include "base/unguessable_token.h"
#include "chrome/browser/ash/attestation/tpm_challenge_key.h"
#include "chrome/browser/ash/platform_keys/key_permissions/key_permissions_service.h"
#include "chrome/browser/ash/platform_keys/key_permissions/key_permissions_service_factory.h"
#include "chrome/browser/ash/platform_keys/platform_keys_service.h"
#include "chrome/browser/ash/platform_keys/platform_keys_service_factory.h"
#include "chrome/browser/chromeos/platform_keys/extension_platform_keys_service.h"
#include "chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/ash/components/dbus/attestation/attestation_ca.pb.h"
#include "chromeos/crosapi/cpp/keystore_service_util.h"
#include "chromeos/crosapi/mojom/keystore_error.mojom.h"
#include "chromeos/crosapi/mojom/keystore_service.mojom-shared.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "net/cert/x509_certificate.h"
#include "third_party/boringssl/src/include/openssl/pool.h"
namespace crosapi {
namespace {
using SigningAlgorithmName = mojom::KeystoreSigningAlgorithmName;
using SigningScheme = mojom::KeystoreSigningScheme;
using ::ash::platform_keys::KeyPermissionsService;
using ::ash::platform_keys::PlatformKeysService;
using ::chromeos::ExtensionPlatformKeysService;
using ::chromeos::platform_keys::TokenId;
const char kUnsupportedKeystoreType[] = "The token is not valid.";
const char kDeprecatedMethodError[] = "Deprecated method was called.";
// Converts a binary blob to a certificate.
scoped_refptr<net::X509Certificate> ParseCertificate(
const std::vector<uint8_t>& input) {
// Allow UTF-8 inside PrintableStrings in client certificates. See
// crbug.com/770323 and crbug.com/788655.
net::X509Certificate::UnsafeCreateOptions options;
options.printable_string_is_utf8 = true;
return net::X509Certificate::CreateFromBytesUnsafeOptions(input, options);
}
std::optional<TokenId> KeystoreToToken(mojom::KeystoreType type) {
if (!crosapi::mojom::IsKnownEnumValue(type)) {
return std::nullopt;
}
switch (type) {
case mojom::KeystoreType::kUser:
return TokenId::kUser;
case mojom::KeystoreType::kDevice:
return TokenId::kSystem;
}
}
std::optional<std::string> StringFromSigningAlgorithmName(
SigningAlgorithmName name) {
switch (name) {
case SigningAlgorithmName::kRsassaPkcs115:
return crosapi::keystore_service_util::kWebCryptoRsassaPkcs1v15;
case SigningAlgorithmName::kEcdsa:
return crosapi::keystore_service_util::kWebCryptoEcdsa;
case SigningAlgorithmName::kUnknown:
return std::nullopt;
}
}
bool UnpackSigningScheme(
SigningScheme scheme,
chromeos::platform_keys::KeyType* key_type,
chromeos::platform_keys::HashAlgorithm* hash_algorithm) {
using chromeos::platform_keys::HashAlgorithm;
using chromeos::platform_keys::KeyType;
switch (scheme) {
case SigningScheme::kUnknown:
return false;
case SigningScheme::kRsassaPkcs1V15None:
*key_type = KeyType::kRsassaPkcs1V15;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_NONE;
return true;
case SigningScheme::kRsassaPkcs1V15Sha1:
*key_type = KeyType::kRsassaPkcs1V15;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA1;
return true;
case SigningScheme::kRsassaPkcs1V15Sha256:
*key_type = KeyType::kRsassaPkcs1V15;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA256;
return true;
case SigningScheme::kRsassaPkcs1V15Sha384:
*key_type = KeyType::kRsassaPkcs1V15;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA384;
return true;
case SigningScheme::kRsassaPkcs1V15Sha512:
*key_type = KeyType::kRsassaPkcs1V15;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA512;
return true;
case SigningScheme::kEcdsaSha1:
*key_type = KeyType::kEcdsa;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA1;
return true;
case SigningScheme::kEcdsaSha256:
*key_type = KeyType::kEcdsa;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA256;
return true;
case SigningScheme::kEcdsaSha384:
*key_type = KeyType::kEcdsa;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA384;
return true;
case SigningScheme::kEcdsaSha512:
*key_type = KeyType::kEcdsa;
*hash_algorithm = HashAlgorithm::HASH_ALGORITHM_SHA512;
return true;
}
NOTREACHED_IN_MIGRATION();
return false;
}
} // namespace
KeystoreServiceAsh::KeystoreServiceAsh(content::BrowserContext* fixed_context)
: fixed_platform_keys_service_(
ash::platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(
fixed_context)),
fixed_key_permissions_service_(
ash::platform_keys::KeyPermissionsServiceFactory::
GetForBrowserContext(fixed_context)) {
CHECK(fixed_platform_keys_service_);
CHECK(fixed_key_permissions_service_);
}
KeystoreServiceAsh::KeystoreServiceAsh(
PlatformKeysService* platform_keys_service,
KeyPermissionsService* key_permissions_service)
: fixed_platform_keys_service_(platform_keys_service),
fixed_key_permissions_service_(key_permissions_service) {
CHECK(fixed_platform_keys_service_);
CHECK(fixed_key_permissions_service_);
}
KeystoreServiceAsh::KeystoreServiceAsh() = default;
KeystoreServiceAsh::~KeystoreServiceAsh() = default;
void KeystoreServiceAsh::BindReceiver(
mojo::PendingReceiver<mojom::KeystoreService> receiver) {
receivers_.Add(this, std::move(receiver));
}
PlatformKeysService* KeystoreServiceAsh::GetPlatformKeys() {
if (fixed_platform_keys_service_) {
return fixed_platform_keys_service_;
}
PlatformKeysService* service =
ash::platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(
ProfileManager::GetPrimaryUserProfile());
CHECK(service);
return service;
}
KeyPermissionsService* KeystoreServiceAsh::GetKeyPermissions() {
if (fixed_key_permissions_service_) {
return fixed_key_permissions_service_;
}
KeyPermissionsService* service =
ash::platform_keys::KeyPermissionsServiceFactory::GetForBrowserContext(
ProfileManager::GetPrimaryUserProfile());
CHECK(service);
return service;
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::ChallengeAttestationOnlyKeystore(
mojom::KeystoreType type,
const std::vector<uint8_t>& challenge,
bool migrate,
mojom::KeystoreSigningAlgorithmName algorithm,
ChallengeAttestationOnlyKeystoreCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!crosapi::mojom::IsKnownEnumValue(type)) {
std::move(callback).Run(
mojom::ChallengeAttestationOnlyKeystoreResult::NewErrorMessage(
kUnsupportedKeystoreType));
return;
}
attestation::KeyType key_crypto_type;
switch (algorithm) {
// Use RSA by default for backwards compatibility.
case mojom::KeystoreSigningAlgorithmName::kUnknown:
case mojom::KeystoreSigningAlgorithmName::kRsassaPkcs115:
key_crypto_type = attestation::KEY_TYPE_RSA;
break;
case mojom::KeystoreSigningAlgorithmName::kEcdsa:
key_crypto_type = attestation::KEY_TYPE_ECC;
break;
}
attestation::VerifiedAccessFlow flow_type;
switch (type) {
case mojom::KeystoreType::kUser:
flow_type = attestation::ENTERPRISE_USER;
break;
case mojom::KeystoreType::kDevice:
flow_type = attestation::ENTERPRISE_MACHINE;
break;
}
Profile* profile = ProfileManager::GetActiveUserProfile();
std::string key_name_for_spkac;
if (migrate && (flow_type == attestation::ENTERPRISE_MACHINE)) {
key_name_for_spkac = base::StrCat(
{ash::attestation::kEnterpriseMachineKeyForSpkacPrefix, "keystore-",
base::UnguessableToken::Create().ToString()});
}
// The lifetime of this object is bound to the callback.
std::unique_ptr<ash::attestation::TpmChallengeKey> challenge_key =
ash::attestation::TpmChallengeKeyFactory::Create();
ash::attestation::TpmChallengeKey* challenge_key_ptr = challenge_key.get();
outstanding_challenges_.push_back(std::move(challenge_key));
challenge_key_ptr->BuildResponse(
flow_type, profile,
base::BindOnce(&KeystoreServiceAsh::DidChallengeAttestationOnlyKeystore,
weak_factory_.GetWeakPtr(), std::move(callback),
challenge_key_ptr),
std::string(challenge.begin(), challenge.end()),
/*register_key=*/migrate, key_crypto_type, key_name_for_spkac,
/*signals=*/std::nullopt);
}
void KeystoreServiceAsh::DidChallengeAttestationOnlyKeystore(
ChallengeAttestationOnlyKeystoreCallback callback,
void* challenge_key_ptr,
const ash::attestation::TpmChallengeKeyResult& result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
crosapi::mojom::ChallengeAttestationOnlyKeystoreResultPtr result_ptr;
if (result.IsSuccess()) {
result_ptr =
mojom::ChallengeAttestationOnlyKeystoreResult::NewChallengeResponse(
std::vector<uint8_t>(result.challenge_response.begin(),
result.challenge_response.end()));
} else {
result_ptr = mojom::ChallengeAttestationOnlyKeystoreResult::NewErrorMessage(
result.GetErrorMessage());
}
std::move(callback).Run(std::move(result_ptr));
// Remove the outstanding challenge_key object.
bool found = false;
for (auto it = outstanding_challenges_.begin();
it != outstanding_challenges_.end(); ++it) {
if (it->get() == challenge_key_ptr) {
outstanding_challenges_.erase(it);
found = true;
break;
}
}
DCHECK(found);
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_ChallengeAttestationOnlyKeystore(
const std::string& challenge,
mojom::KeystoreType type,
bool migrate,
DEPRECATED_ChallengeAttestationOnlyKeystoreCallback callback) {
LOG(ERROR) << "DEPRECATED_ChallengeAttestationOnlyKeystore was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(
mojom::DEPRECATED_KeystoreStringResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::GetKeyStores(GetKeyStoresCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
GetPlatformKeys()->GetTokens(base::BindOnce(
&KeystoreServiceAsh::DidGetKeyStores, std::move(callback)));
}
// static
void KeystoreServiceAsh::DidGetKeyStores(
GetKeyStoresCallback callback,
const std::vector<TokenId> platform_keys_token_ids,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::GetKeyStoresResultPtr result_ptr;
if (status == chromeos::platform_keys::Status::kSuccess) {
std::vector<mojom::KeystoreType> key_stores;
for (const TokenId token_id : platform_keys_token_ids) {
switch (token_id) {
case TokenId::kUser:
key_stores.push_back(mojom::KeystoreType::kUser);
break;
case TokenId::kSystem:
key_stores.push_back(mojom::KeystoreType::kDevice);
break;
}
}
result_ptr = mojom::GetKeyStoresResult::NewKeyStores(std::move(key_stores));
} else {
result_ptr = mojom::GetKeyStoresResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_GetKeyStores(
DEPRECATED_GetKeyStoresCallback callback) {
LOG(ERROR) << "DEPRECATED_GetKeyStores method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(mojom::DEPRECATED_GetKeyStoresResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::SelectClientCertificates(
const std::vector<std::vector<uint8_t>>& certificate_authorities,
SelectClientCertificatesCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::vector<std::string> cert_authorities_str;
cert_authorities_str.reserve(certificate_authorities.size());
for (const std::vector<uint8_t>& ca : certificate_authorities) {
cert_authorities_str.emplace_back(ca.begin(), ca.end());
}
GetPlatformKeys()->SelectClientCertificates(
std::move(cert_authorities_str),
base::BindOnce(&KeystoreServiceAsh::DidSelectClientCertificates,
std::move(callback)));
}
// static
void KeystoreServiceAsh::DidSelectClientCertificates(
SelectClientCertificatesCallback callback,
std::unique_ptr<net::CertificateList> matches,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::KeystoreSelectClientCertificatesResultPtr result_ptr;
if (status == chromeos::platform_keys::Status::kSuccess) {
std::vector<std::vector<uint8_t>> output;
for (scoped_refptr<net::X509Certificate> cert : *matches) {
CRYPTO_BUFFER* der_buffer = cert->cert_buffer();
const uint8_t* data = CRYPTO_BUFFER_data(der_buffer);
std::vector<uint8_t> der_x509_certificate(
data, data + CRYPTO_BUFFER_len(der_buffer));
output.push_back(std::move(der_x509_certificate));
}
result_ptr = mojom::KeystoreSelectClientCertificatesResult::NewCertificates(
std::move(output));
} else {
result_ptr = mojom::KeystoreSelectClientCertificatesResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::GetCertificates(mojom::KeystoreType keystore,
GetCertificatesCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PlatformKeysService* platform_keys_service = GetPlatformKeys();
std::optional<TokenId> token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(mojom::GetCertificatesResult::NewError(
mojom::KeystoreError::kUnsupportedKeystoreType));
return;
}
platform_keys_service->GetCertificates(
token_id.value(), base::BindOnce(&KeystoreServiceAsh::DidGetCertificates,
std::move(callback)));
}
// static
void KeystoreServiceAsh::DidGetCertificates(
GetCertificatesCallback callback,
std::unique_ptr<net::CertificateList> certs,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::GetCertificatesResultPtr result_ptr;
if (status == chromeos::platform_keys::Status::kSuccess) {
std::vector<std::vector<uint8_t>> output;
for (scoped_refptr<net::X509Certificate> cert : *certs) {
CRYPTO_BUFFER* der_buffer = cert->cert_buffer();
const uint8_t* data = CRYPTO_BUFFER_data(der_buffer);
std::vector<uint8_t> der_x509_certificate(
data, data + CRYPTO_BUFFER_len(der_buffer));
output.push_back(std::move(der_x509_certificate));
}
result_ptr =
mojom::GetCertificatesResult::NewCertificates(std::move(output));
} else {
result_ptr = mojom::GetCertificatesResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_GetCertificates(
mojom::KeystoreType keystore,
DEPRECATED_GetCertificatesCallback callback) {
LOG(ERROR) << "DEPRECATED_GetCertificates method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(
mojom::DEPRECATED_GetCertificatesResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::AddCertificate(mojom::KeystoreType keystore,
const std::vector<uint8_t>& certificate,
AddCertificateCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
scoped_refptr<net::X509Certificate> cert_x509 = ParseCertificate(certificate);
if (!cert_x509.get()) {
std::move(callback).Run(/*is_error=*/true,
mojom::KeystoreError::kCertificateInvalid);
return;
}
std::optional<TokenId> token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(/*is_error=*/true,
mojom::KeystoreError::kUnsupportedKeystoreType);
return;
}
PlatformKeysService* platform_keys_service = GetPlatformKeys();
platform_keys_service->ImportCertificate(
token_id.value(), cert_x509,
base::BindOnce(&KeystoreServiceAsh::DidImportCertificate,
std::move(callback)));
}
void KeystoreServiceAsh::DidImportCertificate(
AddCertificateCallback callback,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (status == chromeos::platform_keys::Status::kSuccess) {
std::move(callback).Run(/*is_error=*/false, mojom::KeystoreError::kUnknown);
} else {
std::move(callback).Run(
/*is_error=*/true,
chromeos::platform_keys::StatusToKeystoreError(status));
}
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_AddCertificate(
mojom::KeystoreType keystore,
const std::vector<uint8_t>& certificate,
DEPRECATED_AddCertificateCallback callback) {
LOG(ERROR) << "DEPRECATED_AddCertificate method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(kDeprecatedMethodError);
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::RemoveCertificate(
mojom::KeystoreType keystore,
const std::vector<uint8_t>& certificate,
RemoveCertificateCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
scoped_refptr<net::X509Certificate> cert_x509 = ParseCertificate(certificate);
if (!cert_x509.get()) {
std::move(callback).Run(/*is_error=*/true,
mojom::KeystoreError::kCertificateInvalid);
return;
}
std::optional<TokenId> token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(/*is_error=*/true,
mojom::KeystoreError::kUnsupportedKeystoreType);
return;
}
PlatformKeysService* platform_keys_service = GetPlatformKeys();
platform_keys_service->RemoveCertificate(
token_id.value(), cert_x509,
base::BindOnce(&KeystoreServiceAsh::DidRemoveCertificate,
std::move(callback)));
}
void KeystoreServiceAsh::DidRemoveCertificate(
RemoveCertificateCallback callback,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (status == chromeos::platform_keys::Status::kSuccess) {
std::move(callback).Run(/*is_error=*/false, mojom::KeystoreError::kUnknown);
} else {
std::move(callback).Run(
/*is_error=*/true,
chromeos::platform_keys::StatusToKeystoreError(status));
}
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_RemoveCertificate(
mojom::KeystoreType keystore,
const std::vector<uint8_t>& certificate,
DEPRECATED_RemoveCertificateCallback callback) {
LOG(ERROR) << "DEPRECATED_RemoveCertificate method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(kDeprecatedMethodError);
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::GetPublicKey(
const std::vector<uint8_t>& certificate,
mojom::KeystoreSigningAlgorithmName algorithm_name,
GetPublicKeyCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::optional<std::string> name =
StringFromSigningAlgorithmName(algorithm_name);
if (!name) {
std::move(callback).Run(mojom::GetPublicKeyResult::NewError(
mojom::KeystoreError::kAlgorithmNotPermittedByCertificate));
return;
}
chromeos::platform_keys::GetPublicKeyAndAlgorithmOutput output =
chromeos::platform_keys::GetPublicKeyAndAlgorithm(certificate,
name.value());
mojom::GetPublicKeyResultPtr result_ptr;
if (output.status == chromeos::platform_keys::Status::kSuccess) {
std::optional<crosapi::mojom::KeystoreSigningAlgorithmPtr>
signing_algorithm =
crosapi::keystore_service_util::SigningAlgorithmFromDictionary(
output.algorithm);
if (signing_algorithm) {
mojom::GetPublicKeySuccessResultPtr success_result_ptr =
mojom::GetPublicKeySuccessResult::New();
success_result_ptr->public_key = std::move(output.public_key);
success_result_ptr->algorithm_properties =
std::move(signing_algorithm.value());
result_ptr = mojom::GetPublicKeyResult::NewSuccessResult(
std::move(success_result_ptr));
} else {
result_ptr = mojom::GetPublicKeyResult::NewError(
crosapi::mojom::KeystoreError::kUnsupportedAlgorithmType);
}
} else {
result_ptr = mojom::GetPublicKeyResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(output.status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_GetPublicKey(
const std::vector<uint8_t>& certificate,
mojom::KeystoreSigningAlgorithmName algorithm_name,
DEPRECATED_GetPublicKeyCallback callback) {
LOG(ERROR) << "DEPRECATED_GetPublicKey method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(mojom::DEPRECATED_GetPublicKeyResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_ExtensionGenerateKey(
mojom::KeystoreType keystore,
mojom::KeystoreSigningAlgorithmPtr algorithm,
const std::optional<std::string>& extension_id,
DEPRECATED_ExtensionGenerateKeyCallback callback) {
LOG(ERROR) << "DEPRECATED_ExtensionGenerateKey method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(
mojom::DEPRECATED_ExtensionKeystoreBinaryResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::DEPRECATED_ExtensionSign(
KeystoreType keystore,
const std::vector<uint8_t>& public_key,
SigningScheme scheme,
const std::vector<uint8_t>& data,
const std::string& extension_id,
DEPRECATED_ExtensionSignCallback callback) {
LOG(ERROR) << "DEPRECATED_ExtensionSign method was called.";
base::debug::DumpWithoutCrashing();
std::move(callback).Run(
mojom::DEPRECATED_ExtensionKeystoreBinaryResult::NewErrorMessage(
kDeprecatedMethodError));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::GenerateKey(
mojom::KeystoreType keystore,
mojom::KeystoreSigningAlgorithmPtr algorithm,
GenerateKeyCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PlatformKeysService* platform_keys_service = GetPlatformKeys();
std::optional<TokenId> token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(mojom::KeystoreBinaryResult::NewError(
mojom::KeystoreError::kUnsupportedKeystoreType));
return;
}
using Tag = mojom::KeystoreSigningAlgorithm::Tag;
switch (algorithm->which()) {
case Tag::kPkcs115: {
platform_keys_service->GenerateRSAKey(
token_id.value(), algorithm->get_pkcs115()->modulus_length,
algorithm->get_pkcs115()->sw_backed,
base::BindOnce(&KeystoreServiceAsh::DidGenerateKey,
std::move(callback)));
return;
}
case Tag::kEcdsa: {
platform_keys_service->GenerateECKey(
token_id.value(), algorithm->get_ecdsa()->named_curve,
base::BindOnce(&KeystoreServiceAsh::DidGenerateKey,
std::move(callback)));
return;
}
default: {
std::move(callback).Run(mojom::KeystoreBinaryResult::NewError(
mojom::KeystoreError::kAlgorithmNotSupported));
return;
}
}
}
// static
void KeystoreServiceAsh::DidGenerateKey(
GenerateKeyCallback callback,
std::vector<uint8_t> public_key,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
crosapi::mojom::KeystoreBinaryResultPtr result_ptr;
if (status == chromeos::platform_keys::Status::kSuccess) {
result_ptr = mojom::KeystoreBinaryResult::NewBlob(std::move(public_key));
} else {
result_ptr = mojom::KeystoreBinaryResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::RemoveKey(KeystoreType keystore,
const std::vector<uint8_t>& public_key,
RemoveKeyCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::optional<TokenId> token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(/*is_error=*/true,
mojom::KeystoreError::kUnsupportedKeystoreType);
return;
}
GetPlatformKeys()->RemoveKey(
token_id.value(), public_key,
base::BindOnce(&KeystoreServiceAsh::DidRemoveKey, std::move(callback)));
}
// static
void KeystoreServiceAsh::DidRemoveKey(RemoveKeyCallback callback,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (status == chromeos::platform_keys::Status::kSuccess) {
std::move(callback).Run(/*is_error=*/false, mojom::KeystoreError::kUnknown);
} else {
std::move(callback).Run(
/*is_error=*/true,
chromeos::platform_keys::StatusToKeystoreError(status));
}
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::Sign(bool is_keystore_provided,
KeystoreType keystore,
const std::vector<uint8_t>& public_key,
SigningScheme scheme,
const std::vector<uint8_t>& data,
SignCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::optional<TokenId> token_id;
if (is_keystore_provided) {
token_id = KeystoreToToken(keystore);
if (!token_id) {
std::move(callback).Run(mojom::KeystoreBinaryResult::NewError(
mojom::KeystoreError::kUnsupportedKeystoreType));
return;
}
}
chromeos::platform_keys::KeyType key_type;
chromeos::platform_keys::HashAlgorithm hash_algorithm;
if (!UnpackSigningScheme(scheme, &key_type, &hash_algorithm)) {
std::move(callback).Run(mojom::KeystoreBinaryResult::NewError(
mojom::KeystoreError::kUnsupportedAlgorithmType));
return;
}
PlatformKeysService* service = GetPlatformKeys();
auto cb = base::BindOnce(&KeystoreServiceAsh::DidSign, std::move(callback));
switch (key_type) {
case chromeos::platform_keys::KeyType::kRsassaPkcs1V15:
if (hash_algorithm == chromeos::platform_keys::HASH_ALGORITHM_NONE) {
service->SignRSAPKCS1Raw(token_id, data, public_key, std::move(cb));
return;
}
service->SignRsaPkcs1(token_id, data, public_key, hash_algorithm,
std::move(cb));
return;
case chromeos::platform_keys::KeyType::kEcdsa:
service->SignEcdsa(token_id, data, public_key, hash_algorithm,
std::move(cb));
return;
}
}
// static
void KeystoreServiceAsh::DidSign(SignCallback callback,
std::vector<uint8_t> signature,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (status == chromeos::platform_keys::Status::kSuccess) {
std::move(callback).Run(
mojom::KeystoreBinaryResult::NewBlob(std::move(signature)));
} else {
std::move(callback).Run(mojom::KeystoreBinaryResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status)));
}
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::GetKeyTags(const std::vector<uint8_t>& public_key,
GetKeyTagsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
GetKeyPermissions()->IsCorporateKey(
public_key,
base::BindOnce(&KeystoreServiceAsh::DidGetKeyTags, std::move(callback)));
}
// static
void KeystoreServiceAsh::DidGetKeyTags(GetKeyTagsCallback callback,
std::optional<bool> corporate,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
using KeyTag = crosapi::mojom::KeyTag;
crosapi::mojom::GetKeyTagsResultPtr result_ptr;
if (status == chromeos::platform_keys::Status::kSuccess) {
DCHECK(corporate.has_value());
static_assert(sizeof(uint64_t) >= sizeof(KeyTag),
"Too many enum values for uint64_t");
uint64_t tags = static_cast<uint64_t>(KeyTag::kNoTags);
if (corporate.value()) {
tags |= static_cast<uint64_t>(KeyTag::kCorporate);
}
result_ptr = crosapi::mojom::GetKeyTagsResult::NewTags(tags);
} else {
result_ptr = crosapi::mojom::GetKeyTagsResult::NewError(
chromeos::platform_keys::StatusToKeystoreError(status));
}
std::move(callback).Run(std::move(result_ptr));
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::AddKeyTags(const std::vector<uint8_t>& public_key,
uint64_t tags,
AddKeyTagsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (tags == static_cast<uint64_t>(mojom::KeyTag::kNoTags)) {
std::move(callback).Run(/*is_error=*/false,
crosapi::mojom::KeystoreError::kUnknown);
return;
}
if (tags == static_cast<uint64_t>(mojom::KeyTag::kCorporate)) {
GetKeyPermissions()->SetCorporateKey(
public_key, base::BindOnce(&KeystoreServiceAsh::DidAddKeyTags,
std::move(callback)));
return;
}
std::move(callback).Run(/*is_error=*/true,
crosapi::mojom::KeystoreError::kUnsupportedKeyTag);
}
// static
void KeystoreServiceAsh::DidAddKeyTags(AddKeyTagsCallback callback,
chromeos::platform_keys::Status status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (status == chromeos::platform_keys::Status::kSuccess) {
std::move(callback).Run(/*is_error=*/false, mojom::KeystoreError::kUnknown);
} else {
std::move(callback).Run(
/*is_error=*/true,
chromeos::platform_keys::StatusToKeystoreError(status));
}
}
//------------------------------------------------------------------------------
void KeystoreServiceAsh::CanUserGrantPermissionForKey(
const std::vector<uint8_t>& public_key,
CanUserGrantPermissionForKeyCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Strictly speaking, crosapi::CanUserGrantPermissionForKeyCallback is a
// different type than platform_keys::CanUserGrantPermissionForKeyCallback.
// But as long as signatures are the same, we can just pass `callback`.
GetKeyPermissions()->CanUserGrantPermissionForKey(public_key,
std::move(callback));
}
} // namespace crosapi