| 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/base/x509_certificate.h" | |
| 6 | |
| 7 #include <CommonCrypto/CommonDigest.h> | |
| 8 #include <CoreServices/CoreServices.h> | |
| 9 #include <Security/Security.h> | |
| 10 #include <time.h> | |
| 11 | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/lazy_instance.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/mac/mac_logging.h" | |
| 17 #include "base/mac/scoped_cftyperef.h" | |
| 18 #include "base/memory/singleton.h" | |
| 19 #include "base/pickle.h" | |
| 20 #include "base/sha1.h" | |
| 21 #include "base/string_piece.h" | |
| 22 #include "base/synchronization/lock.h" | |
| 23 #include "base/sys_string_conversions.h" | |
| 24 #include "crypto/cssm_init.h" | |
| 25 #include "crypto/mac_security_services_lock.h" | |
| 26 #include "crypto/nss_util.h" | |
| 27 #include "crypto/rsa_private_key.h" | |
| 28 #include "net/base/x509_util_mac.h" | |
| 29 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" | |
| 30 | |
| 31 using base::mac::ScopedCFTypeRef; | |
| 32 using base::Time; | |
| 33 | |
| 34 namespace net { | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 void GetCertDistinguishedName( | |
| 39 const x509_util::CSSMCachedCertificate& cached_cert, | |
| 40 const CSSM_OID* oid, | |
| 41 CertPrincipal* result) { | |
| 42 x509_util::CSSMFieldValue distinguished_name; | |
| 43 OSStatus status = cached_cert.GetField(oid, &distinguished_name); | |
| 44 if (status || !distinguished_name.field()) | |
| 45 return; | |
| 46 result->ParseDistinguishedName(distinguished_name.field()->Data, | |
| 47 distinguished_name.field()->Length); | |
| 48 } | |
| 49 | |
| 50 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle, | |
| 51 const std::vector<std::string>& issuers) { | |
| 52 x509_util::CSSMCachedCertificate cached_cert; | |
| 53 if (cached_cert.Init(cert_handle) != CSSM_OK) | |
| 54 return false; | |
| 55 | |
| 56 x509_util::CSSMFieldValue distinguished_name; | |
| 57 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd, | |
| 58 &distinguished_name); | |
| 59 if (status || !distinguished_name.field()) | |
| 60 return false; | |
| 61 | |
| 62 base::StringPiece name_piece( | |
| 63 reinterpret_cast<const char*>(distinguished_name.field()->Data), | |
| 64 static_cast<size_t>(distinguished_name.field()->Length)); | |
| 65 | |
| 66 for (std::vector<std::string>::const_iterator it = issuers.begin(); | |
| 67 it != issuers.end(); ++it) { | |
| 68 base::StringPiece issuer_piece(*it); | |
| 69 if (name_piece == issuer_piece) | |
| 70 return true; | |
| 71 } | |
| 72 | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert, | |
| 77 const CSSM_OID* oid, | |
| 78 Time* result) { | |
| 79 *result = Time::Time(); | |
| 80 | |
| 81 x509_util::CSSMFieldValue field; | |
| 82 OSStatus status = cached_cert.GetField(oid, &field); | |
| 83 if (status) | |
| 84 return; | |
| 85 | |
| 86 const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>(); | |
| 87 if (x509_time->timeType != BER_TAG_UTC_TIME && | |
| 88 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { | |
| 89 LOG(ERROR) << "Unsupported date/time format " | |
| 90 << x509_time->timeType; | |
| 91 return; | |
| 92 } | |
| 93 | |
| 94 base::StringPiece time_string( | |
| 95 reinterpret_cast<const char*>(x509_time->time.Data), | |
| 96 x509_time->time.Length); | |
| 97 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? | |
| 98 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; | |
| 99 if (!ParseCertificateDate(time_string, format, result)) | |
| 100 LOG(ERROR) << "Invalid certificate date/time " << time_string; | |
| 101 } | |
| 102 | |
| 103 std::string GetCertSerialNumber( | |
| 104 const x509_util::CSSMCachedCertificate& cached_cert) { | |
| 105 x509_util::CSSMFieldValue serial_number; | |
| 106 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, | |
| 107 &serial_number); | |
| 108 if (status || !serial_number.field()) | |
| 109 return std::string(); | |
| 110 | |
| 111 return std::string( | |
| 112 reinterpret_cast<const char*>(serial_number.field()->Data), | |
| 113 serial_number.field()->Length); | |
| 114 } | |
| 115 | |
| 116 // Gets the issuer for a given cert, starting with the cert itself and | |
| 117 // including the intermediate and finally root certificates (if any). | |
| 118 // This function calls SecTrust but doesn't actually pay attention to the trust | |
| 119 // result: it shouldn't be used to determine trust, just to traverse the chain. | |
| 120 // Caller is responsible for releasing the value stored into *out_cert_chain. | |
| 121 OSStatus CopyCertChain(SecCertificateRef cert_handle, | |
| 122 CFArrayRef* out_cert_chain) { | |
| 123 DCHECK(cert_handle); | |
| 124 DCHECK(out_cert_chain); | |
| 125 | |
| 126 // Create an SSL policy ref configured for client cert evaluation. | |
| 127 SecPolicyRef ssl_policy; | |
| 128 OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); | |
| 129 if (result) | |
| 130 return result; | |
| 131 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 132 | |
| 133 // Create a SecTrustRef. | |
| 134 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( | |
| 135 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), | |
| 136 1, &kCFTypeArrayCallBacks)); | |
| 137 SecTrustRef trust_ref = NULL; | |
| 138 { | |
| 139 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 140 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, | |
| 141 &trust_ref); | |
| 142 } | |
| 143 if (result) | |
| 144 return result; | |
| 145 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); | |
| 146 | |
| 147 // Evaluate trust, which creates the cert chain. | |
| 148 SecTrustResultType status; | |
| 149 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | |
| 150 { | |
| 151 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 152 result = SecTrustEvaluate(trust, &status); | |
| 153 } | |
| 154 if (result) | |
| 155 return result; | |
| 156 { | |
| 157 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 158 result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); | |
| 159 } | |
| 160 return result; | |
| 161 } | |
| 162 | |
| 163 // Returns true if |purpose| is listed as allowed in |usage|. This | |
| 164 // function also considers the "Any" purpose. If the attribute is | |
| 165 // present and empty, we return false. | |
| 166 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, | |
| 167 const CSSM_OID* purpose) { | |
| 168 for (unsigned p = 0; p < usage->numPurposes; ++p) { | |
| 169 if (CSSMOIDEqual(&usage->purposes[p], purpose)) | |
| 170 return true; | |
| 171 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny)) | |
| 172 return true; | |
| 173 } | |
| 174 return false; | |
| 175 } | |
| 176 | |
| 177 // Test that a given |cert_handle| is actually a valid X.509 certificate, and | |
| 178 // return true if it is. | |
| 179 // | |
| 180 // On OS X, SecCertificateCreateFromData() does not return any errors if | |
| 181 // called with invalid data, as long as data is present. The actual decoding | |
| 182 // of the certificate does not happen until an API that requires a CSSM | |
| 183 // handle is called. While SecCertificateGetCLHandle is the most likely | |
| 184 // candidate, as it performs the parsing, it does not check whether the | |
| 185 // parsing was actually successful. Instead, SecCertificateGetSubject is | |
| 186 // used (supported since 10.3), as a means to check that the certificate | |
| 187 // parsed as a valid X.509 certificate. | |
| 188 bool IsValidOSCertHandle(SecCertificateRef cert_handle) { | |
| 189 const CSSM_X509_NAME* sanity_check = NULL; | |
| 190 OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check); | |
| 191 return status == noErr && sanity_check; | |
| 192 } | |
| 193 | |
| 194 // Parses |data| of length |length|, attempting to decode it as the specified | |
| 195 // |format|. If |data| is in the specified format, any certificates contained | |
| 196 // within are stored into |output|. | |
| 197 void AddCertificatesFromBytes(const char* data, size_t length, | |
| 198 SecExternalFormat format, | |
| 199 X509Certificate::OSCertHandles* output) { | |
| 200 SecExternalFormat input_format = format; | |
| 201 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( | |
| 202 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, | |
| 203 kCFAllocatorNull)); | |
| 204 | |
| 205 CFArrayRef items = NULL; | |
| 206 OSStatus status; | |
| 207 { | |
| 208 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 209 status = SecKeychainItemImport(local_data, NULL, &input_format, | |
| 210 NULL, 0, NULL, NULL, &items); | |
| 211 } | |
| 212 | |
| 213 if (status) { | |
| 214 OSSTATUS_DLOG(WARNING, status) | |
| 215 << "Unable to import items from data of length " << length; | |
| 216 return; | |
| 217 } | |
| 218 | |
| 219 ScopedCFTypeRef<CFArrayRef> scoped_items(items); | |
| 220 CFTypeID cert_type_id = SecCertificateGetTypeID(); | |
| 221 | |
| 222 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { | |
| 223 SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>( | |
| 224 const_cast<void*>(CFArrayGetValueAtIndex(items, i))); | |
| 225 | |
| 226 // While inputFormat implies only certificates will be imported, if/when | |
| 227 // other formats (eg: PKCS#12) are supported, this may also include | |
| 228 // private keys or other items types, so filter appropriately. | |
| 229 if (CFGetTypeID(item) == cert_type_id) { | |
| 230 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item); | |
| 231 // OS X ignores |input_format| if it detects that |local_data| is PEM | |
| 232 // encoded, attempting to decode data based on internal rules for PEM | |
| 233 // block headers. If a PKCS#7 blob is encoded with a PEM block of | |
| 234 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate | |
| 235 // based on the decoded data. If this happens, the certificate should | |
| 236 // not be included in |output|. Because |output| is empty, | |
| 237 // CreateCertificateListfromBytes will use PEMTokenizer to decode the | |
| 238 // data. When called again with the decoded data, OS X will honor | |
| 239 // |input_format|, causing decode to succeed. On OS X 10.6, the data | |
| 240 // is properly decoded as a PKCS#7, whether PEM or not, which avoids | |
| 241 // the need to fallback to internal decoding. | |
| 242 if (IsValidOSCertHandle(cert)) { | |
| 243 CFRetain(cert); | |
| 244 output->push_back(cert); | |
| 245 } | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 struct CSSMOIDString { | |
| 251 const CSSM_OID* oid_; | |
| 252 std::string string_; | |
| 253 }; | |
| 254 | |
| 255 typedef std::vector<CSSMOIDString> CSSMOIDStringVector; | |
| 256 | |
| 257 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) { | |
| 258 struct OIDCSSMMap { | |
| 259 SECOidTag sec_OID_; | |
| 260 const CSSM_OID* cssm_OID_; | |
| 261 }; | |
| 262 | |
| 263 const OIDCSSMMap kOIDs[] = { | |
| 264 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName }, | |
| 265 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName }, | |
| 266 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName }, | |
| 267 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName }, | |
| 268 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress }, | |
| 269 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName }, | |
| 270 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName }, | |
| 271 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier }, | |
| 272 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier }, | |
| 273 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress }, | |
| 274 }; | |
| 275 | |
| 276 CERTRDN** rdns = name->rdns; | |
| 277 for (size_t rdn = 0; rdns[rdn]; ++rdn) { | |
| 278 CERTAVA** avas = rdns[rdn]->avas; | |
| 279 for (size_t pair = 0; avas[pair] != 0; ++pair) { | |
| 280 SECOidTag tag = CERT_GetAVATag(avas[pair]); | |
| 281 if (tag == SEC_OID_UNKNOWN) { | |
| 282 return false; | |
| 283 } | |
| 284 CSSMOIDString oidString; | |
| 285 bool found_oid = false; | |
| 286 for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) { | |
| 287 if (kOIDs[oid].sec_OID_ == tag) { | |
| 288 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); | |
| 289 if (!decode_item) | |
| 290 return false; | |
| 291 | |
| 292 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. | |
| 293 std::string value(reinterpret_cast<char*>(decode_item->data), | |
| 294 decode_item->len); | |
| 295 oidString.oid_ = kOIDs[oid].cssm_OID_; | |
| 296 oidString.string_ = value; | |
| 297 out_values->push_back(oidString); | |
| 298 SECITEM_FreeItem(decode_item, PR_TRUE); | |
| 299 found_oid = true; | |
| 300 break; | |
| 301 } | |
| 302 } | |
| 303 if (!found_oid) { | |
| 304 DLOG(ERROR) << "Unrecognized OID: " << tag; | |
| 305 } | |
| 306 } | |
| 307 } | |
| 308 return true; | |
| 309 } | |
| 310 | |
| 311 class ScopedCertName { | |
| 312 public: | |
| 313 explicit ScopedCertName(CERTName* name) : name_(name) { } | |
| 314 ~ScopedCertName() { | |
| 315 if (name_) CERT_DestroyName(name_); | |
| 316 } | |
| 317 operator CERTName*() { return name_; } | |
| 318 | |
| 319 private: | |
| 320 CERTName* name_; | |
| 321 }; | |
| 322 | |
| 323 class ScopedEncodedCertResults { | |
| 324 public: | |
| 325 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results) | |
| 326 : results_(results) { } | |
| 327 ~ScopedEncodedCertResults() { | |
| 328 if (results_) { | |
| 329 CSSM_ENCODED_CERT* encCert = | |
| 330 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results); | |
| 331 for (uint32 i = 0; i < results_->NumberOfResults; i++) { | |
| 332 crypto::CSSMFree(encCert[i].CertBlob.Data); | |
| 333 } | |
| 334 } | |
| 335 crypto::CSSMFree(results_->Results); | |
| 336 crypto::CSSMFree(results_); | |
| 337 } | |
| 338 | |
| 339 private: | |
| 340 CSSM_TP_RESULT_SET* results_; | |
| 341 }; | |
| 342 | |
| 343 } // namespace | |
| 344 | |
| 345 void X509Certificate::Initialize() { | |
| 346 x509_util::CSSMCachedCertificate cached_cert; | |
| 347 if (cached_cert.Init(cert_handle_) == CSSM_OK) { | |
| 348 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd, | |
| 349 &subject_); | |
| 350 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd, | |
| 351 &issuer_); | |
| 352 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore, | |
| 353 &valid_start_); | |
| 354 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter, | |
| 355 &valid_expiry_); | |
| 356 serial_number_ = GetCertSerialNumber(cached_cert); | |
| 357 } | |
| 358 | |
| 359 fingerprint_ = CalculateFingerprint(cert_handle_); | |
| 360 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | |
| 361 } | |
| 362 | |
| 363 bool X509Certificate::IsIssuedByEncoded( | |
| 364 const std::vector<std::string>& valid_issuers) { | |
| 365 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers)) | |
| 366 return true; | |
| 367 | |
| 368 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); | |
| 369 it != intermediate_ca_certs_.end(); ++it) { | |
| 370 if (IsCertIssuerInEncodedList(*it, valid_issuers)) | |
| 371 return true; | |
| 372 } | |
| 373 return false; | |
| 374 } | |
| 375 | |
| 376 // static | |
| 377 X509Certificate* X509Certificate::CreateSelfSigned( | |
| 378 crypto::RSAPrivateKey* key, | |
| 379 const std::string& subject, | |
| 380 uint32 serial_number, | |
| 381 base::TimeDelta valid_duration) { | |
| 382 DCHECK(key); | |
| 383 DCHECK(!subject.empty()); | |
| 384 | |
| 385 if (valid_duration.InSeconds() > kuint32max) { | |
| 386 LOG(ERROR) << "valid_duration too big " << valid_duration.InSeconds(); | |
| 387 valid_duration = base::TimeDelta::FromSeconds(kuint32max); | |
| 388 } | |
| 389 | |
| 390 // There is a comment in | |
| 391 // http://www.opensource.apple.com/source/security_certtool/security_certtool-
31828/src/CertTool.cpp | |
| 392 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have | |
| 393 // their high bit set. We will continue though and mask it out below. | |
| 394 if (serial_number & 0x80000000) | |
| 395 LOG(ERROR) << "serial_number has high bit set " << serial_number; | |
| 396 | |
| 397 // NSS is used to parse the subject string into a set of | |
| 398 // CSSM_OID/string pairs. There doesn't appear to be a system routine for | |
| 399 // parsing Distinguished Name strings. | |
| 400 crypto::EnsureNSSInit(); | |
| 401 | |
| 402 CSSMOIDStringVector subject_name_oids; | |
| 403 ScopedCertName subject_name( | |
| 404 CERT_AsciiToName(const_cast<char*>(subject.c_str()))); | |
| 405 if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) { | |
| 406 DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject; | |
| 407 return NULL; | |
| 408 } | |
| 409 | |
| 410 // Convert the map of oid/string pairs into an array of | |
| 411 // CSSM_APPLE_TP_NAME_OIDs. | |
| 412 std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names; | |
| 413 for (CSSMOIDStringVector::iterator iter = subject_name_oids.begin(); | |
| 414 iter != subject_name_oids.end(); ++iter) { | |
| 415 CSSM_APPLE_TP_NAME_OID cssm_subject_name; | |
| 416 cssm_subject_name.oid = iter->oid_; | |
| 417 cssm_subject_name.string = iter->string_.c_str(); | |
| 418 cssm_subject_names.push_back(cssm_subject_name); | |
| 419 } | |
| 420 | |
| 421 if (cssm_subject_names.empty()) { | |
| 422 DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject; | |
| 423 return NULL; | |
| 424 } | |
| 425 | |
| 426 // Set up a certificate request. | |
| 427 CSSM_APPLE_TP_CERT_REQUEST certReq; | |
| 428 memset(&certReq, 0, sizeof(certReq)); | |
| 429 certReq.cspHand = crypto::GetSharedCSPHandle(); | |
| 430 certReq.clHand = crypto::GetSharedCLHandle(); | |
| 431 // See comment about serial numbers above. | |
| 432 certReq.serialNumber = serial_number & 0x7fffffff; | |
| 433 certReq.numSubjectNames = cssm_subject_names.size(); | |
| 434 certReq.subjectNames = &cssm_subject_names[0]; | |
| 435 certReq.numIssuerNames = 0; // Root. | |
| 436 certReq.issuerNames = NULL; | |
| 437 certReq.issuerNameX509 = NULL; | |
| 438 certReq.certPublicKey = key->public_key(); | |
| 439 certReq.issuerPrivateKey = key->key(); | |
| 440 // These are the Apple defaults. | |
| 441 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; | |
| 442 certReq.signatureOid = CSSMOID_SHA1WithRSA; | |
| 443 certReq.notBefore = 0; | |
| 444 certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds()); | |
| 445 certReq.numExtensions = 0; | |
| 446 certReq.extensions = NULL; | |
| 447 certReq.challengeString = NULL; | |
| 448 | |
| 449 CSSM_TP_REQUEST_SET reqSet; | |
| 450 reqSet.NumberOfRequests = 1; | |
| 451 reqSet.Requests = &certReq; | |
| 452 | |
| 453 CSSM_FIELD policyId; | |
| 454 memset(&policyId, 0, sizeof(policyId)); | |
| 455 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; | |
| 456 | |
| 457 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext; | |
| 458 memset(&callerAuthContext, 0, sizeof(callerAuthContext)); | |
| 459 callerAuthContext.Policy.NumberOfPolicyIds = 1; | |
| 460 callerAuthContext.Policy.PolicyIds = &policyId; | |
| 461 | |
| 462 CSSM_TP_HANDLE tp_handle = crypto::GetSharedTPHandle(); | |
| 463 CSSM_DATA refId; | |
| 464 memset(&refId, 0, sizeof(refId)); | |
| 465 sint32 estTime; | |
| 466 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL, | |
| 467 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext, | |
| 468 &estTime, &refId); | |
| 469 if (crtn) { | |
| 470 DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn; | |
| 471 return NULL; | |
| 472 } | |
| 473 | |
| 474 CSSM_BOOL confirmRequired; | |
| 475 CSSM_TP_RESULT_SET* resultSet = NULL; | |
| 476 crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime, | |
| 477 &confirmRequired, &resultSet); | |
| 478 ScopedEncodedCertResults scopedResults(resultSet); | |
| 479 crypto::CSSMFree(refId.Data); | |
| 480 if (crtn) { | |
| 481 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn; | |
| 482 return NULL; | |
| 483 } | |
| 484 | |
| 485 if (confirmRequired) { | |
| 486 // Potential leak here of resultSet. |confirmRequired| should never be | |
| 487 // true. | |
| 488 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation"; | |
| 489 return NULL; | |
| 490 } | |
| 491 | |
| 492 if (resultSet->NumberOfResults != 1) { | |
| 493 DLOG(ERROR) << "Unexpected number of results: " | |
| 494 << resultSet->NumberOfResults; | |
| 495 return NULL; | |
| 496 } | |
| 497 | |
| 498 CSSM_ENCODED_CERT* encCert = | |
| 499 reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results); | |
| 500 ScopedCFTypeRef<SecCertificateRef> scoped_cert; | |
| 501 SecCertificateRef certificate_ref = NULL; | |
| 502 OSStatus os_status = | |
| 503 SecCertificateCreateFromData(&encCert->CertBlob, encCert->CertType, | |
| 504 encCert->CertEncoding, &certificate_ref); | |
| 505 if (os_status != 0) { | |
| 506 OSSTATUS_DLOG(ERROR, os_status) << "SecCertificateCreateFromData failed"; | |
| 507 return NULL; | |
| 508 } | |
| 509 scoped_cert.reset(certificate_ref); | |
| 510 | |
| 511 return CreateFromHandle(scoped_cert, X509Certificate::OSCertHandles()); | |
| 512 } | |
| 513 | |
| 514 void X509Certificate::GetSubjectAltName( | |
| 515 std::vector<std::string>* dns_names, | |
| 516 std::vector<std::string>* ip_addrs) const { | |
| 517 if (dns_names) | |
| 518 dns_names->clear(); | |
| 519 if (ip_addrs) | |
| 520 ip_addrs->clear(); | |
| 521 | |
| 522 x509_util::CSSMCachedCertificate cached_cert; | |
| 523 OSStatus status = cached_cert.Init(cert_handle_); | |
| 524 if (status) | |
| 525 return; | |
| 526 x509_util::CSSMFieldValue subject_alt_name; | |
| 527 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name); | |
| 528 if (status || !subject_alt_name.field()) | |
| 529 return; | |
| 530 const CSSM_X509_EXTENSION* cssm_ext = | |
| 531 subject_alt_name.GetAs<CSSM_X509_EXTENSION>(); | |
| 532 if (!cssm_ext || !cssm_ext->value.parsedValue) | |
| 533 return; | |
| 534 const CE_GeneralNames* alt_name = | |
| 535 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue); | |
| 536 | |
| 537 for (size_t name = 0; name < alt_name->numNames; ++name) { | |
| 538 const CE_GeneralName& name_struct = alt_name->generalName[name]; | |
| 539 const CSSM_DATA& name_data = name_struct.name; | |
| 540 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs | |
| 541 // respectively, both of which can be byte copied from | |
| 542 // CSSM_DATA::data into the appropriate output vector. | |
| 543 if (dns_names && name_struct.nameType == GNT_DNSName) { | |
| 544 dns_names->push_back(std::string( | |
| 545 reinterpret_cast<const char*>(name_data.Data), | |
| 546 name_data.Length)); | |
| 547 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { | |
| 548 ip_addrs->push_back(std::string( | |
| 549 reinterpret_cast<const char*>(name_data.Data), | |
| 550 name_data.Length)); | |
| 551 } | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 // static | |
| 556 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | |
| 557 std::string* encoded) { | |
| 558 CSSM_DATA der_data; | |
| 559 if (SecCertificateGetData(cert_handle, &der_data) != noErr) | |
| 560 return false; | |
| 561 encoded->assign(reinterpret_cast<char*>(der_data.Data), | |
| 562 der_data.Length); | |
| 563 return true; | |
| 564 } | |
| 565 | |
| 566 // static | |
| 567 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | |
| 568 X509Certificate::OSCertHandle b) { | |
| 569 DCHECK(a && b); | |
| 570 if (a == b) | |
| 571 return true; | |
| 572 if (CFEqual(a, b)) | |
| 573 return true; | |
| 574 CSSM_DATA a_data, b_data; | |
| 575 return SecCertificateGetData(a, &a_data) == noErr && | |
| 576 SecCertificateGetData(b, &b_data) == noErr && | |
| 577 a_data.Length == b_data.Length && | |
| 578 memcmp(a_data.Data, b_data.Data, a_data.Length) == 0; | |
| 579 } | |
| 580 | |
| 581 // static | |
| 582 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | |
| 583 const char* data, int length) { | |
| 584 CSSM_DATA cert_data; | |
| 585 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); | |
| 586 cert_data.Length = length; | |
| 587 | |
| 588 OSCertHandle cert_handle = NULL; | |
| 589 OSStatus status = SecCertificateCreateFromData(&cert_data, | |
| 590 CSSM_CERT_X_509v3, | |
| 591 CSSM_CERT_ENCODING_DER, | |
| 592 &cert_handle); | |
| 593 if (status != noErr) | |
| 594 return NULL; | |
| 595 if (!IsValidOSCertHandle(cert_handle)) { | |
| 596 CFRelease(cert_handle); | |
| 597 return NULL; | |
| 598 } | |
| 599 return cert_handle; | |
| 600 } | |
| 601 | |
| 602 // static | |
| 603 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | |
| 604 const char* data, int length, Format format) { | |
| 605 OSCertHandles results; | |
| 606 | |
| 607 switch (format) { | |
| 608 case FORMAT_SINGLE_CERTIFICATE: { | |
| 609 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); | |
| 610 if (handle) | |
| 611 results.push_back(handle); | |
| 612 break; | |
| 613 } | |
| 614 case FORMAT_PKCS7: | |
| 615 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results); | |
| 616 break; | |
| 617 default: | |
| 618 NOTREACHED() << "Certificate format " << format << " unimplemented"; | |
| 619 break; | |
| 620 } | |
| 621 | |
| 622 return results; | |
| 623 } | |
| 624 | |
| 625 // static | |
| 626 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | |
| 627 OSCertHandle handle) { | |
| 628 if (!handle) | |
| 629 return NULL; | |
| 630 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); | |
| 631 } | |
| 632 | |
| 633 // static | |
| 634 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | |
| 635 CFRelease(cert_handle); | |
| 636 } | |
| 637 | |
| 638 // static | |
| 639 SHA1HashValue X509Certificate::CalculateFingerprint( | |
| 640 OSCertHandle cert) { | |
| 641 SHA1HashValue sha1; | |
| 642 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 643 | |
| 644 CSSM_DATA cert_data; | |
| 645 OSStatus status = SecCertificateGetData(cert, &cert_data); | |
| 646 if (status) | |
| 647 return sha1; | |
| 648 | |
| 649 DCHECK(cert_data.Data); | |
| 650 DCHECK_NE(cert_data.Length, 0U); | |
| 651 | |
| 652 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | |
| 653 | |
| 654 return sha1; | |
| 655 } | |
| 656 | |
| 657 // static | |
| 658 SHA1HashValue X509Certificate::CalculateCAFingerprint( | |
| 659 const OSCertHandles& intermediates) { | |
| 660 SHA1HashValue sha1; | |
| 661 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 662 | |
| 663 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so | |
| 664 // we don't check their return values. | |
| 665 CC_SHA1_CTX sha1_ctx; | |
| 666 CC_SHA1_Init(&sha1_ctx); | |
| 667 CSSM_DATA cert_data; | |
| 668 for (size_t i = 0; i < intermediates.size(); ++i) { | |
| 669 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data); | |
| 670 if (status) | |
| 671 return sha1; | |
| 672 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); | |
| 673 } | |
| 674 CC_SHA1_Final(sha1.data, &sha1_ctx); | |
| 675 | |
| 676 return sha1; | |
| 677 } | |
| 678 | |
| 679 bool X509Certificate::SupportsSSLClientAuth() const { | |
| 680 x509_util::CSSMCachedCertificate cached_cert; | |
| 681 OSStatus status = cached_cert.Init(cert_handle_); | |
| 682 if (status) | |
| 683 return false; | |
| 684 | |
| 685 // RFC5280 says to take the intersection of the two extensions. | |
| 686 // | |
| 687 // Our underlying crypto libraries don't expose | |
| 688 // ClientCertificateType, so for now we will not support fixed | |
| 689 // Diffie-Hellman mechanisms. For rsa_sign, we need the | |
| 690 // digitalSignature bit. | |
| 691 // | |
| 692 // In particular, if a key has the nonRepudiation bit and not the | |
| 693 // digitalSignature one, we will not offer it to the user. | |
| 694 x509_util::CSSMFieldValue key_usage; | |
| 695 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); | |
| 696 if (status == CSSM_OK && key_usage.field()) { | |
| 697 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
| 698 const CE_KeyUsage* key_usage_value = | |
| 699 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); | |
| 700 if (!((*key_usage_value) & CE_KU_DigitalSignature)) | |
| 701 return false; | |
| 702 } | |
| 703 | |
| 704 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); | |
| 705 if (status == CSSM_OK && key_usage.field()) { | |
| 706 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | |
| 707 const CE_ExtendedKeyUsage* ext_key_usage = | |
| 708 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
| 709 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) | |
| 710 return false; | |
| 711 } | |
| 712 return true; | |
| 713 } | |
| 714 | |
| 715 CFArrayRef X509Certificate::CreateClientCertificateChain() const { | |
| 716 // Initialize the result array with just the IdentityRef of the receiver: | |
| 717 SecIdentityRef identity; | |
| 718 OSStatus result; | |
| 719 { | |
| 720 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 721 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | |
| 722 } | |
| 723 if (result) { | |
| 724 OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; | |
| 725 return NULL; | |
| 726 } | |
| 727 ScopedCFTypeRef<CFMutableArrayRef> chain( | |
| 728 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | |
| 729 CFArrayAppendValue(chain, identity); | |
| 730 | |
| 731 CFArrayRef cert_chain = NULL; | |
| 732 result = CopyCertChain(cert_handle_, &cert_chain); | |
| 733 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); | |
| 734 if (result) { | |
| 735 OSSTATUS_LOG(ERROR, result) << "CreateIdentityCertificateChain error"; | |
| 736 return chain.release(); | |
| 737 } | |
| 738 | |
| 739 // Append the intermediate certs from SecTrust to the result array: | |
| 740 if (cert_chain) { | |
| 741 int chain_count = CFArrayGetCount(cert_chain); | |
| 742 if (chain_count > 1) { | |
| 743 CFArrayAppendArray(chain, | |
| 744 cert_chain, | |
| 745 CFRangeMake(1, chain_count - 1)); | |
| 746 } | |
| 747 } | |
| 748 | |
| 749 return chain.release(); | |
| 750 } | |
| 751 | |
| 752 CFArrayRef X509Certificate::CreateOSCertChainForCert() const { | |
| 753 CFMutableArrayRef cert_list = | |
| 754 CFArrayCreateMutable(kCFAllocatorDefault, 0, | |
| 755 &kCFTypeArrayCallBacks); | |
| 756 if (!cert_list) | |
| 757 return NULL; | |
| 758 | |
| 759 CFArrayAppendValue(cert_list, os_cert_handle()); | |
| 760 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | |
| 761 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); | |
| 762 | |
| 763 return cert_list; | |
| 764 } | |
| 765 | |
| 766 // static | |
| 767 X509Certificate::OSCertHandle | |
| 768 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { | |
| 769 const char* data; | |
| 770 int length; | |
| 771 if (!pickle_iter->ReadData(&data, &length)) | |
| 772 return NULL; | |
| 773 | |
| 774 return CreateOSCertHandleFromBytes(data, length); | |
| 775 } | |
| 776 | |
| 777 // static | |
| 778 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
| 779 Pickle* pickle) { | |
| 780 CSSM_DATA cert_data; | |
| 781 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); | |
| 782 if (status) | |
| 783 return false; | |
| 784 | |
| 785 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), | |
| 786 cert_data.Length); | |
| 787 } | |
| 788 | |
| 789 // static | |
| 790 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
| 791 size_t* size_bits, | |
| 792 PublicKeyType* type) { | |
| 793 // Since we might fail, set the output parameters to default values first. | |
| 794 *type = kPublicKeyTypeUnknown; | |
| 795 *size_bits = 0; | |
| 796 | |
| 797 SecKeyRef key; | |
| 798 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key); | |
| 799 if (status) { | |
| 800 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status; | |
| 801 return; | |
| 802 } | |
| 803 ScopedCFTypeRef<SecKeyRef> scoped_key(key); | |
| 804 | |
| 805 const CSSM_KEY* cssm_key; | |
| 806 status = SecKeyGetCSSMKey(key, &cssm_key); | |
| 807 if (status) { | |
| 808 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status; | |
| 809 return; | |
| 810 } | |
| 811 | |
| 812 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits; | |
| 813 | |
| 814 switch (cssm_key->KeyHeader.AlgorithmId) { | |
| 815 case CSSM_ALGID_RSA: | |
| 816 *type = kPublicKeyTypeRSA; | |
| 817 break; | |
| 818 case CSSM_ALGID_DSA: | |
| 819 *type = kPublicKeyTypeDSA; | |
| 820 break; | |
| 821 case CSSM_ALGID_ECDSA: | |
| 822 *type = kPublicKeyTypeECDSA; | |
| 823 break; | |
| 824 case CSSM_ALGID_DH: | |
| 825 *type = kPublicKeyTypeDH; | |
| 826 break; | |
| 827 default: | |
| 828 *type = kPublicKeyTypeUnknown; | |
| 829 *size_bits = 0; | |
| 830 break; | |
| 831 } | |
| 832 } | |
| 833 | |
| 834 } // namespace net | |
| OLD | NEW |