| OLD | NEW |
| (Empty) |
| 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 SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { | |
| 378 SHA256HashValue sha256; | |
| 379 memset(sha256.data, 0, sizeof(sha256.data)); | |
| 380 | |
| 381 CSSM_DATA cert_data; | |
| 382 OSStatus status = SecCertificateGetData(cert, &cert_data); | |
| 383 if (status) | |
| 384 return sha256; | |
| 385 | |
| 386 DCHECK(cert_data.Data); | |
| 387 DCHECK_NE(cert_data.Length, 0U); | |
| 388 | |
| 389 CC_SHA256(cert_data.Data, cert_data.Length, sha256.data); | |
| 390 | |
| 391 return sha256; | |
| 392 } | |
| 393 | |
| 394 // static | |
| 395 SHA1HashValue X509Certificate::CalculateCAFingerprint( | |
| 396 const OSCertHandles& intermediates) { | |
| 397 SHA1HashValue sha1; | |
| 398 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 399 | |
| 400 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so | |
| 401 // we don't check their return values. | |
| 402 CC_SHA1_CTX sha1_ctx; | |
| 403 CC_SHA1_Init(&sha1_ctx); | |
| 404 CSSM_DATA cert_data; | |
| 405 for (size_t i = 0; i < intermediates.size(); ++i) { | |
| 406 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data); | |
| 407 if (status) | |
| 408 return sha1; | |
| 409 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); | |
| 410 } | |
| 411 CC_SHA1_Final(sha1.data, &sha1_ctx); | |
| 412 | |
| 413 return sha1; | |
| 414 } | |
| 415 | |
| 416 bool X509Certificate::SupportsSSLClientAuth() const { | |
| 417 x509_util::CSSMCachedCertificate cached_cert; | |
| 418 OSStatus status = cached_cert.Init(cert_handle_); | |
| 419 if (status) | |
| 420 return false; | |
| 421 | |
| 422 // RFC5280 says to take the intersection of the two extensions. | |
| 423 // | |
| 424 // Our underlying crypto libraries don't expose | |
| 425 // ClientCertificateType, so for now we will not support fixed | |
| 426 // Diffie-Hellman mechanisms. For rsa_sign, we need the | |
| 427 // digitalSignature bit. | |
| 428 // | |
| 429 // In particular, if a key has the nonRepudiation bit and not the | |
| 430 // digitalSignature one, we will not offer it to the user. | |
| 431 x509_util::CSSMFieldValue key_usage; | |
| 432 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); | |
| 433 if (status == CSSM_OK && key_usage.field()) { | |
| 434 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
| 435 const CE_KeyUsage* key_usage_value = | |
| 436 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); | |
| 437 if (!((*key_usage_value) & CE_KU_DigitalSignature)) | |
| 438 return false; | |
| 439 } | |
| 440 | |
| 441 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); | |
| 442 if (status == CSSM_OK && key_usage.field()) { | |
| 443 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
| 444 const CE_ExtendedKeyUsage* ext_key_usage = | |
| 445 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
| 446 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) | |
| 447 return false; | |
| 448 } | |
| 449 return true; | |
| 450 } | |
| 451 | |
| 452 CFMutableArrayRef X509Certificate::CreateOSCertChainForCert() const { | |
| 453 CFMutableArrayRef cert_list = | |
| 454 CFArrayCreateMutable(kCFAllocatorDefault, 0, | |
| 455 &kCFTypeArrayCallBacks); | |
| 456 if (!cert_list) | |
| 457 return NULL; | |
| 458 | |
| 459 CFArrayAppendValue(cert_list, os_cert_handle()); | |
| 460 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | |
| 461 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); | |
| 462 | |
| 463 return cert_list; | |
| 464 } | |
| 465 | |
| 466 // static | |
| 467 X509Certificate::OSCertHandle | |
| 468 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { | |
| 469 const char* data; | |
| 470 int length; | |
| 471 if (!pickle_iter->ReadData(&data, &length)) | |
| 472 return NULL; | |
| 473 | |
| 474 return CreateOSCertHandleFromBytes(data, length); | |
| 475 } | |
| 476 | |
| 477 // static | |
| 478 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
| 479 Pickle* pickle) { | |
| 480 CSSM_DATA cert_data; | |
| 481 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); | |
| 482 if (status) | |
| 483 return false; | |
| 484 | |
| 485 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), | |
| 486 cert_data.Length); | |
| 487 } | |
| 488 | |
| 489 // static | |
| 490 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
| 491 size_t* size_bits, | |
| 492 PublicKeyType* type) { | |
| 493 // Since we might fail, set the output parameters to default values first. | |
| 494 *type = kPublicKeyTypeUnknown; | |
| 495 *size_bits = 0; | |
| 496 | |
| 497 SecKeyRef key; | |
| 498 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key); | |
| 499 if (status) { | |
| 500 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status; | |
| 501 return; | |
| 502 } | |
| 503 ScopedCFTypeRef<SecKeyRef> scoped_key(key); | |
| 504 | |
| 505 const CSSM_KEY* cssm_key; | |
| 506 status = SecKeyGetCSSMKey(key, &cssm_key); | |
| 507 if (status) { | |
| 508 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status; | |
| 509 return; | |
| 510 } | |
| 511 | |
| 512 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits; | |
| 513 | |
| 514 switch (cssm_key->KeyHeader.AlgorithmId) { | |
| 515 case CSSM_ALGID_RSA: | |
| 516 *type = kPublicKeyTypeRSA; | |
| 517 break; | |
| 518 case CSSM_ALGID_DSA: | |
| 519 *type = kPublicKeyTypeDSA; | |
| 520 break; | |
| 521 case CSSM_ALGID_ECDSA: | |
| 522 *type = kPublicKeyTypeECDSA; | |
| 523 break; | |
| 524 case CSSM_ALGID_DH: | |
| 525 *type = kPublicKeyTypeDH; | |
| 526 break; | |
| 527 default: | |
| 528 *type = kPublicKeyTypeUnknown; | |
| 529 *size_bits = 0; | |
| 530 break; | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 // static | |
| 535 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { | |
| 536 x509_util::CSSMCachedCertificate cached_cert; | |
| 537 OSStatus status = cached_cert.Init(cert_handle); | |
| 538 if (status != noErr) | |
| 539 return false; | |
| 540 | |
| 541 x509_util::CSSMFieldValue subject; | |
| 542 status = cached_cert.GetField(&CSSMOID_X509V1SubjectNameStd, &subject); | |
| 543 if (status != CSSM_OK || !subject.field()) | |
| 544 return false; | |
| 545 | |
| 546 x509_util::CSSMFieldValue issuer; | |
| 547 status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd, &issuer); | |
| 548 if (status != CSSM_OK || !issuer.field()) | |
| 549 return false; | |
| 550 | |
| 551 if (subject.field()->Length != issuer.field()->Length || | |
| 552 memcmp(subject.field()->Data, issuer.field()->Data, | |
| 553 issuer.field()->Length) != 0) { | |
| 554 return false; | |
| 555 } | |
| 556 | |
| 557 CSSM_CL_HANDLE cl_handle = CSSM_INVALID_HANDLE; | |
| 558 status = SecCertificateGetCLHandle(cert_handle, &cl_handle); | |
| 559 if (status) | |
| 560 return false; | |
| 561 CSSM_DATA cert_data; | |
| 562 status = SecCertificateGetData(cert_handle, &cert_data); | |
| 563 if (status) | |
| 564 return false; | |
| 565 | |
| 566 if (CSSM_CL_CertVerify(cl_handle, 0, &cert_data, &cert_data, NULL, 0)) | |
| 567 return false; | |
| 568 return true; | |
| 569 } | |
| 570 | |
| 571 } // namespace net | |
| OLD | NEW |