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