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