| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
| 6 | 6 |
| 7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <Security/Security.h> | 8 #include <Security/Security.h> |
| 9 #include <time.h> | 9 #include <time.h> |
| 10 | 10 |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 name_type == GNT_URI); | 213 name_type == GNT_URI); |
| 214 | 214 |
| 215 CSSMFields fields; | 215 CSSMFields fields; |
| 216 OSStatus status = GetCertFields(cert_handle, &fields); | 216 OSStatus status = GetCertFields(cert_handle, &fields); |
| 217 if (status) | 217 if (status) |
| 218 return; | 218 return; |
| 219 | 219 |
| 220 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 220 for (size_t field = 0; field < fields.num_of_fields; ++field) { |
| 221 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { | 221 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { |
| 222 CSSM_X509_EXTENSION_PTR cssm_ext = | 222 CSSM_X509_EXTENSION_PTR cssm_ext = |
| 223 (CSSM_X509_EXTENSION_PTR)fields.fields[field].FieldValue.Data; | 223 reinterpret_cast<CSSM_X509_EXTENSION_PTR>( |
| 224 fields.fields[field].FieldValue.Data); |
| 224 CE_GeneralNames* alt_name = | 225 CE_GeneralNames* alt_name = |
| 225 (CE_GeneralNames*) cssm_ext->value.parsedValue; | 226 reinterpret_cast<CE_GeneralNames*>(cssm_ext->value.parsedValue); |
| 226 | 227 |
| 227 for (size_t name = 0; name < alt_name->numNames; ++name) { | 228 for (size_t name = 0; name < alt_name->numNames; ++name) { |
| 228 const CE_GeneralName& name_struct = alt_name->generalName[name]; | 229 const CE_GeneralName& name_struct = alt_name->generalName[name]; |
| 229 // All of the general name types we support are encoded as | 230 // All of the general name types we support are encoded as |
| 230 // IA5String. In general, we should be switching off | 231 // IA5String. In general, we should be switching off |
| 231 // |name_struct.nameType| and doing type-appropriate conversions. See | 232 // |name_struct.nameType| and doing type-appropriate conversions. See |
| 232 // certextensions.h and the comment immediately preceding | 233 // certextensions.h and the comment immediately preceding |
| 233 // CE_GeneralNameType for more information. | 234 // CE_GeneralNameType for more information. |
| 234 if (name_struct.nameType == name_type) { | 235 if (name_struct.nameType == name_type) { |
| 235 const CSSM_DATA& name_data = name_struct.name; | 236 const CSSM_DATA& name_data = name_struct.name; |
| 236 std::string value = | 237 std::string value = std::string( |
| 237 std::string(reinterpret_cast<std::string::value_type*> | 238 reinterpret_cast<const char*>(name_data.Data), |
| 238 (name_data.Data), | 239 name_data.Length); |
| 239 name_data.Length); | |
| 240 result->push_back(value); | 240 result->push_back(value); |
| 241 } | 241 } |
| 242 } | 242 } |
| 243 } | 243 } |
| 244 } | 244 } |
| 245 } | 245 } |
| 246 | 246 |
| 247 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle, | 247 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle, |
| 248 CSSM_OID oid, Time* result) { | 248 CSSM_OID oid, Time* result) { |
| 249 *result = Time::Time(); | 249 *result = Time::Time(); |
| 250 | 250 |
| 251 CSSMFields fields; | 251 CSSMFields fields; |
| 252 OSStatus status = GetCertFields(cert_handle, &fields); | 252 OSStatus status = GetCertFields(cert_handle, &fields); |
| 253 if (status) | 253 if (status) |
| 254 return; | 254 return; |
| 255 | 255 |
| 256 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 256 for (size_t field = 0; field < fields.num_of_fields; ++field) { |
| 257 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { | 257 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { |
| 258 CSSM_X509_TIME* x509_time = | 258 CSSM_X509_TIME* x509_time = reinterpret_cast<CSSM_X509_TIME*>( |
| 259 reinterpret_cast<CSSM_X509_TIME *> | 259 fields.fields[field].FieldValue.Data); |
| 260 (fields.fields[field].FieldValue.Data); | 260 if (x509_time->timeType != BER_TAG_UTC_TIME && |
| 261 std::string time_string = | 261 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { |
| 262 std::string(reinterpret_cast<std::string::value_type*> | 262 LOG(ERROR) << "Unsupported date/time format " |
| 263 (x509_time->time.Data), | 263 << x509_time->timeType; |
| 264 x509_time->time.Length); | |
| 265 | |
| 266 DCHECK(x509_time->timeType == BER_TAG_UTC_TIME || | |
| 267 x509_time->timeType == BER_TAG_GENERALIZED_TIME); | |
| 268 | |
| 269 struct tm time; | |
| 270 const char* parse_string; | |
| 271 if (x509_time->timeType == BER_TAG_UTC_TIME) | |
| 272 parse_string = "%y%m%d%H%M%SZ"; | |
| 273 else if (x509_time->timeType == BER_TAG_GENERALIZED_TIME) | |
| 274 parse_string = "%y%m%d%H%M%SZ"; | |
| 275 else { | |
| 276 // Those are the only two BER tags for time; if neither are used then | |
| 277 // this is a rather broken cert. | |
| 278 return; | 264 return; |
| 279 } | 265 } |
| 280 | 266 |
| 281 strptime(time_string.c_str(), parse_string, &time); | 267 base::StringPiece time_string( |
| 282 | 268 reinterpret_cast<const char*>(x509_time->time.Data), |
| 283 Time::Exploded exploded; | 269 x509_time->time.Length); |
| 284 exploded.year = time.tm_year + 1900; | 270 CertificateDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? |
| 285 exploded.month = time.tm_mon + 1; | 271 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; |
| 286 exploded.day_of_week = time.tm_wday; | 272 if (!ParseCertificateDate(time_string, format, result)) |
| 287 exploded.day_of_month = time.tm_mday; | 273 LOG(ERROR) << "Invalid certificate date/time " << time_string; |
| 288 exploded.hour = time.tm_hour; | 274 return; |
| 289 exploded.minute = time.tm_min; | |
| 290 exploded.second = time.tm_sec; | |
| 291 exploded.millisecond = 0; | |
| 292 | |
| 293 *result = Time::FromUTCExploded(exploded); | |
| 294 break; | |
| 295 } | 275 } |
| 296 } | 276 } |
| 297 } | 277 } |
| 298 | 278 |
| 299 // Creates a SecPolicyRef for the given OID, with optional value. | 279 // Creates a SecPolicyRef for the given OID, with optional value. |
| 300 OSStatus CreatePolicy(const CSSM_OID* policy_OID, | 280 OSStatus CreatePolicy(const CSSM_OID* policy_OID, |
| 301 void* option_data, | 281 void* option_data, |
| 302 size_t option_length, | 282 size_t option_length, |
| 303 SecPolicyRef* policy) { | 283 SecPolicyRef* policy) { |
| 304 SecPolicySearchRef search; | 284 SecPolicySearchRef search; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 325 return noErr; | 305 return noErr; |
| 326 } | 306 } |
| 327 | 307 |
| 328 // Gets the issuer for a given cert, starting with the cert itself and | 308 // Gets the issuer for a given cert, starting with the cert itself and |
| 329 // including the intermediate and finally root certificates (if any). | 309 // including the intermediate and finally root certificates (if any). |
| 330 // This function calls SecTrust but doesn't actually pay attention to the trust | 310 // This function calls SecTrust but doesn't actually pay attention to the trust |
| 331 // result: it shouldn't be used to determine trust, just to traverse the chain. | 311 // result: it shouldn't be used to determine trust, just to traverse the chain. |
| 332 // Caller is responsible for releasing the value stored into *out_cert_chain. | 312 // Caller is responsible for releasing the value stored into *out_cert_chain. |
| 333 OSStatus CopyCertChain(SecCertificateRef cert_handle, | 313 OSStatus CopyCertChain(SecCertificateRef cert_handle, |
| 334 CFArrayRef* out_cert_chain) { | 314 CFArrayRef* out_cert_chain) { |
| 335 DCHECK(cert_handle && out_cert_chain); | 315 DCHECK(cert_handle); |
| 316 DCHECK(out_cert_chain); |
| 336 // Create an SSL policy ref configured for client cert evaluation. | 317 // Create an SSL policy ref configured for client cert evaluation. |
| 337 SecPolicyRef ssl_policy; | 318 SecPolicyRef ssl_policy; |
| 338 OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy); | 319 OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy); |
| 339 if (result) | 320 if (result) |
| 340 return result; | 321 return result; |
| 341 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | 322 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); |
| 342 | 323 |
| 343 // Create a SecTrustRef. | 324 // Create a SecTrustRef. |
| 344 ScopedCFTypeRef<CFArrayRef> input_certs( | 325 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( |
| 345 CFArrayCreate(NULL, (const void**)&cert_handle, 1, | 326 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), |
| 346 &kCFTypeArrayCallBacks)); | 327 1, &kCFTypeArrayCallBacks)); |
| 347 SecTrustRef trust_ref = NULL; | 328 SecTrustRef trust_ref = NULL; |
| 348 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); | 329 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); |
| 349 if (result) | 330 if (result) |
| 350 return result; | 331 return result; |
| 351 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); | 332 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); |
| 352 | 333 |
| 353 // Evaluate trust, which creates the cert chain. | 334 // Evaluate trust, which creates the cert chain. |
| 354 SecTrustResultType status; | 335 SecTrustResultType status; |
| 355 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | 336 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; |
| 356 result = SecTrustEvaluate(trust, &status); | 337 result = SecTrustEvaluate(trust, &status); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 } | 372 } |
| 392 | 373 |
| 393 // Parses |data| of length |length|, attempting to decode it as the specified | 374 // Parses |data| of length |length|, attempting to decode it as the specified |
| 394 // |format|. If |data| is in the specified format, any certificates contained | 375 // |format|. If |data| is in the specified format, any certificates contained |
| 395 // within are stored into |output|. | 376 // within are stored into |output|. |
| 396 void AddCertificatesFromBytes(const char* data, size_t length, | 377 void AddCertificatesFromBytes(const char* data, size_t length, |
| 397 SecExternalFormat format, | 378 SecExternalFormat format, |
| 398 X509Certificate::OSCertHandles* output) { | 379 X509Certificate::OSCertHandles* output) { |
| 399 SecExternalFormat input_format = format; | 380 SecExternalFormat input_format = format; |
| 400 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( | 381 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( |
| 401 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), | 382 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, |
| 402 length, kCFAllocatorNull)); | 383 kCFAllocatorNull)); |
| 403 | 384 |
| 404 CFArrayRef items = NULL; | 385 CFArrayRef items = NULL; |
| 405 OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format, | 386 OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format, |
| 406 NULL, 0, NULL, NULL, &items); | 387 NULL, 0, NULL, NULL, &items); |
| 407 if (status) { | 388 if (status) { |
| 408 DLOG(WARNING) << status << " Unable to import items from data of length " | 389 DLOG(WARNING) << status << " Unable to import items from data of length " |
| 409 << length; | 390 << length; |
| 410 return; | 391 return; |
| 411 } | 392 } |
| 412 | 393 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 439 } | 420 } |
| 440 } | 421 } |
| 441 } | 422 } |
| 442 } | 423 } |
| 443 | 424 |
| 444 } // namespace | 425 } // namespace |
| 445 | 426 |
| 446 void X509Certificate::Initialize() { | 427 void X509Certificate::Initialize() { |
| 447 const CSSM_X509_NAME* name; | 428 const CSSM_X509_NAME* name; |
| 448 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 429 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); |
| 449 if (!status) { | 430 if (!status) |
| 450 subject_.Parse(name); | 431 subject_.Parse(name); |
| 451 } | 432 |
| 452 status = SecCertificateGetIssuer(cert_handle_, &name); | 433 status = SecCertificateGetIssuer(cert_handle_, &name); |
| 453 if (!status) { | 434 if (!status) |
| 454 issuer_.Parse(name); | 435 issuer_.Parse(name); |
| 455 } | |
| 456 | 436 |
| 457 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 437 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, |
| 458 &valid_start_); | 438 &valid_start_); |
| 459 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 439 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, |
| 460 &valid_expiry_); | 440 &valid_expiry_); |
| 461 | 441 |
| 462 fingerprint_ = CalculateFingerprint(cert_handle_); | 442 fingerprint_ = CalculateFingerprint(cert_handle_); |
| 463 } | 443 } |
| 464 | 444 |
| 465 // static | 445 // static |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 626 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 647 for (uint32 status_code_index = 0; | 627 for (uint32 status_code_index = 0; |
| 648 status_code_index < chain_info[index].NumStatusCodes; | 628 status_code_index < chain_info[index].NumStatusCodes; |
| 649 ++status_code_index) { | 629 ++status_code_index) { |
| 650 got_certificate_error = true; | 630 got_certificate_error = true; |
| 651 int cert_status = CertStatusFromOSStatus( | 631 int cert_status = CertStatusFromOSStatus( |
| 652 chain_info[index].StatusCodes[status_code_index]); | 632 chain_info[index].StatusCodes[status_code_index]); |
| 653 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { | 633 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { |
| 654 std::vector<std::string> names; | 634 std::vector<std::string> names; |
| 655 GetDNSNames(&names); | 635 GetDNSNames(&names); |
| 656 if (OverrideHostnameMismatch(hostname, &names)) { | 636 if (OverrideHostnameMismatch(hostname, &names)) |
| 657 cert_status = 0; | 637 cert_status = 0; |
| 658 } | |
| 659 } | 638 } |
| 660 verify_result->cert_status |= cert_status; | 639 verify_result->cert_status |= cert_status; |
| 661 } | 640 } |
| 662 } | 641 } |
| 663 // Be paranoid and ensure that we recorded at least one certificate | 642 // Be paranoid and ensure that we recorded at least one certificate |
| 664 // status on receiving kSecTrustResultRecoverableTrustFailure. The | 643 // status on receiving kSecTrustResultRecoverableTrustFailure. The |
| 665 // call to SecTrustGetCssmResultCode() should pick up when the chain | 644 // call to SecTrustGetCssmResultCode() should pick up when the chain |
| 666 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO | 645 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO |
| 667 // should pick up everything else, but let's be safe. | 646 // should pick up everything else, but let's be safe. |
| 668 if (!verify_result->cert_status && !got_certificate_error) { | 647 if (!verify_result->cert_status && !got_certificate_error) { |
| 669 verify_result->cert_status |= CERT_STATUS_INVALID; | 648 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 670 NOTREACHED(); | 649 NOTREACHED(); |
| 671 } | 650 } |
| 672 break; | 651 break; |
| 673 | 652 |
| 674 default: | 653 default: |
| 675 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | 654 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); |
| 676 if (status) | 655 if (status) |
| 677 return NetErrorFromOSStatus(status); | 656 return NetErrorFromOSStatus(status); |
| 678 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | 657 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); |
| 679 if (!verify_result->cert_status) { | 658 if (!verify_result->cert_status) |
| 680 verify_result->cert_status |= CERT_STATUS_INVALID; | 659 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 681 } | |
| 682 break; | 660 break; |
| 683 } | 661 } |
| 684 | 662 |
| 685 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be | 663 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be |
| 686 // compatible with Windows, which in turn implements this behavior to be | 664 // compatible with Windows, which in turn implements this behavior to be |
| 687 // compatible with WinHTTP, which doesn't report this error (bug 3004). | 665 // compatible with WinHTTP, which doesn't report this error (bug 3004). |
| 688 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; | 666 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; |
| 689 | 667 |
| 690 if (IsCertStatusError(verify_result->cert_status)) | 668 if (IsCertStatusError(verify_result->cert_status)) |
| 691 return MapCertStatusToNetError(verify_result->cert_status); | 669 return MapCertStatusToNetError(verify_result->cert_status); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 SHA1Fingerprint X509Certificate::CalculateFingerprint( | 783 SHA1Fingerprint X509Certificate::CalculateFingerprint( |
| 806 OSCertHandle cert) { | 784 OSCertHandle cert) { |
| 807 SHA1Fingerprint sha1; | 785 SHA1Fingerprint sha1; |
| 808 memset(sha1.data, 0, sizeof(sha1.data)); | 786 memset(sha1.data, 0, sizeof(sha1.data)); |
| 809 | 787 |
| 810 CSSM_DATA cert_data; | 788 CSSM_DATA cert_data; |
| 811 OSStatus status = SecCertificateGetData(cert, &cert_data); | 789 OSStatus status = SecCertificateGetData(cert, &cert_data); |
| 812 if (status) | 790 if (status) |
| 813 return sha1; | 791 return sha1; |
| 814 | 792 |
| 815 DCHECK(NULL != cert_data.Data); | 793 DCHECK(cert_data.Data); |
| 816 DCHECK(0 != cert_data.Length); | 794 DCHECK_NE(cert_data.Length, 0U); |
| 817 | 795 |
| 818 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | 796 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); |
| 819 | 797 |
| 820 return sha1; | 798 return sha1; |
| 821 } | 799 } |
| 822 | 800 |
| 823 bool X509Certificate::SupportsSSLClientAuth() const { | 801 bool X509Certificate::SupportsSSLClientAuth() const { |
| 824 CSSMFields fields; | 802 CSSMFields fields; |
| 825 if (GetCertFields(cert_handle_, &fields) != noErr) | 803 if (GetCertFields(cert_handle_, &fields) != noErr) |
| 826 return false; | 804 return false; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 857 return false; | 835 return false; |
| 858 return true; | 836 return true; |
| 859 } | 837 } |
| 860 | 838 |
| 861 bool X509Certificate::IsIssuedBy( | 839 bool X509Certificate::IsIssuedBy( |
| 862 const std::vector<CertPrincipal>& valid_issuers) { | 840 const std::vector<CertPrincipal>& valid_issuers) { |
| 863 // Get the cert's issuer chain. | 841 // Get the cert's issuer chain. |
| 864 CFArrayRef cert_chain = NULL; | 842 CFArrayRef cert_chain = NULL; |
| 865 OSStatus result; | 843 OSStatus result; |
| 866 result = CopyCertChain(os_cert_handle(), &cert_chain); | 844 result = CopyCertChain(os_cert_handle(), &cert_chain); |
| 867 if (result != noErr) | 845 if (result) |
| 868 return false; | 846 return false; |
| 869 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); | 847 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); |
| 870 | 848 |
| 871 // Check all the certs in the chain for a match. | 849 // Check all the certs in the chain for a match. |
| 872 int n = CFArrayGetCount(cert_chain); | 850 int n = CFArrayGetCount(cert_chain); |
| 873 for (int i = 0; i < n; ++i) { | 851 for (int i = 0; i < n; ++i) { |
| 874 SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( | 852 SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( |
| 875 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); | 853 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); |
| 876 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( | 854 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( |
| 877 cert_handle, | 855 cert_handle, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 893 NULL, | 871 NULL, |
| 894 CSSM_APPLE_TP_SSL_CLIENT | 872 CSSM_APPLE_TP_SSL_CLIENT |
| 895 }; | 873 }; |
| 896 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 874 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, |
| 897 &tp_ssl_options, | 875 &tp_ssl_options, |
| 898 sizeof(tp_ssl_options), | 876 sizeof(tp_ssl_options), |
| 899 out_policy); | 877 out_policy); |
| 900 } | 878 } |
| 901 | 879 |
| 902 // static | 880 // static |
| 903 bool X509Certificate::GetSSLClientCertificates ( | 881 bool X509Certificate::GetSSLClientCertificates( |
| 904 const std::string& server_domain, | 882 const std::string& server_domain, |
| 905 const std::vector<CertPrincipal>& valid_issuers, | 883 const std::vector<CertPrincipal>& valid_issuers, |
| 906 std::vector<scoped_refptr<X509Certificate> >* certs) { | 884 CertificateList* certs) { |
| 907 ScopedCFTypeRef<SecIdentityRef> preferred_identity; | 885 ScopedCFTypeRef<SecIdentityRef> preferred_identity; |
| 908 if (!server_domain.empty()) { | 886 if (!server_domain.empty()) { |
| 909 // See if there's an identity preference for this domain: | 887 // See if there's an identity preference for this domain: |
| 910 ScopedCFTypeRef<CFStringRef> domain_str( | 888 ScopedCFTypeRef<CFStringRef> domain_str( |
| 911 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 889 base::SysUTF8ToCFStringRef("https://" + server_domain)); |
| 912 SecIdentityRef identity = NULL; | 890 SecIdentityRef identity = NULL; |
| 913 if (SecIdentityCopyPreference(domain_str, | 891 // While SecIdentityCopyPreferences appears to take a list of CA issuers |
| 914 0, | 892 // to restrict the identity search to, within Security.framework the |
| 915 NULL, // validIssuers argument is ignored :( | 893 // argument is ignored and filtering unimplemented. See |
| 916 &identity) == noErr) | 894 // SecIdentity.cpp in libsecurity_keychain, specifically |
| 895 // _SecIdentityCopyPreferenceMatchingName(). |
| 896 if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr) |
| 917 preferred_identity.reset(identity); | 897 preferred_identity.reset(identity); |
| 918 } | 898 } |
| 919 | 899 |
| 920 // Now enumerate the identities in the available keychains. | 900 // Now enumerate the identities in the available keychains. |
| 921 SecIdentitySearchRef search = nil; | 901 SecIdentitySearchRef search = nil; |
| 922 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 902 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); |
| 923 ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); | 903 ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); |
| 924 while (!err) { | 904 while (!err) { |
| 925 SecIdentityRef identity = NULL; | 905 SecIdentityRef identity = NULL; |
| 926 err = SecIdentitySearchCopyNext(search, &identity); | 906 err = SecIdentitySearchCopyNext(search, &identity); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 984 if (result) { | 964 if (result) { |
| 985 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; | 965 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; |
| 986 return NULL; | 966 return NULL; |
| 987 } | 967 } |
| 988 ScopedCFTypeRef<CFMutableArrayRef> chain( | 968 ScopedCFTypeRef<CFMutableArrayRef> chain( |
| 989 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 969 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); |
| 990 CFArrayAppendValue(chain, identity); | 970 CFArrayAppendValue(chain, identity); |
| 991 | 971 |
| 992 CFArrayRef cert_chain = NULL; | 972 CFArrayRef cert_chain = NULL; |
| 993 result = CopyCertChain(cert_handle_, &cert_chain); | 973 result = CopyCertChain(cert_handle_, &cert_chain); |
| 994 if (result) | 974 if (result) { |
| 995 goto exit; | 975 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; |
| 976 return chain.release(); |
| 977 } |
| 996 | 978 |
| 997 // Append the intermediate certs from SecTrust to the result array: | 979 // Append the intermediate certs from SecTrust to the result array: |
| 998 if (cert_chain) { | 980 if (cert_chain) { |
| 999 int chain_count = CFArrayGetCount(cert_chain); | 981 int chain_count = CFArrayGetCount(cert_chain); |
| 1000 if (chain_count > 1) { | 982 if (chain_count > 1) { |
| 1001 CFArrayAppendArray(chain, | 983 CFArrayAppendArray(chain, |
| 1002 cert_chain, | 984 cert_chain, |
| 1003 CFRangeMake(1, chain_count - 1)); | 985 CFRangeMake(1, chain_count - 1)); |
| 1004 } | 986 } |
| 1005 CFRelease(cert_chain); | 987 CFRelease(cert_chain); |
| 1006 } | 988 } |
| 1007 exit: | 989 |
| 1008 if (result) | |
| 1009 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | |
| 1010 return chain.release(); | 990 return chain.release(); |
| 1011 } | 991 } |
| 1012 | 992 |
| 1013 } // namespace net | 993 } // namespace net |
| OLD | NEW |