• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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/cert/x509_util_win.h"
6 
7 #include "base/logging.h"
8 #include "crypto/scoped_capi_types.h"
9 #include "crypto/sha2.h"
10 #include "net/cert/x509_certificate.h"
11 #include "net/cert/x509_util.h"
12 #include "net/net_buildflags.h"
13 #include "third_party/boringssl/src/include/openssl/pool.h"
14 
15 namespace net {
16 
17 namespace x509_util {
18 
CreateX509CertificateFromCertContexts(PCCERT_CONTEXT os_cert,const std::vector<PCCERT_CONTEXT> & os_chain)19 scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts(
20     PCCERT_CONTEXT os_cert,
21     const std::vector<PCCERT_CONTEXT>& os_chain) {
22   return CreateX509CertificateFromCertContexts(os_cert, os_chain, {});
23 }
24 
CreateX509CertificateFromCertContexts(PCCERT_CONTEXT os_cert,const std::vector<PCCERT_CONTEXT> & os_chain,X509Certificate::UnsafeCreateOptions options)25 scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts(
26     PCCERT_CONTEXT os_cert,
27     const std::vector<PCCERT_CONTEXT>& os_chain,
28     X509Certificate::UnsafeCreateOptions options) {
29   if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded)
30     return nullptr;
31   bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(x509_util::CreateCryptoBuffer(
32       base::make_span(os_cert->pbCertEncoded, os_cert->cbCertEncoded)));
33 
34   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
35   for (PCCERT_CONTEXT os_intermediate : os_chain) {
36     if (!os_intermediate || !os_intermediate->pbCertEncoded ||
37         !os_intermediate->cbCertEncoded)
38       return nullptr;
39     intermediates.push_back(x509_util::CreateCryptoBuffer(base::make_span(
40         os_intermediate->pbCertEncoded, os_intermediate->cbCertEncoded)));
41   }
42 
43   return X509Certificate::CreateFromBufferUnsafeOptions(
44       std::move(cert_handle), std::move(intermediates), options);
45 }
46 
CreateCertContextWithChain(const X509Certificate * cert)47 crypto::ScopedPCCERT_CONTEXT CreateCertContextWithChain(
48     const X509Certificate* cert) {
49   return CreateCertContextWithChain(cert, InvalidIntermediateBehavior::kFail);
50 }
51 
CreateCertContextWithChain(const X509Certificate * cert,InvalidIntermediateBehavior invalid_intermediate_behavior)52 crypto::ScopedPCCERT_CONTEXT CreateCertContextWithChain(
53     const X509Certificate* cert,
54     InvalidIntermediateBehavior invalid_intermediate_behavior) {
55   // Create an in-memory certificate store to hold the certificate and its
56   // intermediate certificates. The store will be referenced in the returned
57   // PCCERT_CONTEXT, and will not be freed until the PCCERT_CONTEXT is freed.
58   crypto::ScopedHCERTSTORE store(
59       CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL,
60                     CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, nullptr));
61   if (!store.is_valid())
62     return nullptr;
63 
64   PCCERT_CONTEXT primary_cert = nullptr;
65 
66   BOOL ok = CertAddEncodedCertificateToStore(
67       store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
68       base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->cert_buffer())),
69       CERT_STORE_ADD_ALWAYS, &primary_cert);
70   if (!ok || !primary_cert)
71     return nullptr;
72   crypto::ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert);
73 
74   for (const auto& intermediate : cert->intermediate_buffers()) {
75     ok = CertAddEncodedCertificateToStore(
76         store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate.get()),
77         base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate.get())),
78         CERT_STORE_ADD_ALWAYS, nullptr);
79     if (!ok) {
80       if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
81         return nullptr;
82       LOG(WARNING) << "error parsing intermediate";
83     }
84   }
85 
86   // Note: |primary_cert| retains a reference to |store|, so the store will
87   // actually be freed when |primary_cert| is freed.
88   return scoped_primary_cert;
89 }
90 
CalculateFingerprint256(PCCERT_CONTEXT cert)91 SHA256HashValue CalculateFingerprint256(PCCERT_CONTEXT cert) {
92   DCHECK(nullptr != cert->pbCertEncoded);
93   DCHECK_NE(0u, cert->cbCertEncoded);
94 
95   SHA256HashValue sha256;
96 
97   // Use crypto::SHA256HashString for two reasons:
98   // * < Windows Vista does not have universal SHA-256 support.
99   // * More efficient on Windows > Vista (less overhead since non-default CSP
100   // is not needed).
101   base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded),
102                              cert->cbCertEncoded);
103   crypto::SHA256HashString(der_cert, sha256.data, sizeof(sha256.data));
104   return sha256;
105 }
106 
IsSelfSigned(PCCERT_CONTEXT cert_handle)107 bool IsSelfSigned(PCCERT_CONTEXT cert_handle) {
108   bool valid_signature = !!CryptVerifyCertificateSignatureEx(
109       NULL, X509_ASN_ENCODING, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
110       reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)),
111       CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
112       reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), 0,
113       nullptr);
114   if (!valid_signature)
115     return false;
116   return !!CertCompareCertificateName(X509_ASN_ENCODING,
117                                       &cert_handle->pCertInfo->Subject,
118                                       &cert_handle->pCertInfo->Issuer);
119 }
120 
121 }  // namespace x509_util
122 
123 }  // namespace net
124