xref: /aosp_15_r20/external/cronet/net/ssl/ssl_platform_key_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/ssl/ssl_platform_key_win.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/feature_list.h"
13 #include "base/logging.h"
14 #include "base/ranges/algorithm.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "crypto/openssl_util.h"
17 #include "crypto/scoped_capi_types.h"
18 #include "crypto/scoped_cng_types.h"
19 #include "crypto/unexportable_key_win.h"
20 #include "net/base/features.h"
21 #include "net/base/net_errors.h"
22 #include "net/cert/x509_certificate.h"
23 #include "net/ssl/ssl_platform_key_util.h"
24 #include "net/ssl/ssl_private_key.h"
25 #include "net/ssl/threaded_ssl_private_key.h"
26 #include "third_party/boringssl/src/include/openssl/bn.h"
27 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
28 #include "third_party/boringssl/src/include/openssl/evp.h"
29 #include "third_party/boringssl/src/include/openssl/ssl.h"
30 
31 namespace net {
32 
33 namespace {
34 
ProbeSHA256(ThreadedSSLPrivateKey::Delegate * delegate)35 bool ProbeSHA256(ThreadedSSLPrivateKey::Delegate* delegate) {
36   if (!base::FeatureList::IsEnabled(features::kPlatformKeyProbeSHA256)) {
37     return false;
38   }
39 
40   // This input is chosen to avoid colliding with other signing inputs used in
41   // TLS 1.2 or TLS 1.3. We use the construct in RFC 8446, section 4.4.3, but
42   // change the context string. The context string ensures we don't collide with
43   // TLS 1.3 and any future version. The 0x20 (space) prefix ensures we don't
44   // collide with TLS 1.2 ServerKeyExchange or CertificateVerify.
45   static const uint8_t kSHA256ProbeInput[] = {
46       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
47       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
48       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
49       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
50       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
51       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 'C',  'h',
52       'r',  'o',  'm',  'i',  'u',  'm',  ',',  ' ',  'S',  'H',  'A',
53       '2',  ' ',  'P',  'r',  'o',  'b',  'e',  0x00,
54   };
55   std::vector<uint8_t> signature;
56   return delegate->Sign(SSL_SIGN_RSA_PKCS1_SHA256, kSHA256ProbeInput,
57                         &signature) == OK;
58 }
59 
GetCAPIProviderName(HCRYPTPROV provider)60 std::string GetCAPIProviderName(HCRYPTPROV provider) {
61   DWORD name_len;
62   if (!CryptGetProvParam(provider, PP_NAME, nullptr, &name_len, 0)) {
63     return "(error getting name)";
64   }
65   std::vector<BYTE> name(name_len);
66   if (!CryptGetProvParam(provider, PP_NAME, name.data(), &name_len, 0)) {
67     return "(error getting name)";
68   }
69   // Per Microsoft's documentation, PP_NAME is NUL-terminated. However,
70   // smartcard drivers are notoriously buggy, so check this.
71   auto nul = base::ranges::find(name, 0);
72   if (nul != name.end()) {
73     name_len = nul - name.begin();
74   }
75   return std::string(reinterpret_cast<const char*>(name.data()), name_len);
76 }
77 
78 class SSLPlatformKeyCAPI : public ThreadedSSLPrivateKey::Delegate {
79  public:
80   // Takes ownership of |provider|.
SSLPlatformKeyCAPI(crypto::ScopedHCRYPTPROV provider,DWORD key_spec)81   SSLPlatformKeyCAPI(crypto::ScopedHCRYPTPROV provider, DWORD key_spec)
82       : provider_name_(GetCAPIProviderName(provider.get())),
83         provider_(std::move(provider)),
84         key_spec_(key_spec) {
85     // Check for SHA-256 support. The CAPI service provider may only be able to
86     // sign pre-TLS-1.2 and SHA-1 hashes. If SHA-256 doesn't work, prioritize
87     // SHA-1 as a workaround. See https://crbug.com/278370.
88     prefer_sha1_ = !ProbeSHA256(this);
89   }
90 
91   SSLPlatformKeyCAPI(const SSLPlatformKeyCAPI&) = delete;
92   SSLPlatformKeyCAPI& operator=(const SSLPlatformKeyCAPI&) = delete;
93 
94   ~SSLPlatformKeyCAPI() override = default;
95 
GetProviderName()96   std::string GetProviderName() override { return "CAPI: " + provider_name_; }
97 
GetAlgorithmPreferences()98   std::vector<uint16_t> GetAlgorithmPreferences() override {
99     if (prefer_sha1_) {
100       return {SSL_SIGN_RSA_PKCS1_SHA1, SSL_SIGN_RSA_PKCS1_SHA256,
101               SSL_SIGN_RSA_PKCS1_SHA384, SSL_SIGN_RSA_PKCS1_SHA512};
102     }
103     return {SSL_SIGN_RSA_PKCS1_SHA256, SSL_SIGN_RSA_PKCS1_SHA384,
104             SSL_SIGN_RSA_PKCS1_SHA512, SSL_SIGN_RSA_PKCS1_SHA1};
105   }
106 
Sign(uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * signature)107   Error Sign(uint16_t algorithm,
108              base::span<const uint8_t> input,
109              std::vector<uint8_t>* signature) override {
110     const EVP_MD* md = SSL_get_signature_algorithm_digest(algorithm);
111     uint8_t digest[EVP_MAX_MD_SIZE];
112     unsigned digest_len;
113     if (!md || !EVP_Digest(input.data(), input.size(), digest, &digest_len, md,
114                            nullptr)) {
115       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
116     }
117 
118     ALG_ID hash_alg;
119     switch (EVP_MD_type(md)) {
120       case NID_md5_sha1:
121         hash_alg = CALG_SSL3_SHAMD5;
122         break;
123       case NID_sha1:
124         hash_alg = CALG_SHA1;
125         break;
126       case NID_sha256:
127         hash_alg = CALG_SHA_256;
128         break;
129       case NID_sha384:
130         hash_alg = CALG_SHA_384;
131         break;
132       case NID_sha512:
133         hash_alg = CALG_SHA_512;
134         break;
135       default:
136         NOTREACHED();
137         return ERR_FAILED;
138     }
139 
140     crypto::ScopedHCRYPTHASH hash_handle;
141     if (!CryptCreateHash(
142             provider_.get(), hash_alg, 0, 0,
143             crypto::ScopedHCRYPTHASH::Receiver(hash_handle).get())) {
144       PLOG(ERROR) << "CreateCreateHash failed";
145       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
146     }
147     DWORD hash_len;
148     DWORD arg_len = sizeof(hash_len);
149     if (!CryptGetHashParam(hash_handle.get(), HP_HASHSIZE,
150                            reinterpret_cast<BYTE*>(&hash_len), &arg_len, 0)) {
151       PLOG(ERROR) << "CryptGetHashParam HP_HASHSIZE failed";
152       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
153     }
154     if (hash_len != digest_len)
155       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
156     if (!CryptSetHashParam(hash_handle.get(), HP_HASHVAL,
157                            const_cast<BYTE*>(digest), 0)) {
158       PLOG(ERROR) << "CryptSetHashParam HP_HASHVAL failed";
159       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
160     }
161     DWORD signature_len = 0;
162     if (!CryptSignHash(hash_handle.get(), key_spec_, nullptr, 0, nullptr,
163                        &signature_len)) {
164       PLOG(ERROR) << "CryptSignHash failed";
165       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
166     }
167     signature->resize(signature_len);
168     if (!CryptSignHash(hash_handle.get(), key_spec_, nullptr, 0,
169                        signature->data(), &signature_len)) {
170       PLOG(ERROR) << "CryptSignHash failed";
171       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
172     }
173     signature->resize(signature_len);
174 
175     // CryptoAPI signs in little-endian, so reverse it.
176     std::reverse(signature->begin(), signature->end());
177     return OK;
178   }
179 
180  private:
181   std::string provider_name_;
182   crypto::ScopedHCRYPTPROV provider_;
183   DWORD key_spec_;
184   bool prefer_sha1_ = false;
185 };
186 
GetCNGProviderName(NCRYPT_KEY_HANDLE key)187 std::wstring GetCNGProviderName(NCRYPT_KEY_HANDLE key) {
188   crypto::ScopedNCryptProvider prov;
189   DWORD prov_len = 0;
190   SECURITY_STATUS status = NCryptGetProperty(
191       key, NCRYPT_PROVIDER_HANDLE_PROPERTY,
192       reinterpret_cast<BYTE*>(
193           crypto::ScopedNCryptProvider::Receiver(prov).get()),
194       sizeof(NCRYPT_PROV_HANDLE), &prov_len, NCRYPT_SILENT_FLAG);
195   if (FAILED(status)) {
196     return L"(error getting provider)";
197   }
198   DCHECK_EQ(sizeof(NCRYPT_PROV_HANDLE), prov_len);
199 
200   // NCRYPT_NAME_PROPERTY is a NUL-terminated Unicode string, which means an
201   // array of wchar_t, however NCryptGetProperty works in bytes, so lengths must
202   // be converted.
203   DWORD name_len = 0;
204   status = NCryptGetProperty(prov.get(), NCRYPT_NAME_PROPERTY, nullptr, 0,
205                              &name_len, NCRYPT_SILENT_FLAG);
206   if (FAILED(status) || name_len % sizeof(wchar_t) != 0) {
207     return L"(error getting provider name)";
208   }
209   std::vector<wchar_t> name;
210   name.reserve(name_len / sizeof(wchar_t));
211   status = NCryptGetProperty(
212       prov.get(), NCRYPT_NAME_PROPERTY, reinterpret_cast<BYTE*>(name.data()),
213       name.size() * sizeof(wchar_t), &name_len, NCRYPT_SILENT_FLAG);
214   if (FAILED(status)) {
215     return L"(error getting provider name)";
216   }
217   name.resize(name_len / sizeof(wchar_t));
218 
219   // Per Microsoft's documentation, the name is NUL-terminated. However,
220   // smartcard drivers are notoriously buggy, so check this.
221   auto nul = base::ranges::find(name, 0);
222   if (nul != name.end()) {
223     name.erase(nul, name.end());
224   }
225   return std::wstring(name.begin(), name.end());
226 }
227 
228 class SSLPlatformKeyCNG : public ThreadedSSLPrivateKey::Delegate {
229  public:
230   // Takes ownership of |key|.
SSLPlatformKeyCNG(crypto::ScopedNCryptKey key,int type,size_t max_length)231   SSLPlatformKeyCNG(crypto::ScopedNCryptKey key, int type, size_t max_length)
232       : provider_name_(GetCNGProviderName(key.get())),
233         key_(std::move(key)),
234         type_(type),
235         max_length_(max_length) {
236     // If this is a 1024-bit RSA key or below, check for SHA-256 support. Older
237     // Estonian ID cards can only sign SHA-1 hashes. If SHA-256 does not work,
238     // prioritize SHA-1 as a workaround. See https://crbug.com/278370.
239     prefer_sha1_ =
240         type_ == EVP_PKEY_RSA && max_length_ <= 1024 / 8 && !ProbeSHA256(this);
241   }
242 
243   SSLPlatformKeyCNG(const SSLPlatformKeyCNG&) = delete;
244   SSLPlatformKeyCNG& operator=(const SSLPlatformKeyCNG&) = delete;
245 
GetProviderName()246   std::string GetProviderName() override {
247     return "CNG: " + base::WideToUTF8(provider_name_);
248   }
249 
GetAlgorithmPreferences()250   std::vector<uint16_t> GetAlgorithmPreferences() override {
251     // Per TLS 1.3 (RFC 8446), the RSA-PSS code points in TLS correspond to
252     // RSA-PSS with salt length equal to the digest length. TPM 2.0's
253     // TPM_ALG_RSAPSS algorithm, however, uses the maximum possible salt length.
254     // The TPM provider will fail signing requests for other salt lengths and
255     // thus cannot generate TLS-compatible PSS signatures.
256     //
257     // However, as of TPM revision 1.16, TPMs which follow FIPS 186-4 will
258     // instead interpret TPM_ALG_RSAPSS using salt length equal to the digest
259     // length. Those TPMs can generate TLS-compatible PSS signatures. As a
260     // result, if this is a TPM-based key, we only report PSS as supported if
261     // the salt length will match the digest length.
262     bool supports_pss = true;
263     if (provider_name_ == MS_PLATFORM_KEY_STORAGE_PROVIDER) {
264       DWORD salt_size = 0;
265       DWORD size_of_salt_size = sizeof(salt_size);
266       HRESULT status =
267           NCryptGetProperty(key_.get(), NCRYPT_PCP_PSS_SALT_SIZE_PROPERTY,
268                             reinterpret_cast<PBYTE>(&salt_size),
269                             size_of_salt_size, &size_of_salt_size, 0);
270       if (FAILED(status) || salt_size != NCRYPT_TPM_PSS_SALT_SIZE_HASHSIZE) {
271         supports_pss = false;
272       }
273     }
274     if (prefer_sha1_) {
275       std::vector<uint16_t> ret = {
276           SSL_SIGN_RSA_PKCS1_SHA1,
277           SSL_SIGN_RSA_PKCS1_SHA256,
278           SSL_SIGN_RSA_PKCS1_SHA384,
279           SSL_SIGN_RSA_PKCS1_SHA512,
280       };
281       if (supports_pss) {
282         ret.push_back(SSL_SIGN_RSA_PSS_SHA256);
283         ret.push_back(SSL_SIGN_RSA_PSS_SHA384);
284         ret.push_back(SSL_SIGN_RSA_PSS_SHA512);
285       }
286       return ret;
287     }
288     return SSLPrivateKey::DefaultAlgorithmPreferences(type_, supports_pss);
289   }
290 
Sign(uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * signature)291   Error Sign(uint16_t algorithm,
292              base::span<const uint8_t> input,
293              std::vector<uint8_t>* signature) override {
294     crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
295 
296     const EVP_MD* md = SSL_get_signature_algorithm_digest(algorithm);
297     uint8_t digest[EVP_MAX_MD_SIZE];
298     unsigned digest_len;
299     if (!md || !EVP_Digest(input.data(), input.size(), digest, &digest_len, md,
300                            nullptr)) {
301       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
302     }
303 
304     BCRYPT_PKCS1_PADDING_INFO pkcs1_padding_info = {nullptr};
305     BCRYPT_PSS_PADDING_INFO pss_padding_info = {nullptr};
306     void* padding_info = nullptr;
307     DWORD flags = 0;
308     if (SSL_get_signature_algorithm_key_type(algorithm) == EVP_PKEY_RSA) {
309       const WCHAR* hash_alg;
310       switch (EVP_MD_type(md)) {
311         case NID_md5_sha1:
312           hash_alg = nullptr;
313           break;
314         case NID_sha1:
315           hash_alg = BCRYPT_SHA1_ALGORITHM;
316           break;
317         case NID_sha256:
318           hash_alg = BCRYPT_SHA256_ALGORITHM;
319           break;
320         case NID_sha384:
321           hash_alg = BCRYPT_SHA384_ALGORITHM;
322           break;
323         case NID_sha512:
324           hash_alg = BCRYPT_SHA512_ALGORITHM;
325           break;
326         default:
327           NOTREACHED();
328           return ERR_FAILED;
329       }
330       if (SSL_is_signature_algorithm_rsa_pss(algorithm)) {
331         pss_padding_info.pszAlgId = hash_alg;
332         pss_padding_info.cbSalt = EVP_MD_size(md);
333         padding_info = &pss_padding_info;
334         flags |= BCRYPT_PAD_PSS;
335       } else {
336         pkcs1_padding_info.pszAlgId = hash_alg;
337         padding_info = &pkcs1_padding_info;
338         flags |= BCRYPT_PAD_PKCS1;
339       }
340     }
341 
342     DWORD signature_len;
343     SECURITY_STATUS status =
344         NCryptSignHash(key_.get(), padding_info, const_cast<BYTE*>(digest),
345                        digest_len, nullptr, 0, &signature_len, flags);
346     if (FAILED(status)) {
347       LOG(ERROR) << "NCryptSignHash failed: " << status;
348       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
349     }
350     signature->resize(signature_len);
351     status = NCryptSignHash(key_.get(), padding_info, const_cast<BYTE*>(digest),
352                             digest_len, signature->data(), signature_len,
353                             &signature_len, flags);
354     if (FAILED(status)) {
355       LOG(ERROR) << "NCryptSignHash failed: " << status;
356       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
357     }
358     signature->resize(signature_len);
359 
360     // CNG emits raw ECDSA signatures, but BoringSSL expects a DER-encoded
361     // ECDSA-Sig-Value.
362     if (type_ == EVP_PKEY_EC) {
363       if (signature->size() % 2 != 0) {
364         LOG(ERROR) << "Bad signature length";
365         return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
366       }
367       size_t order_len = signature->size() / 2;
368 
369       // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value.
370       bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
371       if (!sig || !BN_bin2bn(signature->data(), order_len, sig->r) ||
372           !BN_bin2bn(signature->data() + order_len, order_len, sig->s)) {
373         return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
374       }
375 
376       int len = i2d_ECDSA_SIG(sig.get(), nullptr);
377       if (len <= 0)
378         return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
379       signature->resize(len);
380       uint8_t* ptr = signature->data();
381       len = i2d_ECDSA_SIG(sig.get(), &ptr);
382       if (len <= 0)
383         return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
384       signature->resize(len);
385     }
386 
387     return OK;
388   }
389 
390  private:
391   std::wstring provider_name_;
392   crypto::ScopedNCryptKey key_;
393   int type_;
394   size_t max_length_;
395   bool prefer_sha1_ = false;
396 };
397 
398 }  // namespace
399 
WrapCAPIPrivateKey(const X509Certificate * certificate,crypto::ScopedHCRYPTPROV prov,DWORD key_spec)400 scoped_refptr<SSLPrivateKey> WrapCAPIPrivateKey(
401     const X509Certificate* certificate,
402     crypto::ScopedHCRYPTPROV prov,
403     DWORD key_spec) {
404   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
405       std::make_unique<SSLPlatformKeyCAPI>(std::move(prov), key_spec),
406       GetSSLPlatformKeyTaskRunner());
407 }
408 
WrapCNGPrivateKey(const X509Certificate * certificate,crypto::ScopedNCryptKey key)409 scoped_refptr<SSLPrivateKey> WrapCNGPrivateKey(
410     const X509Certificate* certificate,
411     crypto::ScopedNCryptKey key) {
412   // Rather than query the private key for metadata, extract the public key from
413   // the certificate without using Windows APIs. CNG does not consistently work
414   // depending on the system. See https://crbug.com/468345.
415   int key_type;
416   size_t max_length;
417   if (!GetClientCertInfo(certificate, &key_type, &max_length)) {
418     return nullptr;
419   }
420 
421   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
422       std::make_unique<SSLPlatformKeyCNG>(std::move(key), key_type, max_length),
423       GetSSLPlatformKeyTaskRunner());
424 }
425 
FetchClientCertPrivateKey(const X509Certificate * certificate,PCCERT_CONTEXT cert_context)426 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
427     const X509Certificate* certificate,
428     PCCERT_CONTEXT cert_context) {
429   HCRYPTPROV_OR_NCRYPT_KEY_HANDLE prov_or_key = 0;
430   DWORD key_spec = 0;
431   BOOL must_free = FALSE;
432   DWORD flags = CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG;
433 
434   if (!CryptAcquireCertificatePrivateKey(cert_context, flags, nullptr,
435                                          &prov_or_key, &key_spec, &must_free)) {
436     PLOG(WARNING) << "Could not acquire private key";
437     return nullptr;
438   }
439 
440   // Should never get a cached handle back - ownership must always be
441   // transferred.
442   CHECK_EQ(must_free, TRUE);
443 
444   if (key_spec == CERT_NCRYPT_KEY_SPEC) {
445     return WrapCNGPrivateKey(certificate, crypto::ScopedNCryptKey(prov_or_key));
446   } else {
447     return WrapCAPIPrivateKey(certificate,
448                               crypto::ScopedHCRYPTPROV(prov_or_key), key_spec);
449   }
450 }
451 
WrapUnexportableKeySlowly(const crypto::UnexportableSigningKey & key)452 scoped_refptr<SSLPrivateKey> WrapUnexportableKeySlowly(
453     const crypto::UnexportableSigningKey& key) {
454   // Load NCRYPT_KEY_HANDLE from wrapped.
455   auto wrapped = key.GetWrappedKey();
456   crypto::ScopedNCryptProvider provider;
457   crypto::ScopedNCryptKey key_handle;
458   if (!crypto::LoadWrappedTPMKey(wrapped, provider, key_handle)) {
459     return nullptr;
460   }
461 
462   int key_type;
463   size_t max_length;
464   if (!GetPublicKeyInfo(key.GetSubjectPublicKeyInfo(), &key_type,
465                         &max_length)) {
466     return nullptr;
467   }
468 
469   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
470       std::make_unique<SSLPlatformKeyCNG>(std::move(key_handle), key_type,
471                                           max_length),
472       GetSSLPlatformKeyTaskRunner());
473 }
474 
475 }  // namespace net
476