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