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

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

Issue 2963: Bring X.509 cert handling (at least preliminarily) to the Mac. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 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
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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/x509_certificate.h" 5 #include "net/base/x509_certificate.h"
6 6
7 #include <CommonCrypto/CommonDigest.h>
7 #include <map> 8 #include <map>
8 9
9 #include "base/histogram.h" 10 #include "base/histogram.h"
10 #include "base/lock.h" 11 #include "base/lock.h"
11 #include "base/pickle.h" 12 #include "base/pickle.h"
12 #include "base/singleton.h" 13 #include "base/singleton.h"
13 #include "base/string_tokenizer.h" 14 #include "base/string_tokenizer.h"
14 #include "base/string_util.h" 15 #include "base/string_util.h"
15 #include "net/base/cert_status_flags.h" 16 #include "net/base/cert_status_flags.h"
16 #include "net/base/ev_root_ca_metadata.h" 17 #include "net/base/ev_root_ca_metadata.h"
17 18
18 #pragma comment(lib, "crypt32.lib") 19 // NOTE: This Mac implementation is almost entirely untested. TODO(avi): test
20 // it to make sure it does what the docs imply it does.
21 // NOTE: This implementation doesn't keep track of dates. Calling code is
22 // expected to use SecTrustEvaluate(x509cert.os_cert_handle()) and look at the
23 // result there.
19 24
20 namespace net { 25 namespace net {
21 26
22 namespace { 27 namespace {
23 28
24 // Returns true if this cert fingerprint is the null (all zero) fingerprint. 29 // Returns true if this cert fingerprint is the null (all zero) fingerprint.
25 // We use this as a bogus fingerprint value. 30 // We use this as a bogus fingerprint value.
26 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) { 31 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) {
27 for (int i = 0; i < arraysize(fingerprint.data); ++i) { 32 for (size_t i = 0; i < arraysize(fingerprint.data); ++i) {
28 if (fingerprint.data[i] != 0) 33 if (fingerprint.data[i] != 0)
29 return false; 34 return false;
30 } 35 }
31 return true; 36 return true;
32 } 37 }
33 38
34 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty 39 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty
35 // (all zero) fingerprint on failure. 40 // (all zero) fingerprint on failure.
36 X509Certificate::Fingerprint CalculateFingerprint(PCCERT_CONTEXT cert) { 41 X509Certificate::Fingerprint CalculateFingerprint(
37 DCHECK(NULL != cert->pbCertEncoded); 42 X509Certificate::OSCertHandle cert) {
38 DCHECK(0 != cert->cbCertEncoded); 43 // The Windows code uses CryptHashCertificate, a function specially designed
wtc 2008/09/18 20:37:55 I believe CryptHashCertificate is just a convenien
Avi (use Gerrit) 2008/09/18 20:48:17 Nice, thanks.
44 // to hash certificates. I'm not sure what the difference between using it and
45 // just hashing the data is. WINE's implementation just hashes the data, and
46 // so we'll do that.
47
48 X509Certificate::Fingerprint sha1;
49 memset(sha1.data, 0, sizeof(sha1.data));
50
51 CSSM_DATA cert_data;
52 OSStatus status = SecCertificateGetData(cert, &cert_data);
53 if (status)
54 return sha1;
55
56 DCHECK(NULL != cert_data.Data);
57 DCHECK(0 != cert_data.Length);
58
59 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
39 60
40 BOOL rv;
41 X509Certificate::Fingerprint sha1;
42 DWORD sha1_size = sizeof(sha1.data);
43 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded,
44 cert->cbCertEncoded, sha1.data, &sha1_size);
45 DCHECK(rv && sha1_size == sizeof(sha1.data));
46 if (!rv)
47 memset(sha1.data, 0, sizeof(sha1.data));
48 return sha1; 61 return sha1;
49 } 62 }
50 63
51 // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the 64 inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) {
wtc 2008/09/18 20:37:55 I'm a little surprised that the Security Framework
Avi (use Gerrit) 2008/09/18 20:48:17 Me too, but I looked...
52 // WINAPI calling convention. 65 return oid1->Length == oid2->Length &&
53 void* WINAPI MyCryptAlloc(size_t size) { 66 (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0);
54 return malloc(size);
55 } 67 }
56 68
57 void WINAPI MyCryptFree(void* p) { 69 void ParsePrincipal(const CSSM_X509_NAME* name,
58 free(p); 70 X509Certificate::Principal* principal) {
71 std::vector<std::string> common_names, locality_names, state_names,
72 country_names;
73
74 // TODO(jcampan): add business_category and serial_number.
75 const CSSM_OID* kOIDs[8] = { &CSSMOID_CommonName,
Amanda Walker 2008/09/18 16:14:43 suggest using [] instead of [8] so that we don't n
76 &CSSMOID_LocalityName,
77 &CSSMOID_StateProvinceName,
78 &CSSMOID_CountryName,
79 &CSSMOID_StreetAddress,
80 &CSSMOID_OrganizationName,
81 &CSSMOID_OrganizationalUnitName,
82 &CSSMOID_DNQualifier }; // This should be "DC"
wtc 2008/09/18 20:37:55 "DN" most likely stands for Distinguished Name, so
83 // but is undoubtedly
84 // wrong. Find the right
85 // OID.
Amanda Walker 2008/09/18 16:14:43 Add TODO
86
87 std::vector<std::string>* values[8] = {
Amanda Walker 2008/09/18 16:14:43 suggest using [] instead of [8] so that we don't n
88 &common_names, &locality_names,
89 &state_names, &country_names,
90 &(principal->street_addresses),
91 &(principal->organization_names),
92 &(principal->organization_unit_names),
93 &(principal->domain_components) };
94 DCHECK(arraysize(kOIDs) == arraysize(values));
95
96 for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
97 CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
98 for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
99 CSSM_X509_TYPE_VALUE_PAIR pair_struct =
100 rdn_struct.AttributeTypeAndValue[pair];
101 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
102 if (CSSMOIDEqual(&pair_struct.type, kOIDs[oid])) {
103 std::string value =
104 std::string(reinterpret_cast<std::string::value_type*>
105 (pair_struct.value.Data),
106 pair_struct.value.Length);
107 values[oid]->push_back(value);
108 break;
109 }
110 }
111 }
112 }
113
114 // We don't expect to have more than one CN, L, S, and C.
115 std::vector<std::string>* single_value_lists[4] = {
116 &common_names, &locality_names, &state_names, &country_names };
117 std::string* single_values[4] = {
118 &principal->common_name, &principal->locality_name,
119 &principal->state_or_province_name, &principal->country_name };
120 for (size_t i = 0; i < arraysize(single_value_lists); ++i) {
121 DCHECK(single_value_lists[i]->size() <= 1);
122 if (single_value_lists[i]->size() > 0)
123 *(single_values[i]) = (*(single_value_lists[i]))[0];
124 }
59 } 125 }
60 126
61 // Decodes the cert's subjectAltName extension into a CERT_ALT_NAME_INFO 127 void GetCertFieldsForOID(X509Certificate::OSCertHandle cert_handle,
wtc 2008/09/18 20:37:55 Use "Field", singular. You're returning only one
Avi (use Gerrit) 2008/09/18 20:48:17 The break is a mistake on my part, copied from the
62 // structure and stores it in *output. 128 CSSM_OID oid,
63 void GetCertSubjectAltName(PCCERT_CONTEXT cert, 129 std::vector<std::string>* result) {
64 scoped_ptr_malloc<CERT_ALT_NAME_INFO>* output) { 130 CSSM_DATA cert_data;
65 PCERT_EXTENSION extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2, 131 OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
66 cert->pCertInfo->cExtension, 132 if (status)
67 cert->pCertInfo->rgExtension);
68 if (!extension)
69 return; 133 return;
70 134
71 CRYPT_DECODE_PARA decode_para; 135 CSSM_CL_HANDLE clHandle;
wtc 2008/09/18 20:37:55 clHandle doesn't follow the naming convention in t
72 decode_para.cbSize = sizeof(decode_para); 136 status = SecCertificateGetCLHandle(cert_handle, &clHandle);
73 decode_para.pfnAlloc = MyCryptAlloc; 137 if (status)
74 decode_para.pfnFree = MyCryptFree; 138 return;
75 CERT_ALT_NAME_INFO* alt_name_info = NULL; 139
76 DWORD alt_name_info_size = 0; 140 uint32 numOfFields;
wtc 2008/09/18 20:37:55 numOfFields doesn't follow the naming convention i
77 BOOL rv; 141 CSSM_FIELD_PTR fields;
78 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 142 status = CSSM_CL_CertGetAllFields(clHandle, &cert_data, &numOfFields,
79 szOID_SUBJECT_ALT_NAME2, 143 &fields);
80 extension->Value.pbData, 144 if (status)
81 extension->Value.cbData, 145 return;
82 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, 146
83 &decode_para, 147 for (size_t field = 0; field < numOfFields; ++field) {
84 &alt_name_info, 148 if (CSSMOIDEqual(&fields[field].FieldOid, &oid)) {
85 &alt_name_info_size); 149 std::string value =
86 if (rv) 150 std::string(reinterpret_cast<std::string::value_type*>
87 output->reset(alt_name_info); 151 (fields[field].FieldValue.Data),
152 fields[field].FieldValue.Length);
153 result->push_back(value);
154 break;
155 }
156 }
88 } 157 }
89 158
90 ///////////////////////////////////////////////////////////////////////////
91 //
92 // Functions used by X509Certificate::IsEV
93 //
94 ///////////////////////////////////////////////////////////////////////////
95
96 // Constructs a certificate chain starting from the end certificate
97 // 'cert_context', matching any of the certificate policies.
98 //
99 // Returns the certificate chain context on success, or NULL on failure.
100 // The caller is responsible for freeing the certificate chain context with
101 // CertFreeCertificateChain.
102 PCCERT_CHAIN_CONTEXT ConstructCertChain(
103 PCCERT_CONTEXT cert_context,
104 const char* const* policies,
105 int num_policies) {
106 CERT_CHAIN_PARA chain_para;
107 memset(&chain_para, 0, sizeof(chain_para));
108 chain_para.cbSize = sizeof(chain_para);
109 chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
110 chain_para.RequestedUsage.Usage.cUsageIdentifier = 0;
111 chain_para.RequestedUsage.Usage.rgpszUsageIdentifier = NULL; // LPSTR*
112 chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_OR;
113 chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = num_policies;
114 chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier =
115 const_cast<char**>(policies);
116 PCCERT_CHAIN_CONTEXT chain_context;
117 if (!CertGetCertificateChain(
118 NULL, // default chain engine, HCCE_CURRENT_USER
119 cert_context,
120 NULL, // current system time
121 cert_context->hCertStore, // search this store
122 &chain_para,
123 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
124 CERT_CHAIN_CACHE_END_CERT,
125 NULL, // reserved
126 &chain_context)) {
127 return NULL;
128 }
129 return chain_context;
130 }
131
132 // Decodes the cert's certificatePolicies extension into a CERT_POLICIES_INFO
133 // structure and stores it in *output.
134 void GetCertPoliciesInfo(PCCERT_CONTEXT cert,
135 scoped_ptr_malloc<CERT_POLICIES_INFO>* output) {
136 PCERT_EXTENSION extension = CertFindExtension(szOID_CERT_POLICIES,
137 cert->pCertInfo->cExtension,
138 cert->pCertInfo->rgExtension);
139 if (!extension)
140 return;
141
142 CRYPT_DECODE_PARA decode_para;
143 decode_para.cbSize = sizeof(decode_para);
144 decode_para.pfnAlloc = MyCryptAlloc;
145 decode_para.pfnFree = MyCryptFree;
146 CERT_POLICIES_INFO* policies_info = NULL;
147 DWORD policies_info_size = 0;
148 BOOL rv;
149 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
150 szOID_CERT_POLICIES,
151 extension->Value.pbData,
152 extension->Value.cbData,
153 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
154 &decode_para,
155 &policies_info,
156 &policies_info_size);
157 if (rv)
158 output->reset(policies_info);
159 }
160
161 // Returns true if the policy is in the array of CERT_POLICY_INFO in
162 // the CERT_POLICIES_INFO structure.
163 bool ContainsPolicy(const CERT_POLICIES_INFO* policies_info,
164 const char* policy) {
165 int num_policies = policies_info->cPolicyInfo;
166 for (int i = 0; i < num_policies; i++) {
167 if (!strcmp(policies_info->rgPolicyInfo[i].pszPolicyIdentifier, policy))
168 return true;
169 }
170 return false;
171 }
172
173 // This class wraps the CertFreeCertificateChain function in a class that can
174 // be passed as a template argument to scoped_ptr_malloc.
175 class ScopedPtrMallocFreeCertChain {
176 public:
177 void operator()(const CERT_CHAIN_CONTEXT* x) const {
178 CertFreeCertificateChain(x);
179 }
180 };
181
182 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT,
183 ScopedPtrMallocFreeCertChain> ScopedCertChainContext;
184
185 } // namespace 159 } // namespace
186 160
187 bool X509Certificate::FingerprintLessThan::operator()( 161 bool X509Certificate::FingerprintLessThan::operator()(
188 const Fingerprint& lhs, 162 const Fingerprint& lhs,
189 const Fingerprint& rhs) const { 163 const Fingerprint& rhs) const {
190 for (int i = 0; i < sizeof(lhs.data); ++i) { 164 for (size_t i = 0; i < sizeof(lhs.data); ++i) {
191 if (lhs.data[i] < rhs.data[i]) 165 if (lhs.data[i] < rhs.data[i])
192 return true; 166 return true;
193 if (lhs.data[i] > rhs.data[i]) 167 if (lhs.data[i] > rhs.data[i])
194 return false; 168 return false;
195 } 169 }
196 return false; 170 return false;
197 } 171 }
198 172
199 bool X509Certificate::LessThan::operator()(X509Certificate* lhs, 173 bool X509Certificate::LessThan::operator()(X509Certificate* lhs,
200 X509Certificate* rhs) const { 174 X509Certificate* rhs) const {
201 if (lhs == rhs) 175 if (lhs == rhs)
202 return false; 176 return false;
203 177
204 X509Certificate::FingerprintLessThan fingerprint_functor; 178 X509Certificate::FingerprintLessThan fingerprint_functor;
205 return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_); 179 return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_);
206 } 180 }
207 181
208 // A thread-safe cache for X509Certificate objects. 182 // A thread-safe cache for X509Certificate objects.
Amanda Walker 2008/09/18 16:14:43 Can we move this into a header file, since it has
209 // 183 //
210 // The cache does not hold a reference to the certificate objects. The objects 184 // The cache does not hold a reference to the certificate objects. The objects
211 // must |Remove| themselves from the cache upon destruction (or else the cache 185 // must |Remove| themselves from the cache upon destruction (or else the cache
212 // will be holding dead pointers to the objects). 186 // will be holding dead pointers to the objects).
213 class X509Certificate::Cache { 187 class X509Certificate::Cache {
214 public: 188 public:
215 // Get the singleton object for the cache. 189 // Get the singleton object for the cache.
216 static X509Certificate::Cache* GetInstance() { 190 static X509Certificate::Cache* GetInstance() {
217 return Singleton<X509Certificate::Cache>::get(); 191 return Singleton<X509Certificate::Cache>::get();
218 } 192 }
(...skipping 30 matching lines...) Expand all
249 return NULL; 223 return NULL;
250 224
251 return pos->second; 225 return pos->second;
252 }; 226 };
253 227
254 private: 228 private:
255 typedef std::map<Fingerprint, X509Certificate*, FingerprintLessThan> CertMap; 229 typedef std::map<Fingerprint, X509Certificate*, FingerprintLessThan> CertMap;
256 230
257 // Obtain an instance of X509Certificate::Cache via GetInstance(). 231 // Obtain an instance of X509Certificate::Cache via GetInstance().
258 Cache() { } 232 Cache() { }
259 friend DefaultSingletonTraits<X509Certificate::Cache>; 233 friend class DefaultSingletonTraits<X509Certificate::Cache>;
260 234
261 // You must acquire this lock before using any private data of this object. 235 // You must acquire this lock before using any private data of this object.
262 // You must not block while holding this lock. 236 // You must not block while holding this lock.
263 Lock lock_; 237 Lock lock_;
264 238
265 // The certificate cache. You must acquire |lock_| before using |cache_|. 239 // The certificate cache. You must acquire |lock_| before using |cache_|.
266 CertMap cache_; 240 CertMap cache_;
267 241
268 DISALLOW_EVIL_CONSTRUCTORS(X509Certificate::Cache); 242 DISALLOW_COPY_AND_ASSIGN(Cache);
269 }; 243 };
270 244
271 void X509Certificate::Initialize() { 245 void X509Certificate::Initialize() {
272 std::wstring subject_info; 246 const CSSM_X509_NAME* name;
273 std::wstring issuer_info; 247 OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
274 DWORD name_size; 248 if (!status) {
275 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, 249 ParsePrincipal(name, &subject_);
276 &cert_handle_->pCertInfo->Subject, 250 }
277 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, 251 status = SecCertificateGetIssuer(cert_handle_, &name);
278 NULL, 0); 252 if (!status) {
279 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, 253 ParsePrincipal(name, &issuer_);
280 &cert_handle_->pCertInfo->Subject, 254 }
281 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, 255
282 WriteInto(&subject_info, name_size), name_size);
283 name_size = CertNameToStr(cert_handle_->dwCertEncodingType,
284 &cert_handle_->pCertInfo->Issuer,
285 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
286 NULL, 0);
287 name_size = CertNameToStr(cert_handle_->dwCertEncodingType,
288 &cert_handle_->pCertInfo->Issuer,
289 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
290 WriteInto(&issuer_info, name_size), name_size);
291 ParsePrincipal(WideToUTF8(subject_info), &subject_);
292 ParsePrincipal(WideToUTF8(issuer_info), &issuer_);
293
294 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore);
295 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter);
296
297 fingerprint_ = CalculateFingerprint(cert_handle_); 256 fingerprint_ = CalculateFingerprint(cert_handle_);
298 257
299 // Store the certificate in the cache in case we need it later. 258 // Store the certificate in the cache in case we need it later.
300 X509Certificate::Cache::GetInstance()->Insert(this); 259 X509Certificate::Cache::GetInstance()->Insert(this);
301 } 260 }
302 261
303 // static 262 // static
304 X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { 263 X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) {
305 DCHECK(cert_handle); 264 DCHECK(cert_handle);
306 265
307 // Check if we already have this certificate in memory. 266 // Check if we already have this certificate in memory.
308 X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); 267 X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance();
309 X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); 268 X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle));
310 if (cert) { 269 if (cert) {
311 // We've found a certificate with the same fingerprint in our cache. We own 270 // We've found a certificate with the same fingerprint in our cache. We own
312 // the |cert_handle|, which makes it our job to free it. 271 // the |cert_handle|, which makes it our job to free it.
313 CertFreeCertificateContext(cert_handle); 272 CFRelease(cert_handle);
314 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); 273 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1);
315 return cert; 274 return cert;
316 } 275 }
317 // Otherwise, allocate a new object. 276 // Otherwise, allocate a new object.
318 return new X509Certificate(cert_handle); 277 return new X509Certificate(cert_handle);
319 } 278 }
320 279
321 // static 280 // static
322 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, 281 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
323 void** pickle_iter) { 282 void** pickle_iter) {
324 const char* data; 283 const char* data;
325 int length; 284 int length;
326 if (!pickle.ReadData(pickle_iter, &data, &length)) 285 if (!pickle.ReadData(pickle_iter, &data, &length))
327 return NULL; 286 return NULL;
287 CSSM_DATA cert_data;
288 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
289 cert_data.Length = length;
328 290
329 OSCertHandle cert_handle = NULL; 291 OSCertHandle cert_handle = NULL;
330 if (!CertAddSerializedElementToStore( 292 OSStatus status = SecCertificateCreateFromData(&cert_data,
331 NULL, // the cert won't be persisted in any cert store 293 CSSM_CERT_X_509v3,
332 reinterpret_cast<const BYTE*>(data), length, 294 CSSM_CERT_ENCODING_BER,
333 CERT_STORE_ADD_USE_EXISTING, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, 295 &cert_handle);
334 NULL, reinterpret_cast<const void **>(&cert_handle))) 296 if (status)
335 return NULL; 297 return NULL;
336 298
337 return CreateFromHandle(cert_handle); 299 return CreateFromHandle(cert_handle);
338 } 300 }
339 301
340 X509Certificate::X509Certificate(OSCertHandle cert_handle) 302 X509Certificate::X509Certificate(OSCertHandle cert_handle)
341 : cert_handle_(cert_handle) { 303 : cert_handle_(cert_handle) {
342 Initialize(); 304 Initialize();
343 } 305 }
344 306
345 X509Certificate::X509Certificate(std::string subject, std::string issuer, 307 X509Certificate::X509Certificate(std::string subject, std::string issuer,
346 Time start_date, Time expiration_date) 308 Time, Time)
347 : subject_(subject), 309 : subject_(subject),
348 issuer_(issuer), 310 issuer_(issuer),
349 valid_start_(start_date),
350 valid_expiry_(expiration_date),
351 cert_handle_(NULL) { 311 cert_handle_(NULL) {
352 memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); 312 memset(fingerprint_.data, 0, sizeof(fingerprint_.data));
353 } 313 }
354 314
355 void X509Certificate::Persist(Pickle* pickle) { 315 void X509Certificate::Persist(Pickle* pickle) {
356 DWORD length; 316 CSSM_DATA cert_data;
357 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, 317 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data);
358 NULL, &length)) { 318 if (status) {
359 NOTREACHED(); 319 NOTREACHED();
360 return; 320 return;
361 } 321 }
362 BYTE* data = reinterpret_cast<BYTE*>(pickle->BeginWriteData(length)); 322
363 if (!CertSerializeCertificateStoreElement(cert_handle_, 0, 323 pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), cert_data.Length);
364 data, &length)) {
365 NOTREACHED();
366 length = 0;
367 }
368 pickle->TrimWriteData(length);
369 } 324 }
370 325
371 X509Certificate::~X509Certificate() { 326 X509Certificate::~X509Certificate() {
372 // We might not be in the cache, but it is safe to remove ourselves anyway. 327 // We might not be in the cache, but it is safe to remove ourselves anyway.
373 X509Certificate::Cache::GetInstance()->Remove(this); 328 X509Certificate::Cache::GetInstance()->Remove(this);
374 if (cert_handle_) 329 if (cert_handle_)
375 CertFreeCertificateContext(cert_handle_); 330 CFRelease(cert_handle_);
376 } 331 }
377 332
378 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { 333 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
379 dns_names->clear(); 334 dns_names->clear();
380 scoped_ptr_malloc<CERT_ALT_NAME_INFO> alt_name_info; 335
381 GetCertSubjectAltName(cert_handle_, &alt_name_info); 336 GetCertFieldsForOID(cert_handle_, CSSMOID_SubjectAltName, dns_names);
wtc 2008/09/18 20:37:55 Add a TODO comment to note that we still need to p
Avi (use Gerrit) 2008/09/18 20:48:17 OK; this is me coding not quite sure what needs to
382 CERT_ALT_NAME_INFO* alt_name = alt_name_info.get(); 337
383 if (alt_name) {
384 int num_entries = alt_name->cAltEntry;
385 for (int i = 0; i < num_entries; i++) {
386 // dNSName is an ASN.1 IA5String representing a string of ASCII
387 // characters, so we can use WideToASCII here.
388 if (alt_name->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME)
389 dns_names->push_back(WideToASCII(alt_name->rgAltEntry[i].pwszDNSName));
390 }
391 }
392 if (dns_names->empty()) 338 if (dns_names->empty())
393 dns_names->push_back(subject_.common_name); 339 dns_names->push_back(subject_.common_name);
394 } 340 }
395 341
396 bool X509Certificate::HasExpired() const {
397 return Time::Now() > valid_expiry();
398 }
399
400 // Returns true if the certificate is an extended-validation certificate. 342 // Returns true if the certificate is an extended-validation certificate.
401 // 343 //
402 // The certificate has already been verified by the HTTP library. cert_status 344 // The certificate has already been verified by the HTTP library. cert_status
403 // represents the result of that verification. This function performs 345 // represents the result of that verification. This function performs
404 // additional checks of the certificatePolicies extensions of the certificates 346 // additional checks of the certificatePolicies extensions of the certificates
405 // in the certificate chain according to Section 7 (pp. 11-12) of the EV 347 // in the certificate chain according to Section 7 (pp. 11-12) of the EV
406 // Certificate Guidelines Version 1.0 at 348 // Certificate Guidelines Version 1.0 at
407 // http://cabforum.org/EV_Certificate_Guidelines.pdf. 349 // http://cabforum.org/EV_Certificate_Guidelines.pdf.
408 bool X509Certificate::IsEV(int cert_status) const { 350 bool X509Certificate::IsEV(int cert_status) const {
409 if (net::IsCertStatusError(cert_status) || 351 // TODO(avi): implement this
410 (cert_status & net::CERT_STATUS_REV_CHECKING_ENABLED) == 0) 352 NOTIMPLEMENTED();
411 return false; 353 return false;
412
413 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance();
414
415 PCCERT_CHAIN_CONTEXT chain_context = ConstructCertChain(cert_handle_,
416 metadata->GetPolicyOIDs(), metadata->NumPolicyOIDs());
417 if (!chain_context)
418 return false;
419 ScopedCertChainContext scoped_chain_context(chain_context);
420
421 DCHECK(chain_context->cChain != 0);
422 // If the cert doesn't match any of the policies, the
423 // CERT_TRUST_IS_NOT_VALID_FOR_USAGE bit (0x10) in
424 // chain_context->TrustStatus.dwErrorStatus is set.
425 DWORD error_status = chain_context->TrustStatus.dwErrorStatus;
426 DWORD info_status = chain_context->TrustStatus.dwInfoStatus;
427 if (!chain_context->cChain || error_status != CERT_TRUST_NO_ERROR)
428 return false;
429
430 // Check the end certificate simple chain (chain_context->rgpChain[0]).
431 // If the end certificate's certificatePolicies extension contains the
432 // EV policy OID of the root CA, return true.
433 PCERT_CHAIN_ELEMENT* element = chain_context->rgpChain[0]->rgpElement;
434 int num_elements = chain_context->rgpChain[0]->cElement;
435 if (num_elements < 2)
436 return false;
437
438 // Look up the EV policy OID of the root CA.
439 PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext;
440 X509Certificate::Fingerprint fingerprint = CalculateFingerprint(root_cert);
441 std::string ev_policy_oid;
442 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid))
443 return false;
444 DCHECK(!ev_policy_oid.empty());
445
446 // Get the certificatePolicies extension of the end certificate.
447 PCCERT_CONTEXT end_cert = element[0]->pCertContext;
448 scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info;
449 GetCertPoliciesInfo(end_cert, &policies_info);
450 if (!policies_info.get())
451 return false;
452
453 return ContainsPolicy(policies_info.get(), ev_policy_oid.c_str());
454 }
455
456 // static
457 void X509Certificate::ParsePrincipal(const std::string& description,
458 Principal* principal) {
459 // The description of the principal is a string with each LDAP value on
460 // a separate line.
461 const std::string kDelimiters("\r\n");
462
463 std::vector<std::string> common_names, locality_names, state_names,
464 country_names, street_addresses;
465
466 // TODO(jcampan): add business_category and serial_number.
467 const std::string kPrefixes[8] = { std::string("CN="),
468 std::string("L="),
469 std::string("S="),
470 std::string("C="),
471 std::string("STREET="),
472 std::string("O="),
473 std::string("OU="),
474 std::string("DC=") };
475
476 std::vector<std::string>* values[8] = {
477 &common_names, &locality_names,
478 &state_names, &country_names,
479 &(principal->street_addresses),
480 &(principal->organization_names),
481 &(principal->organization_unit_names),
482 &(principal->domain_components) };
483 DCHECK(arraysize(kPrefixes) == arraysize(values));
484
485 StringTokenizer str_tok(description, kDelimiters);
486 while (str_tok.GetNext()) {
487 std::string entry = str_tok.token();
488 for (int i = 0; i < arraysize(kPrefixes); i++) {
489 if (!entry.compare(0, kPrefixes[i].length(), kPrefixes[i])) {
490 std::string value = entry.substr(kPrefixes[i].length());
491 // Remove enclosing double-quotes if any.
492 if (value.size() >= 2 &&
493 value[0] == '"' && value[value.size() - 1] == '"')
494 value = value.substr(1, value.size() - 2);
495 values[i]->push_back(value);
496 break;
497 }
498 }
499 }
500
501 // We don't expect to have more than one CN, L, S, and C.
502 std::vector<std::string>* single_value_lists[4] = {
503 &common_names, &locality_names, &state_names, &country_names };
504 std::string* single_values[4] = {
505 &principal->common_name, &principal->locality_name,
506 &principal->state_or_province_name, &principal->country_name };
507 for (int i = 0; i < arraysize(single_value_lists); ++i) {
508 int length = static_cast<int>(single_value_lists[i]->size());
509 DCHECK(single_value_lists[i]->size() <= 1);
510 if (single_value_lists[i]->size() > 0)
511 *(single_values[i]) = (*(single_value_lists[i]))[0];
512 }
513 } 354 }
514 355
515 X509Certificate::Policy::Judgment X509Certificate::Policy::Check( 356 X509Certificate::Policy::Judgment X509Certificate::Policy::Check(
Amanda Walker 2008/09/18 16:14:43 If X509Certificate::Policy has no platform depende
516 X509Certificate* cert) const { 357 X509Certificate* cert) const {
517 // It shouldn't matter which set we check first, but we check denied first 358 // It shouldn't matter which set we check first, but we check denied first
518 // in case something strange has happened. 359 // in case something strange has happened.
519 360
520 if (denied_.find(cert->fingerprint()) != denied_.end()) { 361 if (denied_.find(cert->fingerprint()) != denied_.end()) {
521 // DCHECK that the order didn't matter. 362 // DCHECK that the order didn't matter.
522 DCHECK(allowed_.find(cert->fingerprint()) == allowed_.end()); 363 DCHECK(allowed_.find(cert->fingerprint()) == allowed_.end());
523 return DENIED; 364 return DENIED;
524 } 365 }
525 366
(...skipping 14 matching lines...) Expand all
540 } 381 }
541 382
542 void X509Certificate::Policy::Deny(X509Certificate* cert) { 383 void X509Certificate::Policy::Deny(X509Certificate* cert) {
543 // Put the cert in the denied set and (maybe) remove it from the allowed set. 384 // Put the cert in the denied set and (maybe) remove it from the allowed set.
544 allowed_.erase(cert->fingerprint()); 385 allowed_.erase(cert->fingerprint());
545 denied_.insert(cert->fingerprint()); 386 denied_.insert(cert->fingerprint());
546 } 387 }
547 388
548 } // namespace net 389 } // namespace net
549 390
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698