Home | History | Annotate | Download | only in cert
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/cert/x509_certificate.h"
      6 
      7 #include <CommonCrypto/CommonDigest.h>
      8 #include <CoreServices/CoreServices.h>
      9 #include <Security/Security.h>
     10 
     11 #include <vector>
     12 
     13 #include "base/lazy_instance.h"
     14 #include "base/logging.h"
     15 #include "base/mac/mac_logging.h"
     16 #include "base/mac/scoped_cftyperef.h"
     17 #include "base/memory/singleton.h"
     18 #include "base/pickle.h"
     19 #include "base/sha1.h"
     20 #include "base/strings/string_piece.h"
     21 #include "base/strings/sys_string_conversions.h"
     22 #include "base/synchronization/lock.h"
     23 #include "crypto/cssm_init.h"
     24 #include "crypto/mac_security_services_lock.h"
     25 #include "net/cert/x509_util_mac.h"
     26 
     27 using base::ScopedCFTypeRef;
     28 using base::Time;
     29 
     30 namespace net {
     31 
     32 namespace {
     33 
     34 void GetCertDistinguishedName(
     35     const x509_util::CSSMCachedCertificate& cached_cert,
     36     const CSSM_OID* oid,
     37     CertPrincipal* result) {
     38   x509_util::CSSMFieldValue distinguished_name;
     39   OSStatus status = cached_cert.GetField(oid, &distinguished_name);
     40   if (status || !distinguished_name.field())
     41     return;
     42   result->ParseDistinguishedName(distinguished_name.field()->Data,
     43                                  distinguished_name.field()->Length);
     44 }
     45 
     46 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle,
     47                                const std::vector<std::string>& issuers) {
     48   x509_util::CSSMCachedCertificate cached_cert;
     49   if (cached_cert.Init(cert_handle) != CSSM_OK)
     50     return false;
     51 
     52   x509_util::CSSMFieldValue distinguished_name;
     53   OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd,
     54                                          &distinguished_name);
     55   if (status || !distinguished_name.field())
     56     return false;
     57 
     58   base::StringPiece name_piece(
     59       reinterpret_cast<const char*>(distinguished_name.field()->Data),
     60       static_cast<size_t>(distinguished_name.field()->Length));
     61 
     62   for (std::vector<std::string>::const_iterator it = issuers.begin();
     63        it != issuers.end(); ++it) {
     64     base::StringPiece issuer_piece(*it);
     65     if (name_piece == issuer_piece)
     66       return true;
     67   }
     68 
     69   return false;
     70 }
     71 
     72 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
     73                        const CSSM_OID* oid,
     74                        Time* result) {
     75   *result = Time::Time();
     76 
     77   x509_util::CSSMFieldValue field;
     78   OSStatus status = cached_cert.GetField(oid, &field);
     79   if (status)
     80     return;
     81 
     82   const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>();
     83   if (x509_time->timeType != BER_TAG_UTC_TIME &&
     84       x509_time->timeType != BER_TAG_GENERALIZED_TIME) {
     85     LOG(ERROR) << "Unsupported date/time format "
     86                << x509_time->timeType;
     87     return;
     88   }
     89 
     90   base::StringPiece time_string(
     91       reinterpret_cast<const char*>(x509_time->time.Data),
     92       x509_time->time.Length);
     93   CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ?
     94       CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
     95   if (!ParseCertificateDate(time_string, format, result))
     96     LOG(ERROR) << "Invalid certificate date/time " << time_string;
     97 }
     98 
     99 std::string GetCertSerialNumber(
    100     const x509_util::CSSMCachedCertificate& cached_cert) {
    101   x509_util::CSSMFieldValue serial_number;
    102   OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber,
    103                                          &serial_number);
    104   if (status || !serial_number.field())
    105     return std::string();
    106 
    107   return std::string(
    108       reinterpret_cast<const char*>(serial_number.field()->Data),
    109       serial_number.field()->Length);
    110 }
    111 
    112 // Returns true if |purpose| is listed as allowed in |usage|. This
    113 // function also considers the "Any" purpose. If the attribute is
    114 // present and empty, we return false.
    115 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage,
    116                             const CSSM_OID* purpose) {
    117   for (unsigned p = 0; p < usage->numPurposes; ++p) {
    118     if (CSSMOIDEqual(&usage->purposes[p], purpose))
    119       return true;
    120     if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
    121       return true;
    122   }
    123   return false;
    124 }
    125 
    126 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
    127 // return true if it is.
    128 //
    129 // On OS X, SecCertificateCreateFromData() does not return any errors if
    130 // called with invalid data, as long as data is present. The actual decoding
    131 // of the certificate does not happen until an API that requires a CSSM
    132 // handle is called. While SecCertificateGetCLHandle is the most likely
    133 // candidate, as it performs the parsing, it does not check whether the
    134 // parsing was actually successful. Instead, SecCertificateGetSubject is
    135 // used (supported since 10.3), as a means to check that the certificate
    136 // parsed as a valid X.509 certificate.
    137 bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
    138   const CSSM_X509_NAME* sanity_check = NULL;
    139   OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check);
    140   return status == noErr && sanity_check;
    141 }
    142 
    143 // Parses |data| of length |length|, attempting to decode it as the specified
    144 // |format|. If |data| is in the specified format, any certificates contained
    145 // within are stored into |output|.
    146 void AddCertificatesFromBytes(const char* data, size_t length,
    147                               SecExternalFormat format,
    148                               X509Certificate::OSCertHandles* output) {
    149   SecExternalFormat input_format = format;
    150   ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
    151       kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
    152       kCFAllocatorNull));
    153 
    154   CFArrayRef items = NULL;
    155   OSStatus status;
    156   {
    157     base::AutoLock lock(crypto::GetMacSecurityServicesLock());
    158     status = SecKeychainItemImport(local_data, NULL, &input_format,
    159                                    NULL, 0, NULL, NULL, &items);
    160   }
    161 
    162   if (status) {
    163     OSSTATUS_DLOG(WARNING, status)
    164         << "Unable to import items from data of length " << length;
    165     return;
    166   }
    167 
    168   ScopedCFTypeRef<CFArrayRef> scoped_items(items);
    169   CFTypeID cert_type_id = SecCertificateGetTypeID();
    170 
    171   for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
    172     SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
    173         const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
    174 
    175     // While inputFormat implies only certificates will be imported, if/when
    176     // other formats (eg: PKCS#12) are supported, this may also include
    177     // private keys or other items types, so filter appropriately.
    178     if (CFGetTypeID(item) == cert_type_id) {
    179       SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item);
    180       // OS X ignores |input_format| if it detects that |local_data| is PEM
    181       // encoded, attempting to decode data based on internal rules for PEM
    182       // block headers. If a PKCS#7 blob is encoded with a PEM block of
    183       // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
    184       // based on the decoded data. If this happens, the certificate should
    185       // not be included in |output|. Because |output| is empty,
    186       // CreateCertificateListfromBytes will use PEMTokenizer to decode the
    187       // data. When called again with the decoded data, OS X will honor
    188       // |input_format|, causing decode to succeed. On OS X 10.6, the data
    189       // is properly decoded as a PKCS#7, whether PEM or not, which avoids
    190       // the need to fallback to internal decoding.
    191       if (IsValidOSCertHandle(cert)) {
    192         CFRetain(cert);
    193         output->push_back(cert);
    194       }
    195     }
    196   }
    197 }
    198 
    199 }  // namespace
    200 
    201 void X509Certificate::Initialize() {
    202   x509_util::CSSMCachedCertificate cached_cert;
    203   if (cached_cert.Init(cert_handle_) == CSSM_OK) {
    204     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
    205                              &subject_);
    206     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
    207                              &issuer_);
    208     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
    209                       &valid_start_);
    210     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
    211                       &valid_expiry_);
    212     serial_number_ = GetCertSerialNumber(cached_cert);
    213   }
    214 
    215   fingerprint_ = CalculateFingerprint(cert_handle_);
    216   ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
    217 }
    218 
    219 bool X509Certificate::IsIssuedByEncoded(
    220     const std::vector<std::string>& valid_issuers) {
    221   if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
    222     return true;
    223 
    224   for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
    225        it != intermediate_ca_certs_.end(); ++it) {
    226     if (IsCertIssuerInEncodedList(*it, valid_issuers))
    227       return true;
    228   }
    229   return false;
    230 }
    231 
    232 void X509Certificate::GetSubjectAltName(
    233     std::vector<std::string>* dns_names,
    234     std::vector<std::string>* ip_addrs) const {
    235   if (dns_names)
    236     dns_names->clear();
    237   if (ip_addrs)
    238     ip_addrs->clear();
    239 
    240   x509_util::CSSMCachedCertificate cached_cert;
    241   OSStatus status = cached_cert.Init(cert_handle_);
    242   if (status)
    243     return;
    244   x509_util::CSSMFieldValue subject_alt_name;
    245   status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
    246   if (status || !subject_alt_name.field())
    247     return;
    248   const CSSM_X509_EXTENSION* cssm_ext =
    249       subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
    250   if (!cssm_ext || !cssm_ext->value.parsedValue)
    251     return;
    252   const CE_GeneralNames* alt_name =
    253       reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
    254 
    255   for (size_t name = 0; name < alt_name->numNames; ++name) {
    256     const CE_GeneralName& name_struct = alt_name->generalName[name];
    257     const CSSM_DATA& name_data = name_struct.name;
    258     // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
    259     // respectively, both of which can be byte copied from
    260     // CSSM_DATA::data into the appropriate output vector.
    261     if (dns_names && name_struct.nameType == GNT_DNSName) {
    262       dns_names->push_back(std::string(
    263           reinterpret_cast<const char*>(name_data.Data),
    264           name_data.Length));
    265     } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
    266       ip_addrs->push_back(std::string(
    267           reinterpret_cast<const char*>(name_data.Data),
    268           name_data.Length));
    269     }
    270   }
    271 }
    272 
    273 // static
    274 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
    275                                     std::string* encoded) {
    276   CSSM_DATA der_data;
    277   if (!cert_handle || SecCertificateGetData(cert_handle, &der_data) != noErr)
    278     return false;
    279   encoded->assign(reinterpret_cast<char*>(der_data.Data),
    280                   der_data.Length);
    281   return true;
    282 }
    283 
    284 // static
    285 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
    286                                    X509Certificate::OSCertHandle b) {
    287   DCHECK(a && b);
    288   if (a == b)
    289     return true;
    290   if (CFEqual(a, b))
    291     return true;
    292   CSSM_DATA a_data, b_data;
    293   return SecCertificateGetData(a, &a_data) == noErr &&
    294       SecCertificateGetData(b, &b_data) == noErr &&
    295       a_data.Length == b_data.Length &&
    296       memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
    297 }
    298 
    299 // static
    300 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
    301     const char* data, int length) {
    302   CSSM_DATA cert_data;
    303   cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
    304   cert_data.Length = length;
    305 
    306   OSCertHandle cert_handle = NULL;
    307   OSStatus status = SecCertificateCreateFromData(&cert_data,
    308                                                  CSSM_CERT_X_509v3,
    309                                                  CSSM_CERT_ENCODING_DER,
    310                                                  &cert_handle);
    311   if (status != noErr)
    312     return NULL;
    313   if (!IsValidOSCertHandle(cert_handle)) {
    314     CFRelease(cert_handle);
    315     return NULL;
    316   }
    317   return cert_handle;
    318 }
    319 
    320 // static
    321 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
    322     const char* data, int length, Format format) {
    323   OSCertHandles results;
    324 
    325   switch (format) {
    326     case FORMAT_SINGLE_CERTIFICATE: {
    327       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
    328       if (handle)
    329         results.push_back(handle);
    330       break;
    331     }
    332     case FORMAT_PKCS7:
    333       AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
    334       break;
    335     default:
    336       NOTREACHED() << "Certificate format " << format << " unimplemented";
    337       break;
    338   }
    339 
    340   return results;
    341 }
    342 
    343 // static
    344 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
    345     OSCertHandle handle) {
    346   if (!handle)
    347     return NULL;
    348   return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
    349 }
    350 
    351 // static
    352 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
    353   if (cert_handle)
    354     CFRelease(cert_handle);
    355 }
    356 
    357 // static
    358 SHA1HashValue X509Certificate::CalculateFingerprint(
    359     OSCertHandle cert) {
    360   SHA1HashValue sha1;
    361   memset(sha1.data, 0, sizeof(sha1.data));
    362 
    363   CSSM_DATA cert_data;
    364   OSStatus status = SecCertificateGetData(cert, &cert_data);
    365   if (status)
    366     return sha1;
    367 
    368   DCHECK(cert_data.Data);
    369   DCHECK_NE(cert_data.Length, 0U);
    370 
    371   CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
    372 
    373   return sha1;
    374 }
    375 
    376 // static
    377 SHA1HashValue X509Certificate::CalculateCAFingerprint(
    378     const OSCertHandles& intermediates) {
    379   SHA1HashValue sha1;
    380   memset(sha1.data, 0, sizeof(sha1.data));
    381 
    382   // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
    383   // we don't check their return values.
    384   CC_SHA1_CTX sha1_ctx;
    385   CC_SHA1_Init(&sha1_ctx);
    386   CSSM_DATA cert_data;
    387   for (size_t i = 0; i < intermediates.size(); ++i) {
    388     OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
    389     if (status)
    390       return sha1;
    391     CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
    392   }
    393   CC_SHA1_Final(sha1.data, &sha1_ctx);
    394 
    395   return sha1;
    396 }
    397 
    398 bool X509Certificate::SupportsSSLClientAuth() const {
    399   x509_util::CSSMCachedCertificate cached_cert;
    400   OSStatus status = cached_cert.Init(cert_handle_);
    401   if (status)
    402     return false;
    403 
    404   // RFC5280 says to take the intersection of the two extensions.
    405   //
    406   // Our underlying crypto libraries don't expose
    407   // ClientCertificateType, so for now we will not support fixed
    408   // Diffie-Hellman mechanisms. For rsa_sign, we need the
    409   // digitalSignature bit.
    410   //
    411   // In particular, if a key has the nonRepudiation bit and not the
    412   // digitalSignature one, we will not offer it to the user.
    413   x509_util::CSSMFieldValue key_usage;
    414   status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
    415   if (status == CSSM_OK && key_usage.field()) {
    416     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
    417     const CE_KeyUsage* key_usage_value =
    418         reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
    419     if (!((*key_usage_value) & CE_KU_DigitalSignature))
    420       return false;
    421   }
    422 
    423   status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
    424   if (status == CSSM_OK && key_usage.field()) {
    425     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
    426     const CE_ExtendedKeyUsage* ext_key_usage =
    427         reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
    428     if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
    429       return false;
    430   }
    431   return true;
    432 }
    433 
    434 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
    435   CFMutableArrayRef cert_list =
    436       CFArrayCreateMutable(kCFAllocatorDefault, 0,
    437                            &kCFTypeArrayCallBacks);
    438   if (!cert_list)
    439     return NULL;
    440 
    441   CFArrayAppendValue(cert_list, os_cert_handle());
    442   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
    443     CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
    444 
    445   return cert_list;
    446 }
    447 
    448 // static
    449 X509Certificate::OSCertHandle
    450 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
    451   const char* data;
    452   int length;
    453   if (!pickle_iter->ReadData(&data, &length))
    454     return NULL;
    455 
    456   return CreateOSCertHandleFromBytes(data, length);
    457 }
    458 
    459 // static
    460 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
    461                                                 Pickle* pickle) {
    462   CSSM_DATA cert_data;
    463   OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
    464   if (status)
    465     return false;
    466 
    467   return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
    468                            cert_data.Length);
    469 }
    470 
    471 // static
    472 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
    473                                        size_t* size_bits,
    474                                        PublicKeyType* type) {
    475   // Since we might fail, set the output parameters to default values first.
    476   *type = kPublicKeyTypeUnknown;
    477   *size_bits = 0;
    478 
    479   SecKeyRef key;
    480   OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
    481   if (status) {
    482     NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
    483     return;
    484   }
    485   ScopedCFTypeRef<SecKeyRef> scoped_key(key);
    486 
    487   const CSSM_KEY* cssm_key;
    488   status = SecKeyGetCSSMKey(key, &cssm_key);
    489   if (status) {
    490     NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
    491     return;
    492   }
    493 
    494   *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
    495 
    496   switch (cssm_key->KeyHeader.AlgorithmId) {
    497     case CSSM_ALGID_RSA:
    498       *type = kPublicKeyTypeRSA;
    499       break;
    500     case CSSM_ALGID_DSA:
    501       *type = kPublicKeyTypeDSA;
    502       break;
    503     case CSSM_ALGID_ECDSA:
    504       *type = kPublicKeyTypeECDSA;
    505       break;
    506     case CSSM_ALGID_DH:
    507       *type = kPublicKeyTypeDH;
    508       break;
    509     default:
    510       *type = kPublicKeyTypeUnknown;
    511       *size_bits = 0;
    512       break;
    513   }
    514 }
    515 
    516 }  // namespace net
    517