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