// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/cert/x509_certificate.h" #include <CommonCrypto/CommonDigest.h> #include <Security/Security.h> #include <cert.h> #include <cryptohi.h> #include <keyhi.h> #include <nss.h> #include <pk11pub.h> #include <prerror.h> #include <prtime.h> #include <prtypes.h> #include <secder.h> #include <secerr.h> #include <sslerr.h> #include <vector> #include "base/logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/scoped_ptr.h" #include "base/pickle.h" #include "base/time/time.h" #include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" #include "net/base/net_errors.h" #include "net/cert/asn1_util.h" #include "net/cert/cert_status_flags.h" #include "net/cert/cert_verify_result.h" #include "net/cert/ev_root_ca_metadata.h" #include "net/cert/x509_util_ios.h" #include "net/cert/x509_util_nss.h" using base::ScopedCFTypeRef; namespace net { namespace { // Returns true if a given |cert_handle| is actually a valid X.509 certificate // handle. // // SecCertificateCreateFromData() does not always force the immediate parsing of // the certificate, and as such, may return a SecCertificateRef for an // invalid/unparsable certificate. Force parsing to occur to ensure that the // SecCertificateRef is correct. On later versions where // SecCertificateCreateFromData() immediately parses, rather than lazily, this // call is cheap, as the subject is cached. bool IsValidOSCertHandle(SecCertificateRef cert_handle) { ScopedCFTypeRef<CFStringRef> sanity_check( SecCertificateCopySubjectSummary(cert_handle)); return sanity_check != NULL; } } // namespace void X509Certificate::Initialize() { x509_util_ios::NSSCertificate nss_cert(cert_handle_); CERTCertificate* cert_handle = nss_cert.cert_handle(); if (cert_handle) { x509_util::ParsePrincipal(&cert_handle->subject, &subject_); x509_util::ParsePrincipal(&cert_handle->issuer, &issuer_); x509_util::ParseDate(&cert_handle->validity.notBefore, &valid_start_); x509_util::ParseDate(&cert_handle->validity.notAfter, &valid_expiry_); serial_number_ = x509_util::ParseSerialNumber(cert_handle); } fingerprint_ = CalculateFingerprint(cert_handle_); ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); } bool X509Certificate::IsIssuedByEncoded( const std::vector<std::string>& valid_issuers) { x509_util_ios::NSSCertChain nss_chain(this); // Convert to scoped CERTName* list. std::vector<CERTName*> issuers; crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!x509_util::GetIssuersFromEncodedList(valid_issuers, arena.get(), &issuers)) { return false; } return x509_util::IsCertificateIssuedBy( nss_chain.cert_chain(), issuers); } void X509Certificate::GetSubjectAltName( std::vector<std::string>* dns_names, std::vector<std::string>* ip_addrs) const { x509_util_ios::NSSCertificate nss_cert(cert_handle_); CERTCertificate* cert_handle = nss_cert.cert_handle(); if (!cert_handle) { if (dns_names) dns_names->clear(); if (ip_addrs) ip_addrs->clear(); return; } x509_util::GetSubjectAltName(cert_handle, dns_names, ip_addrs); } // static bool X509Certificate::GetDEREncoded(OSCertHandle cert_handle, std::string* encoded) { if (!cert_handle) return false; ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle)); if (!der_data) return false; encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), CFDataGetLength(der_data)); return true; } // static bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, X509Certificate::OSCertHandle b) { DCHECK(a && b); if (a == b) return true; if (CFEqual(a, b)) return true; ScopedCFTypeRef<CFDataRef> a_data(SecCertificateCopyData(a)); ScopedCFTypeRef<CFDataRef> b_data(SecCertificateCopyData(b)); return a_data && b_data && CFDataGetLength(a_data) == CFDataGetLength(b_data) && memcmp(CFDataGetBytePtr(a_data), CFDataGetBytePtr(b_data), CFDataGetLength(a_data)) == 0; } // static X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( const char* data, int length) { ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(data), length, kCFAllocatorNull)); if (!cert_data) return NULL; OSCertHandle cert_handle = SecCertificateCreateWithData(NULL, cert_data); if (!cert_handle) return NULL; if (!IsValidOSCertHandle(cert_handle)) { CFRelease(cert_handle); return NULL; } return cert_handle; } // static X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( const char* data, int length, Format format) { return x509_util::CreateOSCertHandlesFromBytes(data, length, format); } // static X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( OSCertHandle handle) { if (!handle) return NULL; return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); } // static void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { if (cert_handle) CFRelease(cert_handle); } // static SHA1HashValue X509Certificate::CalculateFingerprint( OSCertHandle cert) { SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert)); if (!cert_data) return sha1; DCHECK(CFDataGetBytePtr(cert_data)); DCHECK_NE(0, CFDataGetLength(cert_data)); CC_SHA1(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), sha1.data); return sha1; } // static SHA1HashValue X509Certificate::CalculateCAFingerprint( const OSCertHandles& intermediates) { SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so // we don't check their return values. CC_SHA1_CTX sha1_ctx; CC_SHA1_Init(&sha1_ctx); for (size_t i = 0; i < intermediates.size(); ++i) { ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(intermediates[i])); if (!cert_data) return sha1; CC_SHA1_Update(&sha1_ctx, CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data)); } CC_SHA1_Final(sha1.data, &sha1_ctx); return sha1; } // static X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { return x509_util::ReadOSCertHandleFromPickle(pickle_iter); } // static bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, Pickle* pickle) { ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle)); if (!cert_data) return false; return pickle->WriteData( reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)), CFDataGetLength(cert_data)); } // static void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, size_t* size_bits, PublicKeyType* type) { x509_util_ios::NSSCertificate nss_cert(cert_handle); x509_util::GetPublicKeyInfo(nss_cert.cert_handle(), size_bits, type); } } // namespace net