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