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 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_EXTENSION_PLATFORM_KEYS_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_EXTENSION_PLATFORM_KEYS_SERVICE_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/queue.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/platform_keys/key_permissions/key_permissions_service.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
#include "chromeos/crosapi/mojom/keystore_error.mojom.h"
#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
class BrowserContext;
class WebContents;
} // namespace content
namespace net {
class X509Certificate;
typedef std::vector<scoped_refptr<X509Certificate>> CertificateList;
} // namespace net
namespace chromeos {
class ExtensionPlatformKeysService : public KeyedService {
public:
// The SelectDelegate is used to select a single certificate from all
// certificates matching a request (see SelectClientCertificates). E.g. this
// can happen by exposing UI to let the user select.
class SelectDelegate {
public:
using CertificateSelectedCallback =
base::OnceCallback<void(scoped_refptr<net::X509Certificate> selection)>;
SelectDelegate();
SelectDelegate(const SelectDelegate&) = delete;
auto operator=(const SelectDelegate&) = delete;
virtual ~SelectDelegate();
// Called on an interactive SelectClientCertificates call with the list of
// matching certificates, |certs|.
// The certificate passed to |callback| will be forwarded to the
// calling extension and the extension will get unlimited sign permission
// for this cert. By passing null to |callback|, no cert will be selected.
// Must eventually call |callback| or be destructed. |callback| must not be
// called after this delegate is destructed.
// |web_contents| and |context| provide the context in which the
// certificates were requested and are not null.
virtual void Select(const std::string& extension_id,
const net::CertificateList& certs,
CertificateSelectedCallback callback,
content::WebContents* web_contents,
content::BrowserContext* context) = 0;
};
// |browser_context| must not be null and must outlive this object.
explicit ExtensionPlatformKeysService(
content::BrowserContext* browser_context);
ExtensionPlatformKeysService(const ExtensionPlatformKeysService&) = delete;
auto operator=(const ExtensionPlatformKeysService&) = delete;
~ExtensionPlatformKeysService() override;
// Sets the delegate which will be used for interactive
// SelectClientCertificates calls.
void SetSelectDelegate(std::unique_ptr<SelectDelegate> delegate);
// If the generation was successful, |public_key_spki_der| will contain the
// DER encoding of the SubjectPublicKeyInfo of the generated key. If it
// failed, |public_key_spki_der| will be empty.
using GenerateKeyCallback = base::OnceCallback<void(
std::vector<uint8_t> public_key_spki_der,
std::optional<crosapi::mojom::KeystoreError> error)>;
// Generates a RSA key pair with `modulus_length_bits` and marks the key as
// corporate. `key_type` should be either `kRsassaPkcs1V15` or `kRsaOaep` (the
// only RSA key algorithms currently supported). If `key_type` is equal to
// `kRsassaPkcs1V15`, the key will be registered to allow a single sign
// operation by the given extension. `token_id` specifies the token to store
// the key pair on. If `sw_backed` is true, the generated RSA key pair will be
// software-backed. If the generation was successful, `callback` will be
// invoked with the resulting public key. If it failed, the resulting public
// key will be empty. Will only call back during the lifetime of this object.
void GenerateRSAKey(platform_keys::TokenId token_id,
platform_keys::KeyType key_type,
unsigned int modulus_length_bits,
bool sw_backed,
std::string extension_id,
GenerateKeyCallback callback);
// Generates an EC key pair with `named_curve`, marks the key as corporate,
// and registers it to allow a single sign operation by the given extension.
// `key_type` should be `kEcdsa` (the only EC key algorithm currently
// supported). `token_id` specifies the token to store the key pair on. If the
// generation was successful, `callback` will be invoked with the resulting
// public key. If it failed, the resulting public key will be empty. Will only
// call back during the lifetime of this object.
void GenerateECKey(platform_keys::TokenId token_id,
platform_keys::KeyType key_type,
std::string named_curve,
std::string extension_id,
GenerateKeyCallback callback);
// Gets the current profile using the BrowserContext object and returns
// whether the current profile is a sign in profile with
// ProfileHelper::IsSigninProfile.
bool IsUsingSigninProfile();
// If signing was successful, |signature| will contain the signature. If it
// failed, |signature| will be empty.
using SignCallback = base::OnceCallback<void(
std::vector<uint8_t> signature,
std::optional<crosapi::mojom::KeystoreError> error)>;
// Digests |data|, applies PKCS1 padding if specified by |hash_algorithm| and
// chooses the signature algorithm according to |key_type| and signs the data
// with the private key matching |public_key_spki_der|. If a |token_id|
// is provided and the key is not found in that token, the operation aborts.
// If |token_id| is not provided (nullopt), all tokens available to the caller
// will be considered while searching for the key.
// If the extension does not have permissions for signing with this key, the
// operation aborts. In case of a one time permission (granted after
// generating the key), this function also removes the permission to prevent
// future signing attempts. If signing was successful, |callback| will be
// invoked with the signature. If it failed, the resulting signature will be
// empty. Will only call back during the lifetime of this object.
void SignDigest(std::optional<platform_keys::TokenId> token_id,
std::vector<uint8_t> data,
std::vector<uint8_t> public_key_spki_der,
platform_keys::KeyType key_type,
platform_keys::HashAlgorithm hash_algorithm,
std::string extension_id,
SignCallback callback);
// Applies PKCS1 padding and afterwards signs the data with the private key
// matching |public_key_spki_der|. |data| is not digested. If a |token_id|
// is provided and the key is not found in that token, the operation aborts.
// If |token_id| is not provided (nullopt), all available tokens to the caller
// will be considered while searching for the key. The size of |data| (number
// of octets) must be smaller than k - 11, where k is the key size in octets.
// If the extension does not have permissions for signing with this key, the
// operation aborts. In case of a one time permission (granted after
// generating the key), this function also removes the permission to prevent
// future signing attempts. If signing was successful, |callback| will be
// invoked with the signature. If it failed, the resulting signature will be
// empty. Will only call back during the lifetime of this object.
void SignRSAPKCS1Raw(std::optional<platform_keys::TokenId> token_id,
std::vector<uint8_t> data,
std::vector<uint8_t> public_key_spki_der,
std::string extension_id,
SignCallback callback);
// If the certificate request could be processed successfully, |matches| will
// contain the list of matching certificates (maybe empty). If an error
// occurred, |matches| will be null.
using SelectCertificatesCallback = base::OnceCallback<void(
std::unique_ptr<net::CertificateList> matches,
std::optional<crosapi::mojom::KeystoreError> error)>;
// Returns a list of certificates matching |request|.
// 1) all certificates that match the request (like being rooted in one of the
// give CAs) are determined.
// 2) if |client_certificates| is not null, drops all certificates that are
// not elements of |client_certificates|,
// 3) if |interactive| is true, the currently set SelectDelegate is used to
// select a single certificate from these matches
// which will the extension will also be granted access to.
// 4) only certificates, that the extension has unlimited sign permission for,
// will be returned.
// If selection was successful, |callback| will be invoked with these
// certificates. If it failed, the resulting certificate list will be empty
// and an error status will be returned. Will only call back during the
// lifetime of this object. |web_contents| must not be null.
void SelectClientCertificates(
const platform_keys::ClientCertificateRequest& request,
std::unique_ptr<net::CertificateList> client_certificates,
bool interactive,
std::string extension_id,
SelectCertificatesCallback callback,
content::WebContents* web_contents);
using SetKeyTagCallback = base::OnceCallback<void(
std::optional<crosapi::mojom::KeystoreError> error)>;
// Sets a custom |tag| to a key that matches |public_key_spki_der|. This tag
// can later be used to find the key based on some external logic.
// |token_id| represents the token where the key is located.
// If the extension does not have permissions to use this key, the
// operation aborts. In any case |callback| will be invoked and if the
// operation failed it will contain an error. Will only call back during the
// lifetime of this object.
void SetKeyTag(platform_keys::TokenId token_id,
std::vector<uint8_t> tag,
std::vector<uint8_t> public_key_spki_der,
std::string extension_id,
SetKeyTagCallback callback);
private:
class GenerateRSAKeyTask;
class GenerateECKeyTask;
class GenerateKeyTask;
class SelectTask;
class SignTask;
class SetKeyTagTask;
class Task;
// Starts |task| eventually. To ensure that at most one |Task| is running at a
// time, it queues |task| for later execution if necessary.
void StartOrQueueTask(std::unique_ptr<Task> task);
// Must be called after |task| is done. |task| will be invalid after this
// call. This must not be called for any but the task that ran last. If any
// other tasks are queued (see StartOrQueueTask()), it will start the next
// one.
void TaskFinished(Task* task);
const raw_ptr<content::BrowserContext> browser_context_ = nullptr;
const raw_ptr<crosapi::mojom::KeystoreService> keystore_service_ = nullptr;
std::unique_ptr<SelectDelegate> select_delegate_;
base::queue<std::unique_ptr<Task>> tasks_;
base::WeakPtrFactory<ExtensionPlatformKeysService> weak_factory_{this};
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_EXTENSION_PLATFORM_KEYS_SERVICE_H_
|