1// Copyright (c) 2010 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/base/test_root_certs.h" 6 7#include <Security/Security.h> 8 9#include "base/logging.h" 10#include "base/mac/scoped_cftyperef.h" 11#include "net/base/x509_certificate.h" 12 13namespace net { 14 15namespace { 16 17#if !defined(MAC_OS_X_VERSION_10_6) || \ 18 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 19// Declared in <Security/SecBase.h> of the 10.6 SDK. 20enum { 21 errSecUnimplemented = -4, 22}; 23#endif 24 25typedef OSStatus (*SecTrustSetAnchorCertificatesOnlyFuncPtr)(SecTrustRef, 26 Boolean); 27 28Boolean OurSecCertificateEqual(const void* value1, const void* value2) { 29 if (CFGetTypeID(value1) != SecCertificateGetTypeID() || 30 CFGetTypeID(value2) != SecCertificateGetTypeID()) 31 return CFEqual(value1, value2); 32 return X509Certificate::IsSameOSCert( 33 reinterpret_cast<SecCertificateRef>(const_cast<void*>(value1)), 34 reinterpret_cast<SecCertificateRef>(const_cast<void*>(value2))); 35} 36 37const void* RetainWrapper(CFAllocatorRef unused, const void* value) { 38 return CFRetain(value); 39} 40 41void ReleaseWrapper(CFAllocatorRef unused, const void* value) { 42 CFRelease(value); 43} 44 45// CFEqual prior to 10.6 only performed pointer checks on SecCertificateRefs, 46// rather than checking if they were the same (logical) certificate, so a 47// custom structure is used for the array callbacks. 48const CFArrayCallBacks kCertArrayCallbacks = { 49 0, // version 50 RetainWrapper, 51 ReleaseWrapper, 52 CFCopyDescription, 53 OurSecCertificateEqual, 54}; 55 56} // namespace 57 58bool TestRootCerts::Add(X509Certificate* certificate) { 59 if (CFArrayContainsValue(temporary_roots_, 60 CFRangeMake(0, CFArrayGetCount(temporary_roots_)), 61 certificate->os_cert_handle())) 62 return true; 63 CFArrayAppendValue(temporary_roots_, certificate->os_cert_handle()); 64 return true; 65} 66 67void TestRootCerts::Clear() { 68 CFArrayRemoveAllValues(temporary_roots_); 69} 70 71bool TestRootCerts::IsEmpty() const { 72 return CFArrayGetCount(temporary_roots_) == 0; 73} 74 75OSStatus TestRootCerts::FixupSecTrustRef(SecTrustRef trust_ref) const { 76 if (IsEmpty()) 77 return noErr; 78 79 CFBundleRef bundle = 80 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); 81 SecTrustSetAnchorCertificatesOnlyFuncPtr set_anchor_certificates_only = NULL; 82 if (bundle) { 83 set_anchor_certificates_only = 84 reinterpret_cast<SecTrustSetAnchorCertificatesOnlyFuncPtr>( 85 CFBundleGetFunctionPointerForName(bundle, 86 CFSTR("SecTrustSetAnchorCertificatesOnly"))); 87 } 88 89 OSStatus status = noErr; 90 if (set_anchor_certificates_only) { 91 // OS X 10.6 includes a function where the system trusts can be 92 // preserved while appending application trusts. This is preferable, 93 // because it preserves any user trust settings (explicit distrust), 94 // which the naive copy in 10.5 does not. Unfortunately, though the 95 // function pointer may be available, it is not always implemented. If it 96 // returns errSecUnimplemented, fall through to the 10.5 behaviour. 97 status = SecTrustSetAnchorCertificates(trust_ref, temporary_roots_); 98 if (status) 99 return status; 100 status = set_anchor_certificates_only(trust_ref, false); 101 if (status != errSecUnimplemented) 102 return status; 103 104 // Restore the original settings before falling back. 105 status = SecTrustSetAnchorCertificates(trust_ref, NULL); 106 if (status) 107 return status; 108 } 109 110 // On 10.5, the system certificates have to be copied and merged into 111 // the application trusts, and may override any user trust settings. 112 CFArrayRef system_roots = NULL; 113 status = SecTrustCopyAnchorCertificates(&system_roots); 114 if (status) 115 return status; 116 117 base::mac::ScopedCFTypeRef<CFArrayRef> scoped_system_roots(system_roots); 118 base::mac::ScopedCFTypeRef<CFMutableArrayRef> scoped_roots( 119 CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, 120 scoped_system_roots)); 121 DCHECK(scoped_roots.get()); 122 123 CFArrayAppendArray(scoped_roots, temporary_roots_, 124 CFRangeMake(0, CFArrayGetCount(temporary_roots_))); 125 return SecTrustSetAnchorCertificates(trust_ref, scoped_roots); 126} 127 128TestRootCerts::~TestRootCerts() {} 129 130void TestRootCerts::Init() { 131 temporary_roots_.reset(CFArrayCreateMutable(kCFAllocatorDefault, 0, 132 &kCertArrayCallbacks)); 133} 134 135} // namespace net 136