15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CommonCrypto/CommonDigest.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CoreServices/CoreServices.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Security/Security.h>
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sha1.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/cssm_init.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/mac_security_services_lock.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_mac.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::ScopedCFTypeRef;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetCertDistinguishedName(
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const x509_util::CSSMCachedCertificate& cached_cert,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CSSM_OID* oid,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CertPrincipal* result) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMFieldValue distinguished_name;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = cached_cert.GetField(oid, &distinguished_name);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status || !distinguished_name.field())
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->ParseDistinguishedName(distinguished_name.field()->Data,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 distinguished_name.field()->Length);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle,
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const std::vector<std::string>& issuers) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  x509_util::CSSMCachedCertificate cached_cert;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cached_cert.Init(cert_handle) != CSSM_OK)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  x509_util::CSSMFieldValue distinguished_name;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd,
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         &distinguished_name);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status || !distinguished_name.field())
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::StringPiece name_piece(
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<const char*>(distinguished_name.field()->Data),
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<size_t>(distinguished_name.field()->Length));
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<std::string>::const_iterator it = issuers.begin();
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != issuers.end(); ++it) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::StringPiece issuer_piece(*it);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name_piece == issuer_piece)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const CSSM_OID* oid,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       Time* result) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *result = Time::Time();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMFieldValue field;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = cached_cert.GetField(oid, &field);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x509_time->timeType != BER_TAG_UTC_TIME &&
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x509_time->timeType != BER_TAG_GENERALIZED_TIME) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unsupported date/time format "
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << x509_time->timeType;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringPiece time_string(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const char*>(x509_time->time.Data),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x509_time->time.Length);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ?
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ParseCertificateDate(time_string, format, result))
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Invalid certificate date/time " << time_string;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetCertSerialNumber(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const x509_util::CSSMCachedCertificate& cached_cert) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMFieldValue serial_number;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &serial_number);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status || !serial_number.field())
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::string(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const char*>(serial_number.field()->Data),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      serial_number.field()->Length);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |purpose| is listed as allowed in |usage|. This
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function also considers the "Any" purpose. If the attribute is
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// present and empty, we return false.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const CSSM_OID* purpose) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned p = 0; p < usage->numPurposes; ++p) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CSSMOIDEqual(&usage->purposes[p], purpose))
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that a given |cert_handle| is actually a valid X.509 certificate, and
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// return true if it is.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On OS X, SecCertificateCreateFromData() does not return any errors if
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// called with invalid data, as long as data is present. The actual decoding
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the certificate does not happen until an API that requires a CSSM
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handle is called. While SecCertificateGetCLHandle is the most likely
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// candidate, as it performs the parsing, it does not check whether the
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parsing was actually successful. Instead, SecCertificateGetSubject is
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used (supported since 10.3), as a means to check that the certificate
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parsed as a valid X.509 certificate.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_X509_NAME* sanity_check = NULL;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return status == noErr && sanity_check;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parses |data| of length |length|, attempting to decode it as the specified
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |format|. If |data| is in the specified format, any certificates contained
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// within are stored into |output|.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddCertificatesFromBytes(const char* data, size_t length,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              SecExternalFormat format,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              X509Certificate::OSCertHandles* output) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecExternalFormat input_format = format;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kCFAllocatorNull));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFArrayRef items = NULL;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(crypto::GetMacSecurityServicesLock());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status = SecKeychainItemImport(local_data, NULL, &input_format,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   NULL, 0, NULL, NULL, &items);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSSTATUS_DLOG(WARNING, status)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "Unable to import items from data of length " << length;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCFTypeRef<CFArrayRef> scoped_items(items);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFTypeID cert_type_id = SecCertificateGetTypeID();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // While inputFormat implies only certificates will be imported, if/when
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // other formats (eg: PKCS#12) are supported, this may also include
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // private keys or other items types, so filter appropriately.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CFGetTypeID(item) == cert_type_id) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // OS X ignores |input_format| if it detects that |local_data| is PEM
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // encoded, attempting to decode data based on internal rules for PEM
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // block headers. If a PKCS#7 blob is encoded with a PEM block of
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // based on the decoded data. If this happens, the certificate should
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // not be included in |output|. Because |output| is empty,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // CreateCertificateListfromBytes will use PEMTokenizer to decode the
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // data. When called again with the decoded data, OS X will honor
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |input_format|, causing decode to succeed. On OS X 10.6, the data
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // is properly decoded as a PKCS#7, whether PEM or not, which avoids
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the need to fallback to internal decoding.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (IsValidOSCertHandle(cert)) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CFRetain(cert);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output->push_back(cert);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void X509Certificate::Initialize() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMCachedCertificate cached_cert;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cached_cert.Init(cert_handle_) == CSSM_OK) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &subject_);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &issuer_);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &valid_start_);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &valid_expiry_);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    serial_number_ = GetCertSerialNumber(cached_cert);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fingerprint_ = CalculateFingerprint(cert_handle_);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool X509Certificate::IsIssuedByEncoded(
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<std::string>& valid_issuers) {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != intermediate_ca_certs_.end(); ++it) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (IsCertIssuerInEncodedList(*it, valid_issuers))
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void X509Certificate::GetSubjectAltName(
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* dns_names,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* ip_addrs) const {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dns_names)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_names->clear();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ip_addrs)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ip_addrs->clear();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMCachedCertificate cached_cert;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = cached_cert.Init(cert_handle_);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMFieldValue subject_alt_name;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status || !subject_alt_name.field())
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_X509_EXTENSION* cssm_ext =
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cssm_ext || !cssm_ext->value.parsedValue)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CE_GeneralNames* alt_name =
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t name = 0; name < alt_name->numNames; ++name) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CE_GeneralName& name_struct = alt_name->generalName[name];
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CSSM_DATA& name_data = name_struct.name;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // respectively, both of which can be byte copied from
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // CSSM_DATA::data into the appropriate output vector.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dns_names && name_struct.nameType == GNT_DNSName) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dns_names->push_back(std::string(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reinterpret_cast<const char*>(name_data.Data),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name_data.Length));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ip_addrs->push_back(std::string(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reinterpret_cast<const char*>(name_data.Data),
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name_data.Length));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    std::string* encoded) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA der_data;
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!cert_handle || SecCertificateGetData(cert_handle, &der_data) != noErr)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  encoded->assign(reinterpret_cast<char*>(der_data.Data),
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  der_data.Length);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   X509Certificate::OSCertHandle b) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(a && b);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (a == b)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CFEqual(a, b))
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA a_data, b_data;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SecCertificateGetData(a, &a_data) == noErr &&
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SecCertificateGetData(b, &b_data) == noErr &&
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a_data.Length == b_data.Length &&
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* data, int length) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA cert_data;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cert_data.Length = length;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSCertHandle cert_handle = NULL;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = SecCertificateCreateFromData(&cert_data,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 CSSM_CERT_X_509v3,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 CSSM_CERT_ENCODING_DER,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &cert_handle);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != noErr)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidOSCertHandle(cert_handle)) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease(cert_handle);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cert_handle;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* data, int length, Format format) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSCertHandles results;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (format) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FORMAT_SINGLE_CERTIFICATE: {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handle)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        results.push_back(handle);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FORMAT_PKCS7:
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Certificate format " << format << " unimplemented";
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return results;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSCertHandle handle) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handle)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cert_handle)
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CFRelease(cert_handle);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SHA1HashValue X509Certificate::CalculateFingerprint(
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSCertHandle cert) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHA1HashValue sha1;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(sha1.data, 0, sizeof(sha1.data));
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA cert_data;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = SecCertificateGetData(cert, &cert_data);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sha1;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cert_data.Data);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(cert_data.Length, 0U);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sha1;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SHA1HashValue X509Certificate::CalculateCAFingerprint(
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const OSCertHandles& intermediates) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHA1HashValue sha1;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(sha1.data, 0, sizeof(sha1.data));
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we don't check their return values.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA1_CTX sha1_ctx;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA1_Init(&sha1_ctx);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA cert_data;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < intermediates.size(); ++i) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return sha1;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CC_SHA1_Final(sha1.data, &sha1_ctx);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sha1;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool X509Certificate::SupportsSSLClientAuth() const {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMCachedCertificate cached_cert;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = cached_cert.Init(cert_handle_);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RFC5280 says to take the intersection of the two extensions.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our underlying crypto libraries don't expose
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ClientCertificateType, so for now we will not support fixed
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Diffie-Hellman mechanisms. For rsa_sign, we need the
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // digitalSignature bit.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In particular, if a key has the nonRepudiation bit and not the
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // digitalSignature one, we will not offer it to the user.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x509_util::CSSMFieldValue key_usage;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == CSSM_OK && key_usage.field()) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CE_KeyUsage* key_usage_value =
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!((*key_usage_value) & CE_KU_DigitalSignature))
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == CSSM_OK && key_usage.field()) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CE_ExtendedKeyUsage* ext_key_usage =
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFMutableArrayRef cert_list =
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CFArrayCreateMutable(kCFAllocatorDefault, 0,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &kCFTypeArrayCallBacks);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cert_list)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFArrayAppendValue(cert_list, os_cert_handle());
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cert_list;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X509Certificate::OSCertHandle
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* data;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int length;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pickle_iter->ReadData(&data, &length))
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateOSCertHandleFromBytes(data, length);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                Pickle* pickle) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA cert_data;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           cert_data.Length);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       size_t* size_bits,
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       PublicKeyType* type) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we might fail, set the output parameters to default values first.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *type = kPublicKeyTypeUnknown;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *size_bits = 0;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeyRef key;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCFTypeRef<SecKeyRef> scoped_key(key);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_KEY* cssm_key;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = SecKeyGetCSSMKey(key, &cssm_key);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cssm_key->KeyHeader.AlgorithmId) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CSSM_ALGID_RSA:
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *type = kPublicKeyTypeRSA;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CSSM_ALGID_DSA:
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *type = kPublicKeyTypeDSA;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CSSM_ALGID_ECDSA:
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *type = kPublicKeyTypeECDSA;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CSSM_ALGID_DH:
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *type = kPublicKeyTypeDH;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *type = kPublicKeyTypeUnknown;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *size_bits = 0;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
517