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_apple.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <CommonCrypto/CommonDigest.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/cert/x509_certificate.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/cert/x509_util.h"
18*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/pool.h"
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker namespace net {
21*6777b538SAndroid Build Coastguard Worker namespace x509_util {
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker namespace {
24*6777b538SAndroid Build Coastguard Worker
CertBufferFromSecCertificate(SecCertificateRef sec_cert)25*6777b538SAndroid Build Coastguard Worker bssl::UniquePtr<CRYPTO_BUFFER> CertBufferFromSecCertificate(
26*6777b538SAndroid Build Coastguard Worker SecCertificateRef sec_cert) {
27*6777b538SAndroid Build Coastguard Worker if (!sec_cert) {
28*6777b538SAndroid Build Coastguard Worker return nullptr;
29*6777b538SAndroid Build Coastguard Worker }
30*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFDataRef> der_data(
31*6777b538SAndroid Build Coastguard Worker SecCertificateCopyData(sec_cert));
32*6777b538SAndroid Build Coastguard Worker if (!der_data) {
33*6777b538SAndroid Build Coastguard Worker return nullptr;
34*6777b538SAndroid Build Coastguard Worker }
35*6777b538SAndroid Build Coastguard Worker return CreateCryptoBuffer(base::make_span(
36*6777b538SAndroid Build Coastguard Worker CFDataGetBytePtr(der_data.get()),
37*6777b538SAndroid Build Coastguard Worker base::checked_cast<size_t>(CFDataGetLength(der_data.get()))));
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker } // namespace
41*6777b538SAndroid Build Coastguard Worker
CreateSecCertificateFromBytes(base::span<const uint8_t> data)42*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromBytes(
43*6777b538SAndroid Build Coastguard Worker base::span<const uint8_t> data) {
44*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreate(
45*6777b538SAndroid Build Coastguard Worker kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data.data()),
46*6777b538SAndroid Build Coastguard Worker base::checked_cast<CFIndex>(data.size())));
47*6777b538SAndroid Build Coastguard Worker if (!cert_data) {
48*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<SecCertificateRef>();
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker
51*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<SecCertificateRef>(
52*6777b538SAndroid Build Coastguard Worker SecCertificateCreateWithData(nullptr, cert_data.get()));
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef>
CreateSecCertificateFromX509Certificate(const X509Certificate * cert)56*6777b538SAndroid Build Coastguard Worker CreateSecCertificateFromX509Certificate(const X509Certificate* cert) {
57*6777b538SAndroid Build Coastguard Worker return CreateSecCertificateFromBytes(CryptoBufferAsSpan(cert->cert_buffer()));
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFMutableArrayRef>
CreateSecCertificateArrayForX509Certificate(X509Certificate * cert)61*6777b538SAndroid Build Coastguard Worker CreateSecCertificateArrayForX509Certificate(X509Certificate* cert) {
62*6777b538SAndroid Build Coastguard Worker return CreateSecCertificateArrayForX509Certificate(
63*6777b538SAndroid Build Coastguard Worker cert, InvalidIntermediateBehavior::kFail);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFMutableArrayRef>
CreateSecCertificateArrayForX509Certificate(X509Certificate * cert,InvalidIntermediateBehavior invalid_intermediate_behavior)67*6777b538SAndroid Build Coastguard Worker CreateSecCertificateArrayForX509Certificate(
68*6777b538SAndroid Build Coastguard Worker X509Certificate* cert,
69*6777b538SAndroid Build Coastguard Worker InvalidIntermediateBehavior invalid_intermediate_behavior) {
70*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFMutableArrayRef> cert_list(
71*6777b538SAndroid Build Coastguard Worker CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
72*6777b538SAndroid Build Coastguard Worker if (!cert_list)
73*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<CFMutableArrayRef>();
74*6777b538SAndroid Build Coastguard Worker std::string bytes;
75*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert(
76*6777b538SAndroid Build Coastguard Worker CreateSecCertificateFromBytes(CryptoBufferAsSpan(cert->cert_buffer())));
77*6777b538SAndroid Build Coastguard Worker if (!sec_cert) {
78*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<CFMutableArrayRef>();
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker CFArrayAppendValue(cert_list.get(), sec_cert.get());
81*6777b538SAndroid Build Coastguard Worker for (const auto& intermediate : cert->intermediate_buffers()) {
82*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef> intermediate_cert(
83*6777b538SAndroid Build Coastguard Worker CreateSecCertificateFromBytes(CryptoBufferAsSpan(intermediate.get())));
84*6777b538SAndroid Build Coastguard Worker if (!intermediate_cert) {
85*6777b538SAndroid Build Coastguard Worker if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
86*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<CFMutableArrayRef>();
87*6777b538SAndroid Build Coastguard Worker LOG(WARNING) << "error parsing intermediate";
88*6777b538SAndroid Build Coastguard Worker continue;
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker CFArrayAppendValue(cert_list.get(), intermediate_cert.get());
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker return cert_list;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker
CreateX509CertificateFromSecCertificate(base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert,const std::vector<base::apple::ScopedCFTypeRef<SecCertificateRef>> & sec_chain)95*6777b538SAndroid Build Coastguard Worker scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
96*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert,
97*6777b538SAndroid Build Coastguard Worker const std::vector<base::apple::ScopedCFTypeRef<SecCertificateRef>>&
98*6777b538SAndroid Build Coastguard Worker sec_chain) {
99*6777b538SAndroid Build Coastguard Worker return CreateX509CertificateFromSecCertificate(sec_cert, sec_chain, {});
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker
CreateX509CertificateFromSecCertificate(base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert,const std::vector<base::apple::ScopedCFTypeRef<SecCertificateRef>> & sec_chain,X509Certificate::UnsafeCreateOptions options)102*6777b538SAndroid Build Coastguard Worker scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
103*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert,
104*6777b538SAndroid Build Coastguard Worker const std::vector<base::apple::ScopedCFTypeRef<SecCertificateRef>>&
105*6777b538SAndroid Build Coastguard Worker sec_chain,
106*6777b538SAndroid Build Coastguard Worker X509Certificate::UnsafeCreateOptions options) {
107*6777b538SAndroid Build Coastguard Worker bssl::UniquePtr<CRYPTO_BUFFER> cert_handle =
108*6777b538SAndroid Build Coastguard Worker CertBufferFromSecCertificate(sec_cert.get());
109*6777b538SAndroid Build Coastguard Worker if (!cert_handle) {
110*6777b538SAndroid Build Coastguard Worker return nullptr;
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
113*6777b538SAndroid Build Coastguard Worker for (const auto& sec_intermediate : sec_chain) {
114*6777b538SAndroid Build Coastguard Worker bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle =
115*6777b538SAndroid Build Coastguard Worker CertBufferFromSecCertificate(sec_intermediate.get());
116*6777b538SAndroid Build Coastguard Worker if (!intermediate_cert_handle) {
117*6777b538SAndroid Build Coastguard Worker return nullptr;
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker intermediates.push_back(std::move(intermediate_cert_handle));
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker scoped_refptr<X509Certificate> result(
122*6777b538SAndroid Build Coastguard Worker X509Certificate::CreateFromBufferUnsafeOptions(
123*6777b538SAndroid Build Coastguard Worker std::move(cert_handle), std::move(intermediates), options));
124*6777b538SAndroid Build Coastguard Worker return result;
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker
CalculateFingerprint256(SecCertificateRef cert)127*6777b538SAndroid Build Coastguard Worker SHA256HashValue CalculateFingerprint256(SecCertificateRef cert) {
128*6777b538SAndroid Build Coastguard Worker SHA256HashValue sha256;
129*6777b538SAndroid Build Coastguard Worker memset(sha256.data, 0, sizeof(sha256.data));
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFDataRef> cert_data(
132*6777b538SAndroid Build Coastguard Worker SecCertificateCopyData(cert));
133*6777b538SAndroid Build Coastguard Worker if (!cert_data) {
134*6777b538SAndroid Build Coastguard Worker return sha256;
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker DCHECK(CFDataGetBytePtr(cert_data.get()));
138*6777b538SAndroid Build Coastguard Worker DCHECK_NE(CFDataGetLength(cert_data.get()), 0);
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker CC_SHA256(CFDataGetBytePtr(cert_data.get()), CFDataGetLength(cert_data.get()),
141*6777b538SAndroid Build Coastguard Worker sha256.data);
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker return sha256;
144*6777b538SAndroid Build Coastguard Worker }
145*6777b538SAndroid Build Coastguard Worker
CertificateChainFromSecTrust(SecTrustRef trust)146*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFArrayRef> CertificateChainFromSecTrust(
147*6777b538SAndroid Build Coastguard Worker SecTrustRef trust) {
148*6777b538SAndroid Build Coastguard Worker if (__builtin_available(macOS 12.0, iOS 15.0, *)) {
149*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<CFArrayRef>(
150*6777b538SAndroid Build Coastguard Worker SecTrustCopyCertificateChain(trust));
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1426476): Remove code when it is no longer needed.
154*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_MAC) && \
155*6777b538SAndroid Build Coastguard Worker MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0) || \
156*6777b538SAndroid Build Coastguard Worker (BUILDFLAG(IS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_15_0)
157*6777b538SAndroid Build Coastguard Worker base::apple::ScopedCFTypeRef<CFMutableArrayRef> chain(
158*6777b538SAndroid Build Coastguard Worker CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
159*6777b538SAndroid Build Coastguard Worker const CFIndex chain_length = SecTrustGetCertificateCount(trust);
160*6777b538SAndroid Build Coastguard Worker for (CFIndex i = 0; i < chain_length; ++i) {
161*6777b538SAndroid Build Coastguard Worker CFArrayAppendValue(chain.get(), SecTrustGetCertificateAtIndex(trust, i));
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker return chain;
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker #else
166*6777b538SAndroid Build Coastguard Worker // The other logic paths should be used, this is just to make the compiler
167*6777b538SAndroid Build Coastguard Worker // happy.
168*6777b538SAndroid Build Coastguard Worker NOTREACHED();
169*6777b538SAndroid Build Coastguard Worker return base::apple::ScopedCFTypeRef<CFArrayRef>(nullptr);
170*6777b538SAndroid Build Coastguard Worker #endif // (BUILDFLAG(IS_MAC) && MAC_OS_X_VERSION_MIN_REQUIRED <
171*6777b538SAndroid Build Coastguard Worker // MAC_OS_VERSION_12_0)
172*6777b538SAndroid Build Coastguard Worker // || (BUILDFLAG(IS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED <
173*6777b538SAndroid Build Coastguard Worker // __IPHONE_15_0)
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker } // namespace x509_util
177*6777b538SAndroid Build Coastguard Worker } // namespace net
178