check if acerts linked_list has been initialized before destroying it
[strongswan.git] / src / pluto / ac.c
1 /* Support of X.509 attribute certificates
2 * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
3 * Copyright (C) 2003 Martin Berner, Lukas Suter
4 * Copyright (C) 2009 Andreas Steffen
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <sys/stat.h>
18 #include <time.h>
19
20 #include <debug.h>
21 #include <utils/enumerator.h>
22 #include <utils/linked_list.h>
23 #include <credentials/certificates/ac.h>
24
25 #include "ac.h"
26 #include "ca.h"
27 #include "certs.h"
28 #include "fetch.h"
29 #include "log.h"
30
31 /**
32 * Chained list of X.509 attribute certificates
33 */
34 static linked_list_t *acerts = NULL;
35
36 /**
37 * Initialize the linked list of attribute certificates
38 */
39 void ac_initialize(void)
40 {
41 acerts = linked_list_create();
42 }
43
44 /**
45 * Free the linked list of attribute certificates
46 */
47 void ac_finalize(void)
48 {
49 if (acerts)
50 {
51 acerts->destroy_offset(acerts, offsetof(certificate_t, destroy));
52 }
53 }
54
55 /**
56 * Get a X.509 attribute certificate for a given holder
57 */
58 certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial)
59 {
60 enumerator_t *enumerator;
61 certificate_t *cert, *found = NULL;
62
63 enumerator = acerts->create_enumerator(acerts);
64 while (enumerator->enumerate(enumerator, &cert))
65 {
66 ac_t *ac = (ac_t*)cert;
67
68 if (issuer->equals(issuer, ac->get_holderIssuer(ac)) &&
69 chunk_equals(serial, ac->get_holderSerial(ac)))
70 {
71 found = cert;
72 break;
73 }
74 }
75 enumerator->destroy(enumerator);
76 return found;
77 }
78
79 /**
80 * Verifies a X.509 attribute certificate
81 */
82 bool ac_verify_cert(certificate_t *cert, bool strict)
83 {
84 ac_t *ac = (ac_t*)cert;
85 identification_t *subject = cert->get_subject(cert);
86 identification_t *issuer = cert->get_issuer(cert);
87 chunk_t authKeyID = ac->get_authKeyIdentifier(ac);
88 x509cert_t *aacert;
89 time_t notBefore, valid_until;
90
91 DBG1("holder: '%Y'", subject);
92 DBG1("issuer: '%Y'", issuer);
93
94 if (!cert->get_validity(cert, NULL, NULL, &valid_until))
95 {
96 DBG1("attribute certificate is invalid (valid from %T to %T)",
97 &notBefore, FALSE, &valid_until, FALSE);
98 return FALSE;
99 }
100 DBG1("attribute certificate is valid until %T", &valid_until, FALSE);
101
102 lock_authcert_list("verify_x509acert");
103 aacert = get_authcert(issuer, authKeyID, X509_AA);
104 unlock_authcert_list("verify_x509acert");
105
106 if (aacert == NULL)
107 {
108 DBG1("issuer aacert not found");
109 return FALSE;
110 }
111 DBG2("issuer aacert found");
112
113 if (!cert->issued_by(cert, aacert->cert))
114 {
115 DBG1("attribute certificate signature is invalid");
116 return FALSE;
117 }
118 DBG1("attribute certificate signature is valid");
119
120 return verify_x509cert(aacert, strict, &valid_until);
121 }
122
123 /**
124 * Add a X.509 attribute certificate to the chained list
125 */
126 static void ac_add_cert(certificate_t *cert)
127 {
128 ac_t *ac = (ac_t*)cert;
129 identification_t *hIssuer = ac->get_holderIssuer(ac);
130 chunk_t hSerial = ac->get_holderSerial(ac);
131
132 enumerator_t *enumerator;
133 certificate_t *cert_old;
134
135 enumerator = acerts->create_enumerator(acerts);
136 while (enumerator->enumerate(enumerator, &cert_old))
137 {
138 ac_t *ac_old = (ac_t*)cert_old;
139
140 if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) &&
141 chunk_equals(hSerial, ac_old->get_holderSerial(ac_old)))
142 {
143 if (cert->is_newer(cert, cert_old))
144 {
145 acerts->remove_at(acerts, enumerator);
146 cert_old->destroy(cert_old);
147 }
148 else
149 {
150 cert->destroy(cert);
151 cert = NULL;
152 }
153 break;
154 }
155 }
156 enumerator->destroy(enumerator);
157
158 if (cert)
159 {
160 acerts->insert_last(acerts, cert);
161 }
162 }
163
164 /**
165 * Check if at least one peer attribute matches a connection attribute
166 */
167 bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn,
168 ietf_attributes_t *conn_attributes)
169 {
170 bool match;
171
172 if (conn_attributes == NULL)
173 {
174 return TRUE;
175 }
176
177 match = conn_attributes->matches(conn_attributes, peer_attributes);
178 DBG1("%s: peer with attributes '%s' is %sa member of the groups '%s'",
179 conn, peer_attributes->get_string(peer_attributes),
180 match ? "" : "not ", conn_attributes->get_string(conn_attributes));
181
182 return match;
183 }
184
185 /**
186 * Loads X.509 attribute certificates
187 */
188 void ac_load_certs(void)
189 {
190 enumerator_t *enumerator;
191 struct stat st;
192 char *file;
193
194 DBG1("loading attribute certificates from '%s'", A_CERT_PATH);
195
196 enumerator = enumerator_create_directory(A_CERT_PATH);
197 if (!enumerator)
198 {
199 return;
200 }
201
202 while (enumerator->enumerate(enumerator, NULL, &file, &st))
203 {
204 certificate_t *cert;
205
206 if (!S_ISREG(st.st_mode))
207 {
208 /* skip special file */
209 continue;
210 }
211 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
212 BUILD_FROM_FILE, file, BUILD_END);
213 if (cert)
214 {
215 DBG1(" loaded attribute certificate from '%s'", file);
216 ac_add_cert(cert);
217 }
218 }
219 enumerator->destroy(enumerator);
220 }
221
222 /**
223 * List all X.509 attribute certificates in the chained list
224 */
225 void ac_list_certs(bool utc)
226 {
227 enumerator_t *enumerator;
228 certificate_t *cert;
229 time_t now;
230
231 /* determine the current time */
232 time(&now);
233
234 if (acerts->get_count(acerts) > 0)
235 {
236 whack_log(RC_COMMENT, " ");
237 whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
238 }
239
240 enumerator = acerts->create_enumerator(acerts);
241 while (enumerator->enumerate(enumerator, &cert))
242 {
243 ac_t *ac = (ac_t*)cert;
244 identification_t *entityName, *holderIssuer, *issuer;
245 chunk_t holderSerial, serial, authKeyID;
246 time_t notBefore, notAfter;
247 ietf_attributes_t *groups;
248
249 whack_log(RC_COMMENT, " ");
250
251 entityName = cert->get_subject(cert);
252 if (entityName)
253 {
254 whack_log(RC_COMMENT, " holder: \"%Y\"", entityName);
255 }
256
257 holderIssuer = ac->get_holderIssuer(ac);
258 if (holderIssuer)
259 {
260 whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer);
261 }
262
263 holderSerial = ac->get_holderSerial(ac);
264 if (holderSerial.ptr)
265 {
266 whack_log(RC_COMMENT, " hserial: %#B", &holderSerial);
267 }
268
269 groups = ac->get_groups(ac);
270 if (groups)
271 {
272 whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups));
273 groups->destroy(groups);
274 }
275
276 issuer = cert->get_issuer(cert);
277 whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer);
278
279 serial = ac->get_serial(ac);
280 whack_log(RC_COMMENT, " serial: %#B", &serial);
281
282 cert->get_validity(cert, &now, &notBefore, &notAfter);
283 whack_log(RC_COMMENT, " validity: not before %T %s",
284 &notBefore, utc,
285 (notBefore < now)?"ok":"fatal (not valid yet)");
286 whack_log(RC_COMMENT, " not after %T %s", &notAfter, utc,
287 check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE));
288
289 authKeyID = ac->get_authKeyIdentifier(ac);
290 if (authKeyID.ptr)
291 {
292 whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
293 }
294 }
295 enumerator->destroy(enumerator);
296 }
297