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