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