• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 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 "base/histogram.h"
8 #include "base/logging.h"
9 #include "base/time.h"
10 
11 namespace net {
12 
13 namespace {
14 
15 // Returns true if this cert fingerprint is the null (all zero) fingerprint.
16 // We use this as a bogus fingerprint value.
IsNullFingerprint(const X509Certificate::Fingerprint & fingerprint)17 bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) {
18   for (size_t i = 0; i < arraysize(fingerprint.data); ++i) {
19     if (fingerprint.data[i] != 0)
20       return false;
21   }
22   return true;
23 }
24 
25 }  // namespace
26 
operator ()(const Fingerprint & lhs,const Fingerprint & rhs) const27 bool X509Certificate::FingerprintLessThan::operator()(
28     const Fingerprint& lhs,
29     const Fingerprint& rhs) const {
30   for (size_t i = 0; i < sizeof(lhs.data); ++i) {
31     if (lhs.data[i] < rhs.data[i])
32       return true;
33     if (lhs.data[i] > rhs.data[i])
34       return false;
35   }
36   return false;
37 }
38 
operator ()(X509Certificate * lhs,X509Certificate * rhs) const39 bool X509Certificate::LessThan::operator()(X509Certificate* lhs,
40                                            X509Certificate* rhs) const {
41   if (lhs == rhs)
42     return false;
43 
44   X509Certificate::FingerprintLessThan fingerprint_functor;
45   return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_);
46 }
47 
48 // A thread-safe cache for X509Certificate objects.
49 //
50 // The cache does not hold a reference to the certificate objects.  The objects
51 // must |Remove| themselves from the cache upon destruction (or else the cache
52 // will be holding dead pointers to the objects).
53 
54 // Get the singleton object for the cache.
55 // static
GetInstance()56 X509Certificate::Cache* X509Certificate::Cache::GetInstance() {
57   return Singleton<X509Certificate::Cache>::get();
58 }
59 
60 // Insert |cert| into the cache.  The cache does NOT AddRef |cert|.  The cache
61 // must not already contain a certificate with the same fingerprint.
Insert(X509Certificate * cert)62 void X509Certificate::Cache::Insert(X509Certificate* cert) {
63   AutoLock lock(lock_);
64 
65   DCHECK(!IsNullFingerprint(cert->fingerprint())) <<
66       "Only insert certs with real fingerprints.";
67   DCHECK(cache_.find(cert->fingerprint()) == cache_.end());
68   cache_[cert->fingerprint()] = cert;
69 };
70 
71 // Remove |cert| from the cache.  The cache does not assume that |cert| is
72 // already in the cache.
Remove(X509Certificate * cert)73 void X509Certificate::Cache::Remove(X509Certificate* cert) {
74   AutoLock lock(lock_);
75 
76   CertMap::iterator pos(cache_.find(cert->fingerprint()));
77   if (pos == cache_.end())
78     return;  // It is not an error to remove a cert that is not in the cache.
79   cache_.erase(pos);
80 };
81 
82 // Find a certificate in the cache with the given fingerprint.  If one does
83 // not exist, this method returns NULL.
Find(const Fingerprint & fingerprint)84 X509Certificate* X509Certificate::Cache::Find(const Fingerprint& fingerprint) {
85   AutoLock lock(lock_);
86 
87   CertMap::iterator pos(cache_.find(fingerprint));
88   if (pos == cache_.end())
89     return NULL;
90 
91   return pos->second;
92 };
93 
Check(X509Certificate * cert) const94 X509Certificate::Policy::Judgment X509Certificate::Policy::Check(
95     X509Certificate* cert) const {
96   // It shouldn't matter which set we check first, but we check denied first
97   // in case something strange has happened.
98 
99   if (denied_.find(cert->fingerprint()) != denied_.end()) {
100     // DCHECK that the order didn't matter.
101     DCHECK(allowed_.find(cert->fingerprint()) == allowed_.end());
102     return DENIED;
103   }
104 
105   if (allowed_.find(cert->fingerprint()) != allowed_.end()) {
106     // DCHECK that the order didn't matter.
107     DCHECK(denied_.find(cert->fingerprint()) == denied_.end());
108     return ALLOWED;
109   }
110 
111   // We don't have a policy for this cert.
112   return UNKNOWN;
113 }
114 
Allow(X509Certificate * cert)115 void X509Certificate::Policy::Allow(X509Certificate* cert) {
116   // Put the cert in the allowed set and (maybe) remove it from the denied set.
117   denied_.erase(cert->fingerprint());
118   allowed_.insert(cert->fingerprint());
119 }
120 
Deny(X509Certificate * cert)121 void X509Certificate::Policy::Deny(X509Certificate* cert) {
122   // Put the cert in the denied set and (maybe) remove it from the allowed set.
123   allowed_.erase(cert->fingerprint());
124   denied_.insert(cert->fingerprint());
125 }
126 
HasAllowedCert() const127 bool X509Certificate::Policy::HasAllowedCert() const {
128   return !allowed_.empty();
129 }
130 
HasDeniedCert() const131 bool X509Certificate::Policy::HasDeniedCert() const {
132   return !denied_.empty();
133 }
134 
135 // static
CreateFromHandle(OSCertHandle cert_handle,Source source)136 X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle,
137                                                    Source source) {
138   DCHECK(cert_handle);
139   DCHECK(source != SOURCE_UNUSED);
140 
141   // Check if we already have this certificate in memory.
142   X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance();
143   X509Certificate* cached_cert =
144       cache->Find(CalculateFingerprint(cert_handle));
145   if (cached_cert) {
146     DCHECK(cached_cert->source_ != SOURCE_UNUSED);
147     if (cached_cert->source_ >= source) {
148       // We've found a certificate with the same fingerprint in our cache.  We
149       // own the |cert_handle|, which makes it our job to free it.
150       FreeOSCertHandle(cert_handle);
151       DHISTOGRAM_COUNTS("X509CertificateReuseCount", 1);
152       return cached_cert;
153     }
154     // Kick out the old certificate from our cache.  The new one is better.
155     cache->Remove(cached_cert);
156   }
157   // Otherwise, allocate a new object.
158   return new X509Certificate(cert_handle, source);
159 }
160 
161 // static
CreateFromBytes(const char * data,int length)162 X509Certificate* X509Certificate::CreateFromBytes(const char* data,
163                                                   int length) {
164   OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length);
165   if (!cert_handle)
166     return NULL;
167 
168   return CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT);
169 }
170 
X509Certificate(OSCertHandle cert_handle,Source source)171 X509Certificate::X509Certificate(OSCertHandle cert_handle, Source source)
172     : cert_handle_(cert_handle),
173       source_(source) {
174   Initialize();
175 }
176 
X509Certificate(const std::string & subject,const std::string & issuer,base::Time start_date,base::Time expiration_date)177 X509Certificate::X509Certificate(const std::string& subject,
178                                  const std::string& issuer,
179                                  base::Time start_date,
180                                  base::Time expiration_date)
181     : subject_(subject),
182       issuer_(issuer),
183       valid_start_(start_date),
184       valid_expiry_(expiration_date),
185       cert_handle_(NULL),
186       source_(SOURCE_UNUSED) {
187   memset(fingerprint_.data, 0, sizeof(fingerprint_.data));
188 }
189 
~X509Certificate()190 X509Certificate::~X509Certificate() {
191   // We might not be in the cache, but it is safe to remove ourselves anyway.
192   X509Certificate::Cache::GetInstance()->Remove(this);
193   if (cert_handle_)
194     FreeOSCertHandle(cert_handle_);
195 #if defined(OS_MACOSX) || defined(OS_WIN)
196   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
197     FreeOSCertHandle(intermediate_ca_certs_[i]);
198 #endif
199 }
200 
HasExpired() const201 bool X509Certificate::HasExpired() const {
202   return base::Time::Now() > valid_expiry();
203 }
204 
205 }  // namespace net
206