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