Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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 <time.h>
      9 
     10 #include "base/scoped_cftyperef.h"
     11 #include "base/logging.h"
     12 #include "base/pickle.h"
     13 #include "net/base/cert_status_flags.h"
     14 #include "net/base/cert_verify_result.h"
     15 #include "net/base/net_errors.h"
     16 
     17 using base::Time;
     18 
     19 namespace net {
     20 
     21 class MacTrustedCertificates {
     22  public:
     23   // Sets the trusted root certificate used by tests. Call with |cert| set
     24   // to NULL to clear the test certificate.
     25   void SetTestCertificate(X509Certificate* cert) {
     26     AutoLock lock(lock_);
     27     test_certificate_ = cert;
     28   }
     29 
     30   // Returns an array containing the trusted certificates for use with
     31   // SecTrustSetAnchorCertificates(). Returns NULL if the system-supplied
     32   // list of trust anchors is acceptable (that is, there is not test
     33   // certificate available). Ownership follows the Create Rule (caller
     34   // is responsible for calling CFRelease on the non-NULL result).
     35   CFArrayRef CopyTrustedCertificateArray() {
     36     AutoLock lock(lock_);
     37 
     38     if (!test_certificate_)
     39       return NULL;
     40 
     41     // Failure to copy the anchor certificates or add the test certificate
     42     // is non-fatal; SecTrustEvaluate() will use the system anchors instead.
     43     CFArrayRef anchor_array;
     44     OSStatus status = SecTrustCopyAnchorCertificates(&anchor_array);
     45     if (status)
     46       return NULL;
     47     scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array);
     48     CFMutableArrayRef merged_array = CFArrayCreateMutableCopy(
     49         kCFAllocatorDefault, 0, anchor_array);
     50     if (!merged_array)
     51       return NULL;
     52     CFArrayAppendValue(merged_array, test_certificate_->os_cert_handle());
     53 
     54     return merged_array;
     55   }
     56  private:
     57   friend struct DefaultSingletonTraits<MacTrustedCertificates>;
     58 
     59   // Obtain an instance of MacTrustedCertificates via the singleton
     60   // interface.
     61   MacTrustedCertificates() : test_certificate_(NULL) { }
     62 
     63   // An X509Certificate object that may be appended to the list of
     64   // system trusted anchors.
     65   scoped_refptr<X509Certificate> test_certificate_;
     66 
     67   // The trusted cache may be accessed from multiple threads.
     68   mutable Lock lock_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(MacTrustedCertificates);
     71 };
     72 
     73 void SetMacTestCertificate(X509Certificate* cert) {
     74   Singleton<MacTrustedCertificates>::get()->SetTestCertificate(cert);
     75 }
     76 
     77 namespace {
     78 
     79 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef,
     80                                                       CFDictionaryRef*);
     81 
     82 inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) {
     83   return oid1->Length == oid2->Length &&
     84       (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0);
     85 }
     86 
     87 int NetErrorFromOSStatus(OSStatus status) {
     88   switch (status) {
     89     case noErr:
     90       return OK;
     91     case errSecNotAvailable:
     92     case errSecNoCertificateModule:
     93     case errSecNoPolicyModule:
     94       return ERR_NOT_IMPLEMENTED;
     95     case errSecAuthFailed:
     96       return ERR_ACCESS_DENIED;
     97     default:
     98       LOG(ERROR) << "Unknown error " << status << " mapped to net::ERR_FAILED";
     99       return ERR_FAILED;
    100   }
    101 }
    102 
    103 int CertStatusFromOSStatus(OSStatus status) {
    104   switch (status) {
    105     case noErr:
    106       return 0;
    107 
    108     case CSSMERR_TP_INVALID_ANCHOR_CERT:
    109     case CSSMERR_TP_NOT_TRUSTED:
    110     case CSSMERR_TP_INVALID_CERT_AUTHORITY:
    111       return CERT_STATUS_AUTHORITY_INVALID;
    112 
    113     case CSSMERR_TP_CERT_EXPIRED:
    114     case CSSMERR_TP_CERT_NOT_VALID_YET:
    115       // "Expired" and "not yet valid" collapse into a single status.
    116       return CERT_STATUS_DATE_INVALID;
    117 
    118     case CSSMERR_TP_CERT_REVOKED:
    119     case CSSMERR_TP_CERT_SUSPENDED:
    120       return CERT_STATUS_REVOKED;
    121 
    122     case CSSMERR_APPLETP_HOSTNAME_MISMATCH:
    123       return CERT_STATUS_COMMON_NAME_INVALID;
    124 
    125     case CSSMERR_APPLETP_CRL_NOT_FOUND:
    126     case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK:
    127     case CSSMERR_APPLETP_OCSP_UNAVAILABLE:
    128       return CERT_STATUS_NO_REVOCATION_MECHANISM;
    129 
    130     case CSSMERR_APPLETP_CRL_NOT_TRUSTED:
    131     case CSSMERR_APPLETP_CRL_SERVER_DOWN:
    132     case CSSMERR_APPLETP_CRL_NOT_VALID_YET:
    133     case CSSMERR_APPLETP_NETWORK_FAILURE:
    134     case CSSMERR_APPLETP_OCSP_BAD_RESPONSE:
    135     case CSSMERR_APPLETP_OCSP_NO_SIGNER:
    136     case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED:
    137     case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED:
    138     case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ:
    139     case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR:
    140     case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER:
    141       // We asked for a revocation check, but didn't get it.
    142       return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
    143 
    144     default:
    145       // Failure was due to something Chromium doesn't define a
    146       // specific status for (such as basic constraints violation, or
    147       // unknown critical extension)
    148       return CERT_STATUS_INVALID;
    149   }
    150 }
    151 
    152 bool OverrideHostnameMismatch(const std::string& hostname,
    153                               std::vector<std::string>* dns_names) {
    154   // SecTrustEvaluate() does not check dotted IP addresses. If
    155   // hostname is provided as, say, 127.0.0.1, then the error
    156   // CSSMERR_APPLETP_HOSTNAME_MISMATCH will always be returned,
    157   // even if the certificate contains 127.0.0.1 as one of its names.
    158   // We, however, want to allow that behavior. SecTrustEvaluate()
    159   // only checks for digits and dots when considering whether a
    160   // hostname is an IP address, so IPv6 and hex addresses go through
    161   // its normal comparison.
    162   bool is_dotted_ip = true;
    163   bool override_hostname_mismatch = false;
    164   for (std::string::const_iterator c = hostname.begin();
    165        c != hostname.end() && is_dotted_ip; ++c)
    166     is_dotted_ip = (*c >= '0' && *c <= '9') || *c == '.';
    167   if (is_dotted_ip) {
    168     for (std::vector<std::string>::const_iterator name = dns_names->begin();
    169          name != dns_names->end() && !override_hostname_mismatch; ++name)
    170       override_hostname_mismatch = (*name == hostname);
    171   }
    172   return override_hostname_mismatch;
    173 }
    174 
    175 void ParsePrincipal(const CSSM_X509_NAME* name,
    176                     X509Certificate::Principal* principal) {
    177   std::vector<std::string> common_names, locality_names, state_names,
    178       country_names;
    179 
    180   // TODO(jcampan): add business_category and serial_number.
    181   const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName,
    182                               &CSSMOID_LocalityName,
    183                               &CSSMOID_StateProvinceName,
    184                               &CSSMOID_CountryName,
    185                               &CSSMOID_StreetAddress,
    186                               &CSSMOID_OrganizationName,
    187                               &CSSMOID_OrganizationalUnitName,
    188                               &CSSMOID_DNQualifier };  // This should be "DC"
    189                                                        // but is undoubtedly
    190                                                        // wrong. TODO(avi):
    191                                                        // Find the right OID.
    192 
    193   std::vector<std::string>* values[] = {
    194       &common_names, &locality_names,
    195       &state_names, &country_names,
    196       &(principal->street_addresses),
    197       &(principal->organization_names),
    198       &(principal->organization_unit_names),
    199       &(principal->domain_components) };
    200   DCHECK(arraysize(kOIDs) == arraysize(values));
    201 
    202   for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
    203     CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
    204     for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
    205       CSSM_X509_TYPE_VALUE_PAIR pair_struct =
    206           rdn_struct.AttributeTypeAndValue[pair];
    207       for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
    208         if (CSSMOIDEqual(&pair_struct.type, kOIDs[oid])) {
    209           std::string value =
    210               std::string(reinterpret_cast<std::string::value_type*>
    211                               (pair_struct.value.Data),
    212                           pair_struct.value.Length);
    213           values[oid]->push_back(value);
    214           break;
    215         }
    216       }
    217     }
    218   }
    219 
    220   // We don't expect to have more than one CN, L, S, and C.
    221   std::vector<std::string>* single_value_lists[4] = {
    222       &common_names, &locality_names, &state_names, &country_names };
    223   std::string* single_values[4] = {
    224       &principal->common_name, &principal->locality_name,
    225       &principal->state_or_province_name, &principal->country_name };
    226   for (size_t i = 0; i < arraysize(single_value_lists); ++i) {
    227     DCHECK(single_value_lists[i]->size() <= 1);
    228     if (single_value_lists[i]->size() > 0)
    229       *(single_values[i]) = (*(single_value_lists[i]))[0];
    230   }
    231 }
    232 
    233 struct CSSMFields {
    234   CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {}
    235   ~CSSMFields() {
    236     if (cl_handle)
    237       CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields);
    238   }
    239 
    240   CSSM_CL_HANDLE cl_handle;
    241   uint32 num_of_fields;
    242   CSSM_FIELD_PTR fields;
    243 };
    244 
    245 OSStatus GetCertFields(X509Certificate::OSCertHandle cert_handle,
    246                        CSSMFields* fields) {
    247   DCHECK(cert_handle);
    248   DCHECK(fields);
    249 
    250   CSSM_DATA cert_data;
    251   OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
    252   if (status)
    253     return status;
    254 
    255   status = SecCertificateGetCLHandle(cert_handle, &fields->cl_handle);
    256   if (status) {
    257     DCHECK(!fields->cl_handle);
    258     return status;
    259   }
    260 
    261   status = CSSM_CL_CertGetAllFields(fields->cl_handle, &cert_data,
    262                                     &fields->num_of_fields, &fields->fields);
    263   return status;
    264 }
    265 
    266 void GetCertGeneralNamesForOID(X509Certificate::OSCertHandle cert_handle,
    267                                CSSM_OID oid, CE_GeneralNameType name_type,
    268                                std::vector<std::string>* result) {
    269   // For future extension: We only support general names of types
    270   // GNT_RFC822Name, GNT_DNSName or GNT_URI.
    271   DCHECK(name_type == GNT_RFC822Name ||
    272          name_type == GNT_DNSName ||
    273          name_type == GNT_URI);
    274 
    275   CSSMFields fields;
    276   OSStatus status = GetCertFields(cert_handle, &fields);
    277   if (status)
    278     return;
    279 
    280   for (size_t field = 0; field < fields.num_of_fields; ++field) {
    281     if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
    282       CSSM_X509_EXTENSION_PTR cssm_ext =
    283           (CSSM_X509_EXTENSION_PTR)fields.fields[field].FieldValue.Data;
    284       CE_GeneralNames* alt_name =
    285           (CE_GeneralNames*) cssm_ext->value.parsedValue;
    286 
    287       for (size_t name = 0; name < alt_name->numNames; ++name) {
    288         const CE_GeneralName& name_struct = alt_name->generalName[name];
    289         // All of the general name types we support are encoded as
    290         // IA5String. In general, we should be switching off
    291         // |name_struct.nameType| and doing type-appropriate conversions. See
    292         // certextensions.h and the comment immediately preceding
    293         // CE_GeneralNameType for more information.
    294         if (name_struct.nameType == name_type) {
    295           const CSSM_DATA& name_data = name_struct.name;
    296           std::string value =
    297           std::string(reinterpret_cast<std::string::value_type*>
    298                       (name_data.Data),
    299                       name_data.Length);
    300           result->push_back(value);
    301         }
    302       }
    303     }
    304   }
    305 }
    306 
    307 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle,
    308                        CSSM_OID oid, Time* result) {
    309   *result = Time::Time();
    310 
    311   CSSMFields fields;
    312   OSStatus status = GetCertFields(cert_handle, &fields);
    313   if (status)
    314     return;
    315 
    316   for (size_t field = 0; field < fields.num_of_fields; ++field) {
    317     if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
    318       CSSM_X509_TIME* x509_time =
    319           reinterpret_cast<CSSM_X509_TIME *>
    320             (fields.fields[field].FieldValue.Data);
    321       std::string time_string =
    322           std::string(reinterpret_cast<std::string::value_type*>
    323                       (x509_time->time.Data),
    324                       x509_time->time.Length);
    325 
    326       DCHECK(x509_time->timeType == BER_TAG_UTC_TIME ||
    327              x509_time->timeType == BER_TAG_GENERALIZED_TIME);
    328 
    329       struct tm time;
    330       const char* parse_string;
    331       if (x509_time->timeType == BER_TAG_UTC_TIME)
    332         parse_string = "%y%m%d%H%M%SZ";
    333       else if (x509_time->timeType == BER_TAG_GENERALIZED_TIME)
    334         parse_string = "%y%m%d%H%M%SZ";
    335       else {
    336         // Those are the only two BER tags for time; if neither are used then
    337         // this is a rather broken cert.
    338         return;
    339       }
    340 
    341       strptime(time_string.c_str(), parse_string, &time);
    342 
    343       Time::Exploded exploded;
    344       exploded.year         = time.tm_year + 1900;
    345       exploded.month        = time.tm_mon + 1;
    346       exploded.day_of_week  = time.tm_wday;
    347       exploded.day_of_month = time.tm_mday;
    348       exploded.hour         = time.tm_hour;
    349       exploded.minute       = time.tm_min;
    350       exploded.second       = time.tm_sec;
    351       exploded.millisecond  = 0;
    352 
    353       *result = Time::FromUTCExploded(exploded);
    354       break;
    355     }
    356   }
    357 }
    358 
    359 }  // namespace
    360 
    361 void X509Certificate::Initialize() {
    362   const CSSM_X509_NAME* name;
    363   OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
    364   if (!status) {
    365     ParsePrincipal(name, &subject_);
    366   }
    367   status = SecCertificateGetIssuer(cert_handle_, &name);
    368   if (!status) {
    369     ParsePrincipal(name, &issuer_);
    370   }
    371 
    372   GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore,
    373                     &valid_start_);
    374   GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter,
    375                     &valid_expiry_);
    376 
    377   fingerprint_ = CalculateFingerprint(cert_handle_);
    378 
    379   // Store the certificate in the cache in case we need it later.
    380   X509Certificate::Cache::GetInstance()->Insert(this);
    381 }
    382 
    383 // static
    384 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
    385                                                    void** pickle_iter) {
    386   const char* data;
    387   int length;
    388   if (!pickle.ReadData(pickle_iter, &data, &length))
    389     return NULL;
    390 
    391   return CreateFromBytes(data, length);
    392 }
    393 
    394 void X509Certificate::Persist(Pickle* pickle) {
    395   CSSM_DATA cert_data;
    396   OSStatus status = SecCertificateGetData(cert_handle_, &cert_data);
    397   if (status) {
    398     NOTREACHED();
    399     return;
    400   }
    401 
    402   pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), cert_data.Length);
    403 }
    404 
    405 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
    406   dns_names->clear();
    407 
    408   GetCertGeneralNamesForOID(cert_handle_, CSSMOID_SubjectAltName, GNT_DNSName,
    409                             dns_names);
    410 
    411   if (dns_names->empty())
    412     dns_names->push_back(subject_.common_name);
    413 }
    414 
    415 int X509Certificate::Verify(const std::string& hostname, int flags,
    416                             CertVerifyResult* verify_result) const {
    417   verify_result->Reset();
    418 
    419   // Create an SSL SecPolicyRef, and configure it to perform hostname
    420   // validation. The hostname check does 99% of what we want, with the
    421   // exception of dotted IPv4 addreses, which we handle ourselves below.
    422   SecPolicySearchRef ssl_policy_search_ref = NULL;
    423   OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3,
    424                                           &CSSMOID_APPLE_TP_SSL,
    425                                           NULL,
    426                                           &ssl_policy_search_ref);
    427   if (status)
    428     return NetErrorFromOSStatus(status);
    429   scoped_cftyperef<SecPolicySearchRef>
    430       scoped_ssl_policy_search_ref(ssl_policy_search_ref);
    431   SecPolicyRef ssl_policy = NULL;
    432   status = SecPolicySearchCopyNext(ssl_policy_search_ref, &ssl_policy);
    433   if (status)
    434     return NetErrorFromOSStatus(status);
    435   scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
    436   CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { CSSM_APPLE_TP_SSL_OPTS_VERSION };
    437   tp_ssl_options.ServerName = hostname.data();
    438   tp_ssl_options.ServerNameLen = hostname.size();
    439   CSSM_DATA tp_ssl_options_data_value;
    440   tp_ssl_options_data_value.Data = reinterpret_cast<uint8*>(&tp_ssl_options);
    441   tp_ssl_options_data_value.Length = sizeof(tp_ssl_options);
    442   status = SecPolicySetValue(ssl_policy, &tp_ssl_options_data_value);
    443   if (status)
    444     return NetErrorFromOSStatus(status);
    445 
    446   // Create and configure a SecTrustRef, which takes our certificate(s)
    447   // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
    448   // array of certificates, the first of which is the certificate we're
    449   // verifying, and the subsequent (optional) certificates are used for
    450   // chain building.
    451   CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
    452                                                       &kCFTypeArrayCallBacks);
    453   if (!cert_array)
    454     return ERR_OUT_OF_MEMORY;
    455   scoped_cftyperef<CFArrayRef> scoped_cert_array(cert_array);
    456   CFArrayAppendValue(cert_array, cert_handle_);
    457   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
    458     CFArrayAppendValue(cert_array, intermediate_ca_certs_[i]);
    459 
    460   SecTrustRef trust_ref = NULL;
    461   status = SecTrustCreateWithCertificates(cert_array, ssl_policy, &trust_ref);
    462   if (status)
    463     return NetErrorFromOSStatus(status);
    464   scoped_cftyperef<SecTrustRef> scoped_trust_ref(trust_ref);
    465 
    466   // Set the trusted anchor certificates for the SecTrustRef by merging the
    467   // system trust anchors and the test root certificate.
    468   CFArrayRef anchor_array =
    469       Singleton<MacTrustedCertificates>::get()->CopyTrustedCertificateArray();
    470   scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array);
    471   if (anchor_array) {
    472     status = SecTrustSetAnchorCertificates(trust_ref, anchor_array);
    473     if (status)
    474       return NetErrorFromOSStatus(status);
    475   }
    476 
    477   if (flags & VERIFY_REV_CHECKING_ENABLED) {
    478     // When called with VERIFY_REV_CHECKING_ENABLED, we ask SecTrustEvaluate()
    479     // to apply OCSP and CRL checking, but we're still subject to the global
    480     // settings, which are configured in the Keychain Access application (in
    481     // the Certificates tab of the Preferences dialog). If the user has
    482     // revocation disabled (which is the default), then we will get
    483     // kSecTrustResultRecoverableTrustFailure back from SecTrustEvaluate()
    484     // with one of a number of sub error codes indicating that revocation
    485     // checking did not occur. In that case, we'll set our own result to include
    486     // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION.
    487     //
    488     // NOTE: This does not apply to EV certificates, which always get
    489     // revocation checks regardless of the global settings.
    490     verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
    491     CSSM_APPLE_TP_ACTION_DATA tp_action_data = { CSSM_APPLE_TP_ACTION_VERSION };
    492     tp_action_data.ActionFlags = CSSM_TP_ACTION_REQUIRE_REV_PER_CERT;
    493     CFDataRef action_data_ref =
    494         CFDataCreate(NULL, reinterpret_cast<UInt8*>(&tp_action_data),
    495                      sizeof(tp_action_data));
    496     if (!action_data_ref)
    497       return ERR_OUT_OF_MEMORY;
    498     scoped_cftyperef<CFDataRef> scoped_action_data_ref(action_data_ref);
    499     status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT,
    500                                    action_data_ref);
    501     if (status)
    502       return NetErrorFromOSStatus(status);
    503   }
    504 
    505   // Verify the certificate. A non-zero result from SecTrustGetResult()
    506   // indicates that some fatal error occurred and the chain couldn't be
    507   // processed, not that the chain contains no errors. We need to examine the
    508   // output of SecTrustGetResult() to determine that.
    509   SecTrustResultType trust_result;
    510   status = SecTrustEvaluate(trust_ref, &trust_result);
    511   if (status)
    512     return NetErrorFromOSStatus(status);
    513   CFArrayRef completed_chain = NULL;
    514   CSSM_TP_APPLE_EVIDENCE_INFO* chain_info;
    515   status = SecTrustGetResult(trust_ref, &trust_result, &completed_chain,
    516                              &chain_info);
    517   if (status)
    518     return NetErrorFromOSStatus(status);
    519   scoped_cftyperef<CFArrayRef> scoped_completed_chain(completed_chain);
    520 
    521   // Evaluate the results
    522   OSStatus cssm_result;
    523   bool got_certificate_error = false;
    524   switch (trust_result) {
    525     case kSecTrustResultUnspecified:
    526     case kSecTrustResultProceed:
    527       // Certificate chain is valid and trusted ("unspecified" indicates that
    528       // the user has not explicitly set a trust setting)
    529       break;
    530 
    531     case kSecTrustResultDeny:
    532     case kSecTrustResultConfirm:
    533       // Certificate chain is explicitly untrusted. For kSecTrustResultConfirm,
    534       // we're following what Secure Transport does and treating it as
    535       // "deny".
    536       verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
    537       break;
    538 
    539     case kSecTrustResultRecoverableTrustFailure:
    540       // Certificate chain has a failure that can be overridden by the user.
    541       status = SecTrustGetCssmResultCode(trust_ref, &cssm_result);
    542       if (status)
    543         return NetErrorFromOSStatus(status);
    544       switch (cssm_result) {
    545         case CSSMERR_TP_NOT_TRUSTED:
    546         case CSSMERR_TP_INVALID_ANCHOR_CERT:
    547           verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
    548           break;
    549         case CSSMERR_TP_CERT_EXPIRED:
    550         case CSSMERR_TP_CERT_NOT_VALID_YET:
    551           verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
    552           break;
    553         case CSSMERR_TP_CERT_REVOKED:
    554         case CSSMERR_TP_CERT_SUSPENDED:
    555           verify_result->cert_status |= CERT_STATUS_REVOKED;
    556           break;
    557         default:
    558           // Look for specific per-certificate errors below.
    559           break;
    560       }
    561       // Walk the chain of error codes in the CSSM_TP_APPLE_EVIDENCE_INFO
    562       // structure which can catch multiple errors from each certificate.
    563       for (CFIndex index = 0, chain_count = CFArrayGetCount(completed_chain);
    564            index < chain_count; ++index) {
    565         if (chain_info[index].StatusBits & CSSM_CERT_STATUS_EXPIRED ||
    566             chain_info[index].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET)
    567           verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
    568         for (uint32 status_code_index = 0;
    569              status_code_index < chain_info[index].NumStatusCodes;
    570              ++status_code_index) {
    571           got_certificate_error = true;
    572           int cert_status = CertStatusFromOSStatus(
    573               chain_info[index].StatusCodes[status_code_index]);
    574           if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) {
    575             std::vector<std::string> names;
    576             GetDNSNames(&names);
    577             if (OverrideHostnameMismatch(hostname, &names)) {
    578               cert_status = 0;
    579             }
    580           }
    581           verify_result->cert_status |= cert_status;
    582         }
    583       }
    584       // Be paranoid and ensure that we recorded at least one certificate
    585       // status on receiving kSecTrustResultRecoverableTrustFailure. The
    586       // call to SecTrustGetCssmResultCode() should pick up when the chain
    587       // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO
    588       // should pick up everything else, but let's be safe.
    589       if (!verify_result->cert_status && !got_certificate_error) {
    590         verify_result->cert_status |= CERT_STATUS_INVALID;
    591         NOTREACHED();
    592       }
    593       break;
    594 
    595     default:
    596       status = SecTrustGetCssmResultCode(trust_ref, &cssm_result);
    597       if (status)
    598         return NetErrorFromOSStatus(status);
    599       verify_result->cert_status |= CertStatusFromOSStatus(cssm_result);
    600       if (!verify_result->cert_status) {
    601         verify_result->cert_status |= CERT_STATUS_INVALID;
    602       }
    603       break;
    604   }
    605 
    606   // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be
    607   // compatible with Windows, which in turn implements this behavior to be
    608   // compatible with WinHTTP, which doesn't report this error (bug 3004).
    609   verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM;
    610 
    611   if (IsCertStatusError(verify_result->cert_status))
    612     return MapCertStatusToNetError(verify_result->cert_status);
    613 
    614   if (flags & VERIFY_EV_CERT) {
    615     // Determine the certificate's EV status using SecTrustCopyExtendedResult(),
    616     // which we need to look up because the function wasn't added until
    617     // Mac OS X 10.5.7.
    618     CFBundleRef bundle =
    619         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
    620     if (bundle) {
    621       SecTrustCopyExtendedResultFuncPtr copy_extended_result =
    622           reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>(
    623               CFBundleGetFunctionPointerForName(bundle,
    624                   CFSTR("SecTrustCopyExtendedResult")));
    625       if (copy_extended_result) {
    626         CFDictionaryRef ev_dict = NULL;
    627         status = copy_extended_result(trust_ref, &ev_dict);
    628         if (!status && ev_dict) {
    629           // The returned dictionary contains the EV organization name from the
    630           // server certificate, which we don't need at this point (and we
    631           // have other ways to access, anyway). All we care is that
    632           // SecTrustCopyExtendedResult() returned noErr and a non-NULL
    633           // dictionary.
    634           CFRelease(ev_dict);
    635           verify_result->cert_status |= CERT_STATUS_IS_EV;
    636         }
    637       }
    638     }
    639   }
    640 
    641   return OK;
    642 }
    643 
    644 bool X509Certificate::VerifyEV() const {
    645   // We don't call this private method, but we do need to implement it because
    646   // it's defined in x509_certificate.h. We perform EV checking in the
    647   // Verify() above.
    648   NOTREACHED();
    649   return false;
    650 }
    651 
    652 // static
    653 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
    654     const char* data, int length) {
    655   CSSM_DATA cert_data;
    656   cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
    657   cert_data.Length = length;
    658 
    659   OSCertHandle cert_handle = NULL;
    660   OSStatus status = SecCertificateCreateFromData(&cert_data,
    661                                                  CSSM_CERT_X_509v3,
    662                                                  CSSM_CERT_ENCODING_BER,
    663                                                  &cert_handle);
    664   if (status)
    665     return NULL;
    666 
    667   return cert_handle;
    668 }
    669 
    670 // static
    671 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
    672   CFRelease(cert_handle);
    673 }
    674 
    675 // static
    676 X509Certificate::Fingerprint X509Certificate::CalculateFingerprint(
    677     OSCertHandle cert) {
    678   Fingerprint sha1;
    679   memset(sha1.data, 0, sizeof(sha1.data));
    680 
    681   CSSM_DATA cert_data;
    682   OSStatus status = SecCertificateGetData(cert, &cert_data);
    683   if (status)
    684     return sha1;
    685 
    686   DCHECK(NULL != cert_data.Data);
    687   DCHECK(0 != cert_data.Length);
    688 
    689   CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
    690 
    691   return sha1;
    692 }
    693 
    694 }  // namespace net
    695