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