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

ash / components / kcer / kcer_nss / kcer_token_impl_nss.h [blame]

// 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 ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_
#define ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_

#include <stdint.h>

#include <queue>
#include <string>
#include <vector>

#include "ash/components/kcer/cert_cache.h"
#include "ash/components/kcer/chaps/high_level_chaps_client.h"
#include "ash/components/kcer/helpers/pkcs12_reader.h"
#include "ash/components/kcer/kcer_token.h"
#include "ash/components/kcer/kcer_token_utils.h"
#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "base/types/strong_alias.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  // ASH_COMPONENTS_KCER_KCER_NSS_KCER_TOKEN_IMPL_NSS_H_