Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: net/base/cert_database_mac.cc

Issue 2668005: Bring the handling of <keygen> and support for the application/x-x509-user-ce... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Whitespace/style Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ssl/ssl_host_state_unittest.cc ('k') | net/base/cert_database_nss.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/cert_database.h" 5 #include "net/base/cert_database.h"
6 6
7 #include <Security/Security.h> 7 #include <Security/Security.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/scoped_cftyperef.h"
10 #include "net/base/net_errors.h" 11 #include "net/base/net_errors.h"
11 #include "net/base/x509_certificate.h" 12 #include "net/base/x509_certificate.h"
12 13
13 namespace net { 14 namespace net {
14 15
16 namespace {
17
18 const void* CertRetainProc(CFAllocatorRef allocator, const void* value) {
19 return CFRetain(value);
20 }
21
22 void CertReleaseProc(CFAllocatorRef allocator, const void* value) {
23 CFRelease(value);
24 }
25
26 // Compare two certificates for equality. This is used as part of a
27 // CFArrayCallbacks structure, as the CFTypeRef returned by
28 // SecTrustGetResult may not point to the same location as was supplied
29 // to ImportIntermediates(), even when they are equivalent. This ensures
30 // the two certificates are properly compared. On OS X 10.6+, CFEqual can
31 // be safely used, as it will make a proper comparison between the two.
32 Boolean CertEqualityProc(const void* value1, const void* value2) {
33 CFTypeID cert_type = SecCertificateGetTypeID();
34 if (CFGetTypeID(value1) != cert_type || CFGetTypeID(value2) != cert_type)
35 return CFEqual(value1, value2);
36 return X509Certificate::IsSameOSCert(
37 reinterpret_cast<SecCertificateRef>(value1),
38 reinterpret_cast<SecCertificateRef>(value2));
39 }
40
41 // From an arbitrary, unordered list of certificate, attempt to import every
42 // certificate that:
43 // 1) Is a CA
44 // 2) Results in a valid certificate chain
45 void ImportIntermediates(
46 const X509Certificate::OSCertHandles& intermediates) {
47 OSStatus rv = noErr;
48 CFArrayCallbacks array_cb = { 0, CertRetainProc, CertReleaseProc,
49 CFCopyDescription, CertEqualityProc };
50
51 // See the "AppleX509XP Trust Policies" reference for documentation, but
52 // this guarantees that the trust evaluation includes making sure the leaf
53 // is a valid CA certificate.
54 CSSM_APPLE_TP_ACTION_DATA tp_action;
55 tp_action.Version = CSSM_APPLE_TP_ACTION_VERSION;
56 tp_action.ActionFlags = CSSM_TP_ACTION_LEAF_IS_CA;
57
58 scoped_cftyperef<CFDataRef> tp_action_data(CFDataCreateWithBytesNoCopy(
59 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&tp_action),
60 sizeof(tp_action), kCFAllocatorDefault));
61 if (tp_action_data == NULL)
62 return;
63
64 // Create a temporary array so that it can be manipulated at will, and
65 // because Sec* functions expect CFArrays.
66 scoped_cftyperef<CFMutableArrayRef> certs_array(CFArrayCreateMutable(
67 kCFAllocatorDefault, 0, &array_cb));
68 for (X509Certificate::OSCertHandles::const_iterator it =
69 intermediates.begin(); it != intermediates.end(); ++it) {
70 CFArrayAppendValue(certs_array, *it);
71 }
72
73 // Create a basic X.509 policy, which will ensure that each constructed
74 // chain matches the minimal criteria for well-formedness.
75 scoped_cftyperef<SecPolicySearchRef> policy_search_ref;
76 SecPolicySearchRef temp_search_ref = NULL;
77 rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC,
78 NULL, &temp_search_ref);
79 if (rv != noErr || temp_search_ref == NULL)
80 return;
81 policy_search_ref.reset(temp_search_ref);
82
83 scoped_cftyperef<SecPolicyRef> policy_ref;
84 SecPolicyRef temp_policy_ref = NULL;
85 rv = SecPolicySearchCopyNext(policy_search_ref, &temp_policy_ref);
86 if (rv != noErr || temp_trust_ref == NULL)
87 return;
88 policy_ref.reset(temp_policy_ref);
89
90 // Enumerate all the certificates, building a chain for each certificate.
91 // If the constructed chain is trusted, and solely comprised of CA
92 // certificates, add each certificate that was in |intermediates| into the
93 // keychain.
94 CFIndex certs_count = CFArrayGetCount(certs_array);
95 size_t offset = 0;
96 for (CFIndex i = 0; i < certs_count; ++i, ++offset) {
97 if (i > 0 && certs_count > 1) {
98 // Rotate the array so that the last item becomes the first, and
99 // everything else is shifted forward by 1. This is because
100 // SecTrustCreateWithCertificates begins validation against the
101 // certificate at index 0.
102 for (CFIndex j = 0; j < certs_count - 1; ++j) {
103 CFArrayExchangeValuesAtIndices(certs_array, certs_count - 1 - j,
104 certs_count - 2 - j);
105 }
106 }
107
108 SecTrustRef temp_trust_ref = NULL;
109 rv = SecTrustCreateWithCertificates(certs_array, policy_ref,
110 &temp_trust_ref);
111 if (rv != noErr)
112 continue;
113 scoped_cftyperef<SecTrustRef> trust_ref(temp_trust_ref);
114 temp_trust_ref = NULL;
115
116 rv = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT,
117 tp_action_data);
118 if (rv != noErr)
119 continue;
120
121 SecTrustResultType result = kSecTrustResultInvalid;
122 rv = SecTrustEvalute(trust_ref, &result);
123 // Allowing kSecTrustResultConfirm, as it will be honored when a chain is
124 // built using this certificate that ends in the certificate that was
125 // flagged as such. However, kSecTrustResultDeny is honored here, to
126 // match behaviour of NSS/Windows implementations of rejecting chains the
127 // user has explicitly rejected.
128 if (rv != noErr || !(result == kSecTrustResultProceed ||
129 result == kSecTrustResultUnspecified ||
130 result == kSecTrustResultConfirm)) {
131 if (rv != noErr) {
132 DLOG(WARNING) << rv << " Unable to get certificate chain for "
133 << "intermediate " << offset;
134 } else {
135 DLOG(WARNING) << "Certificate chain for intermediate " << offset
136 << " is not trusted. " << result;
137 }
138 continue;
139 }
140
141 CFArrayRef temp_chain = NULL;
142 rv = SecTrustGetResult(trust_ref, &result, &temp_chain, NULL);
143 if (rv != noErr || temp_chain == NULL)
144 continue;
145
146 scoped_cftyperef<CFArrayRef> chain(temp_chain);
147 temp_chain = NULL;
148
149 for (CFIndex j = 0; j < CFArrayGetCount(chain); ++j) {
150 SecCertificateRef chain_cert = CFArrayGetValueAtIndex(chain, j);
151 CFIndex orig_index = CFArrayGetFirstIndexOfValue(certs_array,
152 CFRangeMake(0, 0),
153 chain_cert);
154 if (orig_index == -1)
155 continue;
156 // Not checking the result code, because it doesn't matter too much if
157 // the certificate cannot be imported.
158 rv = SecCertificateAddToKeychain(chain_cert, NULL);
159 if (rv != noErr && rv != errSecDuplicateItem) {
160 DLOG(WARNING) << rv << " Unable to import intermediate "
161 << offset;
162 }
163 }
164 }
165 } // namespace
166
15 CertDatabase::CertDatabase() { 167 CertDatabase::CertDatabase() {
16 } 168 }
17 169
18 int CertDatabase::CheckUserCert(X509Certificate* cert) { 170 int CertDatabase::CheckUserCert(X509Certificate* cert) {
19 if (!cert) 171 if (!cert)
20 return ERR_CERT_INVALID; 172 return ERR_CERT_INVALID;
21 if (cert->HasExpired()) 173 if (cert->HasExpired())
22 return ERR_CERT_DATE_INVALID; 174 return ERR_CERT_DATE_INVALID;
23 if (!cert->SupportsSSLClientAuth())
24 return ERR_CERT_INVALID;
25 175
26 // Verify the Keychain already has the corresponding private key: 176 // Verify the Keychain already has the corresponding private key:
27 SecIdentityRef identity = NULL; 177 SecIdentityRef identity = NULL;
28 OSStatus err = SecIdentityCreateWithCertificate(NULL, cert->os_cert_handle(), 178 OSStatus err = SecIdentityCreateWithCertificate(NULL, cert->os_cert_handle(),
29 &identity); 179 &identity);
30 if (err == errSecItemNotFound) { 180 if (err == errSecItemNotFound) {
31 LOG(ERROR) << "CertDatabase couldn't find private key for user cert"; 181 LOG(ERROR) << "CertDatabase couldn't find private key for user cert";
32 return ERR_NO_PRIVATE_KEY_FOR_CERT; 182 return ERR_NO_PRIVATE_KEY_FOR_CERT;
33 } 183 }
34 if (err != noErr || !identity) { 184 if (err != noErr || !identity) {
35 // TODO(snej): Map the error code more intelligently. 185 // TODO(snej): Map the error code more intelligently.
36 return ERR_CERT_INVALID; 186 return ERR_CERT_INVALID;
37 } 187 }
38 188
39 CFRelease(identity); 189 CFRelease(identity);
40 return OK; 190 return OK;
41 } 191 }
42 192
43 int CertDatabase::AddUserCert(X509Certificate* cert) { 193 int CertDatabase::AddUserCert(X509Certificate* cert) {
44 OSStatus err = SecCertificateAddToKeychain(cert->os_cert_handle(), NULL); 194 OSStatus err = SecCertificateAddToKeychain(cert->os_cert_handle(), NULL);
45 switch (err) { 195 if (err != noErr && err != errSecDuplicateItem) {
46 case noErr: 196 LOG(ERROR) << "CertDatabase failed to add cert to keychain: " << err;
47 case errSecDuplicateItem: 197 // TODO(snej): Map the error code more intelligently.
48 return OK; 198 return ERR_ADD_USER_CERT_FAILED;
49 default:
50 LOG(ERROR) << "CertDatabase failed to add cert to keychain: " << err;
51 // TODO(snej): Map the error code more intelligently.
52 return ERR_ADD_USER_CERT_FAILED;
53 } 199 }
200
201 ImportIntermediates(cert->GetIntermediateCertificates());
202 return OK;
54 } 203 }
55 204
56 } // namespace net 205 } // namespace net
OLDNEW
« no previous file with comments | « chrome/browser/ssl/ssl_host_state_unittest.cc ('k') | net/base/cert_database_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698