1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
13 #include "base/logging.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/numerics/checked_math.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/sys_string_conversions.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/threading/scoped_blocking_call.h"
21 #include "base/threading/scoped_thread_priority.h"
22 #include "crypto/random.h"
23 #include "crypto/scoped_cng_types.h"
24 #include "crypto/sha2.h"
25 #include "crypto/unexportable_key.h"
26 #include "third_party/boringssl/src/include/openssl/bn.h"
27 #include "third_party/boringssl/src/include/openssl/bytestring.h"
28 #include "third_party/boringssl/src/include/openssl/ec.h"
29 #include "third_party/boringssl/src/include/openssl/ec_key.h"
30 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
31 #include "third_party/boringssl/src/include/openssl/evp.h"
32 #include "third_party/boringssl/src/include/openssl/nid.h"
33 #include "third_party/boringssl/src/include/openssl/rsa.h"
39 const char kMetricVirtualCreateKeyError[] = "Crypto.TpmError.VirtualCreateKey";
40 const char kMetricVirtualFinalizeKeyError[] =
41 "Crypto.TpmError.VirtualFinalizeKey";
42 const char kMetricVirtualOpenKeyError[] = "Crypto.TpmError.VirtualOpenKey";
43 const char kMetricVirtualOpenStorageError[] =
44 "Crypto.TpmError.VirtualOpenStorage";
46 std::vector<uint8_t> CBBToVector(const CBB* cbb) {
47 return std::vector<uint8_t>(CBB_data(cbb), CBB_data(cbb) + CBB_len(cbb));
50 // BCryptAlgorithmFor returns the BCrypt algorithm ID for the given Chromium
52 absl::optional<LPCWSTR> BCryptAlgorithmFor(
53 SignatureVerifier::SignatureAlgorithm algo) {
55 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
56 return BCRYPT_RSA_ALGORITHM;
58 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
59 return BCRYPT_ECDSA_P256_ALGORITHM;
66 // GetBestSupported returns the first element of |acceptable_algorithms| that
67 // |provider| supports, or |nullopt| if there isn't any.
68 absl::optional<SignatureVerifier::SignatureAlgorithm> GetBestSupported(
69 NCRYPT_PROV_HANDLE provider,
70 base::span<const SignatureVerifier::SignatureAlgorithm>
71 acceptable_algorithms) {
72 for (auto algo : acceptable_algorithms) {
73 absl::optional<LPCWSTR> bcrypto_algo_name = BCryptAlgorithmFor(algo);
74 if (!bcrypto_algo_name) {
78 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
79 if (!FAILED(NCryptIsAlgSupported(provider, *bcrypto_algo_name,
88 // GetKeyProperty returns the given NCrypt key property of |key|.
89 absl::optional<std::vector<uint8_t>> GetKeyProperty(NCRYPT_KEY_HANDLE key,
91 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
93 if (FAILED(NCryptGetProperty(key, property, nullptr, 0, &size, 0))) {
97 std::vector<uint8_t> ret(size);
99 NCryptGetProperty(key, property, ret.data(), ret.size(), &size, 0))) {
100 return absl::nullopt;
102 CHECK_EQ(ret.size(), size);
107 // ExportKey returns |key| exported in the given format or nullopt on error.
108 absl::optional<std::vector<uint8_t>> ExportKey(NCRYPT_KEY_HANDLE key,
110 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
112 if (FAILED(NCryptExportKey(key, 0, format, nullptr, nullptr, 0, &output_size,
114 return absl::nullopt;
117 std::vector<uint8_t> output(output_size);
118 if (FAILED(NCryptExportKey(key, 0, format, nullptr, output.data(),
119 output.size(), &output_size, 0))) {
120 return absl::nullopt;
122 CHECK_EQ(output.size(), output_size);
127 absl::optional<std::vector<uint8_t>> GetP256ECDSASPKI(NCRYPT_KEY_HANDLE key) {
128 const absl::optional<std::vector<uint8_t>> pub_key =
129 ExportKey(key, BCRYPT_ECCPUBLIC_BLOB);
131 return absl::nullopt;
134 // The exported key is a |BCRYPT_ECCKEY_BLOB| followed by the bytes of the
135 // public key itself.
136 // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecckey_blob
137 BCRYPT_ECCKEY_BLOB header;
138 if (pub_key->size() < sizeof(header)) {
139 return absl::nullopt;
141 memcpy(&header, pub_key->data(), sizeof(header));
142 // |cbKey| is documented[1] as "the length, in bytes, of the key". It is
143 // not. For ECDSA public keys it is the length of a field element.
144 if ((header.dwMagic != BCRYPT_ECDSA_PUBLIC_P256_MAGIC &&
145 header.dwMagic != BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC) ||
146 header.cbKey != 256 / 8 ||
147 pub_key->size() - sizeof(BCRYPT_ECCKEY_BLOB) != 64) {
148 return absl::nullopt;
151 // Sometimes NCrypt will return a generic dwMagic even when asked for a P-256
152 // key. In that case, do extra validation to make sure that `key` is in fact
154 if (header.dwMagic == BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC) {
155 const absl::optional<std::vector<uint8_t>> curve_name =
156 GetKeyProperty(key, NCRYPT_ECC_CURVE_NAME_PROPERTY);
158 return absl::nullopt;
161 if (curve_name->size() != sizeof(BCRYPT_ECC_CURVE_NISTP256) ||
162 memcmp(curve_name->data(), BCRYPT_ECC_CURVE_NISTP256,
163 sizeof(BCRYPT_ECC_CURVE_NISTP256)) != 0) {
164 return absl::nullopt;
168 uint8_t x962[1 + 32 + 32];
169 x962[0] = POINT_CONVERSION_UNCOMPRESSED;
170 memcpy(&x962[1], pub_key->data() + sizeof(BCRYPT_ECCKEY_BLOB), 64);
172 bssl::UniquePtr<EC_GROUP> p256(
173 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
174 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get()));
175 if (!EC_POINT_oct2point(p256.get(), point.get(), x962, sizeof(x962),
177 return absl::nullopt;
179 bssl::UniquePtr<EC_KEY> ec_key(
180 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
181 CHECK(EC_KEY_set_public_key(ec_key.get(), point.get()));
182 bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
183 CHECK(EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()));
186 CHECK(CBB_init(cbb.get(), /*initial_capacity=*/128) &&
187 EVP_marshal_public_key(cbb.get(), pkey.get()));
188 return CBBToVector(cbb.get());
191 absl::optional<std::vector<uint8_t>> GetRSASPKI(NCRYPT_KEY_HANDLE key) {
192 const absl::optional<std::vector<uint8_t>> pub_key =
193 ExportKey(key, BCRYPT_RSAPUBLIC_BLOB);
195 return absl::nullopt;
198 // The exported key is a |BCRYPT_RSAKEY_BLOB| followed by the bytes of the
200 // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob
201 BCRYPT_RSAKEY_BLOB header;
202 if (pub_key->size() < sizeof(header)) {
203 return absl::nullopt;
205 memcpy(&header, pub_key->data(), sizeof(header));
206 if (header.Magic != static_cast<ULONG>(BCRYPT_RSAPUBLIC_MAGIC)) {
207 return absl::nullopt;
211 if (!base::CheckAdd(sizeof(BCRYPT_RSAKEY_BLOB),
212 base::CheckAdd(header.cbPublicExp, header.cbModulus))
213 .AssignIfValid(&bytes_needed) ||
214 pub_key->size() < bytes_needed) {
215 return absl::nullopt;
218 bssl::UniquePtr<BIGNUM> e(
219 BN_bin2bn(&pub_key->data()[sizeof(BCRYPT_RSAKEY_BLOB)],
220 header.cbPublicExp, nullptr));
221 bssl::UniquePtr<BIGNUM> n(BN_bin2bn(
222 &pub_key->data()[sizeof(BCRYPT_RSAKEY_BLOB) + header.cbPublicExp],
223 header.cbModulus, nullptr));
225 bssl::UniquePtr<RSA> rsa(RSA_new());
226 CHECK(RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr));
227 bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
228 CHECK(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()));
231 CHECK(CBB_init(cbb.get(), /*initial_capacity=*/384) &&
232 EVP_marshal_public_key(cbb.get(), pkey.get()));
233 return CBBToVector(cbb.get());
236 absl::optional<std::vector<uint8_t>> SignECDSA(NCRYPT_KEY_HANDLE key,
237 base::span<const uint8_t> data) {
238 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
239 base::BlockingType::WILL_BLOCK);
241 std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
242 // The signature is written as a pair of big-endian field elements for P-256
244 std::vector<uint8_t> sig(64);
247 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
248 if (FAILED(NCryptSignHash(key, nullptr, digest.data(), digest.size(),
249 sig.data(), sig.size(), &sig_size,
250 NCRYPT_SILENT_FLAG))) {
251 return absl::nullopt;
254 CHECK_EQ(sig.size(), sig_size);
256 bssl::UniquePtr<BIGNUM> r(BN_bin2bn(sig.data(), 32, nullptr));
257 bssl::UniquePtr<BIGNUM> s(BN_bin2bn(sig.data() + 32, 32, nullptr));
263 CHECK(CBB_init(cbb.get(), /*initial_capacity=*/72) &&
264 ECDSA_SIG_marshal(cbb.get(), &sig_st));
265 return CBBToVector(cbb.get());
268 absl::optional<std::vector<uint8_t>> SignRSA(NCRYPT_KEY_HANDLE key,
269 base::span<const uint8_t> data) {
270 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
271 base::BlockingType::WILL_BLOCK);
273 std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
274 BCRYPT_PKCS1_PADDING_INFO padding_info = {0};
275 padding_info.pszAlgId = NCRYPT_SHA256_ALGORITHM;
278 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
279 if (FAILED(NCryptSignHash(key, &padding_info, digest.data(), digest.size(),
280 nullptr, 0, &sig_size,
281 NCRYPT_SILENT_FLAG | BCRYPT_PAD_PKCS1))) {
282 return absl::nullopt;
285 std::vector<uint8_t> sig(sig_size);
286 if (FAILED(NCryptSignHash(key, &padding_info, digest.data(), digest.size(),
287 sig.data(), sig.size(), &sig_size,
288 NCRYPT_SILENT_FLAG | BCRYPT_PAD_PKCS1))) {
289 return absl::nullopt;
291 CHECK_EQ(sig.size(), sig_size);
296 // ECDSAKey wraps a TPM-stored P-256 ECDSA key.
297 class ECDSAKey : public UnexportableSigningKey {
299 ECDSAKey(ScopedNCryptKey key,
300 std::vector<uint8_t> wrapped,
301 std::vector<uint8_t> spki)
302 : key_(std::move(key)),
303 wrapped_(std::move(wrapped)),
304 spki_(std::move(spki)) {}
306 SignatureVerifier::SignatureAlgorithm Algorithm() const override {
307 return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
310 std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
314 std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
316 absl::optional<std::vector<uint8_t>> SignSlowly(
317 base::span<const uint8_t> data) override {
318 return SignECDSA(key_.get(), data);
322 ScopedNCryptKey key_;
323 const std::vector<uint8_t> wrapped_;
324 const std::vector<uint8_t> spki_;
327 // RSAKey wraps a TPM-stored RSA key.
328 class RSAKey : public UnexportableSigningKey {
330 RSAKey(ScopedNCryptKey key,
331 std::vector<uint8_t> wrapped,
332 std::vector<uint8_t> spki)
333 : key_(std::move(key)),
334 wrapped_(std::move(wrapped)),
335 spki_(std::move(spki)) {}
337 SignatureVerifier::SignatureAlgorithm Algorithm() const override {
338 return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
341 std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
345 std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
347 absl::optional<std::vector<uint8_t>> SignSlowly(
348 base::span<const uint8_t> data) override {
349 return SignRSA(key_.get(), data);
353 ScopedNCryptKey key_;
354 const std::vector<uint8_t> wrapped_;
355 const std::vector<uint8_t> spki_;
358 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
359 // Provider to expose TPM-backed keys on Windows.
360 class UnexportableKeyProviderWin : public UnexportableKeyProvider {
362 ~UnexportableKeyProviderWin() override = default;
364 absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
365 base::span<const SignatureVerifier::SignatureAlgorithm>
366 acceptable_algorithms) override {
367 ScopedNCryptProvider provider;
369 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
370 if (FAILED(NCryptOpenStorageProvider(
371 ScopedNCryptProvider::Receiver(provider).get(),
372 MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
373 return absl::nullopt;
377 return GetBestSupported(provider.get(), acceptable_algorithms);
380 std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
381 base::span<const SignatureVerifier::SignatureAlgorithm>
382 acceptable_algorithms) override {
383 base::ScopedBlockingCall scoped_blocking_call(
384 FROM_HERE, base::BlockingType::WILL_BLOCK);
386 ScopedNCryptProvider provider;
388 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
389 if (FAILED(NCryptOpenStorageProvider(
390 ScopedNCryptProvider::Receiver(provider).get(),
391 MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
396 absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
397 GetBestSupported(provider.get(), acceptable_algorithms);
404 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
405 // An empty key name stops the key being persisted to disk.
406 if (FAILED(NCryptCreatePersistedKey(
407 provider.get(), ScopedNCryptKey::Receiver(key).get(),
408 BCryptAlgorithmFor(*algo).value(), /*pszKeyName=*/nullptr,
409 /*dwLegacyKeySpec=*/0, /*dwFlags=*/0))) {
413 if (FAILED(NCryptFinalizeKey(key.get(), NCRYPT_SILENT_FLAG))) {
418 const absl::optional<std::vector<uint8_t>> wrapped_key =
419 ExportKey(key.get(), BCRYPT_OPAQUE_KEY_BLOB);
424 absl::optional<std::vector<uint8_t>> spki;
426 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
427 spki = GetP256ECDSASPKI(key.get());
431 return std::make_unique<ECDSAKey>(
432 std::move(key), std::move(*wrapped_key), std::move(spki.value()));
433 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
434 spki = GetRSASPKI(key.get());
438 return std::make_unique<RSAKey>(std::move(key), std::move(*wrapped_key),
439 std::move(spki.value()));
445 std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
446 base::span<const uint8_t> wrapped) override {
447 base::ScopedBlockingCall scoped_blocking_call(
448 FROM_HERE, base::BlockingType::WILL_BLOCK);
450 ScopedNCryptProvider provider;
453 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
454 if (FAILED(NCryptOpenStorageProvider(
455 ScopedNCryptProvider::Receiver(provider).get(),
456 MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
460 if (FAILED(NCryptImportKey(
461 provider.get(), /*hImportKey=*/NULL, BCRYPT_OPAQUE_KEY_BLOB,
462 /*pParameterList=*/nullptr, ScopedNCryptKey::Receiver(key).get(),
463 const_cast<PBYTE>(wrapped.data()), wrapped.size(),
464 /*dwFlags=*/NCRYPT_SILENT_FLAG))) {
469 const absl::optional<std::vector<uint8_t>> algo_bytes =
470 GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
475 // The documentation suggests that |NCRYPT_ALGORITHM_PROPERTY| should return
476 // the original algorithm, i.e. |BCRYPT_ECDSA_P256_ALGORITHM| for ECDSA. But
477 // it actually returns just "ECDSA" for that case.
478 static const wchar_t kECDSA[] = L"ECDSA";
479 static const wchar_t kRSA[] = BCRYPT_RSA_ALGORITHM;
481 absl::optional<std::vector<uint8_t>> spki;
482 if (algo_bytes->size() == sizeof(kECDSA) &&
483 memcmp(algo_bytes->data(), kECDSA, sizeof(kECDSA)) == 0) {
484 spki = GetP256ECDSASPKI(key.get());
488 return std::make_unique<ECDSAKey>(
489 std::move(key), std::vector<uint8_t>(wrapped.begin(), wrapped.end()),
490 std::move(spki.value()));
491 } else if (algo_bytes->size() == sizeof(kRSA) &&
492 memcmp(algo_bytes->data(), kRSA, sizeof(kRSA)) == 0) {
493 spki = GetRSASPKI(key.get());
497 return std::make_unique<RSAKey>(
498 std::move(key), std::vector<uint8_t>(wrapped.begin(), wrapped.end()),
499 std::move(spki.value()));
506 // ECDSASoftwareKey wraps a Credential Guard stored P-256 ECDSA key.
507 class ECDSASoftwareKey : public VirtualUnexportableSigningKey {
509 ECDSASoftwareKey(ScopedNCryptKey key,
511 std::vector<uint8_t> spki)
512 : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
514 SignatureVerifier::SignatureAlgorithm Algorithm() const override {
515 return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
518 std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
522 std::string GetKeyName() const override { return name_; }
524 absl::optional<std::vector<uint8_t>> Sign(
525 base::span<const uint8_t> data) override {
526 if (!key_.is_valid()) {
527 return absl::nullopt;
530 return SignECDSA(key_.get(), data);
533 void DeleteKey() override {
534 if (!key_.is_valid()) {
538 // If key deletion succeeds, NCryptDeleteKey frees the key. To avoid double
539 // free, we need to release the key from the ScopedNCryptKey RAII object.
540 // Key deletion can fail in circumstances which are not under the
541 // application's control. For these cases, ScopedNCrypt key should free the
543 if (NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
544 static_cast<void>(key_.release());
549 ScopedNCryptKey key_;
550 const std::string name_;
551 const std::vector<uint8_t> spki_;
554 // RSASoftwareKey wraps a Credential Guard stored RSA key.
555 class RSASoftwareKey : public VirtualUnexportableSigningKey {
557 RSASoftwareKey(ScopedNCryptKey key,
559 std::vector<uint8_t> spki)
560 : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
562 SignatureVerifier::SignatureAlgorithm Algorithm() const override {
563 return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
566 std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
570 std::string GetKeyName() const override { return name_; }
572 absl::optional<std::vector<uint8_t>> Sign(
573 base::span<const uint8_t> data) override {
574 if (!key_.is_valid()) {
575 return absl::nullopt;
578 return SignRSA(key_.get(), data);
581 void DeleteKey() override {
582 if (!key_.is_valid()) {
586 // If key deletion succeeds, NCryptDeleteKey frees the key. To avoid double
587 // free, we need to release the key from the ScopedNCryptKey RAII object.
588 // Key deletion can fail in circumstances which are not under the
589 // application's control. For these cases, ScopedNCrypt key should free the
591 if (NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
592 static_cast<void>(key_.release());
597 ScopedNCryptKey key_;
599 const std::vector<uint8_t> spki_;
602 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
603 // Provider to expose Credential Guard backed keys on Windows.
604 class VirtualUnexportableKeyProviderWin
605 : public VirtualUnexportableKeyProvider {
607 ~VirtualUnexportableKeyProviderWin() override = default;
609 absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
610 base::span<const SignatureVerifier::SignatureAlgorithm>
611 acceptable_algorithms) override {
612 ScopedNCryptProvider provider;
614 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
615 SECURITY_STATUS status = NCryptOpenStorageProvider(
616 ScopedNCryptProvider::Receiver(provider).get(),
617 MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
618 if (FAILED(status)) {
619 base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
620 return absl::nullopt;
624 return GetBestSupported(provider.get(), acceptable_algorithms);
627 std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey(
628 base::span<const SignatureVerifier::SignatureAlgorithm>
629 acceptable_algorithms,
630 std::string name) override {
631 base::ScopedBlockingCall scoped_blocking_call(
632 FROM_HERE, base::BlockingType::WILL_BLOCK);
634 ScopedNCryptProvider provider;
636 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
637 SECURITY_STATUS status = NCryptOpenStorageProvider(
638 ScopedNCryptProvider::Receiver(provider).get(),
639 MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
640 if (FAILED(status)) {
641 base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
646 absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
647 GetBestSupported(provider.get(), acceptable_algorithms);
654 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
655 // An empty key name stops the key being persisted to disk.
656 SECURITY_STATUS status = NCryptCreatePersistedKey(
657 provider.get(), ScopedNCryptKey::Receiver(key).get(),
658 BCryptAlgorithmFor(*algo).value(), base::SysUTF8ToWide(name).c_str(),
659 /*dwLegacyKeySpec=*/0,
660 /*dwFlags=*/NCRYPT_USE_VIRTUAL_ISOLATION_FLAG);
661 if (FAILED(status)) {
662 base::UmaHistogramSparse(kMetricVirtualCreateKeyError, status);
666 status = NCryptFinalizeKey(
667 key.get(), NCRYPT_PROTECT_TO_LOCAL_SYSTEM | NCRYPT_SILENT_FLAG);
668 if (FAILED(status)) {
669 base::UmaHistogramSparse(kMetricVirtualFinalizeKeyError, status);
674 absl::optional<std::vector<uint8_t>> spki;
676 case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
677 spki = GetP256ECDSASPKI(key.get());
681 return std::make_unique<ECDSASoftwareKey>(std::move(key), name,
682 std::move(spki.value()));
683 case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
684 spki = GetRSASPKI(key.get());
688 return std::make_unique<RSASoftwareKey>(std::move(key), name,
689 std::move(spki.value()));
695 std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName(
696 std::string name) override {
697 base::ScopedBlockingCall scoped_blocking_call(
698 FROM_HERE, base::BlockingType::WILL_BLOCK);
700 ScopedNCryptProvider provider;
703 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
704 SECURITY_STATUS status = NCryptOpenStorageProvider(
705 ScopedNCryptProvider::Receiver(provider).get(),
706 MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
707 if (FAILED(status)) {
708 base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
712 status = NCryptOpenKey(
713 provider.get(), ScopedNCryptKey::Receiver(key).get(),
714 base::SysUTF8ToWide(name).c_str(), /*dwLegacyKeySpec=*/0,
716 if (FAILED(status)) {
717 base::UmaHistogramSparse(kMetricVirtualOpenKeyError, status);
722 const absl::optional<std::vector<uint8_t>> algo_bytes =
723 GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
725 // This is the expected behavior, but note it is different from
727 static const wchar_t kECDSA[] = BCRYPT_ECDSA_P256_ALGORITHM;
728 static const wchar_t kRSA[] = BCRYPT_RSA_ALGORITHM;
730 absl::optional<std::vector<uint8_t>> spki;
731 if (algo_bytes->size() == sizeof(kECDSA) &&
732 memcmp(algo_bytes->data(), kECDSA, sizeof(kECDSA)) == 0) {
733 spki = GetP256ECDSASPKI(key.get());
737 return std::make_unique<ECDSASoftwareKey>(std::move(key), name,
738 std::move(spki.value()));
739 } else if (algo_bytes->size() == sizeof(kRSA) &&
740 memcmp(algo_bytes->data(), kRSA, sizeof(kRSA)) == 0) {
741 spki = GetRSASPKI(key.get());
745 return std::make_unique<RSASoftwareKey>(std::move(key), name,
746 std::move(spki.value()));
755 std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderWin() {
756 return std::make_unique<UnexportableKeyProviderWin>();
759 std::unique_ptr<VirtualUnexportableKeyProvider>
760 GetVirtualUnexportableKeyProviderWin() {
761 return std::make_unique<VirtualUnexportableKeyProviderWin>();
764 } // namespace crypto