| // 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, |
| 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 |