Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / cert / x509_certificate_mac.cc
blob2f8ce438afd3c8213ba3063f513be54b71596a38
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 "net/cert/x509_util_mac.h"
30 using base::ScopedCFTypeRef;
31 using base::Time;
33 namespace net {
35 namespace {
37 void GetCertDistinguishedName(
38 const x509_util::CSSMCachedCertificate& cached_cert,
39 const CSSM_OID* oid,
40 CertPrincipal* result) {
41 x509_util::CSSMFieldValue distinguished_name;
42 OSStatus status = cached_cert.GetField(oid, &distinguished_name);
43 if (status || !distinguished_name.field())
44 return;
45 result->ParseDistinguishedName(distinguished_name.field()->Data,
46 distinguished_name.field()->Length);
49 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle,
50 const std::vector<std::string>& issuers) {
51 x509_util::CSSMCachedCertificate cached_cert;
52 if (cached_cert.Init(cert_handle) != CSSM_OK)
53 return false;
55 x509_util::CSSMFieldValue distinguished_name;
56 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd,
57 &distinguished_name);
58 if (status || !distinguished_name.field())
59 return false;
61 base::StringPiece name_piece(
62 reinterpret_cast<const char*>(distinguished_name.field()->Data),
63 static_cast<size_t>(distinguished_name.field()->Length));
65 for (std::vector<std::string>::const_iterator it = issuers.begin();
66 it != issuers.end(); ++it) {
67 base::StringPiece issuer_piece(*it);
68 if (name_piece == issuer_piece)
69 return true;
72 return false;
75 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
76 const CSSM_OID* oid,
77 Time* result) {
78 *result = Time::Time();
80 x509_util::CSSMFieldValue field;
81 OSStatus status = cached_cert.GetField(oid, &field);
82 if (status)
83 return;
85 const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>();
86 if (x509_time->timeType != BER_TAG_UTC_TIME &&
87 x509_time->timeType != BER_TAG_GENERALIZED_TIME) {
88 LOG(ERROR) << "Unsupported date/time format "
89 << x509_time->timeType;
90 return;
93 base::StringPiece time_string(
94 reinterpret_cast<const char*>(x509_time->time.Data),
95 x509_time->time.Length);
96 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ?
97 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
98 if (!ParseCertificateDate(time_string, format, result))
99 LOG(ERROR) << "Invalid certificate date/time " << time_string;
102 std::string GetCertSerialNumber(
103 const x509_util::CSSMCachedCertificate& cached_cert) {
104 x509_util::CSSMFieldValue serial_number;
105 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber,
106 &serial_number);
107 if (status || !serial_number.field())
108 return std::string();
110 return std::string(
111 reinterpret_cast<const char*>(serial_number.field()->Data),
112 serial_number.field()->Length);
115 // Returns true if |purpose| is listed as allowed in |usage|. This
116 // function also considers the "Any" purpose. If the attribute is
117 // present and empty, we return false.
118 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage,
119 const CSSM_OID* purpose) {
120 for (unsigned p = 0; p < usage->numPurposes; ++p) {
121 if (CSSMOIDEqual(&usage->purposes[p], purpose))
122 return true;
123 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
124 return true;
126 return false;
129 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
130 // return true if it is.
132 // On OS X, SecCertificateCreateFromData() does not return any errors if
133 // called with invalid data, as long as data is present. The actual decoding
134 // of the certificate does not happen until an API that requires a CSSM
135 // handle is called. While SecCertificateGetCLHandle is the most likely
136 // candidate, as it performs the parsing, it does not check whether the
137 // parsing was actually successful. Instead, SecCertificateGetSubject is
138 // used (supported since 10.3), as a means to check that the certificate
139 // parsed as a valid X.509 certificate.
140 bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
141 const CSSM_X509_NAME* sanity_check = NULL;
142 OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check);
143 return status == noErr && sanity_check;
146 // Parses |data| of length |length|, attempting to decode it as the specified
147 // |format|. If |data| is in the specified format, any certificates contained
148 // within are stored into |output|.
149 void AddCertificatesFromBytes(const char* data, size_t length,
150 SecExternalFormat format,
151 X509Certificate::OSCertHandles* output) {
152 SecExternalFormat input_format = format;
153 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
154 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
155 kCFAllocatorNull));
157 CFArrayRef items = NULL;
158 OSStatus status;
160 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
161 status = SecKeychainItemImport(local_data, NULL, &input_format,
162 NULL, 0, NULL, NULL, &items);
165 if (status) {
166 OSSTATUS_DLOG(WARNING, status)
167 << "Unable to import items from data of length " << length;
168 return;
171 ScopedCFTypeRef<CFArrayRef> scoped_items(items);
172 CFTypeID cert_type_id = SecCertificateGetTypeID();
174 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
175 SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
176 const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
178 // While inputFormat implies only certificates will be imported, if/when
179 // other formats (eg: PKCS#12) are supported, this may also include
180 // private keys or other items types, so filter appropriately.
181 if (CFGetTypeID(item) == cert_type_id) {
182 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item);
183 // OS X ignores |input_format| if it detects that |local_data| is PEM
184 // encoded, attempting to decode data based on internal rules for PEM
185 // block headers. If a PKCS#7 blob is encoded with a PEM block of
186 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
187 // based on the decoded data. If this happens, the certificate should
188 // not be included in |output|. Because |output| is empty,
189 // CreateCertificateListfromBytes will use PEMTokenizer to decode the
190 // data. When called again with the decoded data, OS X will honor
191 // |input_format|, causing decode to succeed. On OS X 10.6, the data
192 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
193 // the need to fallback to internal decoding.
194 if (IsValidOSCertHandle(cert)) {
195 CFRetain(cert);
196 output->push_back(cert);
202 struct CSSMOIDString {
203 const CSSM_OID* oid_;
204 std::string string_;
207 typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
209 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) {
210 struct OIDCSSMMap {
211 SECOidTag sec_OID_;
212 const CSSM_OID* cssm_OID_;
215 const OIDCSSMMap kOIDs[] = {
216 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName },
217 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName },
218 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName },
219 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName },
220 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress },
221 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName },
222 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName },
223 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier },
224 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier },
225 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress },
228 CERTRDN** rdns = name->rdns;
229 for (size_t rdn = 0; rdns[rdn]; ++rdn) {
230 CERTAVA** avas = rdns[rdn]->avas;
231 for (size_t pair = 0; avas[pair] != 0; ++pair) {
232 SECOidTag tag = CERT_GetAVATag(avas[pair]);
233 if (tag == SEC_OID_UNKNOWN) {
234 return false;
236 CSSMOIDString oidString;
237 bool found_oid = false;
238 for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) {
239 if (kOIDs[oid].sec_OID_ == tag) {
240 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
241 if (!decode_item)
242 return false;
244 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
245 std::string value(reinterpret_cast<char*>(decode_item->data),
246 decode_item->len);
247 oidString.oid_ = kOIDs[oid].cssm_OID_;
248 oidString.string_ = value;
249 out_values->push_back(oidString);
250 SECITEM_FreeItem(decode_item, PR_TRUE);
251 found_oid = true;
252 break;
255 if (!found_oid) {
256 DLOG(ERROR) << "Unrecognized OID: " << tag;
260 return true;
263 class ScopedCertName {
264 public:
265 explicit ScopedCertName(CERTName* name) : name_(name) { }
266 ~ScopedCertName() {
267 if (name_) CERT_DestroyName(name_);
269 operator CERTName*() { return name_; }
271 private:
272 CERTName* name_;
275 class ScopedEncodedCertResults {
276 public:
277 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
278 : results_(results) { }
279 ~ScopedEncodedCertResults() {
280 if (results_) {
281 CSSM_ENCODED_CERT* encCert =
282 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
283 for (uint32 i = 0; i < results_->NumberOfResults; i++) {
284 crypto::CSSMFree(encCert[i].CertBlob.Data);
287 crypto::CSSMFree(results_->Results);
288 crypto::CSSMFree(results_);
291 private:
292 CSSM_TP_RESULT_SET* results_;
295 } // namespace
297 void X509Certificate::Initialize() {
298 x509_util::CSSMCachedCertificate cached_cert;
299 if (cached_cert.Init(cert_handle_) == CSSM_OK) {
300 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
301 &subject_);
302 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
303 &issuer_);
304 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
305 &valid_start_);
306 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
307 &valid_expiry_);
308 serial_number_ = GetCertSerialNumber(cached_cert);
311 fingerprint_ = CalculateFingerprint(cert_handle_);
312 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
315 bool X509Certificate::IsIssuedByEncoded(
316 const std::vector<std::string>& valid_issuers) {
317 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
318 return true;
320 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
321 it != intermediate_ca_certs_.end(); ++it) {
322 if (IsCertIssuerInEncodedList(*it, valid_issuers))
323 return true;
325 return false;
328 void X509Certificate::GetSubjectAltName(
329 std::vector<std::string>* dns_names,
330 std::vector<std::string>* ip_addrs) const {
331 if (dns_names)
332 dns_names->clear();
333 if (ip_addrs)
334 ip_addrs->clear();
336 x509_util::CSSMCachedCertificate cached_cert;
337 OSStatus status = cached_cert.Init(cert_handle_);
338 if (status)
339 return;
340 x509_util::CSSMFieldValue subject_alt_name;
341 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
342 if (status || !subject_alt_name.field())
343 return;
344 const CSSM_X509_EXTENSION* cssm_ext =
345 subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
346 if (!cssm_ext || !cssm_ext->value.parsedValue)
347 return;
348 const CE_GeneralNames* alt_name =
349 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
351 for (size_t name = 0; name < alt_name->numNames; ++name) {
352 const CE_GeneralName& name_struct = alt_name->generalName[name];
353 const CSSM_DATA& name_data = name_struct.name;
354 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
355 // respectively, both of which can be byte copied from
356 // CSSM_DATA::data into the appropriate output vector.
357 if (dns_names && name_struct.nameType == GNT_DNSName) {
358 dns_names->push_back(std::string(
359 reinterpret_cast<const char*>(name_data.Data),
360 name_data.Length));
361 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
362 ip_addrs->push_back(std::string(
363 reinterpret_cast<const char*>(name_data.Data),
364 name_data.Length));
369 // static
370 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
371 std::string* encoded) {
372 CSSM_DATA der_data;
373 if (SecCertificateGetData(cert_handle, &der_data) != noErr)
374 return false;
375 encoded->assign(reinterpret_cast<char*>(der_data.Data),
376 der_data.Length);
377 return true;
380 // static
381 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
382 X509Certificate::OSCertHandle b) {
383 DCHECK(a && b);
384 if (a == b)
385 return true;
386 if (CFEqual(a, b))
387 return true;
388 CSSM_DATA a_data, b_data;
389 return SecCertificateGetData(a, &a_data) == noErr &&
390 SecCertificateGetData(b, &b_data) == noErr &&
391 a_data.Length == b_data.Length &&
392 memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
395 // static
396 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
397 const char* data, int length) {
398 CSSM_DATA cert_data;
399 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
400 cert_data.Length = length;
402 OSCertHandle cert_handle = NULL;
403 OSStatus status = SecCertificateCreateFromData(&cert_data,
404 CSSM_CERT_X_509v3,
405 CSSM_CERT_ENCODING_DER,
406 &cert_handle);
407 if (status != noErr)
408 return NULL;
409 if (!IsValidOSCertHandle(cert_handle)) {
410 CFRelease(cert_handle);
411 return NULL;
413 return cert_handle;
416 // static
417 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
418 const char* data, int length, Format format) {
419 OSCertHandles results;
421 switch (format) {
422 case FORMAT_SINGLE_CERTIFICATE: {
423 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
424 if (handle)
425 results.push_back(handle);
426 break;
428 case FORMAT_PKCS7:
429 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
430 break;
431 default:
432 NOTREACHED() << "Certificate format " << format << " unimplemented";
433 break;
436 return results;
439 // static
440 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
441 OSCertHandle handle) {
442 if (!handle)
443 return NULL;
444 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
447 // static
448 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
449 CFRelease(cert_handle);
452 // static
453 SHA1HashValue X509Certificate::CalculateFingerprint(
454 OSCertHandle cert) {
455 SHA1HashValue sha1;
456 memset(sha1.data, 0, sizeof(sha1.data));
458 CSSM_DATA cert_data;
459 OSStatus status = SecCertificateGetData(cert, &cert_data);
460 if (status)
461 return sha1;
463 DCHECK(cert_data.Data);
464 DCHECK_NE(cert_data.Length, 0U);
466 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
468 return sha1;
471 // static
472 SHA1HashValue X509Certificate::CalculateCAFingerprint(
473 const OSCertHandles& intermediates) {
474 SHA1HashValue sha1;
475 memset(sha1.data, 0, sizeof(sha1.data));
477 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
478 // we don't check their return values.
479 CC_SHA1_CTX sha1_ctx;
480 CC_SHA1_Init(&sha1_ctx);
481 CSSM_DATA cert_data;
482 for (size_t i = 0; i < intermediates.size(); ++i) {
483 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
484 if (status)
485 return sha1;
486 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
488 CC_SHA1_Final(sha1.data, &sha1_ctx);
490 return sha1;
493 bool X509Certificate::SupportsSSLClientAuth() const {
494 x509_util::CSSMCachedCertificate cached_cert;
495 OSStatus status = cached_cert.Init(cert_handle_);
496 if (status)
497 return false;
499 // RFC5280 says to take the intersection of the two extensions.
501 // Our underlying crypto libraries don't expose
502 // ClientCertificateType, so for now we will not support fixed
503 // Diffie-Hellman mechanisms. For rsa_sign, we need the
504 // digitalSignature bit.
506 // In particular, if a key has the nonRepudiation bit and not the
507 // digitalSignature one, we will not offer it to the user.
508 x509_util::CSSMFieldValue key_usage;
509 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
510 if (status == CSSM_OK && key_usage.field()) {
511 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
512 const CE_KeyUsage* key_usage_value =
513 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
514 if (!((*key_usage_value) & CE_KU_DigitalSignature))
515 return false;
518 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
519 if (status == CSSM_OK && key_usage.field()) {
520 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
521 const CE_ExtendedKeyUsage* ext_key_usage =
522 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
523 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
524 return false;
526 return true;
529 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
530 CFMutableArrayRef cert_list =
531 CFArrayCreateMutable(kCFAllocatorDefault, 0,
532 &kCFTypeArrayCallBacks);
533 if (!cert_list)
534 return NULL;
536 CFArrayAppendValue(cert_list, os_cert_handle());
537 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
538 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
540 return cert_list;
543 // static
544 X509Certificate::OSCertHandle
545 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
546 const char* data;
547 int length;
548 if (!pickle_iter->ReadData(&data, &length))
549 return NULL;
551 return CreateOSCertHandleFromBytes(data, length);
554 // static
555 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
556 Pickle* pickle) {
557 CSSM_DATA cert_data;
558 OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
559 if (status)
560 return false;
562 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
563 cert_data.Length);
566 // static
567 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
568 size_t* size_bits,
569 PublicKeyType* type) {
570 // Since we might fail, set the output parameters to default values first.
571 *type = kPublicKeyTypeUnknown;
572 *size_bits = 0;
574 SecKeyRef key;
575 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
576 if (status) {
577 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
578 return;
580 ScopedCFTypeRef<SecKeyRef> scoped_key(key);
582 const CSSM_KEY* cssm_key;
583 status = SecKeyGetCSSMKey(key, &cssm_key);
584 if (status) {
585 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
586 return;
589 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
591 switch (cssm_key->KeyHeader.AlgorithmId) {
592 case CSSM_ALGID_RSA:
593 *type = kPublicKeyTypeRSA;
594 break;
595 case CSSM_ALGID_DSA:
596 *type = kPublicKeyTypeDSA;
597 break;
598 case CSSM_ALGID_ECDSA:
599 *type = kPublicKeyTypeECDSA;
600 break;
601 case CSSM_ALGID_DH:
602 *type = kPublicKeyTypeDH;
603 break;
604 default:
605 *type = kPublicKeyTypeUnknown;
606 *size_bits = 0;
607 break;
611 } // namespace net