| OLD | NEW | 
|---|
|  | (Empty) | 
| 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/base/x509_certificate.h" |  | 
| 6 |  | 
| 7 #include <CommonCrypto/CommonDigest.h> |  | 
| 8 #include <CoreServices/CoreServices.h> |  | 
| 9 #include <Security/Security.h> |  | 
| 10 #include <time.h> |  | 
| 11 |  | 
| 12 #include <vector> |  | 
| 13 |  | 
| 14 #include "base/lazy_instance.h" |  | 
| 15 #include "base/logging.h" |  | 
| 16 #include "base/mac/mac_logging.h" |  | 
| 17 #include "base/mac/scoped_cftyperef.h" |  | 
| 18 #include "base/memory/singleton.h" |  | 
| 19 #include "base/pickle.h" |  | 
| 20 #include "base/sha1.h" |  | 
| 21 #include "base/string_piece.h" |  | 
| 22 #include "base/synchronization/lock.h" |  | 
| 23 #include "base/sys_string_conversions.h" |  | 
| 24 #include "crypto/cssm_init.h" |  | 
| 25 #include "crypto/mac_security_services_lock.h" |  | 
| 26 #include "crypto/nss_util.h" |  | 
| 27 #include "crypto/rsa_private_key.h" |  | 
| 28 #include "net/base/x509_util_mac.h" |  | 
| 29 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" |  | 
| 30 |  | 
| 31 using base::mac::ScopedCFTypeRef; |  | 
| 32 using base::Time; |  | 
| 33 |  | 
| 34 namespace net { |  | 
| 35 |  | 
| 36 namespace { |  | 
| 37 |  | 
| 38 void GetCertDistinguishedName( |  | 
| 39     const x509_util::CSSMCachedCertificate& cached_cert, |  | 
| 40     const CSSM_OID* oid, |  | 
| 41     CertPrincipal* result) { |  | 
| 42   x509_util::CSSMFieldValue distinguished_name; |  | 
| 43   OSStatus status = cached_cert.GetField(oid, &distinguished_name); |  | 
| 44   if (status || !distinguished_name.field()) |  | 
| 45     return; |  | 
| 46   result->ParseDistinguishedName(distinguished_name.field()->Data, |  | 
| 47                                  distinguished_name.field()->Length); |  | 
| 48 } |  | 
| 49 |  | 
| 50 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle, |  | 
| 51                                const std::vector<std::string>& issuers) { |  | 
| 52   x509_util::CSSMCachedCertificate cached_cert; |  | 
| 53   if (cached_cert.Init(cert_handle) != CSSM_OK) |  | 
| 54     return false; |  | 
| 55 |  | 
| 56   x509_util::CSSMFieldValue distinguished_name; |  | 
| 57   OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd, |  | 
| 58                                          &distinguished_name); |  | 
| 59   if (status || !distinguished_name.field()) |  | 
| 60     return false; |  | 
| 61 |  | 
| 62   base::StringPiece name_piece( |  | 
| 63       reinterpret_cast<const char*>(distinguished_name.field()->Data), |  | 
| 64       static_cast<size_t>(distinguished_name.field()->Length)); |  | 
| 65 |  | 
| 66   for (std::vector<std::string>::const_iterator it = issuers.begin(); |  | 
| 67        it != issuers.end(); ++it) { |  | 
| 68     base::StringPiece issuer_piece(*it); |  | 
| 69     if (name_piece == issuer_piece) |  | 
| 70       return true; |  | 
| 71   } |  | 
| 72 |  | 
| 73   return false; |  | 
| 74 } |  | 
| 75 |  | 
| 76 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert, |  | 
| 77                        const CSSM_OID* oid, |  | 
| 78                        Time* result) { |  | 
| 79   *result = Time::Time(); |  | 
| 80 |  | 
| 81   x509_util::CSSMFieldValue field; |  | 
| 82   OSStatus status = cached_cert.GetField(oid, &field); |  | 
| 83   if (status) |  | 
| 84     return; |  | 
| 85 |  | 
| 86   const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>(); |  | 
| 87   if (x509_time->timeType != BER_TAG_UTC_TIME && |  | 
| 88       x509_time->timeType != BER_TAG_GENERALIZED_TIME) { |  | 
| 89     LOG(ERROR) << "Unsupported date/time format " |  | 
| 90                << x509_time->timeType; |  | 
| 91     return; |  | 
| 92   } |  | 
| 93 |  | 
| 94   base::StringPiece time_string( |  | 
| 95       reinterpret_cast<const char*>(x509_time->time.Data), |  | 
| 96       x509_time->time.Length); |  | 
| 97   CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? |  | 
| 98       CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; |  | 
| 99   if (!ParseCertificateDate(time_string, format, result)) |  | 
| 100     LOG(ERROR) << "Invalid certificate date/time " << time_string; |  | 
| 101 } |  | 
| 102 |  | 
| 103 std::string GetCertSerialNumber( |  | 
| 104     const x509_util::CSSMCachedCertificate& cached_cert) { |  | 
| 105   x509_util::CSSMFieldValue serial_number; |  | 
| 106   OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, |  | 
| 107                                          &serial_number); |  | 
| 108   if (status || !serial_number.field()) |  | 
| 109     return std::string(); |  | 
| 110 |  | 
| 111   return std::string( |  | 
| 112       reinterpret_cast<const char*>(serial_number.field()->Data), |  | 
| 113       serial_number.field()->Length); |  | 
| 114 } |  | 
| 115 |  | 
| 116 // Gets the issuer for a given cert, starting with the cert itself and |  | 
| 117 // including the intermediate and finally root certificates (if any). |  | 
| 118 // This function calls SecTrust but doesn't actually pay attention to the trust |  | 
| 119 // result: it shouldn't be used to determine trust, just to traverse the chain. |  | 
| 120 // Caller is responsible for releasing the value stored into *out_cert_chain. |  | 
| 121 OSStatus CopyCertChain(SecCertificateRef cert_handle, |  | 
| 122                        CFArrayRef* out_cert_chain) { |  | 
| 123   DCHECK(cert_handle); |  | 
| 124   DCHECK(out_cert_chain); |  | 
| 125 |  | 
| 126   // Create an SSL policy ref configured for client cert evaluation. |  | 
| 127   SecPolicyRef ssl_policy; |  | 
| 128   OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); |  | 
| 129   if (result) |  | 
| 130     return result; |  | 
| 131   ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); |  | 
| 132 |  | 
| 133   // Create a SecTrustRef. |  | 
| 134   ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( |  | 
| 135       NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), |  | 
| 136       1, &kCFTypeArrayCallBacks)); |  | 
| 137   SecTrustRef trust_ref = NULL; |  | 
| 138   { |  | 
| 139     base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |  | 
| 140     result = SecTrustCreateWithCertificates(input_certs, ssl_policy, |  | 
| 141                                             &trust_ref); |  | 
| 142   } |  | 
| 143   if (result) |  | 
| 144     return result; |  | 
| 145   ScopedCFTypeRef<SecTrustRef> trust(trust_ref); |  | 
| 146 |  | 
| 147   // Evaluate trust, which creates the cert chain. |  | 
| 148   SecTrustResultType status; |  | 
| 149   CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; |  | 
| 150   { |  | 
| 151     base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |  | 
| 152     result = SecTrustEvaluate(trust, &status); |  | 
| 153   } |  | 
| 154   if (result) |  | 
| 155     return result; |  | 
| 156   { |  | 
| 157     base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |  | 
| 158     result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); |  | 
| 159   } |  | 
| 160   return result; |  | 
| 161 } |  | 
| 162 |  | 
| 163 // Returns true if |purpose| is listed as allowed in |usage|. This |  | 
| 164 // function also considers the "Any" purpose. If the attribute is |  | 
| 165 // present and empty, we return false. |  | 
| 166 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, |  | 
| 167                             const CSSM_OID* purpose) { |  | 
| 168   for (unsigned p = 0; p < usage->numPurposes; ++p) { |  | 
| 169     if (CSSMOIDEqual(&usage->purposes[p], purpose)) |  | 
| 170       return true; |  | 
| 171     if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny)) |  | 
| 172       return true; |  | 
| 173   } |  | 
| 174   return false; |  | 
| 175 } |  | 
| 176 |  | 
| 177 // Test that a given |cert_handle| is actually a valid X.509 certificate, and |  | 
| 178 // return true if it is. |  | 
| 179 // |  | 
| 180 // On OS X, SecCertificateCreateFromData() does not return any errors if |  | 
| 181 // called with invalid data, as long as data is present. The actual decoding |  | 
| 182 // of the certificate does not happen until an API that requires a CSSM |  | 
| 183 // handle is called. While SecCertificateGetCLHandle is the most likely |  | 
| 184 // candidate, as it performs the parsing, it does not check whether the |  | 
| 185 // parsing was actually successful. Instead, SecCertificateGetSubject is |  | 
| 186 // used (supported since 10.3), as a means to check that the certificate |  | 
| 187 // parsed as a valid X.509 certificate. |  | 
| 188 bool IsValidOSCertHandle(SecCertificateRef cert_handle) { |  | 
| 189   const CSSM_X509_NAME* sanity_check = NULL; |  | 
| 190   OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check); |  | 
| 191   return status == noErr && sanity_check; |  | 
| 192 } |  | 
| 193 |  | 
| 194 // Parses |data| of length |length|, attempting to decode it as the specified |  | 
| 195 // |format|. If |data| is in the specified format, any certificates contained |  | 
| 196 // within are stored into |output|. |  | 
| 197 void AddCertificatesFromBytes(const char* data, size_t length, |  | 
| 198                               SecExternalFormat format, |  | 
| 199                               X509Certificate::OSCertHandles* output) { |  | 
| 200   SecExternalFormat input_format = format; |  | 
| 201   ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( |  | 
| 202       kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, |  | 
| 203       kCFAllocatorNull)); |  | 
| 204 |  | 
| 205   CFArrayRef items = NULL; |  | 
| 206   OSStatus status; |  | 
| 207   { |  | 
| 208     base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |  | 
| 209     status = SecKeychainItemImport(local_data, NULL, &input_format, |  | 
| 210                                    NULL, 0, NULL, NULL, &items); |  | 
| 211   } |  | 
| 212 |  | 
| 213   if (status) { |  | 
| 214     OSSTATUS_DLOG(WARNING, status) |  | 
| 215         << "Unable to import items from data of length " << length; |  | 
| 216     return; |  | 
| 217   } |  | 
| 218 |  | 
| 219   ScopedCFTypeRef<CFArrayRef> scoped_items(items); |  | 
| 220   CFTypeID cert_type_id = SecCertificateGetTypeID(); |  | 
| 221 |  | 
| 222   for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { |  | 
| 223     SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>( |  | 
| 224         const_cast<void*>(CFArrayGetValueAtIndex(items, i))); |  | 
| 225 |  | 
| 226     // While inputFormat implies only certificates will be imported, if/when |  | 
| 227     // other formats (eg: PKCS#12) are supported, this may also include |  | 
| 228     // private keys or other items types, so filter appropriately. |  | 
| 229     if (CFGetTypeID(item) == cert_type_id) { |  | 
| 230       SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item); |  | 
| 231       // OS X ignores |input_format| if it detects that |local_data| is PEM |  | 
| 232       // encoded, attempting to decode data based on internal rules for PEM |  | 
| 233       // block headers. If a PKCS#7 blob is encoded with a PEM block of |  | 
| 234       // CERTIFICATE, OS X 10.5 will return a single, invalid certificate |  | 
| 235       // based on the decoded data. If this happens, the certificate should |  | 
| 236       // not be included in |output|. Because |output| is empty, |  | 
| 237       // CreateCertificateListfromBytes will use PEMTokenizer to decode the |  | 
| 238       // data. When called again with the decoded data, OS X will honor |  | 
| 239       // |input_format|, causing decode to succeed. On OS X 10.6, the data |  | 
| 240       // is properly decoded as a PKCS#7, whether PEM or not, which avoids |  | 
| 241       // the need to fallback to internal decoding. |  | 
| 242       if (IsValidOSCertHandle(cert)) { |  | 
| 243         CFRetain(cert); |  | 
| 244         output->push_back(cert); |  | 
| 245       } |  | 
| 246     } |  | 
| 247   } |  | 
| 248 } |  | 
| 249 |  | 
| 250 struct CSSMOIDString { |  | 
| 251   const CSSM_OID* oid_; |  | 
| 252   std::string string_; |  | 
| 253 }; |  | 
| 254 |  | 
| 255 typedef std::vector<CSSMOIDString> CSSMOIDStringVector; |  | 
| 256 |  | 
| 257 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) { |  | 
| 258   struct OIDCSSMMap { |  | 
| 259     SECOidTag sec_OID_; |  | 
| 260     const CSSM_OID* cssm_OID_; |  | 
| 261   }; |  | 
| 262 |  | 
| 263   const OIDCSSMMap kOIDs[] = { |  | 
| 264       { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName }, |  | 
| 265       { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName }, |  | 
| 266       { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName }, |  | 
| 267       { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName }, |  | 
| 268       { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress }, |  | 
| 269       { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName }, |  | 
| 270       { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName }, |  | 
| 271       { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier }, |  | 
| 272       { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier }, |  | 
| 273       { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress }, |  | 
| 274   }; |  | 
| 275 |  | 
| 276   CERTRDN** rdns = name->rdns; |  | 
| 277   for (size_t rdn = 0; rdns[rdn]; ++rdn) { |  | 
| 278     CERTAVA** avas = rdns[rdn]->avas; |  | 
| 279     for (size_t pair = 0; avas[pair] != 0; ++pair) { |  | 
| 280       SECOidTag tag = CERT_GetAVATag(avas[pair]); |  | 
| 281       if (tag == SEC_OID_UNKNOWN) { |  | 
| 282         return false; |  | 
| 283       } |  | 
| 284       CSSMOIDString oidString; |  | 
| 285       bool found_oid = false; |  | 
| 286       for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) { |  | 
| 287         if (kOIDs[oid].sec_OID_ == tag) { |  | 
| 288           SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); |  | 
| 289           if (!decode_item) |  | 
| 290             return false; |  | 
| 291 |  | 
| 292           // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. |  | 
| 293           std::string value(reinterpret_cast<char*>(decode_item->data), |  | 
| 294                             decode_item->len); |  | 
| 295           oidString.oid_ = kOIDs[oid].cssm_OID_; |  | 
| 296           oidString.string_ = value; |  | 
| 297           out_values->push_back(oidString); |  | 
| 298           SECITEM_FreeItem(decode_item, PR_TRUE); |  | 
| 299           found_oid = true; |  | 
| 300           break; |  | 
| 301         } |  | 
| 302       } |  | 
| 303       if (!found_oid) { |  | 
| 304         DLOG(ERROR) << "Unrecognized OID: " << tag; |  | 
| 305       } |  | 
| 306     } |  | 
| 307   } |  | 
| 308   return true; |  | 
| 309 } |  | 
| 310 |  | 
| 311 class ScopedCertName { |  | 
| 312  public: |  | 
| 313   explicit ScopedCertName(CERTName* name) : name_(name) { } |  | 
| 314   ~ScopedCertName() { |  | 
| 315     if (name_) CERT_DestroyName(name_); |  | 
| 316   } |  | 
| 317   operator CERTName*() { return name_; } |  | 
| 318 |  | 
| 319  private: |  | 
| 320   CERTName* name_; |  | 
| 321 }; |  | 
| 322 |  | 
| 323 class ScopedEncodedCertResults { |  | 
| 324  public: |  | 
| 325   explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results) |  | 
| 326       : results_(results) { } |  | 
| 327   ~ScopedEncodedCertResults() { |  | 
| 328     if (results_) { |  | 
| 329       CSSM_ENCODED_CERT* encCert = |  | 
| 330           reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results); |  | 
| 331       for (uint32 i = 0; i < results_->NumberOfResults; i++) { |  | 
| 332         crypto::CSSMFree(encCert[i].CertBlob.Data); |  | 
| 333       } |  | 
| 334     } |  | 
| 335     crypto::CSSMFree(results_->Results); |  | 
| 336     crypto::CSSMFree(results_); |  | 
| 337   } |  | 
| 338 |  | 
| 339  private: |  | 
| 340   CSSM_TP_RESULT_SET* results_; |  | 
| 341 }; |  | 
| 342 |  | 
| 343 }  // namespace |  | 
| 344 |  | 
| 345 void X509Certificate::Initialize() { |  | 
| 346   x509_util::CSSMCachedCertificate cached_cert; |  | 
| 347   if (cached_cert.Init(cert_handle_) == CSSM_OK) { |  | 
| 348     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd, |  | 
| 349                              &subject_); |  | 
| 350     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd, |  | 
| 351                              &issuer_); |  | 
| 352     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore, |  | 
| 353                       &valid_start_); |  | 
| 354     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter, |  | 
| 355                       &valid_expiry_); |  | 
| 356     serial_number_ = GetCertSerialNumber(cached_cert); |  | 
| 357   } |  | 
| 358 |  | 
| 359   fingerprint_ = CalculateFingerprint(cert_handle_); |  | 
| 360   ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); |  | 
| 361 } |  | 
| 362 |  | 
| 363 bool X509Certificate::IsIssuedByEncoded( |  | 
| 364     const std::vector<std::string>& valid_issuers) { |  | 
| 365   if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers)) |  | 
| 366     return true; |  | 
| 367 |  | 
| 368   for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); |  | 
| 369        it != intermediate_ca_certs_.end(); ++it) { |  | 
| 370     if (IsCertIssuerInEncodedList(*it, valid_issuers)) |  | 
| 371       return true; |  | 
| 372   } |  | 
| 373   return false; |  | 
| 374 } |  | 
| 375 |  | 
| 376 // static |  | 
| 377 X509Certificate* X509Certificate::CreateSelfSigned( |  | 
| 378     crypto::RSAPrivateKey* key, |  | 
| 379     const std::string& subject, |  | 
| 380     uint32 serial_number, |  | 
| 381     base::TimeDelta valid_duration) { |  | 
| 382   DCHECK(key); |  | 
| 383   DCHECK(!subject.empty()); |  | 
| 384 |  | 
| 385   if (valid_duration.InSeconds() > kuint32max) { |  | 
| 386      LOG(ERROR) << "valid_duration too big " << valid_duration.InSeconds(); |  | 
| 387      valid_duration = base::TimeDelta::FromSeconds(kuint32max); |  | 
| 388   } |  | 
| 389 |  | 
| 390   // There is a comment in |  | 
| 391   // http://www.opensource.apple.com/source/security_certtool/security_certtool-
     31828/src/CertTool.cpp |  | 
| 392   // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have |  | 
| 393   // their high bit set. We will continue though and mask it out below. |  | 
| 394   if (serial_number & 0x80000000) |  | 
| 395     LOG(ERROR) << "serial_number has high bit set " << serial_number; |  | 
| 396 |  | 
| 397   // NSS is used to parse the subject string into a set of |  | 
| 398   // CSSM_OID/string pairs. There doesn't appear to be a system routine for |  | 
| 399   // parsing Distinguished Name strings. |  | 
| 400   crypto::EnsureNSSInit(); |  | 
| 401 |  | 
| 402   CSSMOIDStringVector subject_name_oids; |  | 
| 403   ScopedCertName subject_name( |  | 
| 404       CERT_AsciiToName(const_cast<char*>(subject.c_str()))); |  | 
| 405   if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) { |  | 
| 406     DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject; |  | 
| 407     return NULL; |  | 
| 408   } |  | 
| 409 |  | 
| 410   // Convert the map of oid/string pairs into an array of |  | 
| 411   // CSSM_APPLE_TP_NAME_OIDs. |  | 
| 412   std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names; |  | 
| 413   for (CSSMOIDStringVector::iterator iter = subject_name_oids.begin(); |  | 
| 414       iter != subject_name_oids.end(); ++iter) { |  | 
| 415     CSSM_APPLE_TP_NAME_OID cssm_subject_name; |  | 
| 416     cssm_subject_name.oid = iter->oid_; |  | 
| 417     cssm_subject_name.string = iter->string_.c_str(); |  | 
| 418     cssm_subject_names.push_back(cssm_subject_name); |  | 
| 419   } |  | 
| 420 |  | 
| 421   if (cssm_subject_names.empty()) { |  | 
| 422     DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject; |  | 
| 423     return NULL; |  | 
| 424   } |  | 
| 425 |  | 
| 426   // Set up a certificate request. |  | 
| 427   CSSM_APPLE_TP_CERT_REQUEST certReq; |  | 
| 428   memset(&certReq, 0, sizeof(certReq)); |  | 
| 429   certReq.cspHand = crypto::GetSharedCSPHandle(); |  | 
| 430   certReq.clHand = crypto::GetSharedCLHandle(); |  | 
| 431     // See comment about serial numbers above. |  | 
| 432   certReq.serialNumber = serial_number & 0x7fffffff; |  | 
| 433   certReq.numSubjectNames = cssm_subject_names.size(); |  | 
| 434   certReq.subjectNames = &cssm_subject_names[0]; |  | 
| 435   certReq.numIssuerNames = 0;  // Root. |  | 
| 436   certReq.issuerNames = NULL; |  | 
| 437   certReq.issuerNameX509 = NULL; |  | 
| 438   certReq.certPublicKey = key->public_key(); |  | 
| 439   certReq.issuerPrivateKey = key->key(); |  | 
| 440   // These are the Apple defaults. |  | 
| 441   certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; |  | 
| 442   certReq.signatureOid = CSSMOID_SHA1WithRSA; |  | 
| 443   certReq.notBefore = 0; |  | 
| 444   certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds()); |  | 
| 445   certReq.numExtensions = 0; |  | 
| 446   certReq.extensions = NULL; |  | 
| 447   certReq.challengeString = NULL; |  | 
| 448 |  | 
| 449   CSSM_TP_REQUEST_SET reqSet; |  | 
| 450   reqSet.NumberOfRequests = 1; |  | 
| 451   reqSet.Requests = &certReq; |  | 
| 452 |  | 
| 453   CSSM_FIELD policyId; |  | 
| 454   memset(&policyId, 0, sizeof(policyId)); |  | 
| 455   policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; |  | 
| 456 |  | 
| 457   CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext; |  | 
| 458   memset(&callerAuthContext, 0, sizeof(callerAuthContext)); |  | 
| 459   callerAuthContext.Policy.NumberOfPolicyIds = 1; |  | 
| 460   callerAuthContext.Policy.PolicyIds = &policyId; |  | 
| 461 |  | 
| 462   CSSM_TP_HANDLE tp_handle = crypto::GetSharedTPHandle(); |  | 
| 463   CSSM_DATA refId; |  | 
| 464   memset(&refId, 0, sizeof(refId)); |  | 
| 465   sint32 estTime; |  | 
| 466   CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL, |  | 
| 467       CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext, |  | 
| 468        &estTime, &refId); |  | 
| 469   if (crtn) { |  | 
| 470     DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn; |  | 
| 471     return NULL; |  | 
| 472   } |  | 
| 473 |  | 
| 474   CSSM_BOOL confirmRequired; |  | 
| 475   CSSM_TP_RESULT_SET* resultSet = NULL; |  | 
| 476   crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime, |  | 
| 477                                     &confirmRequired, &resultSet); |  | 
| 478   ScopedEncodedCertResults scopedResults(resultSet); |  | 
| 479   crypto::CSSMFree(refId.Data); |  | 
| 480   if (crtn) { |  | 
| 481     DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn; |  | 
| 482     return NULL; |  | 
| 483   } |  | 
| 484 |  | 
| 485   if (confirmRequired) { |  | 
| 486     // Potential leak here of resultSet. |confirmRequired| should never be |  | 
| 487     // true. |  | 
| 488     DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation"; |  | 
| 489     return NULL; |  | 
| 490   } |  | 
| 491 |  | 
| 492   if (resultSet->NumberOfResults != 1) { |  | 
| 493      DLOG(ERROR) << "Unexpected number of results: " |  | 
| 494                  << resultSet->NumberOfResults; |  | 
| 495     return NULL; |  | 
| 496   } |  | 
| 497 |  | 
| 498   CSSM_ENCODED_CERT* encCert = |  | 
| 499       reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results); |  | 
| 500   ScopedCFTypeRef<SecCertificateRef> scoped_cert; |  | 
| 501   SecCertificateRef certificate_ref = NULL; |  | 
| 502   OSStatus os_status = |  | 
| 503       SecCertificateCreateFromData(&encCert->CertBlob, encCert->CertType, |  | 
| 504                                    encCert->CertEncoding, &certificate_ref); |  | 
| 505   if (os_status != 0) { |  | 
| 506     OSSTATUS_DLOG(ERROR, os_status) << "SecCertificateCreateFromData failed"; |  | 
| 507     return NULL; |  | 
| 508   } |  | 
| 509   scoped_cert.reset(certificate_ref); |  | 
| 510 |  | 
| 511   return CreateFromHandle(scoped_cert, X509Certificate::OSCertHandles()); |  | 
| 512 } |  | 
| 513 |  | 
| 514 void X509Certificate::GetSubjectAltName( |  | 
| 515     std::vector<std::string>* dns_names, |  | 
| 516     std::vector<std::string>* ip_addrs) const { |  | 
| 517   if (dns_names) |  | 
| 518     dns_names->clear(); |  | 
| 519   if (ip_addrs) |  | 
| 520     ip_addrs->clear(); |  | 
| 521 |  | 
| 522   x509_util::CSSMCachedCertificate cached_cert; |  | 
| 523   OSStatus status = cached_cert.Init(cert_handle_); |  | 
| 524   if (status) |  | 
| 525     return; |  | 
| 526   x509_util::CSSMFieldValue subject_alt_name; |  | 
| 527   status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name); |  | 
| 528   if (status || !subject_alt_name.field()) |  | 
| 529     return; |  | 
| 530   const CSSM_X509_EXTENSION* cssm_ext = |  | 
| 531       subject_alt_name.GetAs<CSSM_X509_EXTENSION>(); |  | 
| 532   if (!cssm_ext || !cssm_ext->value.parsedValue) |  | 
| 533     return; |  | 
| 534   const CE_GeneralNames* alt_name = |  | 
| 535       reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue); |  | 
| 536 |  | 
| 537   for (size_t name = 0; name < alt_name->numNames; ++name) { |  | 
| 538     const CE_GeneralName& name_struct = alt_name->generalName[name]; |  | 
| 539     const CSSM_DATA& name_data = name_struct.name; |  | 
| 540     // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs |  | 
| 541     // respectively, both of which can be byte copied from |  | 
| 542     // CSSM_DATA::data into the appropriate output vector. |  | 
| 543     if (dns_names && name_struct.nameType == GNT_DNSName) { |  | 
| 544       dns_names->push_back(std::string( |  | 
| 545           reinterpret_cast<const char*>(name_data.Data), |  | 
| 546           name_data.Length)); |  | 
| 547     } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { |  | 
| 548       ip_addrs->push_back(std::string( |  | 
| 549           reinterpret_cast<const char*>(name_data.Data), |  | 
| 550           name_data.Length)); |  | 
| 551     } |  | 
| 552   } |  | 
| 553 } |  | 
| 554 |  | 
| 555 // static |  | 
| 556 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, |  | 
| 557                                     std::string* encoded) { |  | 
| 558   CSSM_DATA der_data; |  | 
| 559   if (SecCertificateGetData(cert_handle, &der_data) != noErr) |  | 
| 560     return false; |  | 
| 561   encoded->assign(reinterpret_cast<char*>(der_data.Data), |  | 
| 562                   der_data.Length); |  | 
| 563   return true; |  | 
| 564 } |  | 
| 565 |  | 
| 566 // static |  | 
| 567 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, |  | 
| 568                                    X509Certificate::OSCertHandle b) { |  | 
| 569   DCHECK(a && b); |  | 
| 570   if (a == b) |  | 
| 571     return true; |  | 
| 572   if (CFEqual(a, b)) |  | 
| 573     return true; |  | 
| 574   CSSM_DATA a_data, b_data; |  | 
| 575   return SecCertificateGetData(a, &a_data) == noErr && |  | 
| 576       SecCertificateGetData(b, &b_data) == noErr && |  | 
| 577       a_data.Length == b_data.Length && |  | 
| 578       memcmp(a_data.Data, b_data.Data, a_data.Length) == 0; |  | 
| 579 } |  | 
| 580 |  | 
| 581 // static |  | 
| 582 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |  | 
| 583     const char* data, int length) { |  | 
| 584   CSSM_DATA cert_data; |  | 
| 585   cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); |  | 
| 586   cert_data.Length = length; |  | 
| 587 |  | 
| 588   OSCertHandle cert_handle = NULL; |  | 
| 589   OSStatus status = SecCertificateCreateFromData(&cert_data, |  | 
| 590                                                  CSSM_CERT_X_509v3, |  | 
| 591                                                  CSSM_CERT_ENCODING_DER, |  | 
| 592                                                  &cert_handle); |  | 
| 593   if (status != noErr) |  | 
| 594     return NULL; |  | 
| 595   if (!IsValidOSCertHandle(cert_handle)) { |  | 
| 596     CFRelease(cert_handle); |  | 
| 597     return NULL; |  | 
| 598   } |  | 
| 599   return cert_handle; |  | 
| 600 } |  | 
| 601 |  | 
| 602 // static |  | 
| 603 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( |  | 
| 604     const char* data, int length, Format format) { |  | 
| 605   OSCertHandles results; |  | 
| 606 |  | 
| 607   switch (format) { |  | 
| 608     case FORMAT_SINGLE_CERTIFICATE: { |  | 
| 609       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); |  | 
| 610       if (handle) |  | 
| 611         results.push_back(handle); |  | 
| 612       break; |  | 
| 613     } |  | 
| 614     case FORMAT_PKCS7: |  | 
| 615       AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results); |  | 
| 616       break; |  | 
| 617     default: |  | 
| 618       NOTREACHED() << "Certificate format " << format << " unimplemented"; |  | 
| 619       break; |  | 
| 620   } |  | 
| 621 |  | 
| 622   return results; |  | 
| 623 } |  | 
| 624 |  | 
| 625 // static |  | 
| 626 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( |  | 
| 627     OSCertHandle handle) { |  | 
| 628   if (!handle) |  | 
| 629     return NULL; |  | 
| 630   return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); |  | 
| 631 } |  | 
| 632 |  | 
| 633 // static |  | 
| 634 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { |  | 
| 635   CFRelease(cert_handle); |  | 
| 636 } |  | 
| 637 |  | 
| 638 // static |  | 
| 639 SHA1HashValue X509Certificate::CalculateFingerprint( |  | 
| 640     OSCertHandle cert) { |  | 
| 641   SHA1HashValue sha1; |  | 
| 642   memset(sha1.data, 0, sizeof(sha1.data)); |  | 
| 643 |  | 
| 644   CSSM_DATA cert_data; |  | 
| 645   OSStatus status = SecCertificateGetData(cert, &cert_data); |  | 
| 646   if (status) |  | 
| 647     return sha1; |  | 
| 648 |  | 
| 649   DCHECK(cert_data.Data); |  | 
| 650   DCHECK_NE(cert_data.Length, 0U); |  | 
| 651 |  | 
| 652   CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); |  | 
| 653 |  | 
| 654   return sha1; |  | 
| 655 } |  | 
| 656 |  | 
| 657 // static |  | 
| 658 SHA1HashValue X509Certificate::CalculateCAFingerprint( |  | 
| 659     const OSCertHandles& intermediates) { |  | 
| 660   SHA1HashValue sha1; |  | 
| 661   memset(sha1.data, 0, sizeof(sha1.data)); |  | 
| 662 |  | 
| 663   // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so |  | 
| 664   // we don't check their return values. |  | 
| 665   CC_SHA1_CTX sha1_ctx; |  | 
| 666   CC_SHA1_Init(&sha1_ctx); |  | 
| 667   CSSM_DATA cert_data; |  | 
| 668   for (size_t i = 0; i < intermediates.size(); ++i) { |  | 
| 669     OSStatus status = SecCertificateGetData(intermediates[i], &cert_data); |  | 
| 670     if (status) |  | 
| 671       return sha1; |  | 
| 672     CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); |  | 
| 673   } |  | 
| 674   CC_SHA1_Final(sha1.data, &sha1_ctx); |  | 
| 675 |  | 
| 676   return sha1; |  | 
| 677 } |  | 
| 678 |  | 
| 679 bool X509Certificate::SupportsSSLClientAuth() const { |  | 
| 680   x509_util::CSSMCachedCertificate cached_cert; |  | 
| 681   OSStatus status = cached_cert.Init(cert_handle_); |  | 
| 682   if (status) |  | 
| 683     return false; |  | 
| 684 |  | 
| 685   // RFC5280 says to take the intersection of the two extensions. |  | 
| 686   // |  | 
| 687   // Our underlying crypto libraries don't expose |  | 
| 688   // ClientCertificateType, so for now we will not support fixed |  | 
| 689   // Diffie-Hellman mechanisms. For rsa_sign, we need the |  | 
| 690   // digitalSignature bit. |  | 
| 691   // |  | 
| 692   // In particular, if a key has the nonRepudiation bit and not the |  | 
| 693   // digitalSignature one, we will not offer it to the user. |  | 
| 694   x509_util::CSSMFieldValue key_usage; |  | 
| 695   status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); |  | 
| 696   if (status == CSSM_OK && key_usage.field()) { |  | 
| 697     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |  | 
| 698     const CE_KeyUsage* key_usage_value = |  | 
| 699         reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); |  | 
| 700     if (!((*key_usage_value) & CE_KU_DigitalSignature)) |  | 
| 701       return false; |  | 
| 702   } |  | 
| 703 |  | 
| 704   status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); |  | 
| 705   if (status == CSSM_OK && key_usage.field()) { |  | 
| 706     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |  | 
| 707     const CE_ExtendedKeyUsage* ext_key_usage = |  | 
| 708         reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); |  | 
| 709     if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) |  | 
| 710       return false; |  | 
| 711   } |  | 
| 712   return true; |  | 
| 713 } |  | 
| 714 |  | 
| 715 CFArrayRef X509Certificate::CreateClientCertificateChain() const { |  | 
| 716   // Initialize the result array with just the IdentityRef of the receiver: |  | 
| 717   SecIdentityRef identity; |  | 
| 718   OSStatus result; |  | 
| 719   { |  | 
| 720     base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |  | 
| 721     result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); |  | 
| 722   } |  | 
| 723   if (result) { |  | 
| 724     OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; |  | 
| 725     return NULL; |  | 
| 726   } |  | 
| 727   ScopedCFTypeRef<CFMutableArrayRef> chain( |  | 
| 728       CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); |  | 
| 729   CFArrayAppendValue(chain, identity); |  | 
| 730 |  | 
| 731   CFArrayRef cert_chain = NULL; |  | 
| 732   result = CopyCertChain(cert_handle_, &cert_chain); |  | 
| 733   ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); |  | 
| 734   if (result) { |  | 
| 735     OSSTATUS_LOG(ERROR, result) << "CreateIdentityCertificateChain error"; |  | 
| 736     return chain.release(); |  | 
| 737   } |  | 
| 738 |  | 
| 739   // Append the intermediate certs from SecTrust to the result array: |  | 
| 740   if (cert_chain) { |  | 
| 741     int chain_count = CFArrayGetCount(cert_chain); |  | 
| 742     if (chain_count > 1) { |  | 
| 743       CFArrayAppendArray(chain, |  | 
| 744                          cert_chain, |  | 
| 745                          CFRangeMake(1, chain_count - 1)); |  | 
| 746     } |  | 
| 747   } |  | 
| 748 |  | 
| 749   return chain.release(); |  | 
| 750 } |  | 
| 751 |  | 
| 752 CFArrayRef X509Certificate::CreateOSCertChainForCert() const { |  | 
| 753   CFMutableArrayRef cert_list = |  | 
| 754       CFArrayCreateMutable(kCFAllocatorDefault, 0, |  | 
| 755                            &kCFTypeArrayCallBacks); |  | 
| 756   if (!cert_list) |  | 
| 757     return NULL; |  | 
| 758 |  | 
| 759   CFArrayAppendValue(cert_list, os_cert_handle()); |  | 
| 760   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) |  | 
| 761     CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); |  | 
| 762 |  | 
| 763   return cert_list; |  | 
| 764 } |  | 
| 765 |  | 
| 766 // static |  | 
| 767 X509Certificate::OSCertHandle |  | 
| 768 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { |  | 
| 769   const char* data; |  | 
| 770   int length; |  | 
| 771   if (!pickle_iter->ReadData(&data, &length)) |  | 
| 772     return NULL; |  | 
| 773 |  | 
| 774   return CreateOSCertHandleFromBytes(data, length); |  | 
| 775 } |  | 
| 776 |  | 
| 777 // static |  | 
| 778 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, |  | 
| 779                                                 Pickle* pickle) { |  | 
| 780   CSSM_DATA cert_data; |  | 
| 781   OSStatus status = SecCertificateGetData(cert_handle, &cert_data); |  | 
| 782   if (status) |  | 
| 783     return false; |  | 
| 784 |  | 
| 785   return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), |  | 
| 786                            cert_data.Length); |  | 
| 787 } |  | 
| 788 |  | 
| 789 // static |  | 
| 790 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, |  | 
| 791                                        size_t* size_bits, |  | 
| 792                                        PublicKeyType* type) { |  | 
| 793   // Since we might fail, set the output parameters to default values first. |  | 
| 794   *type = kPublicKeyTypeUnknown; |  | 
| 795   *size_bits = 0; |  | 
| 796 |  | 
| 797   SecKeyRef key; |  | 
| 798   OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key); |  | 
| 799   if (status) { |  | 
| 800     NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status; |  | 
| 801     return; |  | 
| 802   } |  | 
| 803   ScopedCFTypeRef<SecKeyRef> scoped_key(key); |  | 
| 804 |  | 
| 805   const CSSM_KEY* cssm_key; |  | 
| 806   status = SecKeyGetCSSMKey(key, &cssm_key); |  | 
| 807   if (status) { |  | 
| 808     NOTREACHED() << "SecKeyGetCSSMKey failed: " << status; |  | 
| 809     return; |  | 
| 810   } |  | 
| 811 |  | 
| 812   *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits; |  | 
| 813 |  | 
| 814   switch (cssm_key->KeyHeader.AlgorithmId) { |  | 
| 815     case CSSM_ALGID_RSA: |  | 
| 816       *type = kPublicKeyTypeRSA; |  | 
| 817       break; |  | 
| 818     case CSSM_ALGID_DSA: |  | 
| 819       *type = kPublicKeyTypeDSA; |  | 
| 820       break; |  | 
| 821     case CSSM_ALGID_ECDSA: |  | 
| 822       *type = kPublicKeyTypeECDSA; |  | 
| 823       break; |  | 
| 824     case CSSM_ALGID_DH: |  | 
| 825       *type = kPublicKeyTypeDH; |  | 
| 826       break; |  | 
| 827     default: |  | 
| 828       *type = kPublicKeyTypeUnknown; |  | 
| 829       *size_bits = 0; |  | 
| 830       break; |  | 
| 831   } |  | 
| 832 } |  | 
| 833 |  | 
| 834 }  // namespace net |  | 
| OLD | NEW | 
|---|