blob: 50f94d87552c5ff2c2589f1ca74c91b95e5222e2 [file] [log] [blame]
mattmea4ed8232017-02-28 23:13:231// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/cert/internal/trust_store_mac.h"
6
7#include <Security/Security.h>
8
Matt Mueller5d105e72019-07-01 17:38:429#include "base/atomicops.h"
10#include "base/bind.h"
11#include "base/callback_list.h"
12#include "base/containers/flat_map.h"
Matt Mueller1b4c2342021-03-16 17:57:0413#include "base/containers/mru_cache.h"
mattmea4ed8232017-02-28 23:13:2314#include "base/logging.h"
15#include "base/mac/foundation_util.h"
16#include "base/mac/mac_logging.h"
Matt Mueller5d105e72019-07-01 17:38:4217#include "base/no_destructor.h"
mattmea4ed8232017-02-28 23:13:2318#include "base/synchronization/lock.h"
19#include "crypto/mac_security_services_lock.h"
Matt Mueller5d105e72019-07-01 17:38:4220#include "net/base/hash_value.h"
21#include "net/base/network_notification_thread_mac.h"
mattmea4ed8232017-02-28 23:13:2322#include "net/cert/internal/cert_errors.h"
23#include "net/cert/internal/parse_name.h"
24#include "net/cert/internal/parsed_certificate.h"
Matt Mueller1b4c2342021-03-16 17:57:0425#include "net/cert/known_roots_mac.h"
mattmea4ed8232017-02-28 23:13:2326#include "net/cert/test_keychain_search_list_mac.h"
mattmea4ed8232017-02-28 23:13:2327#include "net/cert/x509_util.h"
mattm4cede8d2017-04-11 02:55:0128#include "net/cert/x509_util_mac.h"
Matt Mueller5d105e72019-07-01 17:38:4229#include "third_party/boringssl/src/include/openssl/sha.h"
mattmea4ed8232017-02-28 23:13:2330
31namespace net {
32
33namespace {
34
35// The rules for interpreting trust settings are documented at:
36// https://developer.apple.com/reference/security/1400261-sectrustsettingscopytrustsetting?language=objc
37
38// Indicates the trust status of a certificate.
39enum class TrustStatus {
Matt Mueller5d105e72019-07-01 17:38:4240 // Trust status is unknown / uninitialized.
41 UNKNOWN,
mattmea4ed8232017-02-28 23:13:2342 // Certificate inherits trust value from its issuer. If the certificate is the
43 // root of the chain, this implies distrust.
44 UNSPECIFIED,
45 // Certificate is a trust anchor.
46 TRUSTED,
Ryan Sleevia9d6aa62019-07-26 13:32:1847 // Certificate is blocked / explicitly distrusted.
mattmea4ed8232017-02-28 23:13:2348 DISTRUSTED
49};
50
Matt Mueller7ac4af5c2021-03-30 18:58:5351enum class KnownRootStatus {
52 UNKNOWN,
53 IS_KNOWN_ROOT,
54 NOT_KNOWN_ROOT,
55};
56
Matt Mueller370a7fda2019-08-22 00:38:5957const void* kResultDebugDataKey = &kResultDebugDataKey;
58
mattmea4ed8232017-02-28 23:13:2359// Returns trust status of usage constraints dictionary |trust_dict| for a
Matt Mueller59ebd7d2019-04-19 17:56:4060// certificate that |is_self_issued|.
mattmea4ed8232017-02-28 23:13:2361TrustStatus IsTrustDictionaryTrustedForPolicy(
62 CFDictionaryRef trust_dict,
Matt Mueller59ebd7d2019-04-19 17:56:4063 bool is_self_issued,
Matt Mueller370a7fda2019-08-22 00:38:5964 const CFStringRef target_policy_oid,
65 int* debug_info) {
mattmea4ed8232017-02-28 23:13:2366 // An empty trust dict should be interpreted as
67 // kSecTrustSettingsResultTrustRoot. This is handled by falling through all
68 // the conditions below with the default value of |trust_settings_result|.
Matt Mueller370a7fda2019-08-22 00:38:5969 CFIndex dict_size = CFDictionaryGetCount(trust_dict);
70 if (dict_size == 0)
71 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_EMPTY;
72
73 CFIndex known_elements = 0;
74 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsPolicy)) {
75 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_POLICY;
76 known_elements++;
77 }
78 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsApplication)) {
79 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_APPLICATION;
80 known_elements++;
81 }
82 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsPolicyString)) {
83 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_POLICY_STRING;
84 known_elements++;
85 }
86 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsKeyUsage)) {
87 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_KEY_USAGE;
88 known_elements++;
89 }
90 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsResult)) {
91 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_RESULT;
92 known_elements++;
93 }
94 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsAllowedError)) {
95 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_ALLOWED_ERROR;
96 known_elements++;
97 }
98 if (known_elements != dict_size)
99 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_UNKNOWN_KEY;
mattmea4ed8232017-02-28 23:13:23100
101 // Trust settings may be scoped to a single application, by checking that the
102 // code signing identity of the current application matches the serialized
103 // code signing identity in the kSecTrustSettingsApplication key.
104 // As this is not presently supported, skip any trust settings scoped to the
105 // application.
106 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsApplication))
107 return TrustStatus::UNSPECIFIED;
108
109 // Trust settings may be scoped using policy-specific constraints. For
110 // example, SSL trust settings might be scoped to a single hostname, or EAP
111 // settings specific to a particular WiFi network.
112 // As this is not presently supported, skip any policy-specific trust
113 // settings.
114 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsPolicyString))
115 return TrustStatus::UNSPECIFIED;
116
117 // Ignoring kSecTrustSettingsKeyUsage for now; it does not seem relevant to
118 // the TLS case.
119
120 // If the trust settings are scoped to a specific policy (via
121 // kSecTrustSettingsPolicy), ensure that the policy is the same policy as
122 // |target_policy_oid|. If there is no kSecTrustSettingsPolicy key, it's
123 // considered a match for all policies.
Matt Mueller370a7fda2019-08-22 00:38:59124 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsPolicy)) {
125 SecPolicyRef policy_ref = base::mac::GetValueFromDictionary<SecPolicyRef>(
126 trust_dict, kSecTrustSettingsPolicy);
127 if (!policy_ref) {
128 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_INVALID_POLICY_TYPE;
129 return TrustStatus::UNSPECIFIED;
130 }
mattmea4ed8232017-02-28 23:13:23131 base::ScopedCFTypeRef<CFDictionaryRef> policy_dict;
132 {
133 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
134 policy_dict.reset(SecPolicyCopyProperties(policy_ref));
135 }
136
137 // kSecPolicyOid is guaranteed to be present in the policy dictionary.
mattmea4ed8232017-02-28 23:13:23138 CFStringRef policy_oid = base::mac::GetValueFromDictionary<CFStringRef>(
Avi Drissman905bac72020-10-24 17:26:31139 policy_dict, kSecPolicyOid);
mattmea4ed8232017-02-28 23:13:23140
141 if (!CFEqual(policy_oid, target_policy_oid))
142 return TrustStatus::UNSPECIFIED;
143 }
144
145 // If kSecTrustSettingsResult is not present in the trust dict,
146 // kSecTrustSettingsResultTrustRoot is assumed.
147 int trust_settings_result = kSecTrustSettingsResultTrustRoot;
Matt Mueller370a7fda2019-08-22 00:38:59148 if (CFDictionaryContainsKey(trust_dict, kSecTrustSettingsResult)) {
149 CFNumberRef trust_settings_result_ref =
150 base::mac::GetValueFromDictionary<CFNumberRef>(trust_dict,
151 kSecTrustSettingsResult);
152 if (!trust_settings_result_ref ||
153 !CFNumberGetValue(trust_settings_result_ref, kCFNumberIntType,
154 &trust_settings_result)) {
155 *debug_info |= TrustStoreMac::TRUST_SETTINGS_DICT_INVALID_RESULT_TYPE;
156 return TrustStatus::UNSPECIFIED;
157 }
mattmea4ed8232017-02-28 23:13:23158 }
159
160 if (trust_settings_result == kSecTrustSettingsResultDeny)
161 return TrustStatus::DISTRUSTED;
162
Matt Mueller59ebd7d2019-04-19 17:56:40163 // This is a bit of a hack: if the cert is self-issued allow either
164 // kSecTrustSettingsResultTrustRoot or kSecTrustSettingsResultTrustAsRoot on
165 // the basis that SecTrustSetTrustSettings should not allow creating an
166 // invalid trust record in the first place. (The spec is that
mattmea4ed8232017-02-28 23:13:23167 // kSecTrustSettingsResultTrustRoot can only be applied to root(self-signed)
Matt Mueller59ebd7d2019-04-19 17:56:40168 // certs and kSecTrustSettingsResultTrustAsRoot is used for other certs.)
169 // This hack avoids having to check the signature on the cert which is slow
170 // if using the platform APIs, and may require supporting MD5 signature
171 // algorithms on some older OSX versions or locally added roots, which is
172 // undesirable in the built-in signature verifier.
173 if (is_self_issued) {
174 return (trust_settings_result == kSecTrustSettingsResultTrustRoot ||
175 trust_settings_result == kSecTrustSettingsResultTrustAsRoot)
mattmea4ed8232017-02-28 23:13:23176 ? TrustStatus::TRUSTED
177 : TrustStatus::UNSPECIFIED;
Matt Mueller59ebd7d2019-04-19 17:56:40178 }
mattmea4ed8232017-02-28 23:13:23179
180 // kSecTrustSettingsResultTrustAsRoot can only be applied to non-root certs.
181 return (trust_settings_result == kSecTrustSettingsResultTrustAsRoot)
182 ? TrustStatus::TRUSTED
183 : TrustStatus::UNSPECIFIED;
184}
185
186// Returns true if the trust settings array |trust_settings| for a certificate
Matt Mueller59ebd7d2019-04-19 17:56:40187// that |is_self_issued| should be treated as a trust anchor.
mattmea4ed8232017-02-28 23:13:23188TrustStatus IsTrustSettingsTrustedForPolicy(CFArrayRef trust_settings,
Matt Mueller59ebd7d2019-04-19 17:56:40189 bool is_self_issued,
Matt Mueller370a7fda2019-08-22 00:38:59190 const CFStringRef policy_oid,
191 int* debug_info) {
mattmea4ed8232017-02-28 23:13:23192 // An empty trust settings array (that is, the trust_settings parameter
193 // returns a valid but empty CFArray) means "always trust this certificate"
194 // with an overall trust setting for the certificate of
195 // kSecTrustSettingsResultTrustRoot.
Matt Mueller370a7fda2019-08-22 00:38:59196 if (CFArrayGetCount(trust_settings) == 0) {
197 *debug_info |= TrustStoreMac::TRUST_SETTINGS_ARRAY_EMPTY;
198 return is_self_issued ? TrustStatus::TRUSTED : TrustStatus::UNSPECIFIED;
199 }
mattmea4ed8232017-02-28 23:13:23200
201 for (CFIndex i = 0, settings_count = CFArrayGetCount(trust_settings);
202 i < settings_count; ++i) {
203 CFDictionaryRef trust_dict = reinterpret_cast<CFDictionaryRef>(
204 const_cast<void*>(CFArrayGetValueAtIndex(trust_settings, i)));
205 TrustStatus trust = IsTrustDictionaryTrustedForPolicy(
Matt Mueller370a7fda2019-08-22 00:38:59206 trust_dict, is_self_issued, policy_oid, debug_info);
mattmea4ed8232017-02-28 23:13:23207 if (trust != TrustStatus::UNSPECIFIED)
208 return trust;
209 }
210 return TrustStatus::UNSPECIFIED;
211}
212
Matt Mueller5d105e72019-07-01 17:38:42213// Returns the trust status for |cert_handle| for the policy |policy_oid| in
214// |trust_domain|.
Matt Mueller1b4c2342021-03-16 17:57:04215TrustStatus IsSecCertificateTrustedForPolicyInDomain(
216 SecCertificateRef cert_handle,
217 const bool is_self_issued,
218 const CFStringRef policy_oid,
219 SecTrustSettingsDomain trust_domain,
220 int* debug_info) {
221 base::ScopedCFTypeRef<CFArrayRef> trust_settings;
222 OSStatus err;
223 {
224 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
225 err = SecTrustSettingsCopyTrustSettings(cert_handle, trust_domain,
226 trust_settings.InitializeInto());
227 }
228 if (err == errSecItemNotFound) {
229 // No trust settings for that domain.. try the next.
230 return TrustStatus::UNSPECIFIED;
231 }
232 if (err) {
233 OSSTATUS_LOG(ERROR, err) << "SecTrustSettingsCopyTrustSettings error";
Matt Muellerb87777a2021-09-07 18:16:07234 *debug_info |= TrustStoreMac::COPY_TRUST_SETTINGS_ERROR;
Matt Mueller1b4c2342021-03-16 17:57:04235 return TrustStatus::UNSPECIFIED;
236 }
237 TrustStatus trust = IsTrustSettingsTrustedForPolicy(
238 trust_settings, is_self_issued, policy_oid, debug_info);
239 return trust;
240}
241
Matt Mueller5d105e72019-07-01 17:38:42242TrustStatus IsCertificateTrustedForPolicyInDomain(
David Benjamin24381632021-09-03 17:01:45243 const ParsedCertificate* cert,
Matt Mueller5d105e72019-07-01 17:38:42244 const CFStringRef policy_oid,
Matt Mueller370a7fda2019-08-22 00:38:59245 SecTrustSettingsDomain trust_domain,
246 int* debug_info) {
Matt Mueller5d105e72019-07-01 17:38:42247 // TODO(eroman): Inefficient -- path building will convert between
248 // SecCertificateRef and ParsedCertificate representations multiple times
249 // (when getting the issuers, and again here).
250 //
251 // This conversion will also be done for each domain the cert policy is
252 // checked, but the TrustDomainCache ensures this function is only called on
253 // domains that actually have settings for the cert. The common case is that
254 // a cert will have trust settings in only zero or one domains, and when in
255 // more than one domain it would generally be because one domain is
256 // overriding the setting in the next, so it would only get done once anyway.
257 base::ScopedCFTypeRef<SecCertificateRef> cert_handle =
258 x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
259 cert->der_cert().Length());
260 if (!cert_handle)
261 return TrustStatus::UNSPECIFIED;
262
Matt Mueller59ebd7d2019-04-19 17:56:40263 const bool is_self_issued =
264 cert->normalized_subject() == cert->normalized_issuer();
Matt Mueller5d105e72019-07-01 17:38:42265
Matt Mueller1b4c2342021-03-16 17:57:04266 return IsSecCertificateTrustedForPolicyInDomain(
267 cert_handle, is_self_issued, policy_oid, trust_domain, debug_info);
Matt Mueller5d105e72019-07-01 17:38:42268}
269
Matt Mueller7ac4af5c2021-03-30 18:58:53270KnownRootStatus IsCertificateKnownRoot(const ParsedCertificate* cert) {
271 base::ScopedCFTypeRef<SecCertificateRef> cert_handle =
272 x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
273 cert->der_cert().Length());
274 if (!cert_handle)
275 return KnownRootStatus::NOT_KNOWN_ROOT;
276
277 base::ScopedCFTypeRef<CFArrayRef> trust_settings;
278 OSStatus err;
279 {
280 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
281 err = SecTrustSettingsCopyTrustSettings(cert_handle,
282 kSecTrustSettingsDomainSystem,
283 trust_settings.InitializeInto());
284 }
285 return (err == errSecSuccess) ? KnownRootStatus::IS_KNOWN_ROOT
286 : KnownRootStatus::NOT_KNOWN_ROOT;
287}
288
289TrustStatus IsCertificateTrustedForPolicy(const ParsedCertificate* cert,
290 const CFStringRef policy_oid,
291 int* debug_info,
292 KnownRootStatus* out_is_known_root) {
293 // |*out_is_known_root| is intentionally not cleared before starting, as
294 // there may have been a value already calculated and cached independently.
295 // The caller is expected to initialize |*out_is_known_root| to UNKNOWN if
296 // the value has not been calculated.
297
Matt Mueller1b4c2342021-03-16 17:57:04298 base::ScopedCFTypeRef<SecCertificateRef> cert_handle =
299 x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
300 cert->der_cert().Length());
301 if (!cert_handle)
302 return TrustStatus::UNSPECIFIED;
303
304 const bool is_self_issued =
305 cert->normalized_subject() == cert->normalized_issuer();
306
307 // Evaluate trust domains in user, admin, system order. Admin settings can
308 // override system ones, and user settings can override both admin and system.
309 for (const auto& trust_domain :
310 {kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin,
311 kSecTrustSettingsDomainSystem}) {
312 base::ScopedCFTypeRef<CFArrayRef> trust_settings;
313 OSStatus err;
314 {
315 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
316 err = SecTrustSettingsCopyTrustSettings(cert_handle, trust_domain,
317 trust_settings.InitializeInto());
318 }
Matt Mueller7ac4af5c2021-03-30 18:58:53319 if (err != errSecSuccess) {
320 if (out_is_known_root && trust_domain == kSecTrustSettingsDomainSystem) {
321 // If trust settings are not present for |cert| in the system domain,
322 // record it as not a known root.
323 *out_is_known_root = KnownRootStatus::NOT_KNOWN_ROOT;
324 }
325 if (err == errSecItemNotFound) {
326 // No trust settings for that domain.. try the next.
327 continue;
328 }
Matt Mueller1b4c2342021-03-16 17:57:04329 OSSTATUS_LOG(ERROR, err) << "SecTrustSettingsCopyTrustSettings error";
Matt Muellerb87777a2021-09-07 18:16:07330 *debug_info |= TrustStoreMac::COPY_TRUST_SETTINGS_ERROR;
Matt Mueller1b4c2342021-03-16 17:57:04331 continue;
332 }
Matt Mueller7ac4af5c2021-03-30 18:58:53333 if (out_is_known_root && trust_domain == kSecTrustSettingsDomainSystem) {
334 // If trust settings are present for |cert| in the system domain, record
335 // it as a known root.
336 *out_is_known_root = KnownRootStatus::IS_KNOWN_ROOT;
337 }
Matt Mueller1b4c2342021-03-16 17:57:04338 TrustStatus trust = IsTrustSettingsTrustedForPolicy(
339 trust_settings, is_self_issued, policy_oid, debug_info);
340 if (trust != TrustStatus::UNSPECIFIED)
341 return trust;
342 }
343
344 // No trust settings, or none of the settings were for the correct policy, or
345 // had the correct trust result.
346 return TrustStatus::UNSPECIFIED;
347}
348
349void UpdateUserData(int debug_info,
350 base::SupportsUserData* user_data,
351 TrustStoreMac::TrustImplType impl_type) {
Matt Mueller370a7fda2019-08-22 00:38:59352 if (!user_data)
353 return;
354 TrustStoreMac::ResultDebugData* result_debug_data =
355 TrustStoreMac::ResultDebugData::GetOrCreate(user_data);
Matt Mueller1b4c2342021-03-16 17:57:04356 result_debug_data->UpdateTrustDebugInfo(debug_info, impl_type);
Matt Mueller370a7fda2019-08-22 00:38:59357}
358
Matt Mueller5d105e72019-07-01 17:38:42359// Caches calculated trust status for certificates present in a single trust
360// domain.
361class TrustDomainCache {
362 public:
Matt Mueller370a7fda2019-08-22 00:38:59363 struct TrustStatusDetails {
364 TrustStatus trust_status = TrustStatus::UNKNOWN;
365 int debug_info = 0;
366 };
367
Matt Mueller5d105e72019-07-01 17:38:42368 TrustDomainCache(SecTrustSettingsDomain domain, CFStringRef policy_oid)
369 : domain_(domain), policy_oid_(policy_oid) {
370 DCHECK(policy_oid_);
mattmea4ed8232017-02-28 23:13:23371 }
372
Matt Mueller5d105e72019-07-01 17:38:42373 // (Re-)Initializes the cache with the certs in |domain_| set to UNKNOWN trust
374 // status.
375 void Initialize() {
376 trust_status_cache_.clear();
377
378 base::ScopedCFTypeRef<CFArrayRef> cert_array;
379 OSStatus rv;
380 {
381 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
382 rv = SecTrustSettingsCopyCertificates(domain_,
383 cert_array.InitializeInto());
384 }
385 if (rv != noErr) {
386 // Note: SecTrustSettingsCopyCertificates can legitimately return
387 // errSecNoTrustSettings if there are no trust settings in |domain_|.
388 return;
389 }
Matt Mueller370a7fda2019-08-22 00:38:59390 std::vector<std::pair<SHA256HashValue, TrustStatusDetails>>
391 trust_status_vector;
Matt Mueller5d105e72019-07-01 17:38:42392 for (CFIndex i = 0, size = CFArrayGetCount(cert_array); i < size; ++i) {
393 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
394 const_cast<void*>(CFArrayGetValueAtIndex(cert_array, i)));
395 trust_status_vector.emplace_back(x509_util::CalculateFingerprint256(cert),
Matt Mueller370a7fda2019-08-22 00:38:59396 TrustStatusDetails());
Matt Mueller5d105e72019-07-01 17:38:42397 }
Matt Mueller370a7fda2019-08-22 00:38:59398 trust_status_cache_ = base::flat_map<SHA256HashValue, TrustStatusDetails>(
Matt Mueller5d105e72019-07-01 17:38:42399 std::move(trust_status_vector));
400 }
401
402 // Returns the trust status for |cert| in |domain_|.
David Benjamin24381632021-09-03 17:01:45403 TrustStatus IsCertTrusted(const ParsedCertificate* cert,
Matt Mueller370a7fda2019-08-22 00:38:59404 const SHA256HashValue& cert_hash,
405 base::SupportsUserData* debug_data) {
Matt Mueller5d105e72019-07-01 17:38:42406 auto cache_iter = trust_status_cache_.find(cert_hash);
407 if (cache_iter == trust_status_cache_.end()) {
408 // Cert does not have trust settings in this domain, return UNSPECIFIED.
Matt Muellerb3c3cbc2021-03-30 20:20:11409 UpdateUserData(0, debug_data, TrustStoreMac::TrustImplType::kDomainCache);
Matt Mueller5d105e72019-07-01 17:38:42410 return TrustStatus::UNSPECIFIED;
411 }
412
Matt Mueller370a7fda2019-08-22 00:38:59413 if (cache_iter->second.trust_status != TrustStatus::UNKNOWN) {
Matt Mueller5d105e72019-07-01 17:38:42414 // Cert has trust settings and trust has already been calculated, return
415 // the cached value.
Matt Mueller1b4c2342021-03-16 17:57:04416 UpdateUserData(cache_iter->second.debug_info, debug_data,
417 TrustStoreMac::TrustImplType::kDomainCache);
Matt Mueller370a7fda2019-08-22 00:38:59418 return cache_iter->second.trust_status;
Matt Mueller5d105e72019-07-01 17:38:42419 }
420
421 // Cert has trust settings but trust has not been calculated yet.
422 // Calculate it now, insert into cache, and return.
Matt Mueller370a7fda2019-08-22 00:38:59423 TrustStatus cert_trust = IsCertificateTrustedForPolicyInDomain(
424 cert, policy_oid_, domain_, &cache_iter->second.debug_info);
425 cache_iter->second.trust_status = cert_trust;
Matt Mueller1b4c2342021-03-16 17:57:04426 UpdateUserData(cache_iter->second.debug_info, debug_data,
427 TrustStoreMac::TrustImplType::kDomainCache);
Matt Mueller5d105e72019-07-01 17:38:42428 return cert_trust;
429 }
430
431 // Returns true if the certificate with |cert_hash| is present in |domain_|.
432 bool ContainsCert(const SHA256HashValue& cert_hash) const {
433 return trust_status_cache_.find(cert_hash) != trust_status_cache_.end();
434 }
435
436 private:
437 const SecTrustSettingsDomain domain_;
438 const CFStringRef policy_oid_;
Matt Mueller370a7fda2019-08-22 00:38:59439 base::flat_map<SHA256HashValue, TrustStatusDetails> trust_status_cache_;
Matt Mueller5d105e72019-07-01 17:38:42440
441 DISALLOW_COPY_AND_ASSIGN(TrustDomainCache);
442};
443
444SHA256HashValue CalculateFingerprint256(const der::Input& buffer) {
445 SHA256HashValue sha256;
446 SHA256(buffer.UnsafeData(), buffer.Length(), sha256.data);
447 return sha256;
mattmea4ed8232017-02-28 23:13:23448}
449
Matt Mueller5d105e72019-07-01 17:38:42450// Watches macOS keychain for trust setting changes, and notifies any
451// registered callbacks. This is necessary as the keychain callback API is
452// keyed only on the callback function pointer rather than function pointer +
453// context, so it cannot be safely registered multiple callbacks with the same
454// function pointer and different contexts.
455class KeychainTrustSettingsChangedNotifier {
456 public:
457 // Registers |callback| to be run when the keychain trust settings change.
458 // Must be called on the network notification thread. |callback| will be run
Peter Kasting7ba9440c2020-11-22 01:49:02459 // on the network notification thread. The returned subscription must be
Matt Mueller5d105e72019-07-01 17:38:42460 // destroyed on the network notification thread.
Peter Kasting7ba9440c2020-11-22 01:49:02461 static base::CallbackListSubscription AddCallback(
Matt Mueller5d105e72019-07-01 17:38:42462 base::RepeatingClosure callback) {
463 DCHECK(GetNetworkNotificationThreadMac()->RunsTasksInCurrentSequence());
464 return Get()->callback_list_.Add(std::move(callback));
465 }
466
467 private:
468 friend base::NoDestructor<KeychainTrustSettingsChangedNotifier>;
469
470 KeychainTrustSettingsChangedNotifier() {
471 DCHECK(GetNetworkNotificationThreadMac()->RunsTasksInCurrentSequence());
472 OSStatus status = SecKeychainAddCallback(
473 &KeychainTrustSettingsChangedNotifier::KeychainCallback,
474 kSecTrustSettingsChangedEventMask, this);
475 if (status != noErr)
476 OSSTATUS_LOG(ERROR, status) << "SecKeychainAddCallback failed";
477 }
478
479 ~KeychainTrustSettingsChangedNotifier() = delete;
480
481 static OSStatus KeychainCallback(SecKeychainEvent keychain_event,
482 SecKeychainCallbackInfo* info,
483 void* context) {
484 KeychainTrustSettingsChangedNotifier* notifier =
485 reinterpret_cast<KeychainTrustSettingsChangedNotifier*>(context);
486 notifier->callback_list_.Notify();
487 return errSecSuccess;
488 }
489
490 static KeychainTrustSettingsChangedNotifier* Get() {
491 static base::NoDestructor<KeychainTrustSettingsChangedNotifier> notifier;
492 return notifier.get();
493 }
494
Peter Kasting11c507a42020-08-17 19:11:10495 base::RepeatingClosureList callback_list_;
Matt Mueller5d105e72019-07-01 17:38:42496
497 DISALLOW_COPY_AND_ASSIGN(KeychainTrustSettingsChangedNotifier);
498};
499
500// Observes keychain events and increments the value returned by Iteration()
501// each time the trust settings change.
502class KeychainTrustObserver {
503 public:
504 KeychainTrustObserver() {
505 GetNetworkNotificationThreadMac()->PostTask(
506 FROM_HERE,
507 base::BindOnce(
508 &KeychainTrustObserver::RegisterCallbackOnNotificationThread,
509 base::Unretained(this)));
510 }
511
Peter Boström293b1342021-09-22 17:31:43512 KeychainTrustObserver(const KeychainTrustObserver&) = delete;
513 KeychainTrustObserver& operator=(const KeychainTrustObserver&) = delete;
514
Matt Mueller5d105e72019-07-01 17:38:42515 // Destroying the observer unregisters the callback. Must be destroyed on the
516 // notification thread in order to safely release |subscription_|.
517 ~KeychainTrustObserver() {
518 DCHECK(GetNetworkNotificationThreadMac()->RunsTasksInCurrentSequence());
519 }
520
521 // Returns the current iteration count, which is incremented every time
522 // keychain trust settings change. This may be called from any thread.
523 int64_t Iteration() const { return base::subtle::Acquire_Load(&iteration_); }
524
525 private:
526 void RegisterCallbackOnNotificationThread() {
527 DCHECK(GetNetworkNotificationThreadMac()->RunsTasksInCurrentSequence());
528 subscription_ =
529 KeychainTrustSettingsChangedNotifier::AddCallback(base::BindRepeating(
530 &KeychainTrustObserver::Increment, base::Unretained(this)));
531 }
532
533 void Increment() { base::subtle::Barrier_AtomicIncrement(&iteration_, 1); }
534
535 // Only accessed on the notification thread.
Peter Kasting7ba9440c2020-11-22 01:49:02536 base::CallbackListSubscription subscription_;
Matt Mueller5d105e72019-07-01 17:38:42537
538 base::subtle::Atomic64 iteration_ = 0;
Matt Mueller5d105e72019-07-01 17:38:42539};
540
eroman2a938c32017-04-28 23:16:58541} // namespace
542
Matt Mueller370a7fda2019-08-22 00:38:59543// static
544const TrustStoreMac::ResultDebugData* TrustStoreMac::ResultDebugData::Get(
545 const base::SupportsUserData* debug_data) {
546 return static_cast<ResultDebugData*>(
547 debug_data->GetUserData(kResultDebugDataKey));
548}
549
550// static
551TrustStoreMac::ResultDebugData* TrustStoreMac::ResultDebugData::GetOrCreate(
552 base::SupportsUserData* debug_data) {
553 ResultDebugData* data = static_cast<ResultDebugData*>(
554 debug_data->GetUserData(kResultDebugDataKey));
555 if (!data) {
556 std::unique_ptr<ResultDebugData> new_data =
557 std::make_unique<ResultDebugData>();
558 data = new_data.get();
559 debug_data->SetUserData(kResultDebugDataKey, std::move(new_data));
560 }
561 return data;
562}
563
564void TrustStoreMac::ResultDebugData::UpdateTrustDebugInfo(
Matt Mueller1b4c2342021-03-16 17:57:04565 int trust_debug_info,
566 TrustImplType impl_type) {
Matt Mueller370a7fda2019-08-22 00:38:59567 combined_trust_debug_info_ |= trust_debug_info;
Matt Mueller1b4c2342021-03-16 17:57:04568 trust_impl_ = impl_type;
Matt Mueller370a7fda2019-08-22 00:38:59569}
570
571std::unique_ptr<base::SupportsUserData::Data>
572TrustStoreMac::ResultDebugData::Clone() {
573 return std::make_unique<ResultDebugData>(*this);
574}
575
Matt Mueller1b4c2342021-03-16 17:57:04576// Interface for different implementations of getting trust settings from the
577// Mac APIs. This abstraction can be removed once a single implementation has
578// been chosen and launched.
579class TrustStoreMac::TrustImpl {
Matt Mueller5d105e72019-07-01 17:38:42580 public:
Matt Mueller1b4c2342021-03-16 17:57:04581 virtual ~TrustImpl() = default;
582
583 virtual bool IsKnownRoot(const ParsedCertificate* cert) = 0;
David Benjamin24381632021-09-03 17:01:45584 virtual TrustStatus IsCertTrusted(const ParsedCertificate* cert,
585 base::SupportsUserData* debug_data) = 0;
Matt Mueller1b4c2342021-03-16 17:57:04586 virtual void InitializeTrustCache() = 0;
587};
588
589// TrustImplDomainCache uses SecTrustSettingsCopyCertificates to get the list
590// of certs in each trust domain and then caches the calculated trust status of
591// those certs on access, and ensures the cache is reset if trust settings are
592// modified.
593class TrustStoreMac::TrustImplDomainCache : public TrustStoreMac::TrustImpl {
594 public:
595 explicit TrustImplDomainCache(CFStringRef policy_oid)
Matt Mueller5d105e72019-07-01 17:38:42596 : system_domain_cache_(kSecTrustSettingsDomainSystem, policy_oid),
597 admin_domain_cache_(kSecTrustSettingsDomainAdmin, policy_oid),
598 user_domain_cache_(kSecTrustSettingsDomainUser, policy_oid) {
599 keychain_observer_ = std::make_unique<KeychainTrustObserver>();
600 }
601
Peter Boström293b1342021-09-22 17:31:43602 TrustImplDomainCache(const TrustImplDomainCache&) = delete;
603 TrustImplDomainCache& operator=(const TrustImplDomainCache&) = delete;
604
Matt Mueller1b4c2342021-03-16 17:57:04605 ~TrustImplDomainCache() override {
Matt Mueller5d105e72019-07-01 17:38:42606 GetNetworkNotificationThreadMac()->DeleteSoon(
607 FROM_HERE, std::move(keychain_observer_));
608 }
609
610 // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
Matt Mueller1b4c2342021-03-16 17:57:04611 bool IsKnownRoot(const ParsedCertificate* cert) override {
Matt Mueller5d105e72019-07-01 17:38:42612 SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
613
614 base::AutoLock lock(cache_lock_);
615 MaybeInitializeCache();
616 return system_domain_cache_.ContainsCert(cert_hash);
617 }
618
619 // Returns the trust status for |cert|.
David Benjamin24381632021-09-03 17:01:45620 TrustStatus IsCertTrusted(const ParsedCertificate* cert,
Matt Mueller1b4c2342021-03-16 17:57:04621 base::SupportsUserData* debug_data) override {
Matt Mueller5d105e72019-07-01 17:38:42622 SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
623
624 base::AutoLock lock(cache_lock_);
625 MaybeInitializeCache();
626
627 // Evaluate trust domains in user, admin, system order. Admin settings can
628 // override system ones, and user settings can override both admin and
629 // system.
630 for (TrustDomainCache* trust_domain_cache :
631 {&user_domain_cache_, &admin_domain_cache_, &system_domain_cache_}) {
Matt Mueller370a7fda2019-08-22 00:38:59632 TrustStatus ts =
633 trust_domain_cache->IsCertTrusted(cert, cert_hash, debug_data);
Matt Mueller5d105e72019-07-01 17:38:42634 if (ts != TrustStatus::UNSPECIFIED)
635 return ts;
636 }
637
638 // Cert did not have trust settings in any domain.
639 return TrustStatus::UNSPECIFIED;
640 }
641
Matt Muellerd0506dd82020-12-17 02:25:24642 // Initializes the cache, if it isn't already initialized.
Matt Mueller1b4c2342021-03-16 17:57:04643 void InitializeTrustCache() override {
Matt Muellerd0506dd82020-12-17 02:25:24644 base::AutoLock lock(cache_lock_);
645 MaybeInitializeCache();
646 }
647
Matt Mueller5d105e72019-07-01 17:38:42648 private:
649 // (Re-)Initialize the cache if necessary. Must be called after acquiring
650 // |cache_lock_| and before accessing any of the |*_domain_cache_| members.
651 void MaybeInitializeCache() {
652 cache_lock_.AssertAcquired();
653 int64_t keychain_iteration = keychain_observer_->Iteration();
654 if (iteration_ == keychain_iteration)
655 return;
656
657 iteration_ = keychain_iteration;
658 user_domain_cache_.Initialize();
659 admin_domain_cache_.Initialize();
660 if (!system_domain_initialized_) {
661 // In practice, the system trust domain does not change during runtime,
662 // and SecTrustSettingsCopyCertificates on the system domain is quite
663 // slow, so the system domain cache is not reset on keychain changes.
664 system_domain_cache_.Initialize();
665 system_domain_initialized_ = true;
666 }
667 }
668
669 std::unique_ptr<KeychainTrustObserver> keychain_observer_;
670
671 base::Lock cache_lock_;
672 // |cache_lock_| must be held while accessing any following members.
673 int64_t iteration_ = -1;
674 bool system_domain_initialized_ = false;
675 TrustDomainCache system_domain_cache_;
676 TrustDomainCache admin_domain_cache_;
677 TrustDomainCache user_domain_cache_;
Matt Mueller5d105e72019-07-01 17:38:42678};
679
Matt Mueller1b4c2342021-03-16 17:57:04680// TrustImplNoCache is the simplest approach which calls
681// SecTrustSettingsCopyTrustSettings on every cert checked, with no caching.
682class TrustStoreMac::TrustImplNoCache : public TrustStoreMac::TrustImpl {
683 public:
684 explicit TrustImplNoCache(CFStringRef policy_oid) : policy_oid_(policy_oid) {}
685
Peter Boström293b1342021-09-22 17:31:43686 TrustImplNoCache(const TrustImplNoCache&) = delete;
687 TrustImplNoCache& operator=(const TrustImplNoCache&) = delete;
688
Matt Mueller1b4c2342021-03-16 17:57:04689 ~TrustImplNoCache() override = default;
690
691 // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
692 bool IsKnownRoot(const ParsedCertificate* cert) override {
693 HashValue cert_hash(CalculateFingerprint256(cert->der_cert()));
Matt Muellerccc7913a2021-03-23 02:26:00694 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
Matt Mueller1b4c2342021-03-16 17:57:04695 return net::IsKnownRoot(cert_hash);
696 }
697
698 // Returns the trust status for |cert|.
David Benjamin24381632021-09-03 17:01:45699 TrustStatus IsCertTrusted(const ParsedCertificate* cert,
Matt Mueller1b4c2342021-03-16 17:57:04700 base::SupportsUserData* debug_data) override {
701 int debug_info = 0;
Matt Mueller7ac4af5c2021-03-30 18:58:53702 TrustStatus result = IsCertificateTrustedForPolicy(
David Benjamin24381632021-09-03 17:01:45703 cert, policy_oid_, &debug_info, /*out_is_known_root=*/nullptr);
Matt Mueller1b4c2342021-03-16 17:57:04704 UpdateUserData(debug_info, debug_data,
705 TrustStoreMac::TrustImplType::kSimple);
706 return result;
707 }
708
709 void InitializeTrustCache() override {
710 // No-op for this impl.
711 }
712
713 private:
714 const CFStringRef policy_oid_;
Matt Mueller1b4c2342021-03-16 17:57:04715};
716
717// TrustImplMRUCache is calls SecTrustSettingsCopyTrustSettings on every cert
718// checked, but caches the results in an MRU cache. The cache is cleared on
719// keychain updates.
720class TrustStoreMac::TrustImplMRUCache : public TrustStoreMac::TrustImpl {
721 public:
722 TrustImplMRUCache(CFStringRef policy_oid, size_t cache_size)
723 : policy_oid_(policy_oid), trust_status_cache_(cache_size) {
724 keychain_observer_ = std::make_unique<KeychainTrustObserver>();
725 }
726
Peter Boström293b1342021-09-22 17:31:43727 TrustImplMRUCache(const TrustImplMRUCache&) = delete;
728 TrustImplMRUCache& operator=(const TrustImplMRUCache&) = delete;
729
Matt Mueller1b4c2342021-03-16 17:57:04730 ~TrustImplMRUCache() override {
731 GetNetworkNotificationThreadMac()->DeleteSoon(
732 FROM_HERE, std::move(keychain_observer_));
733 }
734
Matt Mueller7ac4af5c2021-03-30 18:58:53735 // Returns true if |cert| has trust settings in kSecTrustSettingsDomainSystem.
Matt Mueller1b4c2342021-03-16 17:57:04736 bool IsKnownRoot(const ParsedCertificate* cert) override {
Matt Mueller7ac4af5c2021-03-30 18:58:53737 return GetKnownRootStatus(cert) == KnownRootStatus::IS_KNOWN_ROOT;
Matt Mueller1b4c2342021-03-16 17:57:04738 }
739
740 // Returns the trust status for |cert|.
David Benjamin24381632021-09-03 17:01:45741 TrustStatus IsCertTrusted(const ParsedCertificate* cert,
Matt Mueller1b4c2342021-03-16 17:57:04742 base::SupportsUserData* debug_data) override {
David Benjamin24381632021-09-03 17:01:45743 TrustStatusDetails trust_details = GetTrustStatus(cert);
Matt Mueller1b4c2342021-03-16 17:57:04744 UpdateUserData(trust_details.debug_info, debug_data,
745 TrustStoreMac::TrustImplType::kMruCache);
746 return trust_details.trust_status;
747 }
748
749 void InitializeTrustCache() override {
750 // No-op for this impl.
751 }
752
753 private:
754 struct TrustStatusDetails {
755 TrustStatus trust_status = TrustStatus::UNKNOWN;
756 int debug_info = 0;
Matt Mueller7ac4af5c2021-03-30 18:58:53757 KnownRootStatus is_known_root = KnownRootStatus::UNKNOWN;
Matt Mueller1b4c2342021-03-16 17:57:04758 };
759
Matt Mueller7ac4af5c2021-03-30 18:58:53760 KnownRootStatus GetKnownRootStatus(const ParsedCertificate* cert) {
761 SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
762
763 int starting_cache_iteration = -1;
764 {
765 base::AutoLock lock(cache_lock_);
766 MaybeResetCache();
767 starting_cache_iteration = iteration_;
768 auto cache_iter = trust_status_cache_.Get(cert_hash);
769 if (cache_iter != trust_status_cache_.end() &&
770 cache_iter->second.is_known_root != KnownRootStatus::UNKNOWN) {
771 return cache_iter->second.is_known_root;
772 }
773 }
774
775 KnownRootStatus is_known_root = IsCertificateKnownRoot(cert);
776
777 {
778 base::AutoLock lock(cache_lock_);
779 MaybeResetCache();
780 if (iteration_ != starting_cache_iteration)
781 return is_known_root;
782
783 auto cache_iter = trust_status_cache_.Get(cert_hash);
784 // Update |is_known_root| on existing cache entry if there is one,
785 // otherwise create a new cache entry.
786 if (cache_iter != trust_status_cache_.end()) {
787 cache_iter->second.is_known_root = is_known_root;
788 } else {
789 TrustStatusDetails trust_details;
790 trust_details.is_known_root = is_known_root;
791 trust_status_cache_.Put(cert_hash, trust_details);
792 }
793 }
794 return is_known_root;
795 }
796
797 TrustStatusDetails GetTrustStatus(const ParsedCertificate* cert) {
798 SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
799 TrustStatusDetails trust_details;
800
801 int starting_cache_iteration = -1;
802 {
803 base::AutoLock lock(cache_lock_);
804 MaybeResetCache();
805 starting_cache_iteration = iteration_;
806 auto cache_iter = trust_status_cache_.Get(cert_hash);
807 if (cache_iter != trust_status_cache_.end()) {
808 if (cache_iter->second.trust_status != TrustStatus::UNKNOWN)
809 return cache_iter->second;
810 // If there was a cache entry but the trust status was not initialized,
811 // copy the existing values. (|is_known_root| might already be cached.)
812 trust_details = cache_iter->second;
813 }
814 }
815
816 trust_details.trust_status = IsCertificateTrustedForPolicy(
817 cert, policy_oid_, &trust_details.debug_info,
818 &trust_details.is_known_root);
819
820 {
821 base::AutoLock lock(cache_lock_);
822 MaybeResetCache();
823 if (iteration_ != starting_cache_iteration)
824 return trust_details;
825 trust_status_cache_.Put(cert_hash, trust_details);
826 }
827 return trust_details;
828 }
829
Matt Mueller1b4c2342021-03-16 17:57:04830 void MaybeResetCache() {
831 cache_lock_.AssertAcquired();
832 int64_t keychain_iteration = keychain_observer_->Iteration();
833 if (iteration_ == keychain_iteration)
834 return;
835 iteration_ = keychain_iteration;
836 trust_status_cache_.Clear();
837 }
838
839 const CFStringRef policy_oid_;
840 std::unique_ptr<KeychainTrustObserver> keychain_observer_;
841
842 base::Lock cache_lock_;
843 // |cache_lock_| must be held while accessing any following members.
844 base::MRUCache<SHA256HashValue, TrustStatusDetails> trust_status_cache_;
Matt Mueller7ac4af5c2021-03-30 18:58:53845 // Tracks the number of keychain changes that have been observed. If the
846 // keychain observer has noted a change, MaybeResetCache will update
847 // |iteration_| and the cache will be cleared. Any in-flight trust
848 // resolutions that started before the keychain update was observed should
849 // not cache their results, as it isn't clear whether the calculated result
850 // applies to the new or old trust settings.
Matt Mueller1b4c2342021-03-16 17:57:04851 int64_t iteration_ = -1;
Matt Mueller1b4c2342021-03-16 17:57:04852};
853
Matt Mueller884cf6862021-03-16 20:29:32854TrustStoreMac::TrustStoreMac(CFStringRef policy_oid,
855 TrustImplType impl,
856 size_t cache_size) {
Matt Mueller1b4c2342021-03-16 17:57:04857 switch (impl) {
858 case TrustImplType::kUnknown:
859 DCHECK(false);
860 break;
861 case TrustImplType::kDomainCache:
862 trust_cache_ = std::make_unique<TrustImplDomainCache>(policy_oid);
863 break;
864 case TrustImplType::kSimple:
865 trust_cache_ = std::make_unique<TrustImplNoCache>(policy_oid);
866 break;
867 case TrustImplType::kMruCache:
868 trust_cache_ =
869 std::make_unique<TrustImplMRUCache>(policy_oid, cache_size);
870 break;
871 }
872}
eroman2a938c32017-04-28 23:16:58873
874TrustStoreMac::~TrustStoreMac() = default;
875
Matt Muellerd0506dd82020-12-17 02:25:24876void TrustStoreMac::InitializeTrustCache() const {
877 trust_cache_->InitializeTrustCache();
878}
879
Matt Mueller5d105e72019-07-01 17:38:42880bool TrustStoreMac::IsKnownRoot(const ParsedCertificate* cert) const {
881 return trust_cache_->IsKnownRoot(cert);
882}
883
eroman2a938c32017-04-28 23:16:58884void TrustStoreMac::SyncGetIssuersOf(const ParsedCertificate* cert,
885 ParsedCertificateList* issuers) {
886 base::ScopedCFTypeRef<CFDataRef> name_data = GetMacNormalizedIssuer(cert);
Eric Romancdc12c82017-10-18 03:34:06887 if (!name_data)
888 return;
eroman2a938c32017-04-28 23:16:58889
890 base::ScopedCFTypeRef<CFArrayRef> matching_items =
891 FindMatchingCertificatesForMacNormalizedSubject(name_data);
892 if (!matching_items)
893 return;
894
895 // Convert to ParsedCertificate.
mattmea4ed8232017-02-28 23:13:23896 for (CFIndex i = 0, item_count = CFArrayGetCount(matching_items);
897 i < item_count; ++i) {
898 SecCertificateRef match_cert_handle = reinterpret_cast<SecCertificateRef>(
899 const_cast<void*>(CFArrayGetValueAtIndex(matching_items, i)));
900
mattmea4ed8232017-02-28 23:13:23901 base::ScopedCFTypeRef<CFDataRef> der_data(
902 SecCertificateCopyData(match_cert_handle));
903 if (!der_data) {
904 LOG(ERROR) << "SecCertificateCopyData error";
905 continue;
906 }
907
908 CertErrors errors;
909 ParseCertificateOptions options;
910 options.allow_invalid_serial_numbers = true;
911 scoped_refptr<ParsedCertificate> anchor_cert = ParsedCertificate::Create(
912 x509_util::CreateCryptoBuffer(CFDataGetBytePtr(der_data.get()),
913 CFDataGetLength(der_data.get())),
914 options, &errors);
915 if (!anchor_cert) {
916 // TODO(crbug.com/634443): return errors better.
917 LOG(ERROR) << "Error parsing issuer certificate:\n"
918 << errors.ToDebugString();
919 continue;
920 }
921
eroman2a938c32017-04-28 23:16:58922 issuers->push_back(std::move(anchor_cert));
mattmea4ed8232017-02-28 23:13:23923 }
924}
925
David Benjamin24381632021-09-03 17:01:45926CertificateTrust TrustStoreMac::GetTrust(
927 const ParsedCertificate* cert,
928 base::SupportsUserData* debug_data) const {
Matt Mueller370a7fda2019-08-22 00:38:59929 TrustStatus trust_status = trust_cache_->IsCertTrusted(cert, debug_data);
eroman2a938c32017-04-28 23:16:58930 switch (trust_status) {
931 case TrustStatus::TRUSTED:
David Benjamin24381632021-09-03 17:01:45932 return CertificateTrust::ForTrustAnchor();
eroman2a938c32017-04-28 23:16:58933 case TrustStatus::DISTRUSTED:
David Benjamin24381632021-09-03 17:01:45934 return CertificateTrust::ForDistrusted();
eroman2a938c32017-04-28 23:16:58935 case TrustStatus::UNSPECIFIED:
David Benjamin24381632021-09-03 17:01:45936 return CertificateTrust::ForUnspecified();
Matt Mueller5d105e72019-07-01 17:38:42937 case TrustStatus::UNKNOWN:
Matt Mueller1b4c2342021-03-16 17:57:04938 // UNKNOWN is an implementation detail of TrustImpl and should never be
Matt Mueller5d105e72019-07-01 17:38:42939 // returned.
940 NOTREACHED();
941 break;
eroman2a938c32017-04-28 23:16:58942 }
mattmea4ed8232017-02-28 23:13:23943
David Benjamin24381632021-09-03 17:01:45944 return CertificateTrust::ForUnspecified();
mattmea4ed8232017-02-28 23:13:23945}
946
947// static
948base::ScopedCFTypeRef<CFArrayRef>
949TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
950 CFDataRef name_data) {
951 base::ScopedCFTypeRef<CFArrayRef> matching_items;
952 base::ScopedCFTypeRef<CFMutableDictionaryRef> query(
953 CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
954 &kCFTypeDictionaryValueCallBacks));
955
956 CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
957 CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
958 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
959 CFDictionarySetValue(query, kSecAttrSubject, name_data);
960
961 base::ScopedCFTypeRef<CFArrayRef> scoped_alternate_keychain_search_list;
962 if (TestKeychainSearchList::HasInstance()) {
963 OSStatus status = TestKeychainSearchList::GetInstance()->CopySearchList(
964 scoped_alternate_keychain_search_list.InitializeInto());
965 if (status) {
966 OSSTATUS_LOG(ERROR, status)
967 << "TestKeychainSearchList::CopySearchList error";
968 return matching_items;
969 }
970 }
971
972 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
973
974 // If a TestKeychainSearchList is present, it will have already set
975 // |scoped_alternate_keychain_search_list|, which will be used as the
976 // basis for reordering the keychain. Otherwise, get the current keychain
977 // search list and use that.
978 if (!scoped_alternate_keychain_search_list) {
979 OSStatus status = SecKeychainCopySearchList(
980 scoped_alternate_keychain_search_list.InitializeInto());
981 if (status) {
982 OSSTATUS_LOG(ERROR, status) << "SecKeychainCopySearchList error";
983 return matching_items;
984 }
985 }
986
987 CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy(
988 kCFAllocatorDefault,
989 CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1,
990 scoped_alternate_keychain_search_list.get());
991 if (!mutable_keychain_search_list) {
992 LOG(ERROR) << "CFArrayCreateMutableCopy";
993 return matching_items;
994 }
995 scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list);
996
997 base::ScopedCFTypeRef<SecKeychainRef> roots_keychain;
998 // The System Roots keychain is not normally searched by SecItemCopyMatching.
999 // Get a reference to it and include in the keychain search list.
1000 OSStatus status = SecKeychainOpen(
1001 "/System/Library/Keychains/SystemRootCertificates.keychain",
1002 roots_keychain.InitializeInto());
1003 if (status) {
1004 OSSTATUS_LOG(ERROR, status) << "SecKeychainOpen error";
1005 return matching_items;
1006 }
1007 CFArrayAppendValue(mutable_keychain_search_list, roots_keychain);
1008
1009 CFDictionarySetValue(query, kSecMatchSearchList,
1010 scoped_alternate_keychain_search_list.get());
1011
1012 OSStatus err = SecItemCopyMatching(
1013 query, reinterpret_cast<CFTypeRef*>(matching_items.InitializeInto()));
1014 if (err == errSecItemNotFound) {
1015 // No matches found.
1016 return matching_items;
1017 }
1018 if (err) {
1019 OSSTATUS_LOG(ERROR, err) << "SecItemCopyMatching error";
1020 return matching_items;
1021 }
1022 return matching_items;
1023}
1024
1025// static
1026base::ScopedCFTypeRef<CFDataRef> TrustStoreMac::GetMacNormalizedIssuer(
eroman2a938c32017-04-28 23:16:581027 const ParsedCertificate* cert) {
mattmea4ed8232017-02-28 23:13:231028 base::ScopedCFTypeRef<CFDataRef> name_data;
1029 // There does not appear to be any public API to get the normalized version
1030 // of a Name without creating a SecCertificate.
1031 base::ScopedCFTypeRef<SecCertificateRef> cert_handle(
mattm4cede8d2017-04-11 02:55:011032 x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
1033 cert->der_cert().Length()));
mattmea4ed8232017-02-28 23:13:231034 if (!cert_handle) {
Matt Muellera4193272017-12-07 00:23:341035 LOG(ERROR) << "CreateCertBufferFromBytes";
mattmea4ed8232017-02-28 23:13:231036 return name_data;
1037 }
1038 {
1039 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
1040 name_data.reset(
1041 SecCertificateCopyNormalizedIssuerContent(cert_handle, nullptr));
1042 }
1043 if (!name_data)
1044 LOG(ERROR) << "SecCertificateCopyNormalizedIssuerContent";
1045 return name_data;
1046}
1047
mattmea4ed8232017-02-28 23:13:231048} // namespace net