diff options
Diffstat (limited to 'net/base/x509_certificate_mac.cc')
-rw-r--r-- | net/base/x509_certificate_mac.cc | 834 |
1 files changed, 0 insertions, 834 deletions
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc deleted file mode 100644 index fb6ffa9..0000000 --- a/net/base/x509_certificate_mac.cc +++ /dev/null @@ -1,834 +0,0 @@ -// 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/base/x509_certificate.h" - -#include <CommonCrypto/CommonDigest.h> -#include <CoreServices/CoreServices.h> -#include <Security/Security.h> -#include <time.h> - -#include <vector> - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/mac/mac_logging.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/singleton.h" -#include "base/pickle.h" -#include "base/sha1.h" -#include "base/string_piece.h" -#include "base/strings/sys_string_conversions.h" -#include "base/synchronization/lock.h" -#include "crypto/cssm_init.h" -#include "crypto/mac_security_services_lock.h" -#include "crypto/nss_util.h" -#include "crypto/rsa_private_key.h" -#include "net/base/x509_util_mac.h" -#include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" - -using base::mac::ScopedCFTypeRef; -using base::Time; - -namespace net { - -namespace { - -void GetCertDistinguishedName( - const x509_util::CSSMCachedCertificate& cached_cert, - const CSSM_OID* oid, - CertPrincipal* result) { - x509_util::CSSMFieldValue distinguished_name; - OSStatus status = cached_cert.GetField(oid, &distinguished_name); - if (status || !distinguished_name.field()) - return; - result->ParseDistinguishedName(distinguished_name.field()->Data, - distinguished_name.field()->Length); -} - -bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle, - const std::vector<std::string>& issuers) { - x509_util::CSSMCachedCertificate cached_cert; - if (cached_cert.Init(cert_handle) != CSSM_OK) - return false; - - x509_util::CSSMFieldValue distinguished_name; - OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd, - &distinguished_name); - if (status || !distinguished_name.field()) - return false; - - base::StringPiece name_piece( - reinterpret_cast<const char*>(distinguished_name.field()->Data), - static_cast<size_t>(distinguished_name.field()->Length)); - - for (std::vector<std::string>::const_iterator it = issuers.begin(); - it != issuers.end(); ++it) { - base::StringPiece issuer_piece(*it); - if (name_piece == issuer_piece) - return true; - } - - return false; -} - -void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert, - const CSSM_OID* oid, - Time* result) { - *result = Time::Time(); - - x509_util::CSSMFieldValue field; - OSStatus status = cached_cert.GetField(oid, &field); - if (status) - return; - - const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>(); - if (x509_time->timeType != BER_TAG_UTC_TIME && - x509_time->timeType != BER_TAG_GENERALIZED_TIME) { - LOG(ERROR) << "Unsupported date/time format " - << x509_time->timeType; - return; - } - - base::StringPiece time_string( - reinterpret_cast<const char*>(x509_time->time.Data), - x509_time->time.Length); - CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? - CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; - if (!ParseCertificateDate(time_string, format, result)) - LOG(ERROR) << "Invalid certificate date/time " << time_string; -} - -std::string GetCertSerialNumber( - const x509_util::CSSMCachedCertificate& cached_cert) { - x509_util::CSSMFieldValue serial_number; - OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, - &serial_number); - if (status || !serial_number.field()) - return std::string(); - - return std::string( - reinterpret_cast<const char*>(serial_number.field()->Data), - serial_number.field()->Length); -} - -// Gets the issuer for a given cert, starting with the cert itself and -// including the intermediate and finally root certificates (if any). -// This function calls SecTrust but doesn't actually pay attention to the trust -// result: it shouldn't be used to determine trust, just to traverse the chain. -// Caller is responsible for releasing the value stored into *out_cert_chain. -OSStatus CopyCertChain(SecCertificateRef cert_handle, - CFArrayRef* out_cert_chain) { - DCHECK(cert_handle); - DCHECK(out_cert_chain); - - // Create an SSL policy ref configured for client cert evaluation. - SecPolicyRef ssl_policy; - OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); - if (result) - return result; - ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); - - // Create a SecTrustRef. - ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( - NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), - 1, &kCFTypeArrayCallBacks)); - SecTrustRef trust_ref = NULL; - { - base::AutoLock lock(crypto::GetMacSecurityServicesLock()); - result = SecTrustCreateWithCertificates(input_certs, ssl_policy, - &trust_ref); - } - if (result) - return result; - ScopedCFTypeRef<SecTrustRef> trust(trust_ref); - - // Evaluate trust, which creates the cert chain. - SecTrustResultType status; - CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; - { - base::AutoLock lock(crypto::GetMacSecurityServicesLock()); - result = SecTrustEvaluate(trust, &status); - } - if (result) - return result; - { - base::AutoLock lock(crypto::GetMacSecurityServicesLock()); - result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); - } - return result; -} - -// Returns true if |purpose| is listed as allowed in |usage|. This -// function also considers the "Any" purpose. If the attribute is -// present and empty, we return false. -bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, - const CSSM_OID* purpose) { - for (unsigned p = 0; p < usage->numPurposes; ++p) { - if (CSSMOIDEqual(&usage->purposes[p], purpose)) - return true; - if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny)) - return true; - } - return false; -} - -// Test that a given |cert_handle| is actually a valid X.509 certificate, and -// return true if it is. -// -// On OS X, SecCertificateCreateFromData() does not return any errors if -// called with invalid data, as long as data is present. The actual decoding -// of the certificate does not happen until an API that requires a CSSM -// handle is called. While SecCertificateGetCLHandle is the most likely -// candidate, as it performs the parsing, it does not check whether the -// parsing was actually successful. Instead, SecCertificateGetSubject is -// used (supported since 10.3), as a means to check that the certificate -// parsed as a valid X.509 certificate. -bool IsValidOSCertHandle(SecCertificateRef cert_handle) { - const CSSM_X509_NAME* sanity_check = NULL; - OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check); - return status == noErr && sanity_check; -} - -// Parses |data| of length |length|, attempting to decode it as the specified -// |format|. If |data| is in the specified format, any certificates contained -// within are stored into |output|. -void AddCertificatesFromBytes(const char* data, size_t length, - SecExternalFormat format, - X509Certificate::OSCertHandles* output) { - SecExternalFormat input_format = format; - ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, - kCFAllocatorNull)); - - CFArrayRef items = NULL; - OSStatus status; - { - base::AutoLock lock(crypto::GetMacSecurityServicesLock()); - status = SecKeychainItemImport(local_data, NULL, &input_format, - NULL, 0, NULL, NULL, &items); - } - - if (status) { - OSSTATUS_DLOG(WARNING, status) - << "Unable to import items from data of length " << length; - return; - } - - ScopedCFTypeRef<CFArrayRef> scoped_items(items); - CFTypeID cert_type_id = SecCertificateGetTypeID(); - - for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { - SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>( - const_cast<void*>(CFArrayGetValueAtIndex(items, i))); - - // While inputFormat implies only certificates will be imported, if/when - // other formats (eg: PKCS#12) are supported, this may also include - // private keys or other items types, so filter appropriately. - if (CFGetTypeID(item) == cert_type_id) { - SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item); - // OS X ignores |input_format| if it detects that |local_data| is PEM - // encoded, attempting to decode data based on internal rules for PEM - // block headers. If a PKCS#7 blob is encoded with a PEM block of - // CERTIFICATE, OS X 10.5 will return a single, invalid certificate - // based on the decoded data. If this happens, the certificate should - // not be included in |output|. Because |output| is empty, - // CreateCertificateListfromBytes will use PEMTokenizer to decode the - // data. When called again with the decoded data, OS X will honor - // |input_format|, causing decode to succeed. On OS X 10.6, the data - // is properly decoded as a PKCS#7, whether PEM or not, which avoids - // the need to fallback to internal decoding. - if (IsValidOSCertHandle(cert)) { - CFRetain(cert); - output->push_back(cert); - } - } - } -} - -struct CSSMOIDString { - const CSSM_OID* oid_; - std::string string_; -}; - -typedef std::vector<CSSMOIDString> CSSMOIDStringVector; - -bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) { - struct OIDCSSMMap { - SECOidTag sec_OID_; - const CSSM_OID* cssm_OID_; - }; - - const OIDCSSMMap kOIDs[] = { - { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName }, - { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName }, - { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName }, - { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName }, - { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress }, - { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName }, - { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName }, - { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier }, - { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier }, - { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress }, - }; - - CERTRDN** rdns = name->rdns; - for (size_t rdn = 0; rdns[rdn]; ++rdn) { - CERTAVA** avas = rdns[rdn]->avas; - for (size_t pair = 0; avas[pair] != 0; ++pair) { - SECOidTag tag = CERT_GetAVATag(avas[pair]); - if (tag == SEC_OID_UNKNOWN) { - return false; - } - CSSMOIDString oidString; - bool found_oid = false; - for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) { - if (kOIDs[oid].sec_OID_ == tag) { - SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); - if (!decode_item) - return false; - - // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. - std::string value(reinterpret_cast<char*>(decode_item->data), - decode_item->len); - oidString.oid_ = kOIDs[oid].cssm_OID_; - oidString.string_ = value; - out_values->push_back(oidString); - SECITEM_FreeItem(decode_item, PR_TRUE); - found_oid = true; - break; - } - } - if (!found_oid) { - DLOG(ERROR) << "Unrecognized OID: " << tag; - } - } - } - return true; -} - -class ScopedCertName { - public: - explicit ScopedCertName(CERTName* name) : name_(name) { } - ~ScopedCertName() { - if (name_) CERT_DestroyName(name_); - } - operator CERTName*() { return name_; } - - private: - CERTName* name_; -}; - -class ScopedEncodedCertResults { - public: - explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results) - : results_(results) { } - ~ScopedEncodedCertResults() { - if (results_) { - CSSM_ENCODED_CERT* encCert = - reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results); - for (uint32 i = 0; i < results_->NumberOfResults; i++) { - crypto::CSSMFree(encCert[i].CertBlob.Data); - } - } - crypto::CSSMFree(results_->Results); - crypto::CSSMFree(results_); - } - - private: - CSSM_TP_RESULT_SET* results_; -}; - -} // namespace - -void X509Certificate::Initialize() { - x509_util::CSSMCachedCertificate cached_cert; - if (cached_cert.Init(cert_handle_) == CSSM_OK) { - GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd, - &subject_); - GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd, - &issuer_); - GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore, - &valid_start_); - GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter, - &valid_expiry_); - serial_number_ = GetCertSerialNumber(cached_cert); - } - - fingerprint_ = CalculateFingerprint(cert_handle_); - ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); -} - -bool X509Certificate::IsIssuedByEncoded( - const std::vector<std::string>& valid_issuers) { - if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers)) - return true; - - for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); - it != intermediate_ca_certs_.end(); ++it) { - if (IsCertIssuerInEncodedList(*it, valid_issuers)) - return true; - } - return false; -} - -// static -X509Certificate* X509Certificate::CreateSelfSigned( - crypto::RSAPrivateKey* key, - const std::string& subject, - uint32 serial_number, - base::TimeDelta valid_duration) { - DCHECK(key); - DCHECK(!subject.empty()); - - if (valid_duration.InSeconds() > kuint32max) { - LOG(ERROR) << "valid_duration too big " << valid_duration.InSeconds(); - valid_duration = base::TimeDelta::FromSeconds(kuint32max); - } - - // There is a comment in - // http://www.opensource.apple.com/source/security_certtool/security_certtool-31828/src/CertTool.cpp - // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have - // their high bit set. We will continue though and mask it out below. - if (serial_number & 0x80000000) - LOG(ERROR) << "serial_number has high bit set " << serial_number; - - // NSS is used to parse the subject string into a set of - // CSSM_OID/string pairs. There doesn't appear to be a system routine for - // parsing Distinguished Name strings. - crypto::EnsureNSSInit(); - - CSSMOIDStringVector subject_name_oids; - ScopedCertName subject_name( - CERT_AsciiToName(const_cast<char*>(subject.c_str()))); - if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) { - DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject; - return NULL; - } - - // Convert the map of oid/string pairs into an array of - // CSSM_APPLE_TP_NAME_OIDs. - std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names; - for (CSSMOIDStringVector::iterator iter = subject_name_oids.begin(); - iter != subject_name_oids.end(); ++iter) { - CSSM_APPLE_TP_NAME_OID cssm_subject_name; - cssm_subject_name.oid = iter->oid_; - cssm_subject_name.string = iter->string_.c_str(); - cssm_subject_names.push_back(cssm_subject_name); - } - - if (cssm_subject_names.empty()) { - DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject; - return NULL; - } - - // Set up a certificate request. - CSSM_APPLE_TP_CERT_REQUEST certReq; - memset(&certReq, 0, sizeof(certReq)); - certReq.cspHand = crypto::GetSharedCSPHandle(); - certReq.clHand = crypto::GetSharedCLHandle(); - // See comment about serial numbers above. - certReq.serialNumber = serial_number & 0x7fffffff; - certReq.numSubjectNames = cssm_subject_names.size(); - certReq.subjectNames = &cssm_subject_names[0]; - certReq.numIssuerNames = 0; // Root. - certReq.issuerNames = NULL; - certReq.issuerNameX509 = NULL; - certReq.certPublicKey = key->public_key(); - certReq.issuerPrivateKey = key->key(); - // These are the Apple defaults. - certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; - certReq.signatureOid = CSSMOID_SHA1WithRSA; - certReq.notBefore = 0; - certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds()); - certReq.numExtensions = 0; - certReq.extensions = NULL; - certReq.challengeString = NULL; - - CSSM_TP_REQUEST_SET reqSet; - reqSet.NumberOfRequests = 1; - reqSet.Requests = &certReq; - - CSSM_FIELD policyId; - memset(&policyId, 0, sizeof(policyId)); - policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; - - CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext; - memset(&callerAuthContext, 0, sizeof(callerAuthContext)); - callerAuthContext.Policy.NumberOfPolicyIds = 1; - callerAuthContext.Policy.PolicyIds = &policyId; - - CSSM_TP_HANDLE tp_handle = crypto::GetSharedTPHandle(); - CSSM_DATA refId; - memset(&refId, 0, sizeof(refId)); - sint32 estTime; - CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL, - CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext, - &estTime, &refId); - if (crtn) { - DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn; - return NULL; - } - - CSSM_BOOL confirmRequired; - CSSM_TP_RESULT_SET* resultSet = NULL; - crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime, - &confirmRequired, &resultSet); - ScopedEncodedCertResults scopedResults(resultSet); - crypto::CSSMFree(refId.Data); - if (crtn) { - DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn; - return NULL; - } - - if (confirmRequired) { - // Potential leak here of resultSet. |confirmRequired| should never be - // true. - DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation"; - return NULL; - } - - if (resultSet->NumberOfResults != 1) { - DLOG(ERROR) << "Unexpected number of results: " - << resultSet->NumberOfResults; - return NULL; - } - - CSSM_ENCODED_CERT* encCert = - reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results); - ScopedCFTypeRef<SecCertificateRef> scoped_cert; - SecCertificateRef certificate_ref = NULL; - OSStatus os_status = - SecCertificateCreateFromData(&encCert->CertBlob, encCert->CertType, - encCert->CertEncoding, &certificate_ref); - if (os_status != 0) { - OSSTATUS_DLOG(ERROR, os_status) << "SecCertificateCreateFromData failed"; - return NULL; - } - scoped_cert.reset(certificate_ref); - - return CreateFromHandle(scoped_cert, X509Certificate::OSCertHandles()); -} - -void X509Certificate::GetSubjectAltName( - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addrs) const { - if (dns_names) - dns_names->clear(); - if (ip_addrs) - ip_addrs->clear(); - - x509_util::CSSMCachedCertificate cached_cert; - OSStatus status = cached_cert.Init(cert_handle_); - if (status) - return; - x509_util::CSSMFieldValue subject_alt_name; - status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name); - if (status || !subject_alt_name.field()) - return; - const CSSM_X509_EXTENSION* cssm_ext = - subject_alt_name.GetAs<CSSM_X509_EXTENSION>(); - if (!cssm_ext || !cssm_ext->value.parsedValue) - return; - const CE_GeneralNames* alt_name = - reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue); - - for (size_t name = 0; name < alt_name->numNames; ++name) { - const CE_GeneralName& name_struct = alt_name->generalName[name]; - const CSSM_DATA& name_data = name_struct.name; - // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs - // respectively, both of which can be byte copied from - // CSSM_DATA::data into the appropriate output vector. - if (dns_names && name_struct.nameType == GNT_DNSName) { - dns_names->push_back(std::string( - reinterpret_cast<const char*>(name_data.Data), - name_data.Length)); - } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { - ip_addrs->push_back(std::string( - reinterpret_cast<const char*>(name_data.Data), - name_data.Length)); - } - } -} - -// static -bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, - std::string* encoded) { - CSSM_DATA der_data; - if (SecCertificateGetData(cert_handle, &der_data) != noErr) - return false; - encoded->assign(reinterpret_cast<char*>(der_data.Data), - der_data.Length); - 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; - CSSM_DATA a_data, b_data; - return SecCertificateGetData(a, &a_data) == noErr && - SecCertificateGetData(b, &b_data) == noErr && - a_data.Length == b_data.Length && - memcmp(a_data.Data, b_data.Data, a_data.Length) == 0; -} - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, int length) { - CSSM_DATA cert_data; - cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); - cert_data.Length = length; - - OSCertHandle cert_handle = NULL; - OSStatus status = SecCertificateCreateFromData(&cert_data, - CSSM_CERT_X_509v3, - CSSM_CERT_ENCODING_DER, - &cert_handle); - if (status != noErr) - 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) { - OSCertHandles results; - - switch (format) { - case FORMAT_SINGLE_CERTIFICATE: { - OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); - if (handle) - results.push_back(handle); - break; - } - case FORMAT_PKCS7: - AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results); - break; - default: - NOTREACHED() << "Certificate format " << format << " unimplemented"; - break; - } - - return results; -} - -// 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) { - CFRelease(cert_handle); -} - -// static -SHA1HashValue X509Certificate::CalculateFingerprint( - OSCertHandle cert) { - SHA1HashValue sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - CSSM_DATA cert_data; - OSStatus status = SecCertificateGetData(cert, &cert_data); - if (status) - return sha1; - - DCHECK(cert_data.Data); - DCHECK_NE(cert_data.Length, 0U); - - CC_SHA1(cert_data.Data, cert_data.Length, 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); - CSSM_DATA cert_data; - for (size_t i = 0; i < intermediates.size(); ++i) { - OSStatus status = SecCertificateGetData(intermediates[i], &cert_data); - if (status) - return sha1; - CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); - } - CC_SHA1_Final(sha1.data, &sha1_ctx); - - return sha1; -} - -bool X509Certificate::SupportsSSLClientAuth() const { - x509_util::CSSMCachedCertificate cached_cert; - OSStatus status = cached_cert.Init(cert_handle_); - if (status) - return false; - - // RFC5280 says to take the intersection of the two extensions. - // - // Our underlying crypto libraries don't expose - // ClientCertificateType, so for now we will not support fixed - // Diffie-Hellman mechanisms. For rsa_sign, we need the - // digitalSignature bit. - // - // In particular, if a key has the nonRepudiation bit and not the - // digitalSignature one, we will not offer it to the user. - x509_util::CSSMFieldValue key_usage; - status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); - if (status == CSSM_OK && key_usage.field()) { - const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); - const CE_KeyUsage* key_usage_value = - reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); - if (!((*key_usage_value) & CE_KU_DigitalSignature)) - return false; - } - - status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); - if (status == CSSM_OK && key_usage.field()) { - const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); - const CE_ExtendedKeyUsage* ext_key_usage = - reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); - if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) - return false; - } - return true; -} - -CFArrayRef X509Certificate::CreateClientCertificateChain() const { - // Initialize the result array with just the IdentityRef of the receiver: - SecIdentityRef identity; - OSStatus result; - { - base::AutoLock lock(crypto::GetMacSecurityServicesLock()); - result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); - } - if (result) { - OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; - return NULL; - } - ScopedCFTypeRef<CFMutableArrayRef> chain( - CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); - CFArrayAppendValue(chain, identity); - - CFArrayRef cert_chain = NULL; - result = CopyCertChain(cert_handle_, &cert_chain); - ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); - if (result) { - OSSTATUS_LOG(ERROR, result) << "CreateIdentityCertificateChain error"; - return chain.release(); - } - - // Append the intermediate certs from SecTrust to the result array: - if (cert_chain) { - int chain_count = CFArrayGetCount(cert_chain); - if (chain_count > 1) { - CFArrayAppendArray(chain, - cert_chain, - CFRangeMake(1, chain_count - 1)); - } - } - - return chain.release(); -} - -CFArrayRef X509Certificate::CreateOSCertChainForCert() const { - CFMutableArrayRef cert_list = - CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks); - if (!cert_list) - return NULL; - - CFArrayAppendValue(cert_list, os_cert_handle()); - for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) - CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); - - return cert_list; -} - -// static -X509Certificate::OSCertHandle -X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { - const char* data; - int length; - if (!pickle_iter->ReadData(&data, &length)) - return NULL; - - return CreateOSCertHandleFromBytes(data, length); -} - -// static -bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, - Pickle* pickle) { - CSSM_DATA cert_data; - OSStatus status = SecCertificateGetData(cert_handle, &cert_data); - if (status) - return false; - - return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), - cert_data.Length); -} - -// static -void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, - size_t* size_bits, - PublicKeyType* type) { - // Since we might fail, set the output parameters to default values first. - *type = kPublicKeyTypeUnknown; - *size_bits = 0; - - SecKeyRef key; - OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key); - if (status) { - NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status; - return; - } - ScopedCFTypeRef<SecKeyRef> scoped_key(key); - - const CSSM_KEY* cssm_key; - status = SecKeyGetCSSMKey(key, &cssm_key); - if (status) { - NOTREACHED() << "SecKeyGetCSSMKey failed: " << status; - return; - } - - *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits; - - switch (cssm_key->KeyHeader.AlgorithmId) { - case CSSM_ALGID_RSA: - *type = kPublicKeyTypeRSA; - break; - case CSSM_ALGID_DSA: - *type = kPublicKeyTypeDSA; - break; - case CSSM_ALGID_ECDSA: - *type = kPublicKeyTypeECDSA; - break; - case CSSM_ALGID_DH: - *type = kPublicKeyTypeDH; - break; - default: - *type = kPublicKeyTypeUnknown; - *size_bits = 0; - break; - } -} - -} // namespace net |