root/net/cert/x509_certificate_ios.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsValidOSCertHandle
  2. Initialize
  3. IsIssuedByEncoded
  4. GetSubjectAltName
  5. GetDEREncoded
  6. IsSameOSCert
  7. CreateOSCertHandleFromBytes
  8. CreateOSCertHandlesFromBytes
  9. DupOSCertHandle
  10. FreeOSCertHandle
  11. CalculateFingerprint
  12. CalculateCAFingerprint
  13. ReadOSCertHandleFromPickle
  14. WriteOSCertHandleToPickle
  15. GetPublicKeyInfo

// 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) {
  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) {
  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

/* [<][>][^][v][top][bottom][index][help] */