1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_
#define CHROMEOS_ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_
#include <stdint.h>
#include <deque>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "base/types/strong_alias.h"
#include "chromeos/ash/components/kcer/cert_cache.h"
#include "chromeos/ash/components/kcer/chaps/high_level_chaps_client.h"
#include "chromeos/ash/components/kcer/helpers/pkcs12_reader.h"
#include "chromeos/ash/components/kcer/kcer_token.h"
#include "chromeos/ash/components/kcer/kcer_token_utils.h"
#include "crypto/scoped_nss_types.h"
#include "net/cert/cert_database.h"
#include "net/cert/scoped_nss_types.h"
#include "net/cert/x509_certificate.h"
#include "third_party/cros_system_api/constants/pkcs11_custom_attributes.h"
namespace kcer::internal {
using KeyPermissionsAttributeId =
base::StrongAlias<class TagKcerToken0,
pkcs11_custom_attributes::CkAttributeType>;
using CertProvisioningIdAttributeId =
base::StrongAlias<class TagKcerToken1,
pkcs11_custom_attributes::CkAttributeType>;
// Implementation of KcerToken that uses NSS as a permanent storage.
// Exported for unit tests only.
class COMPONENT_EXPORT(KCER) KcerTokenImplNss
: public KcerToken,
public net::CertDatabase::Observer {
public:
enum class State {
// Cache must be updated before it can be used.
kCacheOutdated,
// Cache is currently being updated.
kCacheUpdating,
// Cache is up-to-date and can be used.
kCacheUpToDate,
// Terminal state, initialization failed.
kInitializationFailed,
};
explicit KcerTokenImplNss(Token token, HighLevelChapsClient* chaps_client);
~KcerTokenImplNss() override;
KcerTokenImplNss(const KcerTokenImplNss&) = delete;
KcerTokenImplNss& operator=(const KcerTokenImplNss&) = delete;
KcerTokenImplNss(KcerTokenImplNss&&) = delete;
KcerTokenImplNss& operator=(KcerTokenImplNss&&) = delete;
// Returns a weak pointer for the token. The pointer can be used to post tasks
// for the token.
base::WeakPtr<KcerToken> GetWeakPtr() override;
// Initializes the token with the provided NSS slot. If `nss_slot` is nullptr,
// the initialization is considered failed and the token will return an error
// for all queued and future requests.
void InitializeForNss(crypto::ScopedPK11Slot nss_slot) override;
// Implements net::CertDatabase::Observer.
void OnClientCertStoreChanged() override;
// Implements KcerToken.
void GenerateRsaKey(RsaModulusLength modulus_length_bits,
bool hardware_backed,
Kcer::GenerateKeyCallback callback) override;
void GenerateEcKey(EllipticCurve curve,
bool hardware_backed,
Kcer::GenerateKeyCallback callback) override;
void ImportKey(Pkcs8PrivateKeyInfoDer pkcs8_private_key_info_der,
Kcer::ImportKeyCallback callback) override;
void ImportCertFromBytes(CertDer cert_der,
Kcer::StatusCallback callback) override;
void ImportPkcs12Cert(Pkcs12Blob pkcs12_blob,
std::string password,
bool hardware_backed,
bool mark_as_migrated,
Kcer::StatusCallback callback) override;
void ExportPkcs12Cert(scoped_refptr<const Cert> cert,
Kcer::ExportPkcs12Callback callback) override;
void RemoveKeyAndCerts(PrivateKeyHandle key,
Kcer::StatusCallback callback) override;
void RemoveCert(scoped_refptr<const Cert> cert,
Kcer::StatusCallback callback) override;
void ListKeys(TokenListKeysCallback callback) override;
void ListCerts(TokenListCertsCallback callback) override;
void DoesPrivateKeyExist(PrivateKeyHandle key,
Kcer::DoesKeyExistCallback callback) override;
void Sign(PrivateKeyHandle key,
SigningScheme signing_scheme,
DataToSign data,
Kcer::SignCallback callback) override;
void SignRsaPkcs1Raw(PrivateKeyHandle key,
DigestWithPrefix digest_with_prefix,
Kcer::SignCallback callback) override;
void GetTokenInfo(Kcer::GetTokenInfoCallback callback) override;
void GetKeyInfo(PrivateKeyHandle key,
Kcer::GetKeyInfoCallback callback) override;
void GetKeyPermissions(PrivateKeyHandle key,
Kcer::GetKeyPermissionsCallback callback) override;
void GetCertProvisioningProfileId(
PrivateKeyHandle key,
Kcer::GetCertProvisioningProfileIdCallback callback) override;
void SetKeyNickname(PrivateKeyHandle key,
std::string nickname,
Kcer::StatusCallback callback) override;
void SetKeyPermissions(PrivateKeyHandle key,
chaps::KeyPermissions key_permissions,
Kcer::StatusCallback callback) override;
void SetCertProvisioningProfileId(PrivateKeyHandle key,
std::string profile_id,
Kcer::StatusCallback callback) override;
// NSS software database (softoken) doesn't support custom attributes. If
// attribute translation is enabled, KcerToken will store the attributes in
// some standard attributes, which is wrong in general, but good enough for
// tests.
void SetAttributeTranslationForTesting(bool is_enabled);
private:
// Immediately blocks the queue and returns a closure that unblocks it when
// called or destroyed.
base::OnceClosure BlockQueueGetUnblocker();
// Immediately unblocks the queue and attempts to perform the next task.
void UnblockQueueProcessNextTask();
// Updates the cached certificates to match the ones in NSS.
void UpdateCache();
void UpdateCacheWithCerts(net::ScopedCERTCertificateList certs);
// Convenience method for calling the callback with the
// kTokenInitializationFailed error and scheduling the next task.
template <typename T>
void HandleInitializationFailed(
base::OnceCallback<void(base::expected<T, Error>)> callback);
// Used by operations that may modify the set of certificates on the token. If
// `did_modify` is true, dispatches a notification that the certificate store
// changed. Then forwards `result` to `callback`. Note that `did_modify` may
// be true even if `result` contains an error, because some operations can be
// partially successful.
void OnCertsModified(Kcer::StatusCallback callback,
bool did_modify,
base::expected<void, Error> result);
// These methods return PKCS#11 attribute IDs that should be passed to NSS,
// respecting SetAttributeTranslationForTesting.
KeyPermissionsAttributeId GetKeyPermissionsAttributeId() const;
CertProvisioningIdAttributeId GetCertProvisioningIdAttributeId() const;
// Indicates whether fake attribute ids should be used (for testing).
bool translate_attributes_for_testing_ = false;
// Indicates whether the task queue is blocked. Task queue should be blocked
// until NSS is initialized, during the processing of most requests and
// during updating the cache.
bool is_blocked_ = true;
State state_ = State::kCacheOutdated;
// Token type of this KcerToken.
const Token token_;
// The underlying storage for KcerTokenNss. In this context the words "token"
// and "slot" are synonyms.
crypto::ScopedPK11Slot slot_;
// Queue for the tasks that were received while the task queue was blocked.
std::deque<base::OnceClosure> task_queue_;
// Cache for certificates.
CertCache cert_cache_;
// Created and initialized on the same thread with KcerTokenImplNss, then only
// accessed on the UI thread. It's safe to post tasks for it, the destruction
// task is posted from the destructor of this class.
std::unique_ptr<KcerTokenUtils> kcer_utils_;
base::WeakPtrFactory<KcerTokenImplNss> weak_factory_{this};
};
} // namespace kcer::internal
#endif // CHROMEOS_ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_
|