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

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

Issue 13006020: net: extract net/cert out of net/base (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 8 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 | « net/base/x509_certificate_known_roots_win.h ('k') | net/base/x509_certificate_net_log_param.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « net/base/x509_certificate_known_roots_win.h ('k') | net/base/x509_certificate_net_log_param.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698