| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2017 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/numerics/safe_conversions.h" | 
|  | 8 #include "base/pickle.h" | 
|  | 9 #include "crypto/openssl_util.h" | 
|  | 10 #include "net/base/ip_address.h" | 
|  | 11 #include "net/cert/asn1_util.h" | 
|  | 12 #include "net/cert/internal/cert_errors.h" | 
|  | 13 #include "net/cert/internal/name_constraints.h" | 
|  | 14 #include "net/cert/internal/parse_name.h" | 
|  | 15 #include "net/cert/internal/parsed_certificate.h" | 
|  | 16 #include "net/cert/internal/signature_policy.h" | 
|  | 17 #include "net/cert/internal/verify_name_match.h" | 
|  | 18 #include "net/cert/internal/verify_signed_data.h" | 
|  | 19 #include "net/cert/x509_util.h" | 
|  | 20 #include "net/cert/x509_util_openssl.h" | 
|  | 21 #include "net/der/parser.h" | 
|  | 22 #include "third_party/boringssl/src/include/openssl/evp.h" | 
|  | 23 #include "third_party/boringssl/src/include/openssl/pool.h" | 
|  | 24 #include "third_party/boringssl/src/include/openssl/sha.h" | 
|  | 25 | 
|  | 26 namespace net { | 
|  | 27 | 
|  | 28 namespace { | 
|  | 29 | 
|  | 30 // Converts a GeneralizedTime struct to a base::Time, returning true on success | 
|  | 31 // or false if |generalized| was invalid or cannot be represented by | 
|  | 32 // base::Time. | 
|  | 33 bool GeneralizedTimeToBaseTime(const der::GeneralizedTime& generalized, | 
|  | 34                                base::Time* result) { | 
|  | 35   base::Time::Exploded exploded = {0}; | 
|  | 36   exploded.year = generalized.year; | 
|  | 37   exploded.month = generalized.month; | 
|  | 38   exploded.day_of_month = generalized.day; | 
|  | 39   exploded.hour = generalized.hours; | 
|  | 40   exploded.minute = generalized.minutes; | 
|  | 41   exploded.second = generalized.seconds; | 
|  | 42   return base::Time::FromUTCExploded(exploded, result); | 
|  | 43 } | 
|  | 44 | 
|  | 45 // Sets |value| to the Value from a DER Sequence Tag-Length-Value and return | 
|  | 46 // true, or return false if the TLV was not a valid DER Sequence. | 
|  | 47 WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv, | 
|  | 48                                          der::Input* value) { | 
|  | 49   der::Parser parser(tlv); | 
|  | 50   return parser.ReadTag(der::kSequence, value) && !parser.HasMore(); | 
|  | 51 } | 
|  | 52 | 
|  | 53 // Normalize |cert|'s Issuer and store it in |out_normalized_issuer|, returning | 
|  | 54 // true on success or false if there was a parsing error. | 
|  | 55 bool GetNormalizedCertIssuer(CRYPTO_BUFFER* cert, | 
|  | 56                              std::string* out_normalized_issuer) { | 
|  | 57   der::Input tbs_certificate_tlv; | 
|  | 58   der::Input signature_algorithm_tlv; | 
|  | 59   der::BitString signature_value; | 
|  | 60   if (!ParseCertificate( | 
|  | 61           der::Input(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert)), | 
|  | 62           &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, | 
|  | 63           nullptr)) { | 
|  | 64     return false; | 
|  | 65   } | 
|  | 66   ParsedTbsCertificate tbs; | 
|  | 67   if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) | 
|  | 68     return false; | 
|  | 69 | 
|  | 70   der::Input issuer_value; | 
|  | 71   if (!GetSequenceValue(tbs.issuer_tlv, &issuer_value)) | 
|  | 72     return false; | 
|  | 73 | 
|  | 74   return NormalizeName(issuer_value, out_normalized_issuer); | 
|  | 75 } | 
|  | 76 | 
|  | 77 // Fills |principal| from the DER encoded |name_tlv|, returning true on success | 
|  | 78 // or false if parsing failed or some of the values could not be converted to | 
|  | 79 // UTF-8. | 
|  | 80 bool ParsePrincipal(const der::Input& name_tlv, CertPrincipal* principal) { | 
|  | 81   RDNSequence rdns; | 
|  | 82   if (!ParseName(name_tlv, &rdns)) | 
|  | 83     return false; | 
|  | 84 | 
|  | 85   for (const RelativeDistinguishedName& rdn : rdns) { | 
|  | 86     for (const X509NameAttribute& name_attribute : rdn) { | 
|  | 87       if (name_attribute.type == TypeCommonNameOid()) { | 
|  | 88         if (principal->common_name.empty() && | 
|  | 89             !name_attribute.ValueAsString(&principal->common_name)) { | 
|  | 90           return false; | 
|  | 91         } | 
|  | 92       } else if (name_attribute.type == TypeLocalityNameOid()) { | 
|  | 93         if (principal->locality_name.empty() && | 
|  | 94             !name_attribute.ValueAsString(&principal->locality_name)) { | 
|  | 95           return false; | 
|  | 96         } | 
|  | 97       } else if (name_attribute.type == TypeStateOrProvinceNameOid()) { | 
|  | 98         if (principal->state_or_province_name.empty() && | 
|  | 99             !name_attribute.ValueAsString(&principal->state_or_province_name)) { | 
|  | 100           return false; | 
|  | 101         } | 
|  | 102       } else if (name_attribute.type == TypeCountryNameOid()) { | 
|  | 103         if (principal->country_name.empty() && | 
|  | 104             !name_attribute.ValueAsString(&principal->country_name)) { | 
|  | 105           return false; | 
|  | 106         } | 
|  | 107       } else if (name_attribute.type == TypeStreetAddressOid()) { | 
|  | 108         std::string s; | 
|  | 109         if (!name_attribute.ValueAsString(&s)) | 
|  | 110           return false; | 
|  | 111         principal->street_addresses.push_back(s); | 
|  | 112       } else if (name_attribute.type == TypeOrganizationNameOid()) { | 
|  | 113         std::string s; | 
|  | 114         if (!name_attribute.ValueAsString(&s)) | 
|  | 115           return false; | 
|  | 116         principal->organization_names.push_back(s); | 
|  | 117       } else if (name_attribute.type == TypeOrganizationUnitNameOid()) { | 
|  | 118         std::string s; | 
|  | 119         if (!name_attribute.ValueAsString(&s)) | 
|  | 120           return false; | 
|  | 121         principal->organization_unit_names.push_back(s); | 
|  | 122       } else if (name_attribute.type == TypeDomainComponentOid()) { | 
|  | 123         std::string s; | 
|  | 124         if (!name_attribute.ValueAsString(&s)) | 
|  | 125           return false; | 
|  | 126         principal->domain_components.push_back(s); | 
|  | 127       } | 
|  | 128     } | 
|  | 129   } | 
|  | 130   return true; | 
|  | 131 } | 
|  | 132 | 
|  | 133 // Parses certificates from a PKCS#7 SignedData structure, appending them to | 
|  | 134 // |handles|. | 
|  | 135 void CreateOSCertHandlesFromPKCS7Bytes( | 
|  | 136     const char* data, | 
|  | 137     size_t length, | 
|  | 138     X509Certificate::OSCertHandles* handles) { | 
|  | 139   crypto::EnsureOpenSSLInit(); | 
|  | 140   crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE); | 
|  | 141 | 
|  | 142   CBS der_data; | 
|  | 143   CBS_init(&der_data, reinterpret_cast<const uint8_t*>(data), length); | 
|  | 144   STACK_OF(X509)* certs = sk_X509_new_null(); | 
|  | 145 | 
|  | 146   if (PKCS7_get_certificates(certs, &der_data)) { | 
|  | 147     for (size_t i = 0; i < sk_X509_num(certs); ++i) { | 
|  | 148       base::StringPiece stringpiece; | 
|  | 149       x509_util::GetDER(sk_X509_value(certs, i), &stringpiece); | 
|  | 150       handles->push_back(x509_util::CreateCryptoBuffer(stringpiece).release()); | 
|  | 151     } | 
|  | 152   } | 
|  | 153   sk_X509_pop_free(certs, X509_free); | 
|  | 154 } | 
|  | 155 | 
|  | 156 }  // namespace | 
|  | 157 | 
|  | 158 bool X509Certificate::Initialize() { | 
|  | 159   der::Input tbs_certificate_tlv; | 
|  | 160   der::Input signature_algorithm_tlv; | 
|  | 161   der::BitString signature_value; | 
|  | 162 | 
|  | 163   if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), | 
|  | 164                                    CRYPTO_BUFFER_len(cert_handle_)), | 
|  | 165                         &tbs_certificate_tlv, &signature_algorithm_tlv, | 
|  | 166                         &signature_value, nullptr)) { | 
|  | 167     return false; | 
|  | 168   } | 
|  | 169 | 
|  | 170   ParsedTbsCertificate tbs; | 
|  | 171   if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) | 
|  | 172     return false; | 
|  | 173 | 
|  | 174   if (!ParsePrincipal(tbs.subject_tlv, &subject_) || | 
|  | 175       !ParsePrincipal(tbs.issuer_tlv, &issuer_)) { | 
|  | 176     return false; | 
|  | 177   } | 
|  | 178 | 
|  | 179   if (!GeneralizedTimeToBaseTime(tbs.validity_not_before, &valid_start_) || | 
|  | 180       !GeneralizedTimeToBaseTime(tbs.validity_not_after, &valid_expiry_)) { | 
|  | 181     return false; | 
|  | 182   } | 
|  | 183   serial_number_ = tbs.serial_number.AsString(); | 
|  | 184   return true; | 
|  | 185 } | 
|  | 186 | 
|  | 187 bool X509Certificate::GetSubjectAltName( | 
|  | 188     std::vector<std::string>* dns_names, | 
|  | 189     std::vector<std::string>* ip_addrs) const { | 
|  | 190   if (dns_names) | 
|  | 191     dns_names->clear(); | 
|  | 192   if (ip_addrs) | 
|  | 193     ip_addrs->clear(); | 
|  | 194 | 
|  | 195   der::Input tbs_certificate_tlv; | 
|  | 196   der::Input signature_algorithm_tlv; | 
|  | 197   der::BitString signature_value; | 
|  | 198   if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), | 
|  | 199                                    CRYPTO_BUFFER_len(cert_handle_)), | 
|  | 200                         &tbs_certificate_tlv, &signature_algorithm_tlv, | 
|  | 201                         &signature_value, nullptr)) { | 
|  | 202     return false; | 
|  | 203   } | 
|  | 204 | 
|  | 205   ParsedTbsCertificate tbs; | 
|  | 206   if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) | 
|  | 207     return false; | 
|  | 208   if (!tbs.has_extensions) | 
|  | 209     return false; | 
|  | 210 | 
|  | 211   std::map<der::Input, ParsedExtension> extensions; | 
|  | 212   if (!ParseExtensions(tbs.extensions_tlv, &extensions)) | 
|  | 213     return false; | 
|  | 214 | 
|  | 215   ParsedExtension subject_alt_names_extension; | 
|  | 216   if (!ConsumeExtension(SubjectAltNameOid(), &extensions, | 
|  | 217                         &subject_alt_names_extension)) { | 
|  | 218     return false; | 
|  | 219   } | 
|  | 220 | 
|  | 221   std::unique_ptr<GeneralNames> subject_alt_names = | 
|  | 222       GeneralNames::Create(subject_alt_names_extension.value); | 
|  | 223   if (!subject_alt_names) | 
|  | 224     return false; | 
|  | 225 | 
|  | 226   if (dns_names) | 
|  | 227     *dns_names = subject_alt_names->dns_names; | 
|  | 228   if (ip_addrs) { | 
|  | 229     for (const IPAddress& addr : subject_alt_names->ip_addresses) { | 
|  | 230       ip_addrs->push_back( | 
|  | 231           std::string(reinterpret_cast<const char*>(addr.bytes().data()), | 
|  | 232                       addr.bytes().size())); | 
|  | 233     } | 
|  | 234   } | 
|  | 235 | 
|  | 236   return !subject_alt_names->dns_names.empty() || | 
|  | 237          !subject_alt_names->ip_addresses.empty(); | 
|  | 238 } | 
|  | 239 | 
|  | 240 bool X509Certificate::IsIssuedByEncoded( | 
|  | 241     const std::vector<std::string>& valid_issuers) { | 
|  | 242   std::vector<std::string> normalized_issuers; | 
|  | 243   for (const auto& raw_issuer : valid_issuers) { | 
|  | 244     der::Input issuer_value; | 
|  | 245     std::string normalized_issuer; | 
|  | 246     if (!GetSequenceValue(der::Input(&raw_issuer), &issuer_value) || | 
|  | 247         !NormalizeName(issuer_value, &normalized_issuer)) { | 
|  | 248       continue; | 
|  | 249     } | 
|  | 250     normalized_issuers.push_back(std::move(normalized_issuer)); | 
|  | 251   } | 
|  | 252 | 
|  | 253   std::string normalized_cert_issuer; | 
|  | 254   if (!GetNormalizedCertIssuer(cert_handle_, &normalized_cert_issuer)) | 
|  | 255     return false; | 
|  | 256   if (std::find(normalized_issuers.begin(), normalized_issuers.end(), | 
|  | 257                 normalized_cert_issuer) != normalized_issuers.end()) | 
|  | 258     return true; | 
|  | 259 | 
|  | 260   for (CRYPTO_BUFFER* intermediate : intermediate_ca_certs_) { | 
|  | 261     if (!GetNormalizedCertIssuer(intermediate, &normalized_cert_issuer)) | 
|  | 262       return false; | 
|  | 263     if (std::find(normalized_issuers.begin(), normalized_issuers.end(), | 
|  | 264                   normalized_cert_issuer) != normalized_issuers.end()) | 
|  | 265       return true; | 
|  | 266   } | 
|  | 267   return false; | 
|  | 268 } | 
|  | 269 | 
|  | 270 // static | 
|  | 271 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, | 
|  | 272                                     std::string* encoded) { | 
|  | 273   if (!cert_handle) | 
|  | 274     return false; | 
|  | 275   encoded->assign( | 
|  | 276       reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), | 
|  | 277       CRYPTO_BUFFER_len(cert_handle)); | 
|  | 278   return true; | 
|  | 279 } | 
|  | 280 | 
|  | 281 // static | 
|  | 282 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | 
|  | 283                                        size_t* size_bits, | 
|  | 284                                        PublicKeyType* type) { | 
|  | 285   *type = kPublicKeyTypeUnknown; | 
|  | 286   *size_bits = 0; | 
|  | 287 | 
|  | 288   base::StringPiece spki; | 
|  | 289   if (!asn1::ExtractSPKIFromDERCert( | 
|  | 290           base::StringPiece( | 
|  | 291               reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), | 
|  | 292               CRYPTO_BUFFER_len(cert_handle)), | 
|  | 293           &spki)) { | 
|  | 294     return; | 
|  | 295   } | 
|  | 296 | 
|  | 297   bssl::UniquePtr<EVP_PKEY> pkey; | 
|  | 298   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 
|  | 299   CBS cbs; | 
|  | 300   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spki.data()), spki.size()); | 
|  | 301   pkey.reset(EVP_parse_public_key(&cbs)); | 
|  | 302   if (!pkey) | 
|  | 303     return; | 
|  | 304 | 
|  | 305   switch (pkey->type) { | 
|  | 306     case EVP_PKEY_RSA: | 
|  | 307       *type = kPublicKeyTypeRSA; | 
|  | 308       break; | 
|  | 309     case EVP_PKEY_DSA: | 
|  | 310       *type = kPublicKeyTypeDSA; | 
|  | 311       break; | 
|  | 312     case EVP_PKEY_EC: | 
|  | 313       *type = kPublicKeyTypeECDSA; | 
|  | 314       break; | 
|  | 315     case EVP_PKEY_DH: | 
|  | 316       *type = kPublicKeyTypeDH; | 
|  | 317       break; | 
|  | 318   } | 
|  | 319   *size_bits = base::saturated_cast<size_t>(EVP_PKEY_bits(pkey.get())); | 
|  | 320 } | 
|  | 321 | 
|  | 322 // static | 
|  | 323 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | 
|  | 324                                    X509Certificate::OSCertHandle b) { | 
|  | 325   DCHECK(a && b); | 
|  | 326   if (a == b) | 
|  | 327     return true; | 
|  | 328   return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) && | 
|  | 329          memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b), | 
|  | 330                 CRYPTO_BUFFER_len(a)) == 0; | 
|  | 331 } | 
|  | 332 | 
|  | 333 // static | 
|  | 334 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | 
|  | 335     const char* data, | 
|  | 336     size_t length) { | 
|  | 337   der::Input tbs_certificate_tlv; | 
|  | 338   der::Input signature_algorithm_tlv; | 
|  | 339   der::BitString signature_value; | 
|  | 340   // Do a bare minimum of DER parsing here to make sure the input is not | 
|  | 341   // completely crazy. (This is required for at least | 
|  | 342   // CreateCertificateListFromBytes with FORMAT_AUTO, if not more.) | 
|  | 343   if (!ParseCertificate( | 
|  | 344           der::Input(reinterpret_cast<const uint8_t*>(data), length), | 
|  | 345           &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, | 
|  | 346           nullptr)) { | 
|  | 347     return nullptr; | 
|  | 348   } | 
|  | 349 | 
|  | 350   return CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(data), length, | 
|  | 351                            x509_util::GetBufferPool()); | 
|  | 352 } | 
|  | 353 | 
|  | 354 // static | 
|  | 355 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | 
|  | 356     const char* data, | 
|  | 357     size_t length, | 
|  | 358     Format format) { | 
|  | 359   OSCertHandles results; | 
|  | 360 | 
|  | 361   switch (format) { | 
|  | 362     case FORMAT_SINGLE_CERTIFICATE: { | 
|  | 363       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); | 
|  | 364       if (handle) | 
|  | 365         results.push_back(handle); | 
|  | 366       break; | 
|  | 367     } | 
|  | 368     case FORMAT_PKCS7: { | 
|  | 369       CreateOSCertHandlesFromPKCS7Bytes(data, length, &results); | 
|  | 370       break; | 
|  | 371     } | 
|  | 372     default: { | 
|  | 373       NOTREACHED() << "Certificate format " << format << " unimplemented"; | 
|  | 374       break; | 
|  | 375     } | 
|  | 376   } | 
|  | 377 | 
|  | 378   return results; | 
|  | 379 } | 
|  | 380 | 
|  | 381 // static | 
|  | 382 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | 
|  | 383     OSCertHandle cert_handle) { | 
|  | 384   CRYPTO_BUFFER_up_ref(cert_handle); | 
|  | 385   return cert_handle; | 
|  | 386 } | 
|  | 387 | 
|  | 388 // static | 
|  | 389 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | 
|  | 390   CRYPTO_BUFFER_free(cert_handle); | 
|  | 391 } | 
|  | 392 | 
|  | 393 // static | 
|  | 394 SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { | 
|  | 395   SHA256HashValue sha256; | 
|  | 396 | 
|  | 397   SHA256(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert), sha256.data); | 
|  | 398   return sha256; | 
|  | 399 } | 
|  | 400 | 
|  | 401 // static | 
|  | 402 SHA256HashValue X509Certificate::CalculateCAFingerprint256( | 
|  | 403     const OSCertHandles& intermediates) { | 
|  | 404   SHA256HashValue sha256; | 
|  | 405   memset(sha256.data, 0, sizeof(sha256.data)); | 
|  | 406 | 
|  | 407   SHA256_CTX sha256_ctx; | 
|  | 408   SHA256_Init(&sha256_ctx); | 
|  | 409   for (CRYPTO_BUFFER* cert : intermediates) { | 
|  | 410     SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert), | 
|  | 411                   CRYPTO_BUFFER_len(cert)); | 
|  | 412   } | 
|  | 413   SHA256_Final(sha256.data, &sha256_ctx); | 
|  | 414 | 
|  | 415   return sha256; | 
|  | 416 } | 
|  | 417 | 
|  | 418 // static | 
|  | 419 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { | 
|  | 420   der::Input tbs_certificate_tlv; | 
|  | 421   der::Input signature_algorithm_tlv; | 
|  | 422   der::BitString signature_value; | 
|  | 423   if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle), | 
|  | 424                                    CRYPTO_BUFFER_len(cert_handle)), | 
|  | 425                         &tbs_certificate_tlv, &signature_algorithm_tlv, | 
|  | 426                         &signature_value, nullptr)) { | 
|  | 427     return false; | 
|  | 428   } | 
|  | 429   ParsedTbsCertificate tbs; | 
|  | 430   if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs, nullptr)) { | 
|  | 431     return false; | 
|  | 432   } | 
|  | 433 | 
|  | 434   der::Input subject_value; | 
|  | 435   std::string normalized_subject; | 
|  | 436   if (!GetSequenceValue(tbs.subject_tlv, &subject_value) || | 
|  | 437       !NormalizeName(subject_value, &normalized_subject)) { | 
|  | 438     return false; | 
|  | 439   } | 
|  | 440   der::Input issuer_value; | 
|  | 441   std::string normalized_issuer; | 
|  | 442   if (!GetSequenceValue(tbs.issuer_tlv, &issuer_value) || | 
|  | 443       !NormalizeName(issuer_value, &normalized_issuer)) { | 
|  | 444     return false; | 
|  | 445   } | 
|  | 446 | 
|  | 447   if (normalized_subject != normalized_issuer) | 
|  | 448     return false; | 
|  | 449 | 
|  | 450   std::unique_ptr<SignatureAlgorithm> signature_algorithm = | 
|  | 451       SignatureAlgorithm::Create(signature_algorithm_tlv, nullptr /* errors */); | 
|  | 452   if (!signature_algorithm) | 
|  | 453     return false; | 
|  | 454 | 
|  | 455   SimpleSignaturePolicy signature_policy(1024); | 
|  | 456   CertErrors unused_errors; | 
|  | 457   return VerifySignedData(*signature_algorithm, tbs_certificate_tlv, | 
|  | 458                           signature_value, tbs.spki_tlv, &signature_policy, | 
|  | 459                           &unused_errors); | 
|  | 460 } | 
|  | 461 | 
|  | 462 // static | 
|  | 463 X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle( | 
|  | 464     base::PickleIterator* pickle_iter) { | 
|  | 465   const char* data; | 
|  | 466   int length; | 
|  | 467   if (!pickle_iter->ReadData(&data, &length)) | 
|  | 468     return NULL; | 
|  | 469 | 
|  | 470   return CreateOSCertHandleFromBytes(data, length); | 
|  | 471 } | 
|  | 472 | 
|  | 473 // static | 
|  | 474 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | 
|  | 475                                                 base::Pickle* pickle) { | 
|  | 476   return pickle->WriteData( | 
|  | 477       reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), | 
|  | 478       CRYPTO_BUFFER_len(cert_handle)); | 
|  | 479 } | 
|  | 480 | 
|  | 481 }  // namespace net | 
| OLD | NEW | 
|---|