OLD | NEW |
| (Empty) |
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/base/x509_certificate.h" | |
6 | |
7 #include <CommonCrypto/CommonDigest.h> | |
8 #include <CoreServices/CoreServices.h> | |
9 #include <Security/Security.h> | |
10 #include <time.h> | |
11 | |
12 #include <vector> | |
13 | |
14 #include "base/lazy_instance.h" | |
15 #include "base/logging.h" | |
16 #include "base/mac/mac_logging.h" | |
17 #include "base/mac/scoped_cftyperef.h" | |
18 #include "base/memory/singleton.h" | |
19 #include "base/pickle.h" | |
20 #include "base/sha1.h" | |
21 #include "base/string_piece.h" | |
22 #include "base/strings/sys_string_conversions.h" | |
23 #include "base/synchronization/lock.h" | |
24 #include "crypto/cssm_init.h" | |
25 #include "crypto/mac_security_services_lock.h" | |
26 #include "crypto/nss_util.h" | |
27 #include "crypto/rsa_private_key.h" | |
28 #include "net/base/x509_util_mac.h" | |
29 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" | |
30 | |
31 using base::mac::ScopedCFTypeRef; | |
32 using base::Time; | |
33 | |
34 namespace net { | |
35 | |
36 namespace { | |
37 | |
38 void GetCertDistinguishedName( | |
39 const x509_util::CSSMCachedCertificate& cached_cert, | |
40 const CSSM_OID* oid, | |
41 CertPrincipal* result) { | |
42 x509_util::CSSMFieldValue distinguished_name; | |
43 OSStatus status = cached_cert.GetField(oid, &distinguished_name); | |
44 if (status || !distinguished_name.field()) | |
45 return; | |
46 result->ParseDistinguishedName(distinguished_name.field()->Data, | |
47 distinguished_name.field()->Length); | |
48 } | |
49 | |
50 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle, | |
51 const std::vector<std::string>& issuers) { | |
52 x509_util::CSSMCachedCertificate cached_cert; | |
53 if (cached_cert.Init(cert_handle) != CSSM_OK) | |
54 return false; | |
55 | |
56 x509_util::CSSMFieldValue distinguished_name; | |
57 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd, | |
58 &distinguished_name); | |
59 if (status || !distinguished_name.field()) | |
60 return false; | |
61 | |
62 base::StringPiece name_piece( | |
63 reinterpret_cast<const char*>(distinguished_name.field()->Data), | |
64 static_cast<size_t>(distinguished_name.field()->Length)); | |
65 | |
66 for (std::vector<std::string>::const_iterator it = issuers.begin(); | |
67 it != issuers.end(); ++it) { | |
68 base::StringPiece issuer_piece(*it); | |
69 if (name_piece == issuer_piece) | |
70 return true; | |
71 } | |
72 | |
73 return false; | |
74 } | |
75 | |
76 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert, | |
77 const CSSM_OID* oid, | |
78 Time* result) { | |
79 *result = Time::Time(); | |
80 | |
81 x509_util::CSSMFieldValue field; | |
82 OSStatus status = cached_cert.GetField(oid, &field); | |
83 if (status) | |
84 return; | |
85 | |
86 const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>(); | |
87 if (x509_time->timeType != BER_TAG_UTC_TIME && | |
88 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { | |
89 LOG(ERROR) << "Unsupported date/time format " | |
90 << x509_time->timeType; | |
91 return; | |
92 } | |
93 | |
94 base::StringPiece time_string( | |
95 reinterpret_cast<const char*>(x509_time->time.Data), | |
96 x509_time->time.Length); | |
97 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? | |
98 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; | |
99 if (!ParseCertificateDate(time_string, format, result)) | |
100 LOG(ERROR) << "Invalid certificate date/time " << time_string; | |
101 } | |
102 | |
103 std::string GetCertSerialNumber( | |
104 const x509_util::CSSMCachedCertificate& cached_cert) { | |
105 x509_util::CSSMFieldValue serial_number; | |
106 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, | |
107 &serial_number); | |
108 if (status || !serial_number.field()) | |
109 return std::string(); | |
110 | |
111 return std::string( | |
112 reinterpret_cast<const char*>(serial_number.field()->Data), | |
113 serial_number.field()->Length); | |
114 } | |
115 | |
116 // Gets the issuer for a given cert, starting with the cert itself and | |
117 // including the intermediate and finally root certificates (if any). | |
118 // This function calls SecTrust but doesn't actually pay attention to the trust | |
119 // result: it shouldn't be used to determine trust, just to traverse the chain. | |
120 // Caller is responsible for releasing the value stored into *out_cert_chain. | |
121 OSStatus CopyCertChain(SecCertificateRef cert_handle, | |
122 CFArrayRef* out_cert_chain) { | |
123 DCHECK(cert_handle); | |
124 DCHECK(out_cert_chain); | |
125 | |
126 // Create an SSL policy ref configured for client cert evaluation. | |
127 SecPolicyRef ssl_policy; | |
128 OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); | |
129 if (result) | |
130 return result; | |
131 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
132 | |
133 // Create a SecTrustRef. | |
134 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( | |
135 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), | |
136 1, &kCFTypeArrayCallBacks)); | |
137 SecTrustRef trust_ref = NULL; | |
138 { | |
139 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
140 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, | |
141 &trust_ref); | |
142 } | |
143 if (result) | |
144 return result; | |
145 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); | |
146 | |
147 // Evaluate trust, which creates the cert chain. | |
148 SecTrustResultType status; | |
149 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | |
150 { | |
151 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
152 result = SecTrustEvaluate(trust, &status); | |
153 } | |
154 if (result) | |
155 return result; | |
156 { | |
157 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
158 result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); | |
159 } | |
160 return result; | |
161 } | |
162 | |
163 // Returns true if |purpose| is listed as allowed in |usage|. This | |
164 // function also considers the "Any" purpose. If the attribute is | |
165 // present and empty, we return false. | |
166 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, | |
167 const CSSM_OID* purpose) { | |
168 for (unsigned p = 0; p < usage->numPurposes; ++p) { | |
169 if (CSSMOIDEqual(&usage->purposes[p], purpose)) | |
170 return true; | |
171 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny)) | |
172 return true; | |
173 } | |
174 return false; | |
175 } | |
176 | |
177 // Test that a given |cert_handle| is actually a valid X.509 certificate, and | |
178 // return true if it is. | |
179 // | |
180 // On OS X, SecCertificateCreateFromData() does not return any errors if | |
181 // called with invalid data, as long as data is present. The actual decoding | |
182 // of the certificate does not happen until an API that requires a CSSM | |
183 // handle is called. While SecCertificateGetCLHandle is the most likely | |
184 // candidate, as it performs the parsing, it does not check whether the | |
185 // parsing was actually successful. Instead, SecCertificateGetSubject is | |
186 // used (supported since 10.3), as a means to check that the certificate | |
187 // parsed as a valid X.509 certificate. | |
188 bool IsValidOSCertHandle(SecCertificateRef cert_handle) { | |
189 const CSSM_X509_NAME* sanity_check = NULL; | |
190 OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check); | |
191 return status == noErr && sanity_check; | |
192 } | |
193 | |
194 // Parses |data| of length |length|, attempting to decode it as the specified | |
195 // |format|. If |data| is in the specified format, any certificates contained | |
196 // within are stored into |output|. | |
197 void AddCertificatesFromBytes(const char* data, size_t length, | |
198 SecExternalFormat format, | |
199 X509Certificate::OSCertHandles* output) { | |
200 SecExternalFormat input_format = format; | |
201 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( | |
202 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, | |
203 kCFAllocatorNull)); | |
204 | |
205 CFArrayRef items = NULL; | |
206 OSStatus status; | |
207 { | |
208 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
209 status = SecKeychainItemImport(local_data, NULL, &input_format, | |
210 NULL, 0, NULL, NULL, &items); | |
211 } | |
212 | |
213 if (status) { | |
214 OSSTATUS_DLOG(WARNING, status) | |
215 << "Unable to import items from data of length " << length; | |
216 return; | |
217 } | |
218 | |
219 ScopedCFTypeRef<CFArrayRef> scoped_items(items); | |
220 CFTypeID cert_type_id = SecCertificateGetTypeID(); | |
221 | |
222 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { | |
223 SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>( | |
224 const_cast<void*>(CFArrayGetValueAtIndex(items, i))); | |
225 | |
226 // While inputFormat implies only certificates will be imported, if/when | |
227 // other formats (eg: PKCS#12) are supported, this may also include | |
228 // private keys or other items types, so filter appropriately. | |
229 if (CFGetTypeID(item) == cert_type_id) { | |
230 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item); | |
231 // OS X ignores |input_format| if it detects that |local_data| is PEM | |
232 // encoded, attempting to decode data based on internal rules for PEM | |
233 // block headers. If a PKCS#7 blob is encoded with a PEM block of | |
234 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate | |
235 // based on the decoded data. If this happens, the certificate should | |
236 // not be included in |output|. Because |output| is empty, | |
237 // CreateCertificateListfromBytes will use PEMTokenizer to decode the | |
238 // data. When called again with the decoded data, OS X will honor | |
239 // |input_format|, causing decode to succeed. On OS X 10.6, the data | |
240 // is properly decoded as a PKCS#7, whether PEM or not, which avoids | |
241 // the need to fallback to internal decoding. | |
242 if (IsValidOSCertHandle(cert)) { | |
243 CFRetain(cert); | |
244 output->push_back(cert); | |
245 } | |
246 } | |
247 } | |
248 } | |
249 | |
250 struct CSSMOIDString { | |
251 const CSSM_OID* oid_; | |
252 std::string string_; | |
253 }; | |
254 | |
255 typedef std::vector<CSSMOIDString> CSSMOIDStringVector; | |
256 | |
257 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) { | |
258 struct OIDCSSMMap { | |
259 SECOidTag sec_OID_; | |
260 const CSSM_OID* cssm_OID_; | |
261 }; | |
262 | |
263 const OIDCSSMMap kOIDs[] = { | |
264 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName }, | |
265 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName }, | |
266 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName }, | |
267 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName }, | |
268 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress }, | |
269 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName }, | |
270 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName }, | |
271 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier }, | |
272 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier }, | |
273 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress }, | |
274 }; | |
275 | |
276 CERTRDN** rdns = name->rdns; | |
277 for (size_t rdn = 0; rdns[rdn]; ++rdn) { | |
278 CERTAVA** avas = rdns[rdn]->avas; | |
279 for (size_t pair = 0; avas[pair] != 0; ++pair) { | |
280 SECOidTag tag = CERT_GetAVATag(avas[pair]); | |
281 if (tag == SEC_OID_UNKNOWN) { | |
282 return false; | |
283 } | |
284 CSSMOIDString oidString; | |
285 bool found_oid = false; | |
286 for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) { | |
287 if (kOIDs[oid].sec_OID_ == tag) { | |
288 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); | |
289 if (!decode_item) | |
290 return false; | |
291 | |
292 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. | |
293 std::string value(reinterpret_cast<char*>(decode_item->data), | |
294 decode_item->len); | |
295 oidString.oid_ = kOIDs[oid].cssm_OID_; | |
296 oidString.string_ = value; | |
297 out_values->push_back(oidString); | |
298 SECITEM_FreeItem(decode_item, PR_TRUE); | |
299 found_oid = true; | |
300 break; | |
301 } | |
302 } | |
303 if (!found_oid) { | |
304 DLOG(ERROR) << "Unrecognized OID: " << tag; | |
305 } | |
306 } | |
307 } | |
308 return true; | |
309 } | |
310 | |
311 class ScopedCertName { | |
312 public: | |
313 explicit ScopedCertName(CERTName* name) : name_(name) { } | |
314 ~ScopedCertName() { | |
315 if (name_) CERT_DestroyName(name_); | |
316 } | |
317 operator CERTName*() { return name_; } | |
318 | |
319 private: | |
320 CERTName* name_; | |
321 }; | |
322 | |
323 class ScopedEncodedCertResults { | |
324 public: | |
325 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results) | |
326 : results_(results) { } | |
327 ~ScopedEncodedCertResults() { | |
328 if (results_) { | |
329 CSSM_ENCODED_CERT* encCert = | |
330 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results); | |
331 for (uint32 i = 0; i < results_->NumberOfResults; i++) { | |
332 crypto::CSSMFree(encCert[i].CertBlob.Data); | |
333 } | |
334 } | |
335 crypto::CSSMFree(results_->Results); | |
336 crypto::CSSMFree(results_); | |
337 } | |
338 | |
339 private: | |
340 CSSM_TP_RESULT_SET* results_; | |
341 }; | |
342 | |
343 } // namespace | |
344 | |
345 void X509Certificate::Initialize() { | |
346 x509_util::CSSMCachedCertificate cached_cert; | |
347 if (cached_cert.Init(cert_handle_) == CSSM_OK) { | |
348 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd, | |
349 &subject_); | |
350 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd, | |
351 &issuer_); | |
352 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore, | |
353 &valid_start_); | |
354 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter, | |
355 &valid_expiry_); | |
356 serial_number_ = GetCertSerialNumber(cached_cert); | |
357 } | |
358 | |
359 fingerprint_ = CalculateFingerprint(cert_handle_); | |
360 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | |
361 } | |
362 | |
363 bool X509Certificate::IsIssuedByEncoded( | |
364 const std::vector<std::string>& valid_issuers) { | |
365 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers)) | |
366 return true; | |
367 | |
368 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); | |
369 it != intermediate_ca_certs_.end(); ++it) { | |
370 if (IsCertIssuerInEncodedList(*it, valid_issuers)) | |
371 return true; | |
372 } | |
373 return false; | |
374 } | |
375 | |
376 // static | |
377 X509Certificate* X509Certificate::CreateSelfSigned( | |
378 crypto::RSAPrivateKey* key, | |
379 const std::string& subject, | |
380 uint32 serial_number, | |
381 base::TimeDelta valid_duration) { | |
382 DCHECK(key); | |
383 DCHECK(!subject.empty()); | |
384 | |
385 if (valid_duration.InSeconds() > kuint32max) { | |
386 LOG(ERROR) << "valid_duration too big " << valid_duration.InSeconds(); | |
387 valid_duration = base::TimeDelta::FromSeconds(kuint32max); | |
388 } | |
389 | |
390 // There is a comment in | |
391 // http://www.opensource.apple.com/source/security_certtool/security_certtool-
31828/src/CertTool.cpp | |
392 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have | |
393 // their high bit set. We will continue though and mask it out below. | |
394 if (serial_number & 0x80000000) | |
395 LOG(ERROR) << "serial_number has high bit set " << serial_number; | |
396 | |
397 // NSS is used to parse the subject string into a set of | |
398 // CSSM_OID/string pairs. There doesn't appear to be a system routine for | |
399 // parsing Distinguished Name strings. | |
400 crypto::EnsureNSSInit(); | |
401 | |
402 CSSMOIDStringVector subject_name_oids; | |
403 ScopedCertName subject_name( | |
404 CERT_AsciiToName(const_cast<char*>(subject.c_str()))); | |
405 if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) { | |
406 DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject; | |
407 return NULL; | |
408 } | |
409 | |
410 // Convert the map of oid/string pairs into an array of | |
411 // CSSM_APPLE_TP_NAME_OIDs. | |
412 std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names; | |
413 for (CSSMOIDStringVector::iterator iter = subject_name_oids.begin(); | |
414 iter != subject_name_oids.end(); ++iter) { | |
415 CSSM_APPLE_TP_NAME_OID cssm_subject_name; | |
416 cssm_subject_name.oid = iter->oid_; | |
417 cssm_subject_name.string = iter->string_.c_str(); | |
418 cssm_subject_names.push_back(cssm_subject_name); | |
419 } | |
420 | |
421 if (cssm_subject_names.empty()) { | |
422 DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject; | |
423 return NULL; | |
424 } | |
425 | |
426 // Set up a certificate request. | |
427 CSSM_APPLE_TP_CERT_REQUEST certReq; | |
428 memset(&certReq, 0, sizeof(certReq)); | |
429 certReq.cspHand = crypto::GetSharedCSPHandle(); | |
430 certReq.clHand = crypto::GetSharedCLHandle(); | |
431 // See comment about serial numbers above. | |
432 certReq.serialNumber = serial_number & 0x7fffffff; | |
433 certReq.numSubjectNames = cssm_subject_names.size(); | |
434 certReq.subjectNames = &cssm_subject_names[0]; | |
435 certReq.numIssuerNames = 0; // Root. | |
436 certReq.issuerNames = NULL; | |
437 certReq.issuerNameX509 = NULL; | |
438 certReq.certPublicKey = key->public_key(); | |
439 certReq.issuerPrivateKey = key->key(); | |
440 // These are the Apple defaults. | |
441 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; | |
442 certReq.signatureOid = CSSMOID_SHA1WithRSA; | |
443 certReq.notBefore = 0; | |
444 certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds()); | |
445 certReq.numExtensions = 0; | |
446 certReq.extensions = NULL; | |
447 certReq.challengeString = NULL; | |
448 | |
449 CSSM_TP_REQUEST_SET reqSet; | |
450 reqSet.NumberOfRequests = 1; | |
451 reqSet.Requests = &certReq; | |
452 | |
453 CSSM_FIELD policyId; | |
454 memset(&policyId, 0, sizeof(policyId)); | |
455 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; | |
456 | |
457 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext; | |
458 memset(&callerAuthContext, 0, sizeof(callerAuthContext)); | |
459 callerAuthContext.Policy.NumberOfPolicyIds = 1; | |
460 callerAuthContext.Policy.PolicyIds = &policyId; | |
461 | |
462 CSSM_TP_HANDLE tp_handle = crypto::GetSharedTPHandle(); | |
463 CSSM_DATA refId; | |
464 memset(&refId, 0, sizeof(refId)); | |
465 sint32 estTime; | |
466 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL, | |
467 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext, | |
468 &estTime, &refId); | |
469 if (crtn) { | |
470 DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn; | |
471 return NULL; | |
472 } | |
473 | |
474 CSSM_BOOL confirmRequired; | |
475 CSSM_TP_RESULT_SET* resultSet = NULL; | |
476 crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime, | |
477 &confirmRequired, &resultSet); | |
478 ScopedEncodedCertResults scopedResults(resultSet); | |
479 crypto::CSSMFree(refId.Data); | |
480 if (crtn) { | |
481 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn; | |
482 return NULL; | |
483 } | |
484 | |
485 if (confirmRequired) { | |
486 // Potential leak here of resultSet. |confirmRequired| should never be | |
487 // true. | |
488 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation"; | |
489 return NULL; | |
490 } | |
491 | |
492 if (resultSet->NumberOfResults != 1) { | |
493 DLOG(ERROR) << "Unexpected number of results: " | |
494 << resultSet->NumberOfResults; | |
495 return NULL; | |
496 } | |
497 | |
498 CSSM_ENCODED_CERT* encCert = | |
499 reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results); | |
500 ScopedCFTypeRef<SecCertificateRef> scoped_cert; | |
501 SecCertificateRef certificate_ref = NULL; | |
502 OSStatus os_status = | |
503 SecCertificateCreateFromData(&encCert->CertBlob, encCert->CertType, | |
504 encCert->CertEncoding, &certificate_ref); | |
505 if (os_status != 0) { | |
506 OSSTATUS_DLOG(ERROR, os_status) << "SecCertificateCreateFromData failed"; | |
507 return NULL; | |
508 } | |
509 scoped_cert.reset(certificate_ref); | |
510 | |
511 return CreateFromHandle(scoped_cert, X509Certificate::OSCertHandles()); | |
512 } | |
513 | |
514 void X509Certificate::GetSubjectAltName( | |
515 std::vector<std::string>* dns_names, | |
516 std::vector<std::string>* ip_addrs) const { | |
517 if (dns_names) | |
518 dns_names->clear(); | |
519 if (ip_addrs) | |
520 ip_addrs->clear(); | |
521 | |
522 x509_util::CSSMCachedCertificate cached_cert; | |
523 OSStatus status = cached_cert.Init(cert_handle_); | |
524 if (status) | |
525 return; | |
526 x509_util::CSSMFieldValue subject_alt_name; | |
527 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name); | |
528 if (status || !subject_alt_name.field()) | |
529 return; | |
530 const CSSM_X509_EXTENSION* cssm_ext = | |
531 subject_alt_name.GetAs<CSSM_X509_EXTENSION>(); | |
532 if (!cssm_ext || !cssm_ext->value.parsedValue) | |
533 return; | |
534 const CE_GeneralNames* alt_name = | |
535 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue); | |
536 | |
537 for (size_t name = 0; name < alt_name->numNames; ++name) { | |
538 const CE_GeneralName& name_struct = alt_name->generalName[name]; | |
539 const CSSM_DATA& name_data = name_struct.name; | |
540 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs | |
541 // respectively, both of which can be byte copied from | |
542 // CSSM_DATA::data into the appropriate output vector. | |
543 if (dns_names && name_struct.nameType == GNT_DNSName) { | |
544 dns_names->push_back(std::string( | |
545 reinterpret_cast<const char*>(name_data.Data), | |
546 name_data.Length)); | |
547 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { | |
548 ip_addrs->push_back(std::string( | |
549 reinterpret_cast<const char*>(name_data.Data), | |
550 name_data.Length)); | |
551 } | |
552 } | |
553 } | |
554 | |
555 // static | |
556 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | |
557 std::string* encoded) { | |
558 CSSM_DATA der_data; | |
559 if (SecCertificateGetData(cert_handle, &der_data) != noErr) | |
560 return false; | |
561 encoded->assign(reinterpret_cast<char*>(der_data.Data), | |
562 der_data.Length); | |
563 return true; | |
564 } | |
565 | |
566 // static | |
567 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | |
568 X509Certificate::OSCertHandle b) { | |
569 DCHECK(a && b); | |
570 if (a == b) | |
571 return true; | |
572 if (CFEqual(a, b)) | |
573 return true; | |
574 CSSM_DATA a_data, b_data; | |
575 return SecCertificateGetData(a, &a_data) == noErr && | |
576 SecCertificateGetData(b, &b_data) == noErr && | |
577 a_data.Length == b_data.Length && | |
578 memcmp(a_data.Data, b_data.Data, a_data.Length) == 0; | |
579 } | |
580 | |
581 // static | |
582 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | |
583 const char* data, int length) { | |
584 CSSM_DATA cert_data; | |
585 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); | |
586 cert_data.Length = length; | |
587 | |
588 OSCertHandle cert_handle = NULL; | |
589 OSStatus status = SecCertificateCreateFromData(&cert_data, | |
590 CSSM_CERT_X_509v3, | |
591 CSSM_CERT_ENCODING_DER, | |
592 &cert_handle); | |
593 if (status != noErr) | |
594 return NULL; | |
595 if (!IsValidOSCertHandle(cert_handle)) { | |
596 CFRelease(cert_handle); | |
597 return NULL; | |
598 } | |
599 return cert_handle; | |
600 } | |
601 | |
602 // static | |
603 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | |
604 const char* data, int length, Format format) { | |
605 OSCertHandles results; | |
606 | |
607 switch (format) { | |
608 case FORMAT_SINGLE_CERTIFICATE: { | |
609 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); | |
610 if (handle) | |
611 results.push_back(handle); | |
612 break; | |
613 } | |
614 case FORMAT_PKCS7: | |
615 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results); | |
616 break; | |
617 default: | |
618 NOTREACHED() << "Certificate format " << format << " unimplemented"; | |
619 break; | |
620 } | |
621 | |
622 return results; | |
623 } | |
624 | |
625 // static | |
626 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | |
627 OSCertHandle handle) { | |
628 if (!handle) | |
629 return NULL; | |
630 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); | |
631 } | |
632 | |
633 // static | |
634 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | |
635 CFRelease(cert_handle); | |
636 } | |
637 | |
638 // static | |
639 SHA1HashValue X509Certificate::CalculateFingerprint( | |
640 OSCertHandle cert) { | |
641 SHA1HashValue sha1; | |
642 memset(sha1.data, 0, sizeof(sha1.data)); | |
643 | |
644 CSSM_DATA cert_data; | |
645 OSStatus status = SecCertificateGetData(cert, &cert_data); | |
646 if (status) | |
647 return sha1; | |
648 | |
649 DCHECK(cert_data.Data); | |
650 DCHECK_NE(cert_data.Length, 0U); | |
651 | |
652 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | |
653 | |
654 return sha1; | |
655 } | |
656 | |
657 // static | |
658 SHA1HashValue X509Certificate::CalculateCAFingerprint( | |
659 const OSCertHandles& intermediates) { | |
660 SHA1HashValue sha1; | |
661 memset(sha1.data, 0, sizeof(sha1.data)); | |
662 | |
663 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so | |
664 // we don't check their return values. | |
665 CC_SHA1_CTX sha1_ctx; | |
666 CC_SHA1_Init(&sha1_ctx); | |
667 CSSM_DATA cert_data; | |
668 for (size_t i = 0; i < intermediates.size(); ++i) { | |
669 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data); | |
670 if (status) | |
671 return sha1; | |
672 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); | |
673 } | |
674 CC_SHA1_Final(sha1.data, &sha1_ctx); | |
675 | |
676 return sha1; | |
677 } | |
678 | |
679 bool X509Certificate::SupportsSSLClientAuth() const { | |
680 x509_util::CSSMCachedCertificate cached_cert; | |
681 OSStatus status = cached_cert.Init(cert_handle_); | |
682 if (status) | |
683 return false; | |
684 | |
685 // RFC5280 says to take the intersection of the two extensions. | |
686 // | |
687 // Our underlying crypto libraries don't expose | |
688 // ClientCertificateType, so for now we will not support fixed | |
689 // Diffie-Hellman mechanisms. For rsa_sign, we need the | |
690 // digitalSignature bit. | |
691 // | |
692 // In particular, if a key has the nonRepudiation bit and not the | |
693 // digitalSignature one, we will not offer it to the user. | |
694 x509_util::CSSMFieldValue key_usage; | |
695 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); | |
696 if (status == CSSM_OK && key_usage.field()) { | |
697 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
698 const CE_KeyUsage* key_usage_value = | |
699 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); | |
700 if (!((*key_usage_value) & CE_KU_DigitalSignature)) | |
701 return false; | |
702 } | |
703 | |
704 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); | |
705 if (status == CSSM_OK && key_usage.field()) { | |
706 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
707 const CE_ExtendedKeyUsage* ext_key_usage = | |
708 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
709 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) | |
710 return false; | |
711 } | |
712 return true; | |
713 } | |
714 | |
715 CFArrayRef X509Certificate::CreateClientCertificateChain() const { | |
716 // Initialize the result array with just the IdentityRef of the receiver: | |
717 SecIdentityRef identity; | |
718 OSStatus result; | |
719 { | |
720 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
721 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | |
722 } | |
723 if (result) { | |
724 OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; | |
725 return NULL; | |
726 } | |
727 ScopedCFTypeRef<CFMutableArrayRef> chain( | |
728 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | |
729 CFArrayAppendValue(chain, identity); | |
730 | |
731 CFArrayRef cert_chain = NULL; | |
732 result = CopyCertChain(cert_handle_, &cert_chain); | |
733 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); | |
734 if (result) { | |
735 OSSTATUS_LOG(ERROR, result) << "CreateIdentityCertificateChain error"; | |
736 return chain.release(); | |
737 } | |
738 | |
739 // Append the intermediate certs from SecTrust to the result array: | |
740 if (cert_chain) { | |
741 int chain_count = CFArrayGetCount(cert_chain); | |
742 if (chain_count > 1) { | |
743 CFArrayAppendArray(chain, | |
744 cert_chain, | |
745 CFRangeMake(1, chain_count - 1)); | |
746 } | |
747 } | |
748 | |
749 return chain.release(); | |
750 } | |
751 | |
752 CFArrayRef X509Certificate::CreateOSCertChainForCert() const { | |
753 CFMutableArrayRef cert_list = | |
754 CFArrayCreateMutable(kCFAllocatorDefault, 0, | |
755 &kCFTypeArrayCallBacks); | |
756 if (!cert_list) | |
757 return NULL; | |
758 | |
759 CFArrayAppendValue(cert_list, os_cert_handle()); | |
760 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | |
761 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); | |
762 | |
763 return cert_list; | |
764 } | |
765 | |
766 // static | |
767 X509Certificate::OSCertHandle | |
768 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { | |
769 const char* data; | |
770 int length; | |
771 if (!pickle_iter->ReadData(&data, &length)) | |
772 return NULL; | |
773 | |
774 return CreateOSCertHandleFromBytes(data, length); | |
775 } | |
776 | |
777 // static | |
778 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
779 Pickle* pickle) { | |
780 CSSM_DATA cert_data; | |
781 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); | |
782 if (status) | |
783 return false; | |
784 | |
785 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), | |
786 cert_data.Length); | |
787 } | |
788 | |
789 // static | |
790 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
791 size_t* size_bits, | |
792 PublicKeyType* type) { | |
793 // Since we might fail, set the output parameters to default values first. | |
794 *type = kPublicKeyTypeUnknown; | |
795 *size_bits = 0; | |
796 | |
797 SecKeyRef key; | |
798 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key); | |
799 if (status) { | |
800 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status; | |
801 return; | |
802 } | |
803 ScopedCFTypeRef<SecKeyRef> scoped_key(key); | |
804 | |
805 const CSSM_KEY* cssm_key; | |
806 status = SecKeyGetCSSMKey(key, &cssm_key); | |
807 if (status) { | |
808 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status; | |
809 return; | |
810 } | |
811 | |
812 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits; | |
813 | |
814 switch (cssm_key->KeyHeader.AlgorithmId) { | |
815 case CSSM_ALGID_RSA: | |
816 *type = kPublicKeyTypeRSA; | |
817 break; | |
818 case CSSM_ALGID_DSA: | |
819 *type = kPublicKeyTypeDSA; | |
820 break; | |
821 case CSSM_ALGID_ECDSA: | |
822 *type = kPublicKeyTypeECDSA; | |
823 break; | |
824 case CSSM_ALGID_DH: | |
825 *type = kPublicKeyTypeDH; | |
826 break; | |
827 default: | |
828 *type = kPublicKeyTypeUnknown; | |
829 *size_bits = 0; | |
830 break; | |
831 } | |
832 } | |
833 | |
834 } // namespace net | |
OLD | NEW |