• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 <openssl/asn1.h>
8 #include <openssl/crypto.h>
9 #include <openssl/obj_mac.h>
10 #include <openssl/pem.h>
11 #include <openssl/pkcs7.h>
12 #include <openssl/sha.h>
13 #include <openssl/ssl.h>
14 #include <openssl/x509v3.h>
15 
16 #include "base/memory/singleton.h"
17 #include "base/pickle.h"
18 #include "base/sha1.h"
19 #include "base/string_number_conversions.h"
20 #include "crypto/openssl_util.h"
21 #include "net/base/asn1_util.h"
22 #include "net/base/cert_status_flags.h"
23 #include "net/base/cert_verify_result.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/x509_openssl_util.h"
26 
27 namespace net {
28 
29 namespace nxou = net::x509_openssl_util;
30 
31 namespace {
32 
CreateOSCertHandlesFromPKCS7Bytes(const char * data,int length,X509Certificate::OSCertHandles * handles)33 void CreateOSCertHandlesFromPKCS7Bytes(
34     const char* data, int length,
35     X509Certificate::OSCertHandles* handles) {
36   crypto::EnsureOpenSSLInit();
37   const unsigned char* der_data = reinterpret_cast<const unsigned char*>(data);
38   crypto::ScopedOpenSSL<PKCS7, PKCS7_free> pkcs7_cert(
39       d2i_PKCS7(NULL, &der_data, length));
40   if (!pkcs7_cert.get())
41     return;
42 
43   STACK_OF(X509)* certs = NULL;
44   int nid = OBJ_obj2nid(pkcs7_cert.get()->type);
45   if (nid == NID_pkcs7_signed) {
46     certs = pkcs7_cert.get()->d.sign->cert;
47   } else if (nid == NID_pkcs7_signedAndEnveloped) {
48     certs = pkcs7_cert.get()->d.signed_and_enveloped->cert;
49   }
50 
51   if (certs) {
52     for (int i = 0; i < sk_X509_num(certs); ++i) {
53       X509* x509_cert =
54           X509Certificate::DupOSCertHandle(sk_X509_value(certs, i));
55       handles->push_back(x509_cert);
56     }
57   }
58 }
59 
ParsePrincipalValues(X509_NAME * name,int nid,std::vector<std::string> * fields)60 void ParsePrincipalValues(X509_NAME* name,
61                           int nid,
62                           std::vector<std::string>* fields) {
63   for (int index = -1;
64        (index = X509_NAME_get_index_by_NID(name, nid, index)) != -1;) {
65     std::string field;
66     if (!nxou::ParsePrincipalValueByIndex(name, index, &field))
67       break;
68     fields->push_back(field);
69   }
70 }
71 
ParsePrincipal(X509Certificate::OSCertHandle cert,X509_NAME * x509_name,CertPrincipal * principal)72 void ParsePrincipal(X509Certificate::OSCertHandle cert,
73                     X509_NAME* x509_name,
74                     CertPrincipal* principal) {
75   if (!x509_name)
76     return;
77 
78   ParsePrincipalValues(x509_name, NID_streetAddress,
79                        &principal->street_addresses);
80   ParsePrincipalValues(x509_name, NID_organizationName,
81                        &principal->organization_names);
82   ParsePrincipalValues(x509_name, NID_organizationalUnitName,
83                        &principal->organization_unit_names);
84   ParsePrincipalValues(x509_name, NID_domainComponent,
85                        &principal->domain_components);
86 
87   nxou::ParsePrincipalValueByNID(x509_name, NID_commonName,
88                                  &principal->common_name);
89   nxou::ParsePrincipalValueByNID(x509_name, NID_localityName,
90                                  &principal->locality_name);
91   nxou::ParsePrincipalValueByNID(x509_name, NID_stateOrProvinceName,
92                                  &principal->state_or_province_name);
93   nxou::ParsePrincipalValueByNID(x509_name, NID_countryName,
94                                  &principal->country_name);
95 }
96 
ParseSubjectAltNames(X509Certificate::OSCertHandle cert,std::vector<std::string> * dns_names)97 void ParseSubjectAltNames(X509Certificate::OSCertHandle cert,
98                           std::vector<std::string>* dns_names) {
99   int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
100   X509_EXTENSION* alt_name_ext = X509_get_ext(cert, index);
101   if (!alt_name_ext)
102     return;
103 
104   crypto::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free> alt_names(
105       reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(alt_name_ext)));
106   if (!alt_names.get())
107     return;
108 
109   for (int i = 0; i < sk_GENERAL_NAME_num(alt_names.get()); ++i) {
110     const GENERAL_NAME* name = sk_GENERAL_NAME_value(alt_names.get(), i);
111     if (name->type == GEN_DNS) {
112       unsigned char* dns_name = ASN1_STRING_data(name->d.dNSName);
113       if (!dns_name)
114         continue;
115       int dns_name_len = ASN1_STRING_length(name->d.dNSName);
116       dns_names->push_back(
117           std::string(reinterpret_cast<char*>(dns_name), dns_name_len));
118     }
119   }
120 }
121 
122 // Maps X509_STORE_CTX_get_error() return values to our cert status flags.
MapCertErrorToCertStatus(int err)123 int MapCertErrorToCertStatus(int err) {
124   switch (err) {
125     case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
126       return CERT_STATUS_COMMON_NAME_INVALID;
127     case X509_V_ERR_CERT_NOT_YET_VALID:
128     case X509_V_ERR_CERT_HAS_EXPIRED:
129     case X509_V_ERR_CRL_NOT_YET_VALID:
130     case X509_V_ERR_CRL_HAS_EXPIRED:
131     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
132     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
133     case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
134     case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
135       return CERT_STATUS_DATE_INVALID;
136     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
137     case X509_V_ERR_UNABLE_TO_GET_CRL:
138     case X509_V_ERR_INVALID_CA:
139     case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
140     case X509_V_ERR_INVALID_NON_CA:
141     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
142     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
143     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
144       return CERT_STATUS_AUTHORITY_INVALID;
145 #if 0
146 // TODO(bulach): what should we map to these status?
147       return CERT_STATUS_NO_REVOCATION_MECHANISM;
148       return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
149       return CERT_STATUS_NOT_IN_DNS;
150 #endif
151     case X509_V_ERR_CERT_REVOKED:
152       return CERT_STATUS_REVOKED;
153     case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
154       return CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
155     // All these status are mapped to CERT_STATUS_INVALID.
156     case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
157     case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
158     case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
159     case X509_V_ERR_CERT_SIGNATURE_FAILURE:
160     case X509_V_ERR_CRL_SIGNATURE_FAILURE:
161     case X509_V_ERR_OUT_OF_MEM:
162     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
163     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
164     case X509_V_ERR_PATH_LENGTH_EXCEEDED:
165     case X509_V_ERR_INVALID_PURPOSE:
166     case X509_V_ERR_CERT_UNTRUSTED:
167     case X509_V_ERR_CERT_REJECTED:
168     case X509_V_ERR_AKID_SKID_MISMATCH:
169     case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
170     case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
171     case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
172     case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
173     case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
174     case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
175     case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
176     case X509_V_ERR_INVALID_EXTENSION:
177     case X509_V_ERR_INVALID_POLICY_EXTENSION:
178     case X509_V_ERR_NO_EXPLICIT_POLICY:
179     case X509_V_ERR_UNNESTED_RESOURCE:
180     case X509_V_ERR_APPLICATION_VERIFICATION:
181       return CERT_STATUS_INVALID;
182     default:
183       NOTREACHED() << "Invalid X509 err " << err;
184       return CERT_STATUS_INVALID;
185   }
186 }
187 
188 // sk_X509_free is a function-style macro, so can't be used as a template
189 // param directly.
sk_X509_free_fn(STACK_OF (X509)* st)190 void sk_X509_free_fn(STACK_OF(X509)* st) {
191   sk_X509_free(st);
192 }
193 
194 struct DERCache {
195   unsigned char* data;
196   int data_length;
197 };
198 
DERCache_free(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)199 void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx,
200                    long argl, void* argp) {
201   DERCache* der_cache = static_cast<DERCache*>(ptr);
202   if (!der_cache)
203       return;
204   if (der_cache->data)
205       OPENSSL_free(der_cache->data);
206   OPENSSL_free(der_cache);
207 }
208 
209 class X509InitSingleton {
210  public:
GetInstance()211   static X509InitSingleton* GetInstance() {
212     // We allow the X509 store to leak, because it is used from a non-joinable
213     // worker that is not stopped on shutdown, hence may still be using
214     // OpenSSL library after the AtExit runner has completed.
215     return Singleton<X509InitSingleton,
216                      LeakySingletonTraits<X509InitSingleton> >::get();
217   }
der_cache_ex_index() const218   int der_cache_ex_index() const { return der_cache_ex_index_; }
store() const219   X509_STORE* store() const { return store_.get(); }
220 
ResetCertStore()221   void ResetCertStore() {
222     store_.reset(X509_STORE_new());
223     DCHECK(store_.get());
224     X509_STORE_set_default_paths(store_.get());
225     // TODO(joth): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)).
226   }
227 
228  private:
229   friend struct DefaultSingletonTraits<X509InitSingleton>;
X509InitSingleton()230   X509InitSingleton() {
231     crypto::EnsureOpenSSLInit();
232     der_cache_ex_index_ = X509_get_ex_new_index(0, 0, 0, 0, DERCache_free);
233     DCHECK_NE(der_cache_ex_index_, -1);
234     ResetCertStore();
235   }
236 
237   int der_cache_ex_index_;
238   crypto::ScopedOpenSSL<X509_STORE, X509_STORE_free> store_;
239 
240   DISALLOW_COPY_AND_ASSIGN(X509InitSingleton);
241 };
242 
243 // Takes ownership of |data| (which must have been allocated by OpenSSL).
SetDERCache(X509Certificate::OSCertHandle cert,int x509_der_cache_index,unsigned char * data,int data_length)244 DERCache* SetDERCache(X509Certificate::OSCertHandle cert,
245                       int x509_der_cache_index,
246                       unsigned char* data,
247                       int data_length) {
248   DERCache* internal_cache = static_cast<DERCache*>(
249       OPENSSL_malloc(sizeof(*internal_cache)));
250   if (!internal_cache) {
251     // We took ownership of |data|, so we must free if we can't add it to
252     // |cert|.
253     OPENSSL_free(data);
254     return NULL;
255   }
256 
257   internal_cache->data = data;
258   internal_cache->data_length = data_length;
259   X509_set_ex_data(cert, x509_der_cache_index, internal_cache);
260   return internal_cache;
261 }
262 
263 // Returns true if |der_cache| points to valid data, false otherwise.
264 // (note: the DER-encoded data in |der_cache| is owned by |cert|, callers should
265 // not free it).
GetDERAndCacheIfNeeded(X509Certificate::OSCertHandle cert,DERCache * der_cache)266 bool GetDERAndCacheIfNeeded(X509Certificate::OSCertHandle cert,
267                             DERCache* der_cache) {
268   int x509_der_cache_index =
269       X509InitSingleton::GetInstance()->der_cache_ex_index();
270 
271   // Re-encoding the DER data via i2d_X509 is an expensive operation, but it's
272   // necessary for comparing two certificates. We re-encode at most once per
273   // certificate and cache the data within the X509 cert using X509_set_ex_data.
274   DERCache* internal_cache = static_cast<DERCache*>(
275       X509_get_ex_data(cert, x509_der_cache_index));
276   if (!internal_cache) {
277     unsigned char* data = NULL;
278     int data_length = i2d_X509(cert, &data);
279     if (data_length <= 0 || !data)
280       return false;
281     internal_cache = SetDERCache(cert, x509_der_cache_index, data, data_length);
282     if (!internal_cache)
283       return false;
284   }
285   *der_cache = *internal_cache;
286   return true;
287 }
288 
289 }  // namespace
290 
291 // static
DupOSCertHandle(OSCertHandle cert_handle)292 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
293     OSCertHandle cert_handle) {
294   DCHECK(cert_handle);
295   // Using X509_dup causes the entire certificate to be reparsed. This
296   // conversion, besides being non-trivial, drops any associated
297   // application-specific data set by X509_set_ex_data. Using CRYPTO_add
298   // just bumps up the ref-count for the cert, without causing any allocations
299   // or deallocations.
300   CRYPTO_add(&cert_handle->references, 1, CRYPTO_LOCK_X509);
301   return cert_handle;
302 }
303 
304 // static
FreeOSCertHandle(OSCertHandle cert_handle)305 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
306   // Decrement the ref-count for the cert and, if all references are gone,
307   // free the memory and any application-specific data associated with the
308   // certificate.
309   X509_free(cert_handle);
310 }
311 
Initialize()312 void X509Certificate::Initialize() {
313   crypto::EnsureOpenSSLInit();
314   fingerprint_ = CalculateFingerprint(cert_handle_);
315 
316   ASN1_INTEGER* num = X509_get_serialNumber(cert_handle_);
317   if (num) {
318     serial_number_ = std::string(
319         reinterpret_cast<char*>(num->data),
320         num->length);
321     // Remove leading zeros.
322     while (serial_number_.size() > 1 && serial_number_[0] == 0)
323       serial_number_ = serial_number_.substr(1, serial_number_.size() - 1);
324   }
325 
326   ParsePrincipal(cert_handle_, X509_get_subject_name(cert_handle_), &subject_);
327   ParsePrincipal(cert_handle_, X509_get_issuer_name(cert_handle_), &issuer_);
328   nxou::ParseDate(X509_get_notBefore(cert_handle_), &valid_start_);
329   nxou::ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_);
330 }
331 
332 // static
ResetCertStore()333 void X509Certificate::ResetCertStore() {
334   X509InitSingleton::GetInstance()->ResetCertStore();
335 }
336 
CalculateFingerprint(OSCertHandle cert)337 SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) {
338   SHA1Fingerprint sha1;
339   unsigned int sha1_size = static_cast<unsigned int>(sizeof(sha1.data));
340   int ret = X509_digest(cert, EVP_sha1(), sha1.data, &sha1_size);
341   CHECK(ret);
342   CHECK_EQ(sha1_size, sizeof(sha1.data));
343   return sha1;
344 }
345 
346 // static
CreateOSCertHandleFromBytes(const char * data,int length)347 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
348     const char* data, int length) {
349   if (length < 0)
350     return NULL;
351   crypto::EnsureOpenSSLInit();
352   const unsigned char* d2i_data =
353       reinterpret_cast<const unsigned char*>(data);
354   // Don't cache this data via SetDERCache as this wire format may be not be
355   // identical from the i2d_X509 roundtrip.
356   X509* cert = d2i_X509(NULL, &d2i_data, length);
357   return cert;
358 }
359 
360 // static
CreateOSCertHandlesFromBytes(const char * data,int length,Format format)361 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
362     const char* data, int length, Format format) {
363   OSCertHandles results;
364   if (length < 0)
365     return results;
366 
367   switch (format) {
368     case FORMAT_SINGLE_CERTIFICATE: {
369       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
370       if (handle)
371         results.push_back(handle);
372       break;
373     }
374     case FORMAT_PKCS7: {
375       CreateOSCertHandlesFromPKCS7Bytes(data, length, &results);
376       break;
377     }
378     default: {
379       NOTREACHED() << "Certificate format " << format << " unimplemented";
380       break;
381     }
382   }
383 
384   return results;
385 }
386 
387 // static
CreateSelfSigned(crypto::RSAPrivateKey * key,const std::string & subject,uint32 serial_number,base::TimeDelta valid_duration)388 scoped_refptr<X509Certificate> X509Certificate::CreateSelfSigned(
389     crypto::RSAPrivateKey* key,
390     const std::string& subject,
391     uint32 serial_number,
392     base::TimeDelta valid_duration) {
393   // TODO(port): Implement.
394   return NULL;
395 }
396 
GetDNSNames(std::vector<std::string> * dns_names) const397 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
398   dns_names->clear();
399 
400   ParseSubjectAltNames(cert_handle_, dns_names);
401 
402   if (dns_names->empty())
403     dns_names->push_back(subject_.common_name);
404 }
405 
406 // static
cert_store()407 X509_STORE* X509Certificate::cert_store() {
408   return X509InitSingleton::GetInstance()->store();
409 }
410 
411 #ifndef ANDROID
Verify(const std::string & hostname,int flags,CertVerifyResult * verify_result) const412 int X509Certificate::Verify(const std::string& hostname,
413                             int flags,
414                             CertVerifyResult* verify_result) const {
415   verify_result->Reset();
416 
417   if (IsBlacklisted()) {
418     verify_result->cert_status |= CERT_STATUS_REVOKED;
419     return ERR_CERT_REVOKED;
420   }
421 
422   // TODO(joth): We should fetch the subjectAltNames directly rather than via
423   // GetDNSNames, so we can apply special handling for IP addresses vs DNS
424   // names, etc. See http://crbug.com/62973.
425   std::vector<std::string> cert_names;
426   GetDNSNames(&cert_names);
427   if (!VerifyHostname(hostname, cert_names))
428     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
429 
430   crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(
431       X509_STORE_CTX_new());
432 
433   crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates(
434       sk_X509_new_null());
435   if (!intermediates.get())
436     return ERR_OUT_OF_MEMORY;
437 
438   for (OSCertHandles::const_iterator it = intermediate_ca_certs_.begin();
439        it != intermediate_ca_certs_.end(); ++it) {
440     if (!sk_X509_push(intermediates.get(), *it))
441       return ERR_OUT_OF_MEMORY;
442   }
443   int rv = X509_STORE_CTX_init(ctx.get(), cert_store(),
444                                cert_handle_, intermediates.get());
445   CHECK_EQ(1, rv);
446 
447   if (X509_verify_cert(ctx.get()) != 1) {
448     int x509_error = X509_STORE_CTX_get_error(ctx.get());
449     int cert_status = MapCertErrorToCertStatus(x509_error);
450     LOG(ERROR) << "X509 Verification error "
451         << X509_verify_cert_error_string(x509_error)
452         << " : " << x509_error
453         << " : " << X509_STORE_CTX_get_error_depth(ctx.get())
454         << " : " << cert_status;
455     verify_result->cert_status |= cert_status;
456   }
457 
458   if (IsCertStatusError(verify_result->cert_status))
459     return MapCertStatusToNetError(verify_result->cert_status);
460 
461   STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(ctx.get());
462   for (int i = 0; i < sk_X509_num(chain); ++i) {
463     X509* cert = sk_X509_value(chain, i);
464     DERCache der_cache;
465     if (!GetDERAndCacheIfNeeded(cert, &der_cache))
466       continue;
467 
468     base::StringPiece der_bytes(reinterpret_cast<const char*>(der_cache.data),
469                                 der_cache.data_length);
470     base::StringPiece spki_bytes;
471     if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
472       continue;
473 
474     SHA1Fingerprint hash;
475     base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()),
476                         spki_bytes.size(), hash.data);
477     verify_result->public_key_hashes.push_back(hash);
478   }
479 
480   if (IsPublicKeyBlacklisted(verify_result->public_key_hashes)) {
481     verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
482     return MapCertStatusToNetError(verify_result->cert_status);
483   }
484 
485   // Currently we only ues OpenSSL's default root CA paths, so treat all
486   // correctly verified certs as being from a known root. TODO(joth): if the
487   // motivations described in http://src.chromium.org/viewvc/chrome?view=rev&revision=80778
488   // become an issue on OpenSSL builds, we will need to embed a hardcoded list
489   // of well known root CAs, as per the _mac and _win versions.
490   verify_result->is_issued_by_known_root = true;
491 
492   return OK;
493 }
494 
GetDEREncoded(std::string * encoded)495 bool X509Certificate::GetDEREncoded(std::string* encoded) {
496   DERCache der_cache;
497   if (!GetDERAndCacheIfNeeded(cert_handle_, &der_cache))
498       return false;
499   encoded->assign(reinterpret_cast<const char*>(der_cache.data),
500                   der_cache.data_length);
501   return true;
502 }
503 #endif
504 
505 // static
IsSameOSCert(X509Certificate::OSCertHandle a,X509Certificate::OSCertHandle b)506 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
507                                    X509Certificate::OSCertHandle b) {
508   DCHECK(a && b);
509   if (a == b)
510     return true;
511 
512   // X509_cmp only checks the fingerprint, but we want to compare the whole
513   // DER data. Encoding it from OSCertHandle is an expensive operation, so we
514   // cache the DER (if not already cached via X509_set_ex_data).
515   DERCache der_cache_a, der_cache_b;
516 
517   return GetDERAndCacheIfNeeded(a, &der_cache_a) &&
518       GetDERAndCacheIfNeeded(b, &der_cache_b) &&
519       der_cache_a.data_length == der_cache_b.data_length &&
520       memcmp(der_cache_a.data, der_cache_b.data, der_cache_a.data_length) == 0;
521 }
522 
523 // static
524 X509Certificate::OSCertHandle
ReadCertHandleFromPickle(const Pickle & pickle,void ** pickle_iter)525 X509Certificate::ReadCertHandleFromPickle(const Pickle& pickle,
526                                           void** pickle_iter) {
527   const char* data;
528   int length;
529   if (!pickle.ReadData(pickle_iter, &data, &length))
530     return NULL;
531 
532   return CreateOSCertHandleFromBytes(data, length);
533 }
534 
535 // static
WriteCertHandleToPickle(OSCertHandle cert_handle,Pickle * pickle)536 bool X509Certificate::WriteCertHandleToPickle(OSCertHandle cert_handle,
537                                               Pickle* pickle) {
538   DERCache der_cache;
539   if (!GetDERAndCacheIfNeeded(cert_handle, &der_cache))
540     return false;
541 
542   return pickle->WriteData(
543       reinterpret_cast<const char*>(der_cache.data),
544       der_cache.data_length);
545 }
546 
547 #if defined(ANDROID)
548 // static
GetDEREncodedBytes(OSCertHandle handle)549 std::string X509Certificate::GetDEREncodedBytes(OSCertHandle handle) {
550   DERCache der_cache = {0};
551   GetDERAndCacheIfNeeded(handle, &der_cache);
552   return std::string(reinterpret_cast<const char*>(der_cache.data),
553                      der_cache.data_length);
554 }
555 #endif
556 
557 #if defined(ANDROID)
GetChainDEREncodedBytes(std::vector<std::string> * chain_bytes) const558 void X509Certificate::GetChainDEREncodedBytes(
559     std::vector<std::string>* chain_bytes) const {
560   OSCertHandles cert_handles(intermediate_ca_certs_);
561   // Make sure the peer's own cert is the first in the chain, if it's not
562   // already there.
563   if (cert_handles.empty() || cert_handles[0] != cert_handle_)
564     cert_handles.insert(cert_handles.begin(), cert_handle_);
565 
566   chain_bytes->reserve(cert_handles.size());
567   for (OSCertHandles::const_iterator it = cert_handles.begin();
568        it != cert_handles.end(); ++it) {
569     DERCache der_cache = {0};
570     GetDERAndCacheIfNeeded(*it, &der_cache);
571     std::string cert_bytes = std::string(
572         reinterpret_cast<const char*>(der_cache.data), der_cache.data_length);
573     chain_bytes->push_back(cert_bytes);
574   }
575 }
576 #endif
577 
578 } // namespace net
579