d9b49075f48ae7b2a9dd3bdf1351263482d60961
[strongswan.git] / src / libcharon / plugins / certexpire / certexpire_export.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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
16 #include "certexpire_export.h"
17
18 #include <debug.h>
19 #include <utils/hashtable.h>
20 #include <threading/mutex.h>
21 #include <credentials/certificates/x509.h>
22
23 typedef struct private_certexpire_export_t private_certexpire_export_t;
24
25 /**
26 * Private data of an certexpire_export_t object.
27 */
28 struct private_certexpire_export_t {
29
30 /**
31 * Public certexpire_export_t interface.
32 */
33 certexpire_export_t public;
34
35 /**
36 * hashtable caching local trustchains, mapping entry_t => entry_t
37 */
38 hashtable_t *local;
39
40 /**
41 * hashtable caching remote trustchains, mapping entry_t => entry_t
42 */
43 hashtable_t *remote;
44
45 /**
46 * Mutex to lock hashtables
47 */
48 mutex_t *mutex;
49 };
50
51 /**
52 * Maximum number of expiration dates we store (for subject + IM CAs + CA)
53 */
54 #define MAX_TRUSTCHAIN_LENGTH 7
55
56 /**
57 * Hashtable entry
58 */
59 typedef struct {
60 /** certificate subject as subjectAltName or CN of a DN */
61 char id[128];
62 /** list of expiration dates, 0 if no certificate */
63 time_t expire[MAX_TRUSTCHAIN_LENGTH];
64 } entry_t;
65
66 /**
67 * Hashtable hash function
68 */
69 static u_int hash(entry_t *key)
70 {
71 return chunk_hash(chunk_create(key->id, strlen(key->id)));
72 }
73
74 /**
75 * Hashtable equals function
76 */
77 static bool equals(entry_t *a, entry_t *b)
78 {
79 return streq(a->id, b->id);
80 }
81
82 METHOD(certexpire_export_t, add, void,
83 private_certexpire_export_t *this, linked_list_t *trustchain, bool local)
84 {
85 enumerator_t *enumerator;
86 certificate_t *cert;
87 int count;
88
89 count = min(trustchain->get_count(trustchain), MAX_TRUSTCHAIN_LENGTH) - 1;
90
91 enumerator = trustchain->create_enumerator(trustchain);
92 /* get subject cert */
93 if (enumerator->enumerate(enumerator, &cert))
94 {
95 identification_t *id;
96 entry_t *entry;
97 int i;
98
99 INIT(entry);
100
101 /* prefer FQDN subjectAltName... */
102 if (cert->get_type(cert) == CERT_X509)
103 {
104 x509_t *x509 = (x509_t*)cert;
105 enumerator_t *sans;
106
107 sans = x509->create_subjectAltName_enumerator(x509);
108 while (sans->enumerate(sans, &id))
109 {
110 if (id->get_type(id) == ID_FQDN)
111 {
112 snprintf(entry->id, sizeof(entry->id), "%Y", id);
113 break;
114 }
115 }
116 sans->destroy(sans);
117 }
118 /* fallback to CN of DN */
119 if (!entry->id[0])
120 {
121 enumerator_t *parts;
122 id_part_t part;
123 chunk_t data;
124
125 id = cert->get_subject(cert);
126 parts = id->create_part_enumerator(id);
127 while (parts->enumerate(parts, &part, &data))
128 {
129 if (part == ID_PART_RDN_CN)
130 {
131 snprintf(entry->id, sizeof(entry->id), "%.*s",
132 (int)data.len, data.ptr);
133 break;
134 }
135 }
136 parts->destroy(parts);
137 }
138 /* no usable identity? skip */
139 if (!entry->id[0])
140 {
141 enumerator->destroy(enumerator);
142 free(entry);
143 return;
144 }
145
146 /* get intermediate CA expiration dates */
147 cert->get_validity(cert, NULL, NULL, &entry->expire[0]);
148 for (i = 1; i < count && enumerator->enumerate(enumerator, &cert); i++)
149 {
150 cert->get_validity(cert, NULL, NULL, &entry->expire[i]);
151 }
152 /* get CA expiration date, as last array entry */
153 if (enumerator->enumerate(enumerator, &cert))
154 {
155 cert->get_validity(cert, NULL, NULL,
156 &entry->expire[MAX_TRUSTCHAIN_LENGTH - 1]);
157 }
158 this->mutex->lock(this->mutex);
159 if (local)
160 {
161 entry = this->local->put(this->local, entry, entry);
162 }
163 else
164 {
165 entry = this->remote->put(this->remote, entry, entry);
166 }
167 this->mutex->unlock(this->mutex);
168 if (entry)
169 {
170 free(entry);
171 }
172 }
173 enumerator->destroy(enumerator);
174 }
175
176 METHOD(certexpire_export_t, destroy, void,
177 private_certexpire_export_t *this)
178 {
179 entry_t *key, *value;
180 enumerator_t *enumerator;
181
182 enumerator = this->local->create_enumerator(this->local);
183 while (enumerator->enumerate(enumerator, &key, &value))
184 {
185 free(value);
186 }
187 enumerator->destroy(enumerator);
188 enumerator = this->remote->create_enumerator(this->remote);
189 while (enumerator->enumerate(enumerator, &key, &value))
190 {
191 free(value);
192 }
193 enumerator->destroy(enumerator);
194
195 this->local->destroy(this->local);
196 this->remote->destroy(this->remote);
197 this->mutex->destroy(this->mutex);
198 free(this);
199 }
200
201 /**
202 * See header
203 */
204 certexpire_export_t *certexpire_export_create()
205 {
206 private_certexpire_export_t *this;
207
208 INIT(this,
209 .public = {
210 .add = _add,
211 .destroy = _destroy,
212 },
213 .local = hashtable_create((hashtable_hash_t)hash,
214 (hashtable_equals_t)equals, 4),
215 .remote = hashtable_create((hashtable_hash_t)hash,
216 (hashtable_equals_t)equals, 32),
217 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
218 );
219
220 return &this->public;
221 }