1 // Copyright (c) 2012 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/test_root_certs.h" 6 7 #include <Security/Security.h> 8 9 #include "base/logging.h" 10 #include "base/mac/mac_util.h" 11 #include "base/mac/scoped_cftyperef.h" 12 #include "net/cert/x509_certificate.h" 13 14 namespace net { 15 16 namespace { 17 18 typedef OSStatus (*SecTrustSetAnchorCertificatesOnlyFuncPtr)(SecTrustRef, 19 Boolean); 20 21 Boolean OurSecCertificateEqual(const void* value1, const void* value2) { 22 if (CFGetTypeID(value1) != SecCertificateGetTypeID() || 23 CFGetTypeID(value2) != SecCertificateGetTypeID()) 24 return CFEqual(value1, value2); 25 return X509Certificate::IsSameOSCert( 26 reinterpret_cast<SecCertificateRef>(const_cast<void*>(value1)), 27 reinterpret_cast<SecCertificateRef>(const_cast<void*>(value2))); 28 } 29 30 const void* RetainWrapper(CFAllocatorRef unused, const void* value) { 31 return CFRetain(value); 32 } 33 34 void ReleaseWrapper(CFAllocatorRef unused, const void* value) { 35 CFRelease(value); 36 } 37 38 // CFEqual prior to 10.6 only performed pointer checks on SecCertificateRefs, 39 // rather than checking if they were the same (logical) certificate, so a 40 // custom structure is used for the array callbacks. 41 const CFArrayCallBacks kCertArrayCallbacks = { 42 0, // version 43 RetainWrapper, 44 ReleaseWrapper, 45 CFCopyDescription, 46 OurSecCertificateEqual, 47 }; 48 49 } // namespace 50 51 bool TestRootCerts::Add(X509Certificate* certificate) { 52 if (CFArrayContainsValue(temporary_roots_, 53 CFRangeMake(0, CFArrayGetCount(temporary_roots_)), 54 certificate->os_cert_handle())) 55 return true; 56 CFArrayAppendValue(temporary_roots_, certificate->os_cert_handle()); 57 return true; 58 } 59 60 void TestRootCerts::Clear() { 61 CFArrayRemoveAllValues(temporary_roots_); 62 } 63 64 bool TestRootCerts::IsEmpty() const { 65 return CFArrayGetCount(temporary_roots_) == 0; 66 } 67 68 OSStatus TestRootCerts::FixupSecTrustRef(SecTrustRef trust_ref) const { 69 if (IsEmpty()) 70 return noErr; 71 72 // Despite SecTrustSetAnchorCertificatesOnly existing in OS X 10.6, and 73 // being documented as available, it is not actually implemented. On 10.7+, 74 // however, it always works. 75 if (base::mac::IsOSLionOrLater()) { 76 OSStatus status = SecTrustSetAnchorCertificates(trust_ref, 77 temporary_roots_); 78 if (status) 79 return status; 80 return SecTrustSetAnchorCertificatesOnly(trust_ref, !allow_system_trust_); 81 } 82 83 if (!allow_system_trust_) { 84 // Avoid any copying if system roots are not to be trusted. This acts as 85 // an exclusive list on 10.6, replacing the built-ins. 86 return SecTrustSetAnchorCertificates(trust_ref, temporary_roots_); 87 } 88 89 // Otherwise, both system trust and temporary_roots_ must be trusted. 90 // Emulate the functionality of SecTrustSetAnchorCertificatesOnly by 91 // creating a copy of the system roots and merging with temporary_roots_. 92 CFArrayRef system_roots = NULL; 93 OSStatus status = SecTrustCopyAnchorCertificates(&system_roots); 94 if (status) 95 return status; 96 97 base::ScopedCFTypeRef<CFArrayRef> scoped_system_roots(system_roots); 98 base::ScopedCFTypeRef<CFMutableArrayRef> scoped_roots( 99 CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, scoped_system_roots)); 100 CFArrayAppendArray(scoped_roots, temporary_roots_, 101 CFRangeMake(0, CFArrayGetCount(temporary_roots_))); 102 return SecTrustSetAnchorCertificates(trust_ref, scoped_roots); 103 } 104 105 void TestRootCerts::SetAllowSystemTrust(bool allow_system_trust) { 106 allow_system_trust_ = allow_system_trust; 107 } 108 109 TestRootCerts::~TestRootCerts() {} 110 111 void TestRootCerts::Init() { 112 temporary_roots_.reset(CFArrayCreateMutable(kCFAllocatorDefault, 0, 113 &kCertArrayCallbacks)); 114 allow_system_trust_ = true; 115 } 116 117 } // namespace net 118