caching of ocsp responses (experimental), no crl caching yet
[strongswan.git] / src / charon / credentials / sets / cert_cache.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "cert_cache.h"
19
20 #include <daemon.h>
21 #include <utils/linked_list.h>
22
23 #define CACHE_LIMIT 30
24
25 typedef struct private_cert_cache_t private_cert_cache_t;
26 typedef struct relation_t relation_t;
27
28 /**
29 * private data of cert_cache
30 */
31 struct private_cert_cache_t {
32
33 /**
34 * public functions
35 */
36 cert_cache_t public;
37
38 /**
39 * list of trusted subject-issuer relations, as relation_t
40 */
41 linked_list_t *relations;
42 };
43
44 /**
45 * A trusted relation between subject and issuer
46 */
47 struct relation_t {
48 /** subject of this relation */
49 certificate_t *subject;
50 /** issuer of this relation */
51 certificate_t *issuer;
52 /** time of last use */
53 time_t last_use;
54 };
55
56 /**
57 * destroy a relation_t structure
58 */
59 static void relation_destroy(relation_t *this)
60 {
61 this->subject->destroy(this->subject);
62 this->issuer->destroy(this->issuer);
63 free(this);
64 }
65
66 /**
67 * Implementation of cert_cache_t.issued_by.
68 */
69 static bool issued_by(private_cert_cache_t *this,
70 certificate_t *subject, certificate_t *issuer)
71 {
72 relation_t *found = NULL, *current, *oldest = NULL;
73 enumerator_t *enumerator;
74
75 /* lookup cache */
76 enumerator = this->relations->create_enumerator(this->relations);
77 while (enumerator->enumerate(enumerator, &current))
78 {
79 if (current->subject == subject && current->issuer == issuer)
80 {
81 current->last_use = time(NULL);
82 found = current;
83 break;
84 }
85 if (oldest == NULL || oldest->last_use <= current->last_use)
86 {
87 oldest = current;
88 }
89 }
90 enumerator->destroy(enumerator);
91 if (found)
92 {
93 return TRUE;
94 }
95 /* no cache hit, check signature */
96 if (!subject->issued_by(subject, issuer))
97 {
98 return FALSE;
99 }
100 /* cache if good, respect cache limit */
101 found = malloc_thing(relation_t);
102 found->subject = subject->get_ref(subject);
103 found->issuer = issuer->get_ref(issuer);
104 found->last_use = time(NULL);
105 if (this->relations->get_count(this->relations) > CACHE_LIMIT && oldest)
106 {
107 this->relations->remove(this->relations, oldest, NULL);
108 relation_destroy(oldest);
109 }
110 this->relations->insert_last(this->relations, found);
111 return TRUE;
112 }
113
114 /**
115 * data associated to a cert enumeration
116 */
117 typedef struct {
118 /** type of requested certificate */
119 certificate_type_t cert;
120 /** type of requested key */
121 key_type_t key;
122 /** ID to get a cert from */
123 identification_t *id;
124 } cert_data_t;
125
126 /**
127 * filter function for certs enumerator
128 */
129 static bool certs_filter(cert_data_t *data, relation_t **in, certificate_t **out)
130 {
131 public_key_t *public;
132 certificate_t *cert;
133
134 cert = (*in)->subject;
135 if ((data->cert == CERT_ANY || cert->get_type(cert) == data->cert) &&
136 (!data->id || cert->has_subject(cert, data->id)))
137 {
138 if (data->key == KEY_ANY)
139 {
140 *out = cert;
141 return TRUE;
142 }
143 public = cert->get_public_key(cert);
144 if (public)
145 {
146 if (public->get_type(public) == data->key)
147 {
148 public->destroy(public);
149 *out = cert;
150 return TRUE;
151 }
152 public->destroy(public);
153 }
154 }
155 return FALSE;
156 }
157
158 /**
159 * implementation of credential_set_t.create_cert_enumerator
160 */
161 static enumerator_t *create_enumerator(private_cert_cache_t *this,
162 certificate_type_t cert, key_type_t key,
163 identification_t *id, bool trusted)
164 {
165 cert_data_t *data;
166
167 if (trusted)
168 {
169 return NULL;
170 }
171 data = malloc_thing(cert_data_t);
172 data->cert = cert;
173 data->key = key;
174 data->id = id;
175
176 return enumerator_create_filter(
177 this->relations->create_enumerator(this->relations),
178 (void*)certs_filter, data, (void*)free);
179 }
180
181 /**
182 * Implementation of cert_cache_t.destroy
183 */
184 static void destroy(private_cert_cache_t *this)
185 {
186 this->relations->destroy_function(this->relations, (void*)relation_destroy);
187 free(this);
188 }
189
190 /*
191 * see header file
192 */
193 cert_cache_t *cert_cache_create()
194 {
195 private_cert_cache_t *this = malloc_thing(private_cert_cache_t);
196
197 this->public.set.create_private_enumerator = (void*)return_null;
198 this->public.set.create_cert_enumerator = (void*)create_enumerator;
199 this->public.set.create_shared_enumerator = (void*)return_null;
200 this->public.set.create_cdp_enumerator = (void*)return_null;
201 this->public.issued_by = (bool(*)(cert_cache_t*, certificate_t *subject, certificate_t *issuer))issued_by;
202 this->public.destroy = (void(*)(cert_cache_t*))destroy;
203
204 this->relations = linked_list_create();
205
206 return &this->public;
207 }
208