| 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 "base/logging.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/pickle.h" | |
| 10 #include "base/sha1.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "crypto/capi_util.h" | |
| 14 #include "crypto/scoped_capi_types.h" | |
| 15 #include "crypto/sha2.h" | |
| 16 #include "net/base/net_errors.h" | |
| 17 | |
| 18 // Implement CalculateChainFingerprint() with our native crypto library. | |
| 19 #if defined(USE_OPENSSL) | |
| 20 #include <openssl/sha.h> | |
| 21 #else | |
| 22 #include <blapi.h> | |
| 23 #endif | |
| 24 | |
| 25 #pragma comment(lib, "crypt32.lib") | |
| 26 | |
| 27 using base::Time; | |
| 28 | |
| 29 namespace net { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 typedef crypto::ScopedCAPIHandle< | |
| 34 HCERTSTORE, | |
| 35 crypto::CAPIDestroyerWithFlags<HCERTSTORE, | |
| 36 CertCloseStore, 0> > ScopedHCERTSTORE; | |
| 37 | |
| 38 void ExplodedTimeToSystemTime(const base::Time::Exploded& exploded, | |
| 39 SYSTEMTIME* system_time) { | |
| 40 system_time->wYear = static_cast<WORD>(exploded.year); | |
| 41 system_time->wMonth = static_cast<WORD>(exploded.month); | |
| 42 system_time->wDayOfWeek = static_cast<WORD>(exploded.day_of_week); | |
| 43 system_time->wDay = static_cast<WORD>(exploded.day_of_month); | |
| 44 system_time->wHour = static_cast<WORD>(exploded.hour); | |
| 45 system_time->wMinute = static_cast<WORD>(exploded.minute); | |
| 46 system_time->wSecond = static_cast<WORD>(exploded.second); | |
| 47 system_time->wMilliseconds = static_cast<WORD>(exploded.millisecond); | |
| 48 } | |
| 49 | |
| 50 //----------------------------------------------------------------------------- | |
| 51 | |
| 52 // Decodes the cert's subjectAltName extension into a CERT_ALT_NAME_INFO | |
| 53 // structure and stores it in *output. | |
| 54 void GetCertSubjectAltName( | |
| 55 PCCERT_CONTEXT cert, | |
| 56 scoped_ptr<CERT_ALT_NAME_INFO, base::FreeDeleter>* output) { | |
| 57 PCERT_EXTENSION extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2, | |
| 58 cert->pCertInfo->cExtension, | |
| 59 cert->pCertInfo->rgExtension); | |
| 60 if (!extension) | |
| 61 return; | |
| 62 | |
| 63 CRYPT_DECODE_PARA decode_para; | |
| 64 decode_para.cbSize = sizeof(decode_para); | |
| 65 decode_para.pfnAlloc = crypto::CryptAlloc; | |
| 66 decode_para.pfnFree = crypto::CryptFree; | |
| 67 CERT_ALT_NAME_INFO* alt_name_info = NULL; | |
| 68 DWORD alt_name_info_size = 0; | |
| 69 BOOL rv; | |
| 70 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, | |
| 71 szOID_SUBJECT_ALT_NAME2, | |
| 72 extension->Value.pbData, | |
| 73 extension->Value.cbData, | |
| 74 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, | |
| 75 &decode_para, | |
| 76 &alt_name_info, | |
| 77 &alt_name_info_size); | |
| 78 if (rv) | |
| 79 output->reset(alt_name_info); | |
| 80 } | |
| 81 | |
| 82 void AddCertsFromStore(HCERTSTORE store, | |
| 83 X509Certificate::OSCertHandles* results) { | |
| 84 PCCERT_CONTEXT cert = NULL; | |
| 85 | |
| 86 while ((cert = CertEnumCertificatesInStore(store, cert)) != NULL) { | |
| 87 PCCERT_CONTEXT to_add = NULL; | |
| 88 if (CertAddCertificateContextToStore( | |
| 89 NULL, // The cert won't be persisted in any cert store. This breaks | |
| 90 // any association the context currently has to |store|, which | |
| 91 // allows us, the caller, to safely close |store| without | |
| 92 // releasing the cert handles. | |
| 93 cert, | |
| 94 CERT_STORE_ADD_USE_EXISTING, | |
| 95 &to_add) && to_add != NULL) { | |
| 96 // When processing stores generated from PKCS#7/PKCS#12 files, it | |
| 97 // appears that the order returned is the inverse of the order that it | |
| 98 // appeared in the file. | |
| 99 // TODO(rsleevi): Ensure this order is consistent across all Win | |
| 100 // versions | |
| 101 results->insert(results->begin(), to_add); | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 X509Certificate::OSCertHandles ParsePKCS7(const char* data, size_t length) { | |
| 107 X509Certificate::OSCertHandles results; | |
| 108 CERT_BLOB data_blob; | |
| 109 data_blob.cbData = length; | |
| 110 data_blob.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(data)); | |
| 111 | |
| 112 HCERTSTORE out_store = NULL; | |
| 113 | |
| 114 DWORD expected_types = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | | |
| 115 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | | |
| 116 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED; | |
| 117 | |
| 118 if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &data_blob, expected_types, | |
| 119 CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, | |
| 120 &out_store, NULL, NULL) || out_store == NULL) { | |
| 121 return results; | |
| 122 } | |
| 123 | |
| 124 AddCertsFromStore(out_store, &results); | |
| 125 CertCloseStore(out_store, CERT_CLOSE_STORE_CHECK_FLAG); | |
| 126 | |
| 127 return results; | |
| 128 } | |
| 129 | |
| 130 // Given a CERT_NAME_BLOB, returns true if it appears in a given list, | |
| 131 // formatted as a vector of strings holding DER-encoded X.509 | |
| 132 // DistinguishedName entries. | |
| 133 bool IsCertNameBlobInIssuerList( | |
| 134 CERT_NAME_BLOB* name_blob, | |
| 135 const std::vector<std::string>& issuer_names) { | |
| 136 for (std::vector<std::string>::const_iterator it = issuer_names.begin(); | |
| 137 it != issuer_names.end(); ++it) { | |
| 138 CERT_NAME_BLOB issuer_blob; | |
| 139 issuer_blob.pbData = | |
| 140 reinterpret_cast<BYTE*>(const_cast<char*>(it->data())); | |
| 141 issuer_blob.cbData = static_cast<DWORD>(it->length()); | |
| 142 | |
| 143 BOOL rb = CertCompareCertificateName( | |
| 144 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &issuer_blob, name_blob); | |
| 145 if (rb) | |
| 146 return true; | |
| 147 } | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 } // namespace | |
| 152 | |
| 153 void X509Certificate::Initialize() { | |
| 154 DCHECK(cert_handle_); | |
| 155 subject_.ParseDistinguishedName(cert_handle_->pCertInfo->Subject.pbData, | |
| 156 cert_handle_->pCertInfo->Subject.cbData); | |
| 157 issuer_.ParseDistinguishedName(cert_handle_->pCertInfo->Issuer.pbData, | |
| 158 cert_handle_->pCertInfo->Issuer.cbData); | |
| 159 | |
| 160 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); | |
| 161 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); | |
| 162 | |
| 163 fingerprint_ = CalculateFingerprint(cert_handle_); | |
| 164 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | |
| 165 | |
| 166 const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber; | |
| 167 scoped_ptr<uint8[]> serial_bytes(new uint8[serial->cbData]); | |
| 168 for (unsigned i = 0; i < serial->cbData; i++) | |
| 169 serial_bytes[i] = serial->pbData[serial->cbData - i - 1]; | |
| 170 serial_number_ = std::string( | |
| 171 reinterpret_cast<char*>(serial_bytes.get()), serial->cbData); | |
| 172 } | |
| 173 | |
| 174 void X509Certificate::GetSubjectAltName( | |
| 175 std::vector<std::string>* dns_names, | |
| 176 std::vector<std::string>* ip_addrs) const { | |
| 177 if (dns_names) | |
| 178 dns_names->clear(); | |
| 179 if (ip_addrs) | |
| 180 ip_addrs->clear(); | |
| 181 | |
| 182 if (!cert_handle_) | |
| 183 return; | |
| 184 | |
| 185 scoped_ptr<CERT_ALT_NAME_INFO, base::FreeDeleter> alt_name_info; | |
| 186 GetCertSubjectAltName(cert_handle_, &alt_name_info); | |
| 187 CERT_ALT_NAME_INFO* alt_name = alt_name_info.get(); | |
| 188 if (alt_name) { | |
| 189 int num_entries = alt_name->cAltEntry; | |
| 190 for (int i = 0; i < num_entries; i++) { | |
| 191 // dNSName is an ASN.1 IA5String representing a string of ASCII | |
| 192 // characters, so we can use UTF16ToASCII here. | |
| 193 const CERT_ALT_NAME_ENTRY& entry = alt_name->rgAltEntry[i]; | |
| 194 | |
| 195 if (dns_names && entry.dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) { | |
| 196 dns_names->push_back(base::UTF16ToASCII(entry.pwszDNSName)); | |
| 197 } else if (ip_addrs && | |
| 198 entry.dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) { | |
| 199 ip_addrs->push_back(std::string( | |
| 200 reinterpret_cast<const char*>(entry.IPAddress.pbData), | |
| 201 entry.IPAddress.cbData)); | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 PCCERT_CONTEXT X509Certificate::CreateOSCertChainForCert() const { | |
| 208 // Create an in-memory certificate store to hold this certificate and | |
| 209 // any intermediate certificates in |intermediate_ca_certs_|. The store | |
| 210 // will be referenced in the returned PCCERT_CONTEXT, and will not be freed | |
| 211 // until the PCCERT_CONTEXT is freed. | |
| 212 ScopedHCERTSTORE store(CertOpenStore( | |
| 213 CERT_STORE_PROV_MEMORY, 0, NULL, | |
| 214 CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL)); | |
| 215 if (!store.get()) | |
| 216 return NULL; | |
| 217 | |
| 218 // NOTE: This preserves all of the properties of |os_cert_handle()| except | |
| 219 // for CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two | |
| 220 // properties that hold access to already-opened private keys. If a handle | |
| 221 // has already been unlocked (eg: PIN prompt), then the first time that the | |
| 222 // identity is used for client auth, it may prompt the user again. | |
| 223 PCCERT_CONTEXT primary_cert; | |
| 224 BOOL ok = CertAddCertificateContextToStore(store.get(), os_cert_handle(), | |
| 225 CERT_STORE_ADD_ALWAYS, | |
| 226 &primary_cert); | |
| 227 if (!ok || !primary_cert) | |
| 228 return NULL; | |
| 229 | |
| 230 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { | |
| 231 CertAddCertificateContextToStore(store.get(), intermediate_ca_certs_[i], | |
| 232 CERT_STORE_ADD_ALWAYS, NULL); | |
| 233 } | |
| 234 | |
| 235 // Note: |store| is explicitly not released, as the call to CertCloseStore() | |
| 236 // when |store| goes out of scope will not actually free the store. Instead, | |
| 237 // the store will be freed when |primary_cert| is freed. | |
| 238 return primary_cert; | |
| 239 } | |
| 240 | |
| 241 // static | |
| 242 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | |
| 243 std::string* encoded) { | |
| 244 if (!cert_handle || !cert_handle->pbCertEncoded || | |
| 245 !cert_handle->cbCertEncoded) { | |
| 246 return false; | |
| 247 } | |
| 248 encoded->assign(reinterpret_cast<char*>(cert_handle->pbCertEncoded), | |
| 249 cert_handle->cbCertEncoded); | |
| 250 return true; | |
| 251 } | |
| 252 | |
| 253 // static | |
| 254 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | |
| 255 X509Certificate::OSCertHandle b) { | |
| 256 DCHECK(a && b); | |
| 257 if (a == b) | |
| 258 return true; | |
| 259 return a->cbCertEncoded == b->cbCertEncoded && | |
| 260 memcmp(a->pbCertEncoded, b->pbCertEncoded, a->cbCertEncoded) == 0; | |
| 261 } | |
| 262 | |
| 263 // static | |
| 264 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | |
| 265 const char* data, int length) { | |
| 266 OSCertHandle cert_handle = NULL; | |
| 267 if (!CertAddEncodedCertificateToStore( | |
| 268 NULL, X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(data), | |
| 269 length, CERT_STORE_ADD_USE_EXISTING, &cert_handle)) | |
| 270 return NULL; | |
| 271 | |
| 272 return cert_handle; | |
| 273 } | |
| 274 | |
| 275 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | |
| 276 const char* data, int length, Format format) { | |
| 277 OSCertHandles results; | |
| 278 switch (format) { | |
| 279 case FORMAT_SINGLE_CERTIFICATE: { | |
| 280 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); | |
| 281 if (handle != NULL) | |
| 282 results.push_back(handle); | |
| 283 break; | |
| 284 } | |
| 285 case FORMAT_PKCS7: | |
| 286 results = ParsePKCS7(data, length); | |
| 287 break; | |
| 288 default: | |
| 289 NOTREACHED() << "Certificate format " << format << " unimplemented"; | |
| 290 break; | |
| 291 } | |
| 292 | |
| 293 return results; | |
| 294 } | |
| 295 | |
| 296 // static | |
| 297 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | |
| 298 OSCertHandle cert_handle) { | |
| 299 return CertDuplicateCertificateContext(cert_handle); | |
| 300 } | |
| 301 | |
| 302 // static | |
| 303 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | |
| 304 CertFreeCertificateContext(cert_handle); | |
| 305 } | |
| 306 | |
| 307 // static | |
| 308 SHA1HashValue X509Certificate::CalculateFingerprint( | |
| 309 OSCertHandle cert) { | |
| 310 DCHECK(NULL != cert->pbCertEncoded); | |
| 311 DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded); | |
| 312 | |
| 313 BOOL rv; | |
| 314 SHA1HashValue sha1; | |
| 315 DWORD sha1_size = sizeof(sha1.data); | |
| 316 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, | |
| 317 cert->cbCertEncoded, sha1.data, &sha1_size); | |
| 318 DCHECK(rv && sha1_size == sizeof(sha1.data)); | |
| 319 if (!rv) | |
| 320 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 321 return sha1; | |
| 322 } | |
| 323 | |
| 324 // static | |
| 325 SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { | |
| 326 DCHECK(NULL != cert->pbCertEncoded); | |
| 327 DCHECK_NE(0u, cert->cbCertEncoded); | |
| 328 | |
| 329 SHA256HashValue sha256; | |
| 330 size_t sha256_size = sizeof(sha256.data); | |
| 331 | |
| 332 // Use crypto::SHA256HashString for two reasons: | |
| 333 // * < Windows Vista does not have universal SHA-256 support. | |
| 334 // * More efficient on Windows > Vista (less overhead since non-default CSP | |
| 335 // is not needed). | |
| 336 base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded), | |
| 337 cert->cbCertEncoded); | |
| 338 crypto::SHA256HashString(der_cert, sha256.data, sha256_size); | |
| 339 return sha256; | |
| 340 } | |
| 341 | |
| 342 SHA1HashValue X509Certificate::CalculateCAFingerprint( | |
| 343 const OSCertHandles& intermediates) { | |
| 344 SHA1HashValue sha1; | |
| 345 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 346 | |
| 347 #if defined(USE_OPENSSL) | |
| 348 SHA_CTX ctx; | |
| 349 if (!SHA1_Init(&ctx)) | |
| 350 return sha1; | |
| 351 for (size_t i = 0; i < intermediates.size(); ++i) { | |
| 352 PCCERT_CONTEXT ca_cert = intermediates[i]; | |
| 353 if (!SHA1_Update(&ctx, ca_cert->pbCertEncoded, ca_cert->cbCertEncoded)) | |
| 354 return sha1; | |
| 355 } | |
| 356 SHA1_Final(sha1.data, &ctx); | |
| 357 #else // !USE_OPENSSL | |
| 358 SHA1Context* sha1_ctx = SHA1_NewContext(); | |
| 359 if (!sha1_ctx) | |
| 360 return sha1; | |
| 361 SHA1_Begin(sha1_ctx); | |
| 362 for (size_t i = 0; i < intermediates.size(); ++i) { | |
| 363 PCCERT_CONTEXT ca_cert = intermediates[i]; | |
| 364 SHA1_Update(sha1_ctx, ca_cert->pbCertEncoded, ca_cert->cbCertEncoded); | |
| 365 } | |
| 366 unsigned int result_len; | |
| 367 SHA1_End(sha1_ctx, sha1.data, &result_len, SHA1_LENGTH); | |
| 368 SHA1_DestroyContext(sha1_ctx, PR_TRUE); | |
| 369 #endif // USE_OPENSSL | |
| 370 | |
| 371 return sha1; | |
| 372 } | |
| 373 | |
| 374 // static | |
| 375 X509Certificate::OSCertHandle | |
| 376 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { | |
| 377 const char* data; | |
| 378 int length; | |
| 379 if (!pickle_iter->ReadData(&data, &length)) | |
| 380 return NULL; | |
| 381 | |
| 382 // Legacy serialized certificates were serialized with extended attributes, | |
| 383 // rather than as DER only. As a result, these serialized certificates are | |
| 384 // not portable across platforms and may have side-effects on Windows due | |
| 385 // to extended attributes being serialized/deserialized - | |
| 386 // http://crbug.com/118706. To avoid deserializing these attributes, write | |
| 387 // the deserialized cert into a temporary cert store and then create a new | |
| 388 // cert from the DER - that is, without attributes. | |
| 389 ScopedHCERTSTORE store( | |
| 390 CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL)); | |
| 391 if (!store.get()) | |
| 392 return NULL; | |
| 393 | |
| 394 OSCertHandle cert_handle = NULL; | |
| 395 if (!CertAddSerializedElementToStore( | |
| 396 store.get(), reinterpret_cast<const BYTE*>(data), length, | |
| 397 CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, | |
| 398 NULL, reinterpret_cast<const void **>(&cert_handle))) { | |
| 399 return NULL; | |
| 400 } | |
| 401 | |
| 402 std::string encoded; | |
| 403 bool ok = GetDEREncoded(cert_handle, &encoded); | |
| 404 FreeOSCertHandle(cert_handle); | |
| 405 cert_handle = NULL; | |
| 406 | |
| 407 if (ok) | |
| 408 cert_handle = CreateOSCertHandleFromBytes(encoded.data(), encoded.size()); | |
| 409 return cert_handle; | |
| 410 } | |
| 411 | |
| 412 // static | |
| 413 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
| 414 Pickle* pickle) { | |
| 415 return pickle->WriteData( | |
| 416 reinterpret_cast<char*>(cert_handle->pbCertEncoded), | |
| 417 cert_handle->cbCertEncoded); | |
| 418 } | |
| 419 | |
| 420 // static | |
| 421 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
| 422 size_t* size_bits, | |
| 423 PublicKeyType* type) { | |
| 424 *type = kPublicKeyTypeUnknown; | |
| 425 *size_bits = 0; | |
| 426 | |
| 427 PCCRYPT_OID_INFO oid_info = CryptFindOIDInfo( | |
| 428 CRYPT_OID_INFO_OID_KEY, | |
| 429 cert_handle->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, | |
| 430 CRYPT_PUBKEY_ALG_OID_GROUP_ID); | |
| 431 if (!oid_info) | |
| 432 return; | |
| 433 | |
| 434 CHECK_EQ(oid_info->dwGroupId, | |
| 435 static_cast<DWORD>(CRYPT_PUBKEY_ALG_OID_GROUP_ID)); | |
| 436 | |
| 437 *size_bits = CertGetPublicKeyLength( | |
| 438 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, | |
| 439 &cert_handle->pCertInfo->SubjectPublicKeyInfo); | |
| 440 | |
| 441 if (IS_SPECIAL_OID_INFO_ALGID(oid_info->Algid)) { | |
| 442 // For an EC public key, oid_info->Algid is CALG_OID_INFO_PARAMETERS | |
| 443 // (0xFFFFFFFE). Need to handle it as a special case. | |
| 444 if (strcmp(oid_info->pszOID, szOID_ECC_PUBLIC_KEY) == 0) { | |
| 445 *type = kPublicKeyTypeECDSA; | |
| 446 } else { | |
| 447 NOTREACHED(); | |
| 448 } | |
| 449 return; | |
| 450 } | |
| 451 switch (oid_info->Algid) { | |
| 452 case CALG_RSA_SIGN: | |
| 453 case CALG_RSA_KEYX: | |
| 454 *type = kPublicKeyTypeRSA; | |
| 455 break; | |
| 456 case CALG_DSS_SIGN: | |
| 457 *type = kPublicKeyTypeDSA; | |
| 458 break; | |
| 459 case CALG_ECDSA: | |
| 460 *type = kPublicKeyTypeECDSA; | |
| 461 break; | |
| 462 case CALG_ECDH: | |
| 463 *type = kPublicKeyTypeECDH; | |
| 464 break; | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 bool X509Certificate::IsIssuedByEncoded( | |
| 469 const std::vector<std::string>& valid_issuers) { | |
| 470 | |
| 471 // If the certificate's issuer in the list? | |
| 472 if (IsCertNameBlobInIssuerList(&cert_handle_->pCertInfo->Issuer, | |
| 473 valid_issuers)) { | |
| 474 return true; | |
| 475 } | |
| 476 // Otherwise, is any of the intermediate CA subjects in the list? | |
| 477 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin(); | |
| 478 it != intermediate_ca_certs_.end(); ++it) { | |
| 479 if (IsCertNameBlobInIssuerList(&(*it)->pCertInfo->Issuer, | |
| 480 valid_issuers)) { | |
| 481 return true; | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 return false; | |
| 486 } | |
| 487 | |
| 488 // static | |
| 489 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { | |
| 490 return !!CryptVerifyCertificateSignatureEx( | |
| 491 NULL, | |
| 492 X509_ASN_ENCODING, | |
| 493 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, | |
| 494 reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), | |
| 495 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, | |
| 496 reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), | |
| 497 0, | |
| 498 NULL); | |
| 499 } | |
| 500 | |
| 501 } // namespace net | |
| OLD | NEW |