Update nss_revision to 235242.
[chromium-blink-merge.git] / net / cert / x509_certificate_mac.cc
blob1d874c4b023b29541eb0dc5883e34c5d78c00335
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 class ScopedCertName {
210 public:
211 explicit ScopedCertName(CERTName* name) : name_(name) { }
212 ~ScopedCertName() {
213 if (name_) CERT_DestroyName(name_);
215 operator CERTName*() { return name_; }
217 private:
218 CERTName* name_;
221 class ScopedEncodedCertResults {
222 public:
223 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
224 : results_(results) { }
225 ~ScopedEncodedCertResults() {
226 if (results_) {
227 CSSM_ENCODED_CERT* encCert =
228 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
229 for (uint32 i = 0; i < results_->NumberOfResults; i++) {
230 crypto::CSSMFree(encCert[i].CertBlob.Data);
232 crypto::CSSMFree(results_->Results);
233 crypto::CSSMFree(results_);
237 private:
238 CSSM_TP_RESULT_SET* results_;
241 } // namespace
243 void X509Certificate::Initialize() {
244 x509_util::CSSMCachedCertificate cached_cert;
245 if (cached_cert.Init(cert_handle_) == CSSM_OK) {
246 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
247 &subject_);
248 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
249 &issuer_);
250 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
251 &valid_start_);
252 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
253 &valid_expiry_);
254 serial_number_ = GetCertSerialNumber(cached_cert);
257 fingerprint_ = CalculateFingerprint(cert_handle_);
258 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
261 bool X509Certificate::IsIssuedByEncoded(
262 const std::vector<std::string>& valid_issuers) {
263 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
264 return true;
266 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
267 it != intermediate_ca_certs_.end(); ++it) {
268 if (IsCertIssuerInEncodedList(*it, valid_issuers))
269 return true;
271 return false;
274 void X509Certificate::GetSubjectAltName(
275 std::vector<std::string>* dns_names,
276 std::vector<std::string>* ip_addrs) const {
277 if (dns_names)
278 dns_names->clear();
279 if (ip_addrs)
280 ip_addrs->clear();
282 x509_util::CSSMCachedCertificate cached_cert;
283 OSStatus status = cached_cert.Init(cert_handle_);
284 if (status)
285 return;
286 x509_util::CSSMFieldValue subject_alt_name;
287 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
288 if (status || !subject_alt_name.field())
289 return;
290 const CSSM_X509_EXTENSION* cssm_ext =
291 subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
292 if (!cssm_ext || !cssm_ext->value.parsedValue)
293 return;
294 const CE_GeneralNames* alt_name =
295 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
297 for (size_t name = 0; name < alt_name->numNames; ++name) {
298 const CE_GeneralName& name_struct = alt_name->generalName[name];
299 const CSSM_DATA& name_data = name_struct.name;
300 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
301 // respectively, both of which can be byte copied from
302 // CSSM_DATA::data into the appropriate output vector.
303 if (dns_names && name_struct.nameType == GNT_DNSName) {
304 dns_names->push_back(std::string(
305 reinterpret_cast<const char*>(name_data.Data),
306 name_data.Length));
307 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
308 ip_addrs->push_back(std::string(
309 reinterpret_cast<const char*>(name_data.Data),
310 name_data.Length));
315 // static
316 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
317 std::string* encoded) {
318 CSSM_DATA der_data;
319 if (SecCertificateGetData(cert_handle, &der_data) != noErr)
320 return false;
321 encoded->assign(reinterpret_cast<char*>(der_data.Data),
322 der_data.Length);
323 return true;
326 // static
327 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
328 X509Certificate::OSCertHandle b) {
329 DCHECK(a && b);
330 if (a == b)
331 return true;
332 if (CFEqual(a, b))
333 return true;
334 CSSM_DATA a_data, b_data;
335 return SecCertificateGetData(a, &a_data) == noErr &&
336 SecCertificateGetData(b, &b_data) == noErr &&
337 a_data.Length == b_data.Length &&
338 memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
341 // static
342 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
343 const char* data, int length) {
344 CSSM_DATA cert_data;
345 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
346 cert_data.Length = length;
348 OSCertHandle cert_handle = NULL;
349 OSStatus status = SecCertificateCreateFromData(&cert_data,
350 CSSM_CERT_X_509v3,
351 CSSM_CERT_ENCODING_DER,
352 &cert_handle);
353 if (status != noErr)
354 return NULL;
355 if (!IsValidOSCertHandle(cert_handle)) {
356 CFRelease(cert_handle);
357 return NULL;
359 return cert_handle;
362 // static
363 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
364 const char* data, int length, Format format) {
365 OSCertHandles results;
367 switch (format) {
368 case FORMAT_SINGLE_CERTIFICATE: {
369 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
370 if (handle)
371 results.push_back(handle);
372 break;
374 case FORMAT_PKCS7:
375 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
376 break;
377 default:
378 NOTREACHED() << "Certificate format " << format << " unimplemented";
379 break;
382 return results;
385 // static
386 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
387 OSCertHandle handle) {
388 if (!handle)
389 return NULL;
390 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
393 // static
394 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
395 CFRelease(cert_handle);
398 // static
399 SHA1HashValue X509Certificate::CalculateFingerprint(
400 OSCertHandle cert) {
401 SHA1HashValue sha1;
402 memset(sha1.data, 0, sizeof(sha1.data));
404 CSSM_DATA cert_data;
405 OSStatus status = SecCertificateGetData(cert, &cert_data);
406 if (status)
407 return sha1;
409 DCHECK(cert_data.Data);
410 DCHECK_NE(cert_data.Length, 0U);
412 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
414 return sha1;
417 // static
418 SHA1HashValue X509Certificate::CalculateCAFingerprint(
419 const OSCertHandles& intermediates) {
420 SHA1HashValue sha1;
421 memset(sha1.data, 0, sizeof(sha1.data));
423 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
424 // we don't check their return values.
425 CC_SHA1_CTX sha1_ctx;
426 CC_SHA1_Init(&sha1_ctx);
427 CSSM_DATA cert_data;
428 for (size_t i = 0; i < intermediates.size(); ++i) {
429 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
430 if (status)
431 return sha1;
432 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
434 CC_SHA1_Final(sha1.data, &sha1_ctx);
436 return sha1;
439 bool X509Certificate::SupportsSSLClientAuth() const {
440 x509_util::CSSMCachedCertificate cached_cert;
441 OSStatus status = cached_cert.Init(cert_handle_);
442 if (status)
443 return false;
445 // RFC5280 says to take the intersection of the two extensions.
447 // Our underlying crypto libraries don't expose
448 // ClientCertificateType, so for now we will not support fixed
449 // Diffie-Hellman mechanisms. For rsa_sign, we need the
450 // digitalSignature bit.
452 // In particular, if a key has the nonRepudiation bit and not the
453 // digitalSignature one, we will not offer it to the user.
454 x509_util::CSSMFieldValue key_usage;
455 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
456 if (status == CSSM_OK && key_usage.field()) {
457 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
458 const CE_KeyUsage* key_usage_value =
459 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
460 if (!((*key_usage_value) & CE_KU_DigitalSignature))
461 return false;
464 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
465 if (status == CSSM_OK && key_usage.field()) {
466 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
467 const CE_ExtendedKeyUsage* ext_key_usage =
468 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
469 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
470 return false;
472 return true;
475 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
476 CFMutableArrayRef cert_list =
477 CFArrayCreateMutable(kCFAllocatorDefault, 0,
478 &kCFTypeArrayCallBacks);
479 if (!cert_list)
480 return NULL;
482 CFArrayAppendValue(cert_list, os_cert_handle());
483 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
484 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
486 return cert_list;
489 // static
490 X509Certificate::OSCertHandle
491 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
492 const char* data;
493 int length;
494 if (!pickle_iter->ReadData(&data, &length))
495 return NULL;
497 return CreateOSCertHandleFromBytes(data, length);
500 // static
501 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
502 Pickle* pickle) {
503 CSSM_DATA cert_data;
504 OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
505 if (status)
506 return false;
508 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
509 cert_data.Length);
512 // static
513 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
514 size_t* size_bits,
515 PublicKeyType* type) {
516 // Since we might fail, set the output parameters to default values first.
517 *type = kPublicKeyTypeUnknown;
518 *size_bits = 0;
520 SecKeyRef key;
521 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
522 if (status) {
523 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
524 return;
526 ScopedCFTypeRef<SecKeyRef> scoped_key(key);
528 const CSSM_KEY* cssm_key;
529 status = SecKeyGetCSSMKey(key, &cssm_key);
530 if (status) {
531 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
532 return;
535 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
537 switch (cssm_key->KeyHeader.AlgorithmId) {
538 case CSSM_ALGID_RSA:
539 *type = kPublicKeyTypeRSA;
540 break;
541 case CSSM_ALGID_DSA:
542 *type = kPublicKeyTypeDSA;
543 break;
544 case CSSM_ALGID_ECDSA:
545 *type = kPublicKeyTypeECDSA;
546 break;
547 case CSSM_ALGID_DH:
548 *type = kPublicKeyTypeDH;
549 break;
550 default:
551 *type = kPublicKeyTypeUnknown;
552 *size_bits = 0;
553 break;
557 } // namespace net