• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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