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