[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / crypto / unexportable_key_win.cc
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.
4
5 #include <windows.h>
6
7 #include <ncrypt.h>
8
9 #include <string>
10 #include <tuple>
11 #include <vector>
12
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"
34
35 namespace crypto {
36
37 namespace {
38
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";
45
46 std::vector<uint8_t> CBBToVector(const CBB* cbb) {
47   return std::vector<uint8_t>(CBB_data(cbb), CBB_data(cbb) + CBB_len(cbb));
48 }
49
50 // BCryptAlgorithmFor returns the BCrypt algorithm ID for the given Chromium
51 // signing algorithm.
52 absl::optional<LPCWSTR> BCryptAlgorithmFor(
53     SignatureVerifier::SignatureAlgorithm algo) {
54   switch (algo) {
55     case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
56       return BCRYPT_RSA_ALGORITHM;
57
58     case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
59       return BCRYPT_ECDSA_P256_ALGORITHM;
60
61     default:
62       return absl::nullopt;
63   }
64 }
65
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) {
75       continue;
76     }
77
78     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
79     if (!FAILED(NCryptIsAlgSupported(provider, *bcrypto_algo_name,
80                                      /*flags=*/0))) {
81       return algo;
82     }
83   }
84
85   return absl::nullopt;
86 }
87
88 // GetKeyProperty returns the given NCrypt key property of |key|.
89 absl::optional<std::vector<uint8_t>> GetKeyProperty(NCRYPT_KEY_HANDLE key,
90                                                     LPCWSTR property) {
91   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
92   DWORD size;
93   if (FAILED(NCryptGetProperty(key, property, nullptr, 0, &size, 0))) {
94     return absl::nullopt;
95   }
96
97   std::vector<uint8_t> ret(size);
98   if (FAILED(
99           NCryptGetProperty(key, property, ret.data(), ret.size(), &size, 0))) {
100     return absl::nullopt;
101   }
102   CHECK_EQ(ret.size(), size);
103
104   return ret;
105 }
106
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,
109                                                LPCWSTR format) {
110   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
111   DWORD output_size;
112   if (FAILED(NCryptExportKey(key, 0, format, nullptr, nullptr, 0, &output_size,
113                              0))) {
114     return absl::nullopt;
115   }
116
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;
121   }
122   CHECK_EQ(output.size(), output_size);
123
124   return output;
125 }
126
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);
130   if (!pub_key) {
131     return absl::nullopt;
132   }
133
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;
140   }
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;
149   }
150
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
153   // a P-256 key.
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);
157     if (!curve_name) {
158       return absl::nullopt;
159     }
160
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;
165     }
166   }
167
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);
171
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),
176                           /*ctx=*/nullptr)) {
177     return absl::nullopt;
178   }
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()));
184
185   bssl::ScopedCBB cbb;
186   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/128) &&
187         EVP_marshal_public_key(cbb.get(), pkey.get()));
188   return CBBToVector(cbb.get());
189 }
190
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);
194   if (!pub_key) {
195     return absl::nullopt;
196   }
197
198   // The exported key is a |BCRYPT_RSAKEY_BLOB| followed by the bytes of the
199   // key itself.
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;
204   }
205   memcpy(&header, pub_key->data(), sizeof(header));
206   if (header.Magic != static_cast<ULONG>(BCRYPT_RSAPUBLIC_MAGIC)) {
207     return absl::nullopt;
208   }
209
210   size_t bytes_needed;
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;
216   }
217
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));
224
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()));
229
230   bssl::ScopedCBB cbb;
231   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/384) &&
232         EVP_marshal_public_key(cbb.get(), pkey.get()));
233   return CBBToVector(cbb.get());
234 }
235
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);
240
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
243   // ECDSA.
244   std::vector<uint8_t> sig(64);
245   DWORD sig_size;
246   {
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;
252     }
253   }
254   CHECK_EQ(sig.size(), sig_size);
255
256   bssl::UniquePtr<BIGNUM> r(BN_bin2bn(sig.data(), 32, nullptr));
257   bssl::UniquePtr<BIGNUM> s(BN_bin2bn(sig.data() + 32, 32, nullptr));
258   ECDSA_SIG sig_st;
259   sig_st.r = r.get();
260   sig_st.s = s.get();
261
262   bssl::ScopedCBB cbb;
263   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/72) &&
264         ECDSA_SIG_marshal(cbb.get(), &sig_st));
265   return CBBToVector(cbb.get());
266 }
267
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);
272
273   std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
274   BCRYPT_PKCS1_PADDING_INFO padding_info = {0};
275   padding_info.pszAlgId = NCRYPT_SHA256_ALGORITHM;
276
277   DWORD sig_size;
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;
283   }
284
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;
290   }
291   CHECK_EQ(sig.size(), sig_size);
292
293   return sig;
294 }
295
296 // ECDSAKey wraps a TPM-stored P-256 ECDSA key.
297 class ECDSAKey : public UnexportableSigningKey {
298  public:
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)) {}
305
306   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
307     return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
308   }
309
310   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
311     return spki_;
312   }
313
314   std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
315
316   absl::optional<std::vector<uint8_t>> SignSlowly(
317       base::span<const uint8_t> data) override {
318     return SignECDSA(key_.get(), data);
319   }
320
321  private:
322   ScopedNCryptKey key_;
323   const std::vector<uint8_t> wrapped_;
324   const std::vector<uint8_t> spki_;
325 };
326
327 // RSAKey wraps a TPM-stored RSA key.
328 class RSAKey : public UnexportableSigningKey {
329  public:
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)) {}
336
337   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
338     return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
339   }
340
341   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
342     return spki_;
343   }
344
345   std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
346
347   absl::optional<std::vector<uint8_t>> SignSlowly(
348       base::span<const uint8_t> data) override {
349     return SignRSA(key_.get(), data);
350   }
351
352  private:
353   ScopedNCryptKey key_;
354   const std::vector<uint8_t> wrapped_;
355   const std::vector<uint8_t> spki_;
356 };
357
358 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
359 // Provider to expose TPM-backed keys on Windows.
360 class UnexportableKeyProviderWin : public UnexportableKeyProvider {
361  public:
362   ~UnexportableKeyProviderWin() override = default;
363
364   absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
365       base::span<const SignatureVerifier::SignatureAlgorithm>
366           acceptable_algorithms) override {
367     ScopedNCryptProvider provider;
368     {
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;
374       }
375     }
376
377     return GetBestSupported(provider.get(), acceptable_algorithms);
378   }
379
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);
385
386     ScopedNCryptProvider provider;
387     {
388       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
389       if (FAILED(NCryptOpenStorageProvider(
390               ScopedNCryptProvider::Receiver(provider).get(),
391               MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
392         return nullptr;
393       }
394     }
395
396     absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
397         GetBestSupported(provider.get(), acceptable_algorithms);
398     if (!algo) {
399       return nullptr;
400     }
401
402     ScopedNCryptKey key;
403     {
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))) {
410         return nullptr;
411       }
412
413       if (FAILED(NCryptFinalizeKey(key.get(), NCRYPT_SILENT_FLAG))) {
414         return nullptr;
415       }
416     }
417
418     const absl::optional<std::vector<uint8_t>> wrapped_key =
419         ExportKey(key.get(), BCRYPT_OPAQUE_KEY_BLOB);
420     if (!wrapped_key) {
421       return nullptr;
422     }
423
424     absl::optional<std::vector<uint8_t>> spki;
425     switch (*algo) {
426       case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
427         spki = GetP256ECDSASPKI(key.get());
428         if (!spki) {
429           return nullptr;
430         }
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());
435         if (!spki) {
436           return nullptr;
437         }
438         return std::make_unique<RSAKey>(std::move(key), std::move(*wrapped_key),
439                                         std::move(spki.value()));
440       default:
441         return nullptr;
442     }
443   }
444
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);
449
450     ScopedNCryptProvider provider;
451     ScopedNCryptKey key;
452     {
453       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
454       if (FAILED(NCryptOpenStorageProvider(
455               ScopedNCryptProvider::Receiver(provider).get(),
456               MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
457         return nullptr;
458       }
459
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))) {
465         return nullptr;
466       }
467     }
468
469     const absl::optional<std::vector<uint8_t>> algo_bytes =
470         GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
471     if (!algo_bytes) {
472       return nullptr;
473     }
474
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;
480
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());
485       if (!spki) {
486         return nullptr;
487       }
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());
494       if (!spki) {
495         return nullptr;
496       }
497       return std::make_unique<RSAKey>(
498           std::move(key), std::vector<uint8_t>(wrapped.begin(), wrapped.end()),
499           std::move(spki.value()));
500     }
501
502     return nullptr;
503   }
504 };
505
506 // ECDSASoftwareKey wraps a Credential Guard stored P-256 ECDSA key.
507 class ECDSASoftwareKey : public VirtualUnexportableSigningKey {
508  public:
509   ECDSASoftwareKey(ScopedNCryptKey key,
510                    std::string name,
511                    std::vector<uint8_t> spki)
512       : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
513
514   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
515     return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
516   }
517
518   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
519     return spki_;
520   }
521
522   std::string GetKeyName() const override { return name_; }
523
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;
528     }
529
530     return SignECDSA(key_.get(), data);
531   }
532
533   void DeleteKey() override {
534     if (!key_.is_valid()) {
535       return;
536     }
537
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
542     // key.
543     if (NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
544       static_cast<void>(key_.release());
545     }
546   }
547
548  private:
549   ScopedNCryptKey key_;
550   const std::string name_;
551   const std::vector<uint8_t> spki_;
552 };
553
554 // RSASoftwareKey wraps a Credential Guard stored RSA key.
555 class RSASoftwareKey : public VirtualUnexportableSigningKey {
556  public:
557   RSASoftwareKey(ScopedNCryptKey key,
558                  std::string name,
559                  std::vector<uint8_t> spki)
560       : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
561
562   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
563     return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
564   }
565
566   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
567     return spki_;
568   }
569
570   std::string GetKeyName() const override { return name_; }
571
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;
576     }
577
578     return SignRSA(key_.get(), data);
579   }
580
581   void DeleteKey() override {
582     if (!key_.is_valid()) {
583       return;
584     }
585
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
590     // key.
591     if (NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
592       static_cast<void>(key_.release());
593     }
594   }
595
596  private:
597   ScopedNCryptKey key_;
598   std::string name_;
599   const std::vector<uint8_t> spki_;
600 };
601
602 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
603 // Provider to expose Credential Guard backed keys on Windows.
604 class VirtualUnexportableKeyProviderWin
605     : public VirtualUnexportableKeyProvider {
606  public:
607   ~VirtualUnexportableKeyProviderWin() override = default;
608
609   absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
610       base::span<const SignatureVerifier::SignatureAlgorithm>
611           acceptable_algorithms) override {
612     ScopedNCryptProvider provider;
613     {
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;
621       }
622     }
623
624     return GetBestSupported(provider.get(), acceptable_algorithms);
625   }
626
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);
633
634     ScopedNCryptProvider provider;
635     {
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);
642         return nullptr;
643       }
644     }
645
646     absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
647         GetBestSupported(provider.get(), acceptable_algorithms);
648     if (!algo) {
649       return nullptr;
650     }
651
652     ScopedNCryptKey key;
653     {
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);
663         return nullptr;
664       }
665
666       status = NCryptFinalizeKey(
667           key.get(), NCRYPT_PROTECT_TO_LOCAL_SYSTEM | NCRYPT_SILENT_FLAG);
668       if (FAILED(status)) {
669         base::UmaHistogramSparse(kMetricVirtualFinalizeKeyError, status);
670         return nullptr;
671       }
672     }
673
674     absl::optional<std::vector<uint8_t>> spki;
675     switch (*algo) {
676       case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
677         spki = GetP256ECDSASPKI(key.get());
678         if (!spki) {
679           return nullptr;
680         }
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());
685         if (!spki) {
686           return nullptr;
687         }
688         return std::make_unique<RSASoftwareKey>(std::move(key), name,
689                                                 std::move(spki.value()));
690       default:
691         return nullptr;
692     }
693   }
694
695   std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName(
696       std::string name) override {
697     base::ScopedBlockingCall scoped_blocking_call(
698         FROM_HERE, base::BlockingType::WILL_BLOCK);
699
700     ScopedNCryptProvider provider;
701     ScopedNCryptKey key;
702     {
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);
709         return nullptr;
710       }
711
712       status = NCryptOpenKey(
713           provider.get(), ScopedNCryptKey::Receiver(key).get(),
714           base::SysUTF8ToWide(name).c_str(), /*dwLegacyKeySpec=*/0,
715           /*dwFlags*/ 0);
716       if (FAILED(status)) {
717         base::UmaHistogramSparse(kMetricVirtualOpenKeyError, status);
718         return nullptr;
719       }
720     }
721
722     const absl::optional<std::vector<uint8_t>> algo_bytes =
723         GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
724
725     // This is the expected behavior, but note it is different from
726     // TPM backed keys.
727     static const wchar_t kECDSA[] = BCRYPT_ECDSA_P256_ALGORITHM;
728     static const wchar_t kRSA[] = BCRYPT_RSA_ALGORITHM;
729
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());
734       if (!spki) {
735         return nullptr;
736       }
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());
742       if (!spki) {
743         return nullptr;
744       }
745       return std::make_unique<RSASoftwareKey>(std::move(key), name,
746                                               std::move(spki.value()));
747     }
748
749     return nullptr;
750   }
751 };
752
753 }  // namespace
754
755 std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderWin() {
756   return std::make_unique<UnexportableKeyProviderWin>();
757 }
758
759 std::unique_ptr<VirtualUnexportableKeyProvider>
760 GetVirtualUnexportableKeyProviderWin() {
761   return std::make_unique<VirtualUnexportableKeyProviderWin>();
762 }
763
764 }  // namespace crypto