Add signalSyncPoint to the WebGraphicsContext3D command buffer impls.
[chromium-blink-merge.git] / net / cert / x509_certificate_mac.cc
blob6c3df6f5f3d9368b634cb808b0cfeb0279cf7caa
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.
5 #include "net/cert/x509_certificate.h"
7 #include <CommonCrypto/CommonDigest.h>
8 #include <CoreServices/CoreServices.h>
9 #include <Security/Security.h>
11 #include <cert.h>
13 #include <vector>
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/mac/mac_logging.h"
18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/memory/singleton.h"
20 #include "base/pickle.h"
21 #include "base/sha1.h"
22 #include "base/strings/string_piece.h"
23 #include "base/strings/sys_string_conversions.h"
24 #include "base/synchronization/lock.h"
25 #include "crypto/cssm_init.h"
26 #include "crypto/mac_security_services_lock.h"
27 #include "crypto/nss_util.h"
28 #include "crypto/rsa_private_key.h"
29 #include "net/cert/x509_util_mac.h"
31 using base::mac::ScopedCFTypeRef;
32 using base::Time;
34 namespace net {
36 namespace {
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);
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;
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;
62 base::StringPiece name_piece(
63 reinterpret_cast<const char*>(distinguished_name.field()->Data),
64 static_cast<size_t>(distinguished_name.field()->Length));
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;
73 return false;
76 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
77 const CSSM_OID* oid,
78 Time* result) {
79 *result = Time::Time();
81 x509_util::CSSMFieldValue field;
82 OSStatus status = cached_cert.GetField(oid, &field);
83 if (status)
84 return;
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;
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;
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();
111 return std::string(
112 reinterpret_cast<const char*>(serial_number.field()->Data),
113 serial_number.field()->Length);
116 // Returns true if |purpose| is listed as allowed in |usage|. This
117 // function also considers the "Any" purpose. If the attribute is
118 // present and empty, we return false.
119 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage,
120 const CSSM_OID* purpose) {
121 for (unsigned p = 0; p < usage->numPurposes; ++p) {
122 if (CSSMOIDEqual(&usage->purposes[p], purpose))
123 return true;
124 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
125 return true;
127 return false;
130 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
131 // return true if it is.
133 // On OS X, SecCertificateCreateFromData() does not return any errors if
134 // called with invalid data, as long as data is present. The actual decoding
135 // of the certificate does not happen until an API that requires a CSSM
136 // handle is called. While SecCertificateGetCLHandle is the most likely
137 // candidate, as it performs the parsing, it does not check whether the
138 // parsing was actually successful. Instead, SecCertificateGetSubject is
139 // used (supported since 10.3), as a means to check that the certificate
140 // parsed as a valid X.509 certificate.
141 bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
142 const CSSM_X509_NAME* sanity_check = NULL;
143 OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check);
144 return status == noErr && sanity_check;
147 // Parses |data| of length |length|, attempting to decode it as the specified
148 // |format|. If |data| is in the specified format, any certificates contained
149 // within are stored into |output|.
150 void AddCertificatesFromBytes(const char* data, size_t length,
151 SecExternalFormat format,
152 X509Certificate::OSCertHandles* output) {
153 SecExternalFormat input_format = format;
154 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
155 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
156 kCFAllocatorNull));
158 CFArrayRef items = NULL;
159 OSStatus status;
161 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
162 status = SecKeychainItemImport(local_data, NULL, &input_format,
163 NULL, 0, NULL, NULL, &items);
166 if (status) {
167 OSSTATUS_DLOG(WARNING, status)
168 << "Unable to import items from data of length " << length;
169 return;
172 ScopedCFTypeRef<CFArrayRef> scoped_items(items);
173 CFTypeID cert_type_id = SecCertificateGetTypeID();
175 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
176 SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
177 const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
179 // While inputFormat implies only certificates will be imported, if/when
180 // other formats (eg: PKCS#12) are supported, this may also include
181 // private keys or other items types, so filter appropriately.
182 if (CFGetTypeID(item) == cert_type_id) {
183 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item);
184 // OS X ignores |input_format| if it detects that |local_data| is PEM
185 // encoded, attempting to decode data based on internal rules for PEM
186 // block headers. If a PKCS#7 blob is encoded with a PEM block of
187 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
188 // based on the decoded data. If this happens, the certificate should
189 // not be included in |output|. Because |output| is empty,
190 // CreateCertificateListfromBytes will use PEMTokenizer to decode the
191 // data. When called again with the decoded data, OS X will honor
192 // |input_format|, causing decode to succeed. On OS X 10.6, the data
193 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
194 // the need to fallback to internal decoding.
195 if (IsValidOSCertHandle(cert)) {
196 CFRetain(cert);
197 output->push_back(cert);
203 struct CSSMOIDString {
204 const CSSM_OID* oid_;
205 std::string string_;
208 typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
210 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) {
211 struct OIDCSSMMap {
212 SECOidTag sec_OID_;
213 const CSSM_OID* cssm_OID_;
216 const OIDCSSMMap kOIDs[] = {
217 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName },
218 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName },
219 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName },
220 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName },
221 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress },
222 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName },
223 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName },
224 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier },
225 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier },
226 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress },
229 CERTRDN** rdns = name->rdns;
230 for (size_t rdn = 0; rdns[rdn]; ++rdn) {
231 CERTAVA** avas = rdns[rdn]->avas;
232 for (size_t pair = 0; avas[pair] != 0; ++pair) {
233 SECOidTag tag = CERT_GetAVATag(avas[pair]);
234 if (tag == SEC_OID_UNKNOWN) {
235 return false;
237 CSSMOIDString oidString;
238 bool found_oid = false;
239 for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) {
240 if (kOIDs[oid].sec_OID_ == tag) {
241 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
242 if (!decode_item)
243 return false;
245 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
246 std::string value(reinterpret_cast<char*>(decode_item->data),
247 decode_item->len);
248 oidString.oid_ = kOIDs[oid].cssm_OID_;
249 oidString.string_ = value;
250 out_values->push_back(oidString);
251 SECITEM_FreeItem(decode_item, PR_TRUE);
252 found_oid = true;
253 break;
256 if (!found_oid) {
257 DLOG(ERROR) << "Unrecognized OID: " << tag;
261 return true;
264 class ScopedCertName {
265 public:
266 explicit ScopedCertName(CERTName* name) : name_(name) { }
267 ~ScopedCertName() {
268 if (name_) CERT_DestroyName(name_);
270 operator CERTName*() { return name_; }
272 private:
273 CERTName* name_;
276 class ScopedEncodedCertResults {
277 public:
278 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
279 : results_(results) { }
280 ~ScopedEncodedCertResults() {
281 if (results_) {
282 CSSM_ENCODED_CERT* encCert =
283 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
284 for (uint32 i = 0; i < results_->NumberOfResults; i++) {
285 crypto::CSSMFree(encCert[i].CertBlob.Data);
288 crypto::CSSMFree(results_->Results);
289 crypto::CSSMFree(results_);
292 private:
293 CSSM_TP_RESULT_SET* results_;
296 } // namespace
298 void X509Certificate::Initialize() {
299 x509_util::CSSMCachedCertificate cached_cert;
300 if (cached_cert.Init(cert_handle_) == CSSM_OK) {
301 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
302 &subject_);
303 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
304 &issuer_);
305 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
306 &valid_start_);
307 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
308 &valid_expiry_);
309 serial_number_ = GetCertSerialNumber(cached_cert);
312 fingerprint_ = CalculateFingerprint(cert_handle_);
313 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
316 bool X509Certificate::IsIssuedByEncoded(
317 const std::vector<std::string>& valid_issuers) {
318 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
319 return true;
321 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
322 it != intermediate_ca_certs_.end(); ++it) {
323 if (IsCertIssuerInEncodedList(*it, valid_issuers))
324 return true;
326 return false;
329 // static
330 X509Certificate* X509Certificate::CreateSelfSigned(
331 crypto::RSAPrivateKey* key,
332 const std::string& subject,
333 uint32 serial_number,
334 base::TimeDelta valid_duration) {
335 DCHECK(key);
336 DCHECK(!subject.empty());
338 if (valid_duration.InSeconds() > kuint32max) {
339 LOG(ERROR) << "valid_duration too big " << valid_duration.InSeconds();
340 valid_duration = base::TimeDelta::FromSeconds(kuint32max);
343 // There is a comment in
344 // http://www.opensource.apple.com/source/security_certtool/security_certtool-31828/src/CertTool.cpp
345 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have
346 // their high bit set. We will continue though and mask it out below.
347 if (serial_number & 0x80000000)
348 LOG(ERROR) << "serial_number has high bit set " << serial_number;
350 // NSS is used to parse the subject string into a set of
351 // CSSM_OID/string pairs. There doesn't appear to be a system routine for
352 // parsing Distinguished Name strings.
353 crypto::EnsureNSSInit();
355 CSSMOIDStringVector subject_name_oids;
356 ScopedCertName subject_name(
357 CERT_AsciiToName(const_cast<char*>(subject.c_str())));
358 if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) {
359 DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject;
360 return NULL;
363 // Convert the map of oid/string pairs into an array of
364 // CSSM_APPLE_TP_NAME_OIDs.
365 std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names;
366 for (CSSMOIDStringVector::iterator iter = subject_name_oids.begin();
367 iter != subject_name_oids.end(); ++iter) {
368 CSSM_APPLE_TP_NAME_OID cssm_subject_name;
369 cssm_subject_name.oid = iter->oid_;
370 cssm_subject_name.string = iter->string_.c_str();
371 cssm_subject_names.push_back(cssm_subject_name);
374 if (cssm_subject_names.empty()) {
375 DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject;
376 return NULL;
379 // Set up a certificate request.
380 CSSM_APPLE_TP_CERT_REQUEST certReq;
381 memset(&certReq, 0, sizeof(certReq));
382 certReq.cspHand = crypto::GetSharedCSPHandle();
383 certReq.clHand = crypto::GetSharedCLHandle();
384 // See comment about serial numbers above.
385 certReq.serialNumber = serial_number & 0x7fffffff;
386 certReq.numSubjectNames = cssm_subject_names.size();
387 certReq.subjectNames = &cssm_subject_names[0];
388 certReq.numIssuerNames = 0; // Root.
389 certReq.issuerNames = NULL;
390 certReq.issuerNameX509 = NULL;
391 certReq.certPublicKey = key->public_key();
392 certReq.issuerPrivateKey = key->key();
393 // These are the Apple defaults.
394 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
395 certReq.signatureOid = CSSMOID_SHA1WithRSA;
396 certReq.notBefore = 0;
397 certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds());
398 certReq.numExtensions = 0;
399 certReq.extensions = NULL;
400 certReq.challengeString = NULL;
402 CSSM_TP_REQUEST_SET reqSet;
403 reqSet.NumberOfRequests = 1;
404 reqSet.Requests = &certReq;
406 CSSM_FIELD policyId;
407 memset(&policyId, 0, sizeof(policyId));
408 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
410 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext;
411 memset(&callerAuthContext, 0, sizeof(callerAuthContext));
412 callerAuthContext.Policy.NumberOfPolicyIds = 1;
413 callerAuthContext.Policy.PolicyIds = &policyId;
415 CSSM_TP_HANDLE tp_handle = crypto::GetSharedTPHandle();
416 CSSM_DATA refId;
417 memset(&refId, 0, sizeof(refId));
418 sint32 estTime;
419 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL,
420 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext,
421 &estTime, &refId);
422 if (crtn) {
423 DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn;
424 return NULL;
427 CSSM_BOOL confirmRequired;
428 CSSM_TP_RESULT_SET* resultSet = NULL;
429 crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime,
430 &confirmRequired, &resultSet);
431 ScopedEncodedCertResults scopedResults(resultSet);
432 crypto::CSSMFree(refId.Data);
433 if (crtn) {
434 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn;
435 return NULL;
438 if (confirmRequired) {
439 // Potential leak here of resultSet. |confirmRequired| should never be
440 // true.
441 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation";
442 return NULL;
445 if (resultSet->NumberOfResults != 1) {
446 DLOG(ERROR) << "Unexpected number of results: "
447 << resultSet->NumberOfResults;
448 return NULL;
451 CSSM_ENCODED_CERT* encCert =
452 reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results);
453 ScopedCFTypeRef<SecCertificateRef> scoped_cert;
454 SecCertificateRef certificate_ref = NULL;
455 OSStatus os_status =
456 SecCertificateCreateFromData(&encCert->CertBlob, encCert->CertType,
457 encCert->CertEncoding, &certificate_ref);
458 if (os_status != 0) {
459 OSSTATUS_DLOG(ERROR, os_status) << "SecCertificateCreateFromData failed";
460 return NULL;
462 scoped_cert.reset(certificate_ref);
464 return CreateFromHandle(scoped_cert, X509Certificate::OSCertHandles());
467 void X509Certificate::GetSubjectAltName(
468 std::vector<std::string>* dns_names,
469 std::vector<std::string>* ip_addrs) const {
470 if (dns_names)
471 dns_names->clear();
472 if (ip_addrs)
473 ip_addrs->clear();
475 x509_util::CSSMCachedCertificate cached_cert;
476 OSStatus status = cached_cert.Init(cert_handle_);
477 if (status)
478 return;
479 x509_util::CSSMFieldValue subject_alt_name;
480 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
481 if (status || !subject_alt_name.field())
482 return;
483 const CSSM_X509_EXTENSION* cssm_ext =
484 subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
485 if (!cssm_ext || !cssm_ext->value.parsedValue)
486 return;
487 const CE_GeneralNames* alt_name =
488 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
490 for (size_t name = 0; name < alt_name->numNames; ++name) {
491 const CE_GeneralName& name_struct = alt_name->generalName[name];
492 const CSSM_DATA& name_data = name_struct.name;
493 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
494 // respectively, both of which can be byte copied from
495 // CSSM_DATA::data into the appropriate output vector.
496 if (dns_names && name_struct.nameType == GNT_DNSName) {
497 dns_names->push_back(std::string(
498 reinterpret_cast<const char*>(name_data.Data),
499 name_data.Length));
500 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
501 ip_addrs->push_back(std::string(
502 reinterpret_cast<const char*>(name_data.Data),
503 name_data.Length));
508 // static
509 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
510 std::string* encoded) {
511 CSSM_DATA der_data;
512 if (SecCertificateGetData(cert_handle, &der_data) != noErr)
513 return false;
514 encoded->assign(reinterpret_cast<char*>(der_data.Data),
515 der_data.Length);
516 return true;
519 // static
520 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
521 X509Certificate::OSCertHandle b) {
522 DCHECK(a && b);
523 if (a == b)
524 return true;
525 if (CFEqual(a, b))
526 return true;
527 CSSM_DATA a_data, b_data;
528 return SecCertificateGetData(a, &a_data) == noErr &&
529 SecCertificateGetData(b, &b_data) == noErr &&
530 a_data.Length == b_data.Length &&
531 memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
534 // static
535 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
536 const char* data, int length) {
537 CSSM_DATA cert_data;
538 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
539 cert_data.Length = length;
541 OSCertHandle cert_handle = NULL;
542 OSStatus status = SecCertificateCreateFromData(&cert_data,
543 CSSM_CERT_X_509v3,
544 CSSM_CERT_ENCODING_DER,
545 &cert_handle);
546 if (status != noErr)
547 return NULL;
548 if (!IsValidOSCertHandle(cert_handle)) {
549 CFRelease(cert_handle);
550 return NULL;
552 return cert_handle;
555 // static
556 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
557 const char* data, int length, Format format) {
558 OSCertHandles results;
560 switch (format) {
561 case FORMAT_SINGLE_CERTIFICATE: {
562 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
563 if (handle)
564 results.push_back(handle);
565 break;
567 case FORMAT_PKCS7:
568 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
569 break;
570 default:
571 NOTREACHED() << "Certificate format " << format << " unimplemented";
572 break;
575 return results;
578 // static
579 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
580 OSCertHandle handle) {
581 if (!handle)
582 return NULL;
583 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
586 // static
587 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
588 CFRelease(cert_handle);
591 // static
592 SHA1HashValue X509Certificate::CalculateFingerprint(
593 OSCertHandle cert) {
594 SHA1HashValue sha1;
595 memset(sha1.data, 0, sizeof(sha1.data));
597 CSSM_DATA cert_data;
598 OSStatus status = SecCertificateGetData(cert, &cert_data);
599 if (status)
600 return sha1;
602 DCHECK(cert_data.Data);
603 DCHECK_NE(cert_data.Length, 0U);
605 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
607 return sha1;
610 // static
611 SHA1HashValue X509Certificate::CalculateCAFingerprint(
612 const OSCertHandles& intermediates) {
613 SHA1HashValue sha1;
614 memset(sha1.data, 0, sizeof(sha1.data));
616 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
617 // we don't check their return values.
618 CC_SHA1_CTX sha1_ctx;
619 CC_SHA1_Init(&sha1_ctx);
620 CSSM_DATA cert_data;
621 for (size_t i = 0; i < intermediates.size(); ++i) {
622 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
623 if (status)
624 return sha1;
625 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
627 CC_SHA1_Final(sha1.data, &sha1_ctx);
629 return sha1;
632 bool X509Certificate::SupportsSSLClientAuth() const {
633 x509_util::CSSMCachedCertificate cached_cert;
634 OSStatus status = cached_cert.Init(cert_handle_);
635 if (status)
636 return false;
638 // RFC5280 says to take the intersection of the two extensions.
640 // Our underlying crypto libraries don't expose
641 // ClientCertificateType, so for now we will not support fixed
642 // Diffie-Hellman mechanisms. For rsa_sign, we need the
643 // digitalSignature bit.
645 // In particular, if a key has the nonRepudiation bit and not the
646 // digitalSignature one, we will not offer it to the user.
647 x509_util::CSSMFieldValue key_usage;
648 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
649 if (status == CSSM_OK && key_usage.field()) {
650 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
651 const CE_KeyUsage* key_usage_value =
652 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
653 if (!((*key_usage_value) & CE_KU_DigitalSignature))
654 return false;
657 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
658 if (status == CSSM_OK && key_usage.field()) {
659 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
660 const CE_ExtendedKeyUsage* ext_key_usage =
661 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
662 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
663 return false;
665 return true;
668 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
669 CFMutableArrayRef cert_list =
670 CFArrayCreateMutable(kCFAllocatorDefault, 0,
671 &kCFTypeArrayCallBacks);
672 if (!cert_list)
673 return NULL;
675 CFArrayAppendValue(cert_list, os_cert_handle());
676 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
677 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
679 return cert_list;
682 // static
683 X509Certificate::OSCertHandle
684 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
685 const char* data;
686 int length;
687 if (!pickle_iter->ReadData(&data, &length))
688 return NULL;
690 return CreateOSCertHandleFromBytes(data, length);
693 // static
694 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
695 Pickle* pickle) {
696 CSSM_DATA cert_data;
697 OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
698 if (status)
699 return false;
701 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
702 cert_data.Length);
705 // static
706 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
707 size_t* size_bits,
708 PublicKeyType* type) {
709 // Since we might fail, set the output parameters to default values first.
710 *type = kPublicKeyTypeUnknown;
711 *size_bits = 0;
713 SecKeyRef key;
714 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
715 if (status) {
716 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
717 return;
719 ScopedCFTypeRef<SecKeyRef> scoped_key(key);
721 const CSSM_KEY* cssm_key;
722 status = SecKeyGetCSSMKey(key, &cssm_key);
723 if (status) {
724 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
725 return;
728 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
730 switch (cssm_key->KeyHeader.AlgorithmId) {
731 case CSSM_ALGID_RSA:
732 *type = kPublicKeyTypeRSA;
733 break;
734 case CSSM_ALGID_DSA:
735 *type = kPublicKeyTypeDSA;
736 break;
737 case CSSM_ALGID_ECDSA:
738 *type = kPublicKeyTypeECDSA;
739 break;
740 case CSSM_ALGID_DH:
741 *type = kPublicKeyTypeDH;
742 break;
743 default:
744 *type = kPublicKeyTypeUnknown;
745 *size_bits = 0;
746 break;
750 } // namespace net