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 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
|
// 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_H_
#define CHROMEOS_ASH_COMPONENTS_KCER_KCER_H_
#include <stdint.h>
#include <optional>
#include <string>
#include <vector>
#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/task_runner.h"
#include "base/types/expected.h"
#include "base/types/strong_alias.h"
#include "chromeos/ash/components/kcer/key_permissions.pb.h"
#include "net/cert/x509_certificate.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
namespace kcer {
// Strong alias to Kcer related types to prevent incorrect cross-assignment.
using Pkcs11Id = base::StrongAlias<class TypeTagPkcs11Id, std::vector<uint8_t>>;
using Signature =
base::StrongAlias<class TypeTagSignature, std::vector<uint8_t>>;
using PublicKeySpki =
base::StrongAlias<class TypeTagPublicKeySpki, std::vector<uint8_t>>;
using CertDer = base::StrongAlias<class TypeTagCertDer, std::vector<uint8_t>>;
using Pkcs8PrivateKeyInfoDer =
base::StrongAlias<class TypeTagPkcs8PrivateKeyInfoDer,
std::vector<uint8_t>>;
using Pkcs12Blob =
base::StrongAlias<class TypeTagPkcs12Blob, std::vector<uint8_t>>;
using DataToSign =
base::StrongAlias<class TypeTagDataToSign, std::vector<uint8_t>>;
// Digest of the DataToSign. If the signing algorithm expects a prefix (such as
// DigestInfo for RSA), it is already prepended for this type.
using DigestWithPrefix =
base::StrongAlias<class TypeTagDigestWithPrefix, std::vector<uint8_t>>;
// Values should not be reused or renumbered.
enum class COMPONENT_EXPORT(KCER) Error {
kUnknownError = 0,
kNotImplemented = 1,
kNotSupported = 2,
kTokenIsNotAvailable = 3,
kTokenInitializationFailed = 4,
kFailedToGenerateKey = 5,
kFailedToExportPublicKey = 6,
kFailedToEncodePublicKey = 7,
kFailedToImportKey = 8,
kInvalidCertificate = 9,
kFailedToImportCertificate = 10,
kFailedToRemoveCertificate = 11,
kKeyNotFound = 12,
kUnknownKeyType = 13,
kFailedToGetKeyId = 14,
kFailedToReadAttribute = 15,
kFailedToWriteAttribute = 16,
kFailedToParseKeyPermissions = 17,
kUnexpectedSigningScheme = 18,
kKeyDoesNotSupportSigningScheme = 19,
kFailedToSignFailedToDigest = 20,
kFailedToSignFailedToAddPrefix = 21,
kFailedToSignFailedToGetSignatureLength = 22,
kFailedToSign = 23,
kFailedToSignBadSignatureLength = 24,
kFailedToDerEncode = 25,
kInputTooLong = 26,
kFailedToListKeys = 27,
kFailedToRemovePrivateKey = 28,
kFailedToRemovePublicKey = 29,
kFailedToRemoveObjects = 30,
kFailedToCreateSpki = 31,
kFailedToGetPkcs11Id = 32,
kFailedToSearchForObjects = 33,
kPkcs11SessionFailure = 34,
kBadKeyParams = 35,
kUnexpectedFindResult = 36,
kFailedToDecodeKeyAttributes = 37,
kFailedToRetrieveMechanismList = 38,
kFailedToParseKey = 39,
kFailedToGetIssuerName = 40,
kFailedToGetSubjectName = 41,
kFailedToGetSerialNumber = 42,
kFailedToParsePkcs12 = 43,
kInvalidPkcs12 = 44,
kPkcs12WrongPassword = 45,
kPkcs12InvalidMac = 46,
kFailedToMakeCertNickname = 47,
kAlreadyExists = 48,
kMaxValue = kAlreadyExists,
};
// Handles for tokens on ChromeOS.
enum class COMPONENT_EXPORT(KCER) Token {
// Keys and certificates storage that belongs to a specific user.
kUser,
// Keys and certificates storage that belongs to the entire
// device (some users might still not have access to it).
kDevice,
kMaxValue = kDevice,
};
// Additional info related to a token.
struct COMPONENT_EXPORT(KCER) TokenInfo {
// PKCS#11 id assigned to the token by Chaps.
// Unstable across restarts.
uint32_t pkcs11_id = 0;
// Human readable name of the token.
std::string token_name;
// Human readable name of the module (i.e. Chaps).
std::string module_name;
};
enum class COMPONENT_EXPORT(KCER) KeyType {
kRsa,
kEcc,
};
// Supported sizes for RSA keys. It's allowed to static_cast the values to
// uint32_t.
enum class COMPONENT_EXPORT(KCER) RsaModulusLength {
k1024 = 1024,
k2048 = 2048,
k4096 = 4096
};
enum class COMPONENT_EXPORT(KCER) EllipticCurve {
kP256,
};
// Possible sign schemes (aka algorithms) for Kcer::Sign() method. Maps 1-to-1
// to OpenSSL SSL_* constants. It is allowed to cast SigningScheme to SSL_*.
enum class COMPONENT_EXPORT(KCER) SigningScheme {
kRsaPkcs1Sha1 = SSL_SIGN_RSA_PKCS1_SHA1,
kRsaPkcs1Sha256 = SSL_SIGN_RSA_PKCS1_SHA256,
kRsaPkcs1Sha384 = SSL_SIGN_RSA_PKCS1_SHA384,
kRsaPkcs1Sha512 = SSL_SIGN_RSA_PKCS1_SHA512,
kEcdsaSecp256r1Sha256 = SSL_SIGN_ECDSA_SECP256R1_SHA256,
kEcdsaSecp384r1Sha384 = SSL_SIGN_ECDSA_SECP384R1_SHA384,
kEcdsaSecp521r1Sha512 = SSL_SIGN_ECDSA_SECP521R1_SHA512,
kRsaPssRsaeSha256 = SSL_SIGN_RSA_PSS_RSAE_SHA256,
kRsaPssRsaeSha384 = SSL_SIGN_RSA_PSS_RSAE_SHA384,
kRsaPssRsaeSha512 = SSL_SIGN_RSA_PSS_RSAE_SHA512,
};
class COMPONENT_EXPORT(KCER) PublicKey {
public:
// Public for implementations of Kcer interface, should not be used by end
// users.
PublicKey(Token token, Pkcs11Id pkcs11_id, PublicKeySpki pub_key_spki);
PublicKey(const PublicKey&);
PublicKey& operator=(const PublicKey&);
PublicKey(PublicKey&&);
PublicKey& operator=(PublicKey&&);
~PublicKey();
bool operator==(const PublicKey& other) const;
bool operator!=(const PublicKey& other) const;
Token GetToken() const { return token_; }
const Pkcs11Id& GetPkcs11Id() const { return pkcs11_id_; }
const PublicKeySpki& GetSpki() const { return pub_key_spki_; }
private:
Token token_;
Pkcs11Id pkcs11_id_;
PublicKeySpki pub_key_spki_;
};
// Additional info related to a key pair.
struct COMPONENT_EXPORT(KCER) KeyInfo {
KeyInfo();
~KeyInfo();
KeyInfo(const KeyInfo&);
KeyInfo& operator=(const KeyInfo&);
KeyInfo(KeyInfo&&);
KeyInfo& operator=(KeyInfo&&);
bool is_hardware_backed;
KeyType key_type;
std::vector<SigningScheme> supported_signing_schemes;
std::optional<std::string> nickname;
};
class COMPONENT_EXPORT(KCER) Cert : public base::RefCountedThreadSafe<Cert> {
public:
// Public for implementations of Kcer interface, should not be used by end
// users.
Cert(Token token,
Pkcs11Id pkcs11_id,
std::string nickname,
scoped_refptr<net::X509Certificate> x509_cert);
Token GetToken() const { return token_; }
const Pkcs11Id& GetPkcs11Id() const { return pkcs11_id_; }
// Gets nickname of the certificate (not to be confused with
// the nickname of the key).
const std::string& GetNickname() const { return nickname_; }
scoped_refptr<net::X509Certificate> GetX509Cert() const { return x509_cert_; }
private:
friend class base::RefCountedThreadSafe<Cert>;
~Cert();
const Token token_;
const Pkcs11Id pkcs11_id_;
const std::string nickname_;
const scoped_refptr<net::X509Certificate> x509_cert_;
};
// Handle for a private key. Can be trivially constructed from other related
// objects. It's primarily just a convenience class to call methods that usually
// would require a private key (e.g. Sign). If the corresponding private key
// does not actually exist, the methods will return an error.
class COMPONENT_EXPORT(KCER) PrivateKeyHandle {
public:
explicit PrivateKeyHandle(const PublicKey& public_key);
explicit PrivateKeyHandle(const Cert&);
PrivateKeyHandle(Token token, PublicKeySpki pub_key_spki);
// If possible, prefer specifying the token (use another constructor) for
// better performance. Calling a Kcer method using this overload will make it
// search on all tokens for the key before proceeding with the request.
explicit PrivateKeyHandle(PublicKeySpki pub_key_spki);
// Used internally to convert from `PrivateKeyHandle(PublicKeySpki)`. `other`
// must have no token set.
PrivateKeyHandle(Token token, PrivateKeyHandle&& other);
~PrivateKeyHandle();
PrivateKeyHandle(const PrivateKeyHandle&);
PrivateKeyHandle& operator=(const PrivateKeyHandle&);
PrivateKeyHandle(PrivateKeyHandle&&);
PrivateKeyHandle& operator=(PrivateKeyHandle&&);
// Public for implementations of Kcer only.
const std::optional<Token>& GetTokenInternal() const { return token_; }
const Pkcs11Id& GetPkcs11IdInternal() const { return pkcs11_id_; }
const PublicKeySpki& GetSpkiInternal() const { return pub_key_spki_; }
void SetPkcs11IdInternal(Pkcs11Id pkcs11_id) {
pkcs11_id_ = std::move(pkcs11_id);
}
private:
// Depending on how PrivateKeyHandle is constructed, some member variables
// might not contain valid values, possible combinations:
// * Only `token_` and `pkcs11_id_` are populated.
// * Only `token_` and `pub_key_spki_` are populated.
// * Only `pub_key_spki_` is populated.
// * All member variables are populated.
std::optional<Token> token_;
Pkcs11Id pkcs11_id_;
PublicKeySpki pub_key_spki_;
};
// All the methods provided by Kcer. If the underlying storage is not ready when
// a method is called, it will be queued and executed later.
// Implementation note: most methods take arguments by value so they can be
// moved into base::BindOnce (without extra copy) and posted on a different
// sequence (where tokens live). The callbacks might be executed synchronously
// (without re-posting them).
class COMPONENT_EXPORT(KCER) Kcer {
public:
// base::expected<void, Error> could also be expressed as
// std::optional<Error>, but then result.has_value() would mean opposite
// things for methods with base::expected vs std::optional.
using StatusCallback = base::OnceCallback<void(base::expected<void, Error>)>;
using GenerateKeyCallback =
base::OnceCallback<void(base::expected<PublicKey, Error>)>;
using ImportKeyCallback =
base::OnceCallback<void(base::expected<PublicKey, Error>)>;
using ExportPkcs12Callback =
base::OnceCallback<void(base::expected<CertDer, Error>)>;
using ListKeysCallback =
base::OnceCallback<void(std::vector<PublicKey>,
base::flat_map<Token, Error>)>;
using ListCertsCallback =
base::OnceCallback<void(std::vector<scoped_refptr<const Cert>>,
base::flat_map<Token, Error>)>;
using DoesKeyExistCallback =
base::OnceCallback<void(base::expected<bool, Error>)>;
using SignCallback =
base::OnceCallback<void(base::expected<Signature, Error>)>;
using GetAvailableTokensCallback =
base::OnceCallback<void(base::flat_set<Token>)>;
using GetTokenInfoCallback =
base::OnceCallback<void(base::expected<TokenInfo, Error>)>;
using GetKeyInfoCallback =
base::OnceCallback<void(base::expected<KeyInfo, Error>)>;
using GetKeyPermissionsCallback = base::OnceCallback<void(
base::expected<std::optional<chaps::KeyPermissions>, Error>)>;
using GetCertProvisioningProfileIdCallback = base::OnceCallback<void(
base::expected<std::optional<std::string>, Error>)>;
Kcer() = default;
virtual ~Kcer() = default;
// Saves the `callback` that will be called when client certificates are
// imported / removed.
virtual base::CallbackListSubscription AddObserver(
base::RepeatingClosure callback) = 0;
// Generates a new RSA key pair in the `token`. If `hardware_backed` is false,
// the key pair will not be hardware protected (by the TPM). Software keys are
// usually faster, but less secure. Returns a public key on success, an error
// otherwise.
// TODO(miersh): Software keys are currently only implemented in Ash because
// they are only used there. When Kcer-without-NSS is implemented, they should
// work everywhere.
virtual void GenerateRsaKey(Token token,
RsaModulusLength modulus_length_bits,
bool hardware_backed,
GenerateKeyCallback callback) = 0;
// Generates a new EC key pair in the `token`. If `hardware_backed` is false,
// the key pair will not be hardware protected (by the TPM). Software keys are
// usually faster, but less secure. Returns a public key on success, an error
// otherwise.
virtual void GenerateEcKey(Token token,
EllipticCurve curve,
bool hardware_backed,
GenerateKeyCallback callback) = 0;
// Imports a key pair from bytes `key_pair` in the PKCS#8 format (DER encoded)
// into the `token` (as software-backed). It is caller's responsibility to
// make sure that the same key doesn't end up on several different tokens at
// the same time (otherwise Kcer is allowed to perform any future operations,
// such as RemoveKey, with only one of the keys). Returns a public key on
// success, an error otherwise. WARNING: With the current implementation the
// key can be used with most other methods, but it won't appear in the
// ListKeys() results.
// TODO(miersh): Make ListKeys() return imported keys.
virtual void ImportKey(Token token,
Pkcs8PrivateKeyInfoDer pkcs8_private_key_info_der,
ImportKeyCallback callback) = 0;
// Imports a client certificate from bytes `cert` (DER-encoded X.509
// certificate) into the `token`. A key pair for it should already exist on
// the token (will fail otherwise). Returns an error on failure.
virtual void ImportCertFromBytes(Token token,
CertDer cert_der,
StatusCallback callback) = 0;
// Imports an X.509 certificate `cert` into the `token`. A key pair for it
// should already exist on the token (will fail otherwise). Returns
// base::nullopt on success, an error otherwise.
virtual void ImportX509Cert(Token token,
scoped_refptr<net::X509Certificate> cert,
StatusCallback callback) = 0;
// Imports a client certificate and its private key from `pkcs12_blob` encoded
// in the PKCS#12 format into the `token`. If `hardware_backed` is false, the
// key will not be hardware protected (by the TPM). Returns an error on
// failure. If `mark_as_migrated` is true, all created objects will be marked
// with a special attribute to allow a rollback for b/264387231.
virtual void ImportPkcs12Cert(Token token,
Pkcs12Blob pkcs12_blob,
std::string password,
bool hardware_backed,
bool mark_as_migrated,
StatusCallback callback) = 0;
// Exports an existing certificate in the PKCS#12 format. Returns a non-empty
// certificate (as bytes) on success, an error otherwise. Only certificates
// that were imported using `ImportPkcs12Cert` and are not hardware protected
// are guaranteed to be exportable. Certificates with hardware protected keys
// can never be exported in PKCS#12 format.
virtual void ExportPkcs12Cert(scoped_refptr<const Cert> cert,
ExportPkcs12Callback callback) = 0;
// Removes the key pair and associated client certificates (if any exist).
// Returns an error on failure.
virtual void RemoveKeyAndCerts(PrivateKeyHandle key,
StatusCallback callback) = 0;
// Removes the client certificate. The key for the certificate will remain in
// the storage. Returns success if the cert was removed or already not
// present. Returns an error on failure.
virtual void RemoveCert(scoped_refptr<const Cert> cert,
StatusCallback callback) = 0;
// Lists available key pairs from `tokens`. Each key pair is represented by
// its public key. Returns a vector of public keys that were successfully
// retrieved and a map with errors from each token (can be empty).
virtual void ListKeys(base::flat_set<Token> tokens,
ListKeysCallback callback) = 0;
// Lists available client certificates from `tokens`. Returns a vector of
// scoped_refptr<const Cert>'s that were successfully retrieved and a map with
// errors from each token (can be empty).
virtual void ListCerts(base::flat_set<Token> tokens,
ListCertsCallback callback) = 0;
// Checks whether the private key for the handle `key` exists in the
// certificate storage. Returns true if the key exists, false if it doesn't
// exist, an error if failed to check.
virtual void DoesPrivateKeyExist(PrivateKeyHandle key,
DoesKeyExistCallback callback) = 0;
// Signs `data` using the private `key`. The data will be hashed and signed
// according to the `signing_scheme`. Returns a non-empty signature on
// success, an error otherwise.
virtual void Sign(PrivateKeyHandle key,
SigningScheme signing_scheme,
DataToSign data,
SignCallback callback) = 0;
// Applies RSASSA-PKCS1-v1_5 padding and afterwards signs the `digest` (a
// pre-hashed value) with the private `key` (must be RSA). PKCS1 DigestInfo is
// expected to already be prepended to the `digest`. The size of `digest`
// (number of octets) must be smaller than k-11, where k is the key size in
// octets. Returns a non-empty signature on success, an error otherwise.
//
// WARNING: digest_with_prefix must be the result of hashing the data to be
// signed with a secure hash function, then wrapping in the corresponding
// DigestInfo structure, as described in RSASSA-PKCS1-v1_5. Passing in any
// other input, notably skipping the hash operation, will not result in a
// secure signature scheme. This function does not check either of these and,
// instead, callers are assumed to be trusted to do this.
//
// This is currently only used for the CertProvisioning feature and may not be
// used in other contexts. Please consult Kcer owners if the Sign API does not
// meet your needs.
virtual void SignRsaPkcs1Raw(PrivateKeyHandle key,
DigestWithPrefix digest_with_prefix,
SignCallback callback) = 0;
// Returns tokens that are available to the current instance of Kcer.
virtual void GetAvailableTokens(GetAvailableTokensCallback callback) = 0;
// Retrieves additional info for the loaded `token`. Returns a `TokenInfo`
// struct on success, kTokenNotAvailable if the `token` will never be loaded,
// kTokenLoading if the `token` is still loading (can eventually transition
// into kTokenNotAvailable), some other error otherwise.
virtual void GetTokenInfo(Token token, GetTokenInfoCallback callback) = 0;
// Retrieves additional info for the `key`. Returns a `KeyInfo` struct on
// success, an error otherwise.
virtual void GetKeyInfo(PrivateKeyHandle key,
GetKeyInfoCallback callback) = 0;
// Retrieves key permissions for the `key` (see key_permissions.proto).
virtual void GetKeyPermissions(PrivateKeyHandle key,
GetKeyPermissionsCallback callback) = 0;
// Retrieves "certificate provisioning profile id" for the `key` (i.e.
// "cert_profile_id" from RequiredClientCertificateForUser.yaml and
// RequiredClientCertificateForDevice.yaml).
virtual void GetCertProvisioningProfileId(
PrivateKeyHandle key,
GetCertProvisioningProfileIdCallback callback) = 0;
// Sets the `nickname` on the `key`. (Not to be confused with the nickname of
// the certificate.) Returns an error on failure.
// The nickname on the key is partially independent from the certificates'
// nicknames and is stored as CKA_LABEL in PKCS#11 attributes of the key
// object. When a new certificate is imported, its nickname might be copied
// into the key's nickname (TODO(miersh): this part should be changed in the
// future), but generally speaking they are not kept in sync.
virtual void SetKeyNickname(PrivateKeyHandle key,
std::string nickname,
StatusCallback callback) = 0;
// Sets the `key_permissions` on the `key`. Returns an error on failure.
virtual void SetKeyPermissions(PrivateKeyHandle key,
chaps::KeyPermissions key_permissions,
StatusCallback callback) = 0;
// Sets the Built-In Certificate Provisioning `profile_id` on the `key`.
// Returns an error on failure.
virtual void SetCertProvisioningProfileId(PrivateKeyHandle key,
std::string profile_id,
StatusCallback callback) = 0;
};
} // namespace kcer
#endif // CHROMEOS_ASH_COMPONENTS_KCER_KCER_H_
|