xref: /aosp_15_r20/external/cronet/net/cert/x509_util_apple.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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