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