• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_piece.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/scoped_blocking_call.h"
22 #include "base/threading/scoped_thread_priority.h"
23 #include "crypto/random.h"
24 #include "crypto/scoped_cng_types.h"
25 #include "crypto/sha2.h"
26 #include "crypto/unexportable_key.h"
27 #include "third_party/boringssl/src/include/openssl/bn.h"
28 #include "third_party/boringssl/src/include/openssl/bytestring.h"
29 #include "third_party/boringssl/src/include/openssl/ec.h"
30 #include "third_party/boringssl/src/include/openssl/ec_key.h"
31 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
32 #include "third_party/boringssl/src/include/openssl/evp.h"
33 #include "third_party/boringssl/src/include/openssl/nid.h"
34 #include "third_party/boringssl/src/include/openssl/rsa.h"
35 
36 namespace crypto {
37 
38 namespace {
39 
40 const char kMetricVirtualCreateKeyError[] = "Crypto.TpmError.VirtualCreateKey";
41 const char kMetricVirtualFinalizeKeyError[] =
42     "Crypto.TpmError.VirtualFinalizeKey";
43 const char kMetricVirtualOpenKeyError[] = "Crypto.TpmError.VirtualOpenKey";
44 const char kMetricVirtualOpenStorageError[] =
45     "Crypto.TpmError.VirtualOpenStorage";
46 
CBBToVector(const CBB * cbb)47 std::vector<uint8_t> CBBToVector(const CBB* cbb) {
48   return std::vector<uint8_t>(CBB_data(cbb), CBB_data(cbb) + CBB_len(cbb));
49 }
50 
51 // BCryptAlgorithmFor returns the BCrypt algorithm ID for the given Chromium
52 // signing algorithm.
BCryptAlgorithmFor(SignatureVerifier::SignatureAlgorithm algo)53 absl::optional<LPCWSTR> BCryptAlgorithmFor(
54     SignatureVerifier::SignatureAlgorithm algo) {
55   switch (algo) {
56     case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
57       return BCRYPT_RSA_ALGORITHM;
58 
59     case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
60       return BCRYPT_ECDSA_P256_ALGORITHM;
61 
62     default:
63       return absl::nullopt;
64   }
65 }
66 
67 // GetBestSupported returns the first element of |acceptable_algorithms| that
68 // |provider| supports, or |nullopt| if there isn't any.
GetBestSupported(NCRYPT_PROV_HANDLE provider,base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)69 absl::optional<SignatureVerifier::SignatureAlgorithm> GetBestSupported(
70     NCRYPT_PROV_HANDLE provider,
71     base::span<const SignatureVerifier::SignatureAlgorithm>
72         acceptable_algorithms) {
73   for (auto algo : acceptable_algorithms) {
74     absl::optional<LPCWSTR> bcrypto_algo_name = BCryptAlgorithmFor(algo);
75     if (!bcrypto_algo_name) {
76       continue;
77     }
78 
79     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
80     if (!FAILED(NCryptIsAlgSupported(provider, *bcrypto_algo_name,
81                                      /*flags=*/0))) {
82       return algo;
83     }
84   }
85 
86   return absl::nullopt;
87 }
88 
89 // GetKeyProperty returns the given NCrypt key property of |key|.
GetKeyProperty(NCRYPT_KEY_HANDLE key,LPCWSTR property)90 absl::optional<std::vector<uint8_t>> GetKeyProperty(NCRYPT_KEY_HANDLE key,
91                                                     LPCWSTR property) {
92   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
93   DWORD size;
94   if (FAILED(NCryptGetProperty(key, property, nullptr, 0, &size, 0))) {
95     return absl::nullopt;
96   }
97 
98   std::vector<uint8_t> ret(size);
99   if (FAILED(
100           NCryptGetProperty(key, property, ret.data(), ret.size(), &size, 0))) {
101     return absl::nullopt;
102   }
103   CHECK_EQ(ret.size(), size);
104 
105   return ret;
106 }
107 
108 // ExportKey returns |key| exported in the given format or nullopt on error.
ExportKey(NCRYPT_KEY_HANDLE key,LPCWSTR format)109 absl::optional<std::vector<uint8_t>> ExportKey(NCRYPT_KEY_HANDLE key,
110                                                LPCWSTR format) {
111   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
112   DWORD output_size;
113   if (FAILED(NCryptExportKey(key, 0, format, nullptr, nullptr, 0, &output_size,
114                              0))) {
115     return absl::nullopt;
116   }
117 
118   std::vector<uint8_t> output(output_size);
119   if (FAILED(NCryptExportKey(key, 0, format, nullptr, output.data(),
120                              output.size(), &output_size, 0))) {
121     return absl::nullopt;
122   }
123   CHECK_EQ(output.size(), output_size);
124 
125   return output;
126 }
127 
GetP256ECDSASPKI(NCRYPT_KEY_HANDLE key)128 absl::optional<std::vector<uint8_t>> GetP256ECDSASPKI(NCRYPT_KEY_HANDLE key) {
129   const absl::optional<std::vector<uint8_t>> pub_key =
130       ExportKey(key, BCRYPT_ECCPUBLIC_BLOB);
131   if (!pub_key) {
132     return absl::nullopt;
133   }
134 
135   // The exported key is a |BCRYPT_ECCKEY_BLOB| followed by the bytes of the
136   // public key itself.
137   // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecckey_blob
138   BCRYPT_ECCKEY_BLOB header;
139   if (pub_key->size() < sizeof(header)) {
140     return absl::nullopt;
141   }
142   memcpy(&header, pub_key->data(), sizeof(header));
143   // |cbKey| is documented[1] as "the length, in bytes, of the key". It is
144   // not. For ECDSA public keys it is the length of a field element.
145   if ((header.dwMagic != BCRYPT_ECDSA_PUBLIC_P256_MAGIC &&
146        header.dwMagic != BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC) ||
147       header.cbKey != 256 / 8 ||
148       pub_key->size() - sizeof(BCRYPT_ECCKEY_BLOB) != 64) {
149     return absl::nullopt;
150   }
151 
152   // Sometimes NCrypt will return a generic dwMagic even when asked for a P-256
153   // key. In that case, do extra validation to make sure that `key` is in fact
154   // a P-256 key.
155   if (header.dwMagic == BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC) {
156     const absl::optional<std::vector<uint8_t>> curve_name =
157         GetKeyProperty(key, NCRYPT_ECC_CURVE_NAME_PROPERTY);
158     if (!curve_name) {
159       return absl::nullopt;
160     }
161 
162     if (curve_name->size() != sizeof(BCRYPT_ECC_CURVE_NISTP256) ||
163         memcmp(curve_name->data(), BCRYPT_ECC_CURVE_NISTP256,
164                sizeof(BCRYPT_ECC_CURVE_NISTP256)) != 0) {
165       return absl::nullopt;
166     }
167   }
168 
169   uint8_t x962[1 + 32 + 32];
170   x962[0] = POINT_CONVERSION_UNCOMPRESSED;
171   memcpy(&x962[1], pub_key->data() + sizeof(BCRYPT_ECCKEY_BLOB), 64);
172 
173   bssl::UniquePtr<EC_GROUP> p256(
174       EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
175   bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get()));
176   if (!EC_POINT_oct2point(p256.get(), point.get(), x962, sizeof(x962),
177                           /*ctx=*/nullptr)) {
178     return absl::nullopt;
179   }
180   bssl::UniquePtr<EC_KEY> ec_key(
181       EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
182   CHECK(EC_KEY_set_public_key(ec_key.get(), point.get()));
183   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
184   CHECK(EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()));
185 
186   bssl::ScopedCBB cbb;
187   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/128) &&
188         EVP_marshal_public_key(cbb.get(), pkey.get()));
189   return CBBToVector(cbb.get());
190 }
191 
GetRSASPKI(NCRYPT_KEY_HANDLE key)192 absl::optional<std::vector<uint8_t>> GetRSASPKI(NCRYPT_KEY_HANDLE key) {
193   const absl::optional<std::vector<uint8_t>> pub_key =
194       ExportKey(key, BCRYPT_RSAPUBLIC_BLOB);
195   if (!pub_key) {
196     return absl::nullopt;
197   }
198 
199   // The exported key is a |BCRYPT_RSAKEY_BLOB| followed by the bytes of the
200   // key itself.
201   // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob
202   BCRYPT_RSAKEY_BLOB header;
203   if (pub_key->size() < sizeof(header)) {
204     return absl::nullopt;
205   }
206   memcpy(&header, pub_key->data(), sizeof(header));
207   if (header.Magic != static_cast<ULONG>(BCRYPT_RSAPUBLIC_MAGIC)) {
208     return absl::nullopt;
209   }
210 
211   size_t bytes_needed;
212   if (!base::CheckAdd(sizeof(BCRYPT_RSAKEY_BLOB),
213                       base::CheckAdd(header.cbPublicExp, header.cbModulus))
214            .AssignIfValid(&bytes_needed) ||
215       pub_key->size() < bytes_needed) {
216     return absl::nullopt;
217   }
218 
219   bssl::UniquePtr<BIGNUM> e(
220       BN_bin2bn(&pub_key->data()[sizeof(BCRYPT_RSAKEY_BLOB)],
221                 header.cbPublicExp, nullptr));
222   bssl::UniquePtr<BIGNUM> n(BN_bin2bn(
223       &pub_key->data()[sizeof(BCRYPT_RSAKEY_BLOB) + header.cbPublicExp],
224       header.cbModulus, nullptr));
225 
226   bssl::UniquePtr<RSA> rsa(RSA_new());
227   CHECK(RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr));
228   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
229   CHECK(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()));
230 
231   bssl::ScopedCBB cbb;
232   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/384) &&
233         EVP_marshal_public_key(cbb.get(), pkey.get()));
234   return CBBToVector(cbb.get());
235 }
236 
SignECDSA(NCRYPT_KEY_HANDLE key,base::span<const uint8_t> data)237 absl::optional<std::vector<uint8_t>> SignECDSA(NCRYPT_KEY_HANDLE key,
238                                                base::span<const uint8_t> data) {
239   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
240                                                 base::BlockingType::WILL_BLOCK);
241 
242   std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
243   // The signature is written as a pair of big-endian field elements for P-256
244   // ECDSA.
245   std::vector<uint8_t> sig(64);
246   DWORD sig_size;
247   {
248     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
249     if (FAILED(NCryptSignHash(key, nullptr, digest.data(), digest.size(),
250                               sig.data(), sig.size(), &sig_size,
251                               NCRYPT_SILENT_FLAG))) {
252       return absl::nullopt;
253     }
254   }
255   CHECK_EQ(sig.size(), sig_size);
256 
257   bssl::UniquePtr<BIGNUM> r(BN_bin2bn(sig.data(), 32, nullptr));
258   bssl::UniquePtr<BIGNUM> s(BN_bin2bn(sig.data() + 32, 32, nullptr));
259   ECDSA_SIG sig_st;
260   sig_st.r = r.get();
261   sig_st.s = s.get();
262 
263   bssl::ScopedCBB cbb;
264   CHECK(CBB_init(cbb.get(), /*initial_capacity=*/72) &&
265         ECDSA_SIG_marshal(cbb.get(), &sig_st));
266   return CBBToVector(cbb.get());
267 }
268 
SignRSA(NCRYPT_KEY_HANDLE key,base::span<const uint8_t> data)269 absl::optional<std::vector<uint8_t>> SignRSA(NCRYPT_KEY_HANDLE key,
270                                              base::span<const uint8_t> data) {
271   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
272                                                 base::BlockingType::WILL_BLOCK);
273 
274   std::array<uint8_t, kSHA256Length> digest = SHA256Hash(data);
275   BCRYPT_PKCS1_PADDING_INFO padding_info = {0};
276   padding_info.pszAlgId = NCRYPT_SHA256_ALGORITHM;
277 
278   DWORD sig_size;
279   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
280   if (FAILED(NCryptSignHash(key, &padding_info, digest.data(), digest.size(),
281                             nullptr, 0, &sig_size,
282                             NCRYPT_SILENT_FLAG | BCRYPT_PAD_PKCS1))) {
283     return absl::nullopt;
284   }
285 
286   std::vector<uint8_t> sig(sig_size);
287   if (FAILED(NCryptSignHash(key, &padding_info, digest.data(), digest.size(),
288                             sig.data(), sig.size(), &sig_size,
289                             NCRYPT_SILENT_FLAG | BCRYPT_PAD_PKCS1))) {
290     return absl::nullopt;
291   }
292   CHECK_EQ(sig.size(), sig_size);
293 
294   return sig;
295 }
296 
297 // ECDSAKey wraps a TPM-stored P-256 ECDSA key.
298 class ECDSAKey : public UnexportableSigningKey {
299  public:
ECDSAKey(ScopedNCryptKey key,std::vector<uint8_t> wrapped,std::vector<uint8_t> spki)300   ECDSAKey(ScopedNCryptKey key,
301            std::vector<uint8_t> wrapped,
302            std::vector<uint8_t> spki)
303       : key_(std::move(key)),
304         wrapped_(std::move(wrapped)),
305         spki_(std::move(spki)) {}
306 
Algorithm() const307   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
308     return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
309   }
310 
GetSubjectPublicKeyInfo() const311   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
312     return spki_;
313   }
314 
GetWrappedKey() const315   std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
316 
SignSlowly(base::span<const uint8_t> data)317   absl::optional<std::vector<uint8_t>> SignSlowly(
318       base::span<const uint8_t> data) override {
319     return SignECDSA(key_.get(), data);
320   }
321 
322  private:
323   ScopedNCryptKey key_;
324   const std::vector<uint8_t> wrapped_;
325   const std::vector<uint8_t> spki_;
326 };
327 
328 // RSAKey wraps a TPM-stored RSA key.
329 class RSAKey : public UnexportableSigningKey {
330  public:
RSAKey(ScopedNCryptKey key,std::vector<uint8_t> wrapped,std::vector<uint8_t> spki)331   RSAKey(ScopedNCryptKey key,
332          std::vector<uint8_t> wrapped,
333          std::vector<uint8_t> spki)
334       : key_(std::move(key)),
335         wrapped_(std::move(wrapped)),
336         spki_(std::move(spki)) {}
337 
Algorithm() const338   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
339     return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
340   }
341 
GetSubjectPublicKeyInfo() const342   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
343     return spki_;
344   }
345 
GetWrappedKey() const346   std::vector<uint8_t> GetWrappedKey() const override { return wrapped_; }
347 
SignSlowly(base::span<const uint8_t> data)348   absl::optional<std::vector<uint8_t>> SignSlowly(
349       base::span<const uint8_t> data) override {
350     return SignRSA(key_.get(), data);
351   }
352 
353  private:
354   ScopedNCryptKey key_;
355   const std::vector<uint8_t> wrapped_;
356   const std::vector<uint8_t> spki_;
357 };
358 
359 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
360 // Provider to expose TPM-backed keys on Windows.
361 class UnexportableKeyProviderWin : public UnexportableKeyProvider {
362  public:
363   ~UnexportableKeyProviderWin() override = default;
364 
SelectAlgorithm(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)365   absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
366       base::span<const SignatureVerifier::SignatureAlgorithm>
367           acceptable_algorithms) override {
368     ScopedNCryptProvider provider;
369     {
370       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
371       if (FAILED(NCryptOpenStorageProvider(
372               ScopedNCryptProvider::Receiver(provider).get(),
373               MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
374         return absl::nullopt;
375       }
376     }
377 
378     return GetBestSupported(provider.get(), acceptable_algorithms);
379   }
380 
GenerateSigningKeySlowly(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)381   std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly(
382       base::span<const SignatureVerifier::SignatureAlgorithm>
383           acceptable_algorithms) override {
384     base::ScopedBlockingCall scoped_blocking_call(
385         FROM_HERE, base::BlockingType::WILL_BLOCK);
386 
387     ScopedNCryptProvider provider;
388     {
389       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
390       if (FAILED(NCryptOpenStorageProvider(
391               ScopedNCryptProvider::Receiver(provider).get(),
392               MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
393         return nullptr;
394       }
395     }
396 
397     absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
398         GetBestSupported(provider.get(), acceptable_algorithms);
399     if (!algo) {
400       return nullptr;
401     }
402 
403     ScopedNCryptKey key;
404     {
405       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
406       // An empty key name stops the key being persisted to disk.
407       if (FAILED(NCryptCreatePersistedKey(
408               provider.get(), ScopedNCryptKey::Receiver(key).get(),
409               BCryptAlgorithmFor(*algo).value(), /*pszKeyName=*/nullptr,
410               /*dwLegacyKeySpec=*/0, /*dwFlags=*/0))) {
411         return nullptr;
412       }
413 
414       if (FAILED(NCryptFinalizeKey(key.get(), NCRYPT_SILENT_FLAG))) {
415         return nullptr;
416       }
417     }
418 
419     const absl::optional<std::vector<uint8_t>> wrapped_key =
420         ExportKey(key.get(), BCRYPT_OPAQUE_KEY_BLOB);
421     if (!wrapped_key) {
422       return nullptr;
423     }
424 
425     absl::optional<std::vector<uint8_t>> spki;
426     switch (*algo) {
427       case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
428         spki = GetP256ECDSASPKI(key.get());
429         if (!spki) {
430           return nullptr;
431         }
432         return std::make_unique<ECDSAKey>(
433             std::move(key), std::move(*wrapped_key), std::move(spki.value()));
434       case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
435         spki = GetRSASPKI(key.get());
436         if (!spki) {
437           return nullptr;
438         }
439         return std::make_unique<RSAKey>(std::move(key), std::move(*wrapped_key),
440                                         std::move(spki.value()));
441       default:
442         return nullptr;
443     }
444   }
445 
FromWrappedSigningKeySlowly(base::span<const uint8_t> wrapped)446   std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly(
447       base::span<const uint8_t> wrapped) override {
448     base::ScopedBlockingCall scoped_blocking_call(
449         FROM_HERE, base::BlockingType::WILL_BLOCK);
450 
451     ScopedNCryptProvider provider;
452     ScopedNCryptKey key;
453     {
454       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
455       if (FAILED(NCryptOpenStorageProvider(
456               ScopedNCryptProvider::Receiver(provider).get(),
457               MS_PLATFORM_CRYPTO_PROVIDER, /*flags=*/0))) {
458         return nullptr;
459       }
460 
461       if (FAILED(NCryptImportKey(
462               provider.get(), /*hImportKey=*/NULL, BCRYPT_OPAQUE_KEY_BLOB,
463               /*pParameterList=*/nullptr, ScopedNCryptKey::Receiver(key).get(),
464               const_cast<PBYTE>(wrapped.data()), wrapped.size(),
465               /*dwFlags=*/NCRYPT_SILENT_FLAG))) {
466         return nullptr;
467       }
468     }
469 
470     const absl::optional<std::vector<uint8_t>> algo_bytes =
471         GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
472     if (!algo_bytes) {
473       return nullptr;
474     }
475 
476     // The documentation suggests that |NCRYPT_ALGORITHM_PROPERTY| should return
477     // the original algorithm, i.e. |BCRYPT_ECDSA_P256_ALGORITHM| for ECDSA. But
478     // it actually returns just "ECDSA" for that case.
479     static const wchar_t kECDSA[] = L"ECDSA";
480     static const wchar_t kRSA[] = BCRYPT_RSA_ALGORITHM;
481 
482     absl::optional<std::vector<uint8_t>> spki;
483     if (algo_bytes->size() == sizeof(kECDSA) &&
484         memcmp(algo_bytes->data(), kECDSA, sizeof(kECDSA)) == 0) {
485       spki = GetP256ECDSASPKI(key.get());
486       if (!spki) {
487         return nullptr;
488       }
489       return std::make_unique<ECDSAKey>(
490           std::move(key), std::vector<uint8_t>(wrapped.begin(), wrapped.end()),
491           std::move(spki.value()));
492     } else if (algo_bytes->size() == sizeof(kRSA) &&
493                memcmp(algo_bytes->data(), kRSA, sizeof(kRSA)) == 0) {
494       spki = GetRSASPKI(key.get());
495       if (!spki) {
496         return nullptr;
497       }
498       return std::make_unique<RSAKey>(
499           std::move(key), std::vector<uint8_t>(wrapped.begin(), wrapped.end()),
500           std::move(spki.value()));
501     }
502 
503     return nullptr;
504   }
505 };
506 
507 // ECDSASoftwareKey wraps a Credential Guard stored P-256 ECDSA key.
508 class ECDSASoftwareKey : public VirtualUnexportableSigningKey {
509  public:
ECDSASoftwareKey(ScopedNCryptKey key,std::string name,std::vector<uint8_t> spki)510   ECDSASoftwareKey(ScopedNCryptKey key,
511                    std::string name,
512                    std::vector<uint8_t> spki)
513       : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
514 
Algorithm() const515   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
516     return SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
517   }
518 
GetSubjectPublicKeyInfo() const519   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
520     return spki_;
521   }
522 
GetKeyName() const523   std::string GetKeyName() const override { return name_; }
524 
Sign(base::span<const uint8_t> data)525   absl::optional<std::vector<uint8_t>> Sign(
526       base::span<const uint8_t> data) override {
527     if (!valid_) {
528       return absl::nullopt;
529     }
530 
531     return SignECDSA(key_.get(), data);
532   }
533 
DeleteKey()534   bool DeleteKey() override {
535     if (!valid_) {
536       return false;
537     }
538 
539     auto status = NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG);
540     valid_ = false;
541     return !FAILED(status);
542   }
543 
544  private:
545   ScopedNCryptKey key_;
546   const std::string name_;
547   const std::vector<uint8_t> spki_;
548   bool valid_ = true;
549 };
550 
551 // RSASoftwareKey wraps a Credential Guard stored RSA key.
552 class RSASoftwareKey : public VirtualUnexportableSigningKey {
553  public:
RSASoftwareKey(ScopedNCryptKey key,std::string name,std::vector<uint8_t> spki)554   RSASoftwareKey(ScopedNCryptKey key,
555                  std::string name,
556                  std::vector<uint8_t> spki)
557       : key_(std::move(key)), name_(std::move(name)), spki_(std::move(spki)) {}
558 
Algorithm() const559   SignatureVerifier::SignatureAlgorithm Algorithm() const override {
560     return SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
561   }
562 
GetSubjectPublicKeyInfo() const563   std::vector<uint8_t> GetSubjectPublicKeyInfo() const override {
564     return spki_;
565   }
566 
GetKeyName() const567   std::string GetKeyName() const override { return name_; }
568 
Sign(base::span<const uint8_t> data)569   absl::optional<std::vector<uint8_t>> Sign(
570       base::span<const uint8_t> data) override {
571     if (!valid_) {
572       return absl::nullopt;
573     }
574 
575     return SignRSA(key_.get(), data);
576   }
577 
DeleteKey()578   bool DeleteKey() override {
579     if (!valid_) {
580       return false;
581     }
582 
583     auto status = NCryptDeleteKey(key_.get(), NCRYPT_SILENT_FLAG);
584     valid_ = false;
585     return !FAILED(status);
586   }
587 
588  private:
589   ScopedNCryptKey key_;
590   std::string name_;
591   const std::vector<uint8_t> spki_;
592   bool valid_ = true;
593 };
594 
595 // UnexportableKeyProviderWin uses NCrypt and the Platform Crypto
596 // Provider to expose Credential Guard backed keys on Windows.
597 class VirtualUnexportableKeyProviderWin
598     : public VirtualUnexportableKeyProvider {
599  public:
600   ~VirtualUnexportableKeyProviderWin() override = default;
601 
SelectAlgorithm(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms)602   absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm(
603       base::span<const SignatureVerifier::SignatureAlgorithm>
604           acceptable_algorithms) override {
605     ScopedNCryptProvider provider;
606     {
607       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
608       SECURITY_STATUS status = NCryptOpenStorageProvider(
609           ScopedNCryptProvider::Receiver(provider).get(),
610           MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
611       if (FAILED(status)) {
612         base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
613         return absl::nullopt;
614       }
615     }
616 
617     return GetBestSupported(provider.get(), acceptable_algorithms);
618   }
619 
GenerateSigningKey(base::span<const SignatureVerifier::SignatureAlgorithm> acceptable_algorithms,std::string name)620   std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey(
621       base::span<const SignatureVerifier::SignatureAlgorithm>
622           acceptable_algorithms,
623       std::string name) override {
624     base::ScopedBlockingCall scoped_blocking_call(
625         FROM_HERE, base::BlockingType::WILL_BLOCK);
626 
627     ScopedNCryptProvider provider;
628     {
629       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
630       SECURITY_STATUS status = NCryptOpenStorageProvider(
631           ScopedNCryptProvider::Receiver(provider).get(),
632           MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
633       if (FAILED(status)) {
634         base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
635         return nullptr;
636       }
637     }
638 
639     absl::optional<SignatureVerifier::SignatureAlgorithm> algo =
640         GetBestSupported(provider.get(), acceptable_algorithms);
641     if (!algo) {
642       return nullptr;
643     }
644 
645     ScopedNCryptKey key;
646     {
647       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
648       // An empty key name stops the key being persisted to disk.
649       SECURITY_STATUS status = NCryptCreatePersistedKey(
650           provider.get(), ScopedNCryptKey::Receiver(key).get(),
651           BCryptAlgorithmFor(*algo).value(), base::SysUTF8ToWide(name).c_str(),
652           /*dwLegacyKeySpec=*/0,
653           /*dwFlags=*/NCRYPT_USE_VIRTUAL_ISOLATION_FLAG);
654       if (FAILED(status)) {
655         base::UmaHistogramSparse(kMetricVirtualCreateKeyError, status);
656         return nullptr;
657       }
658 
659       status = NCryptFinalizeKey(
660           key.get(), NCRYPT_PROTECT_TO_LOCAL_SYSTEM | NCRYPT_SILENT_FLAG);
661       if (FAILED(status)) {
662         base::UmaHistogramSparse(kMetricVirtualFinalizeKeyError, status);
663         return nullptr;
664       }
665     }
666 
667     absl::optional<std::vector<uint8_t>> spki;
668     switch (*algo) {
669       case SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
670         spki = GetP256ECDSASPKI(key.get());
671         if (!spki) {
672           return nullptr;
673         }
674         return std::make_unique<ECDSASoftwareKey>(std::move(key), name,
675                                                   std::move(spki.value()));
676       case SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
677         spki = GetRSASPKI(key.get());
678         if (!spki) {
679           return nullptr;
680         }
681         return std::make_unique<RSASoftwareKey>(std::move(key), name,
682                                                 std::move(spki.value()));
683       default:
684         return nullptr;
685     }
686   }
687 
FromKeyName(std::string name)688   std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName(
689       std::string name) override {
690     base::ScopedBlockingCall scoped_blocking_call(
691         FROM_HERE, base::BlockingType::WILL_BLOCK);
692 
693     ScopedNCryptProvider provider;
694     ScopedNCryptKey key;
695     {
696       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
697       SECURITY_STATUS status = NCryptOpenStorageProvider(
698           ScopedNCryptProvider::Receiver(provider).get(),
699           MS_KEY_STORAGE_PROVIDER, /*dwFlags=*/0);
700       if (FAILED(status)) {
701         base::UmaHistogramSparse(kMetricVirtualOpenStorageError, status);
702         return nullptr;
703       }
704 
705       status = NCryptOpenKey(
706           provider.get(), ScopedNCryptKey::Receiver(key).get(),
707           base::SysUTF8ToWide(name).c_str(), /*dwLegacyKeySpec=*/0,
708           /*dwFlags*/ 0);
709       if (FAILED(status)) {
710         base::UmaHistogramSparse(kMetricVirtualOpenKeyError, status);
711         return nullptr;
712       }
713     }
714 
715     const absl::optional<std::vector<uint8_t>> algo_bytes =
716         GetKeyProperty(key.get(), NCRYPT_ALGORITHM_PROPERTY);
717 
718     // This is the expected behavior, but note it is different from
719     // TPM backed keys.
720     static const wchar_t kECDSA[] = BCRYPT_ECDSA_P256_ALGORITHM;
721     static const wchar_t kRSA[] = BCRYPT_RSA_ALGORITHM;
722 
723     absl::optional<std::vector<uint8_t>> spki;
724     if (algo_bytes->size() == sizeof(kECDSA) &&
725         memcmp(algo_bytes->data(), kECDSA, sizeof(kECDSA)) == 0) {
726       spki = GetP256ECDSASPKI(key.get());
727       if (!spki) {
728         return nullptr;
729       }
730       return std::make_unique<ECDSASoftwareKey>(std::move(key), name,
731                                                 std::move(spki.value()));
732     } else if (algo_bytes->size() == sizeof(kRSA) &&
733                memcmp(algo_bytes->data(), kRSA, sizeof(kRSA)) == 0) {
734       spki = GetRSASPKI(key.get());
735       if (!spki) {
736         return nullptr;
737       }
738       return std::make_unique<RSASoftwareKey>(std::move(key), name,
739                                               std::move(spki.value()));
740     }
741 
742     return nullptr;
743   }
744 };
745 
746 }  // namespace
747 
GetUnexportableKeyProviderWin()748 std::unique_ptr<UnexportableKeyProvider> GetUnexportableKeyProviderWin() {
749   return std::make_unique<UnexportableKeyProviderWin>();
750 }
751 
752 std::unique_ptr<VirtualUnexportableKeyProvider>
GetVirtualUnexportableKeyProviderWin()753 GetVirtualUnexportableKeyProviderWin() {
754   return std::make_unique<VirtualUnexportableKeyProviderWin>();
755 }
756 
757 }  // namespace crypto
758