summaryrefslogtreecommitdiff
path: root/chromium/net/cert/x509_util_win.cc
blob: ad819d986f6cd058cc9bfad0129ef6feff7c57ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/cert/x509_util_win.h"

#include "base/logging.h"
#include "crypto/scoped_capi_types.h"
#include "crypto/sha2.h"
#include "net/cert/x509_certificate.h"
#include "net/net_buildflags.h"
#include "third_party/boringssl/src/include/openssl/pool.h"

namespace net {

namespace x509_util {

scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts(
    PCCERT_CONTEXT os_cert,
    const std::vector<PCCERT_CONTEXT>& os_chain) {
  return CreateX509CertificateFromCertContexts(os_cert, os_chain, {});
}

scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts(
    PCCERT_CONTEXT os_cert,
    const std::vector<PCCERT_CONTEXT>& os_chain,
    X509Certificate::UnsafeCreateOptions options) {
  if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded)
    return nullptr;
  bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
      X509Certificate::CreateCertBufferFromBytes(
          base::make_span(os_cert->pbCertEncoded, os_cert->cbCertEncoded)));
  if (!cert_handle)
    return nullptr;
  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
  for (PCCERT_CONTEXT os_intermediate : os_chain) {
    if (!os_intermediate || !os_intermediate->pbCertEncoded ||
        !os_intermediate->cbCertEncoded)
      return nullptr;
    bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
        X509Certificate::CreateCertBufferFromBytes(base::make_span(
            os_intermediate->pbCertEncoded, os_intermediate->cbCertEncoded)));
    if (!intermediate_cert_handle)
      return nullptr;
    intermediates.push_back(std::move(intermediate_cert_handle));
  }
  scoped_refptr<X509Certificate> result(
      X509Certificate::CreateFromBufferUnsafeOptions(
          std::move(cert_handle), std::move(intermediates), options));
  return result;
}

crypto::ScopedPCCERT_CONTEXT CreateCertContextWithChain(
    const X509Certificate* cert) {
  return CreateCertContextWithChain(cert, InvalidIntermediateBehavior::kFail);
}

crypto::ScopedPCCERT_CONTEXT CreateCertContextWithChain(
    const X509Certificate* cert,
    InvalidIntermediateBehavior invalid_intermediate_behavior) {
  // Create an in-memory certificate store to hold the certificate and its
  // intermediate certificates. The store will be referenced in the returned
  // PCCERT_CONTEXT, and will not be freed until the PCCERT_CONTEXT is freed.
  crypto::ScopedHCERTSTORE store(
      CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL,
                    CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, nullptr));
  if (!store.is_valid())
    return nullptr;

  PCCERT_CONTEXT primary_cert = nullptr;

  BOOL ok = CertAddEncodedCertificateToStore(
      store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
      base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->cert_buffer())),
      CERT_STORE_ADD_ALWAYS, &primary_cert);
  if (!ok || !primary_cert)
    return nullptr;
  crypto::ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert);

  for (const auto& intermediate : cert->intermediate_buffers()) {
    ok = CertAddEncodedCertificateToStore(
        store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate.get()),
        base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate.get())),
        CERT_STORE_ADD_ALWAYS, nullptr);
    if (!ok) {
      if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
        return nullptr;
      LOG(WARNING) << "error parsing intermediate";
    }
  }

  // Note: |primary_cert| retains a reference to |store|, so the store will
  // actually be freed when |primary_cert| is freed.
  return scoped_primary_cert;
}

SHA256HashValue CalculateFingerprint256(PCCERT_CONTEXT cert) {
  DCHECK(nullptr != cert->pbCertEncoded);
  DCHECK_NE(0u, cert->cbCertEncoded);

  SHA256HashValue sha256;

  // Use crypto::SHA256HashString for two reasons:
  // * < Windows Vista does not have universal SHA-256 support.
  // * More efficient on Windows > Vista (less overhead since non-default CSP
  // is not needed).
  base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded),
                             cert->cbCertEncoded);
  crypto::SHA256HashString(der_cert, sha256.data, sizeof(sha256.data));
  return sha256;
}

bool IsSelfSigned(PCCERT_CONTEXT cert_handle) {
  bool valid_signature = !!CryptVerifyCertificateSignatureEx(
      NULL, X509_ASN_ENCODING, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
      reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)),
      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
      reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), 0,
      nullptr);
  if (!valid_signature)
    return false;
  return !!CertCompareCertificateName(X509_ASN_ENCODING,
                                      &cert_handle->pCertInfo->Subject,
                                      &cert_handle->pCertInfo->Issuer);
}

}  // namespace x509_util

}  // namespace net