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