pluto now uses x509 plugin for attribute certificate handling
[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 <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <sys/types.h>
23
24 #include <freeswan.h>
25
26 #include <utils.h>
27 #include <credentials/certificates/ac.h>
28
29 #include "ac.h"
30 #include "x509.h"
31 #include "crl.h"
32 #include "ca.h"
33 #include "certs.h"
34 #include "log.h"
35 #include "whack.h"
36 #include "fetch.h"
37 #include "builder.h"
38
39 /**
40 * Chained list of X.509 attribute certificates
41 */
42 static x509acert_t *x509acerts = NULL;
43
44 /**
45 * Free a X.509 attribute certificate
46 */
47 void free_acert(x509acert_t *ac)
48 {
49 if (ac)
50 {
51 DESTROY_IF(ac->ac);
52 free(ac);
53 }
54 }
55
56 /**
57 * Free first X.509 attribute certificate in the chained list
58 */
59 static void free_first_acert(void)
60 {
61 x509acert_t *first = x509acerts;
62 x509acerts = first->next;
63 free_acert(first);
64 }
65
66 /**
67 * Free all attribute certificates in the chained list
68 */
69 void free_acerts(void)
70 {
71 while (x509acerts != NULL)
72 {
73 free_first_acert();
74 }
75 }
76
77 /**
78 * Get a X.509 attribute certificate for a given holder
79 */
80 x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial)
81 {
82 x509acert_t *x509ac = x509acerts;
83 x509acert_t *prev_ac = NULL;
84
85 while (x509ac != NULL)
86 {
87 ac_t *ac = (ac_t*)x509ac->ac;
88 identification_t *holderIssuer = ac->get_holderIssuer(ac);
89 chunk_t holderIssuer_dn = holderIssuer->get_encoding(holderIssuer);
90 chunk_t holderSerial = ac->get_holderSerial(ac);
91
92 if (same_dn(issuer, holderIssuer_dn) &&
93 chunk_equals(serial, holderSerial))
94 {
95 if (x509ac!= x509acerts)
96 {
97 /* bring the certificate up front */
98 prev_ac->next = x509ac->next;
99 x509ac->next = x509acerts;
100 x509acerts = x509ac;
101 }
102 return x509ac;
103 }
104 prev_ac = x509ac;
105 x509ac = x509ac->next;
106 }
107 return NULL;
108 }
109
110 /**
111 * Add a X.509 attribute certificate to the chained list
112 */
113 static void add_acert(x509acert_t *x509ac)
114 {
115 certificate_t *cert_ac = x509ac->ac;
116 ac_t *ac = (ac_t*)cert_ac;
117 identification_t *holderIssuer = ac->get_holderIssuer(ac);
118 chunk_t holderIssuer_dn = holderIssuer->get_encoding(holderIssuer);
119 chunk_t holderSerial = ac->get_serial(ac);
120 x509acert_t *old_ac;
121
122 old_ac = get_x509acert(holderIssuer_dn, holderSerial);
123 if (old_ac != NULL)
124 {
125 if (cert_ac->is_newer(cert_ac, old_ac->ac))
126 {
127 /* delete the old attribute cert */
128 free_first_acert();
129 DBG(DBG_CONTROL,
130 DBG_log("attribute cert is newer - existing cert deleted")
131 )
132 }
133 else
134 {
135 DBG(DBG_CONTROL,
136 DBG_log("attribute cert is not newer - existing cert kept");
137 )
138 free_acert(x509ac);
139 return;
140 }
141 }
142 plog("attribute cert added");
143
144 /* insert new attribute cert at the root of the chain */
145 x509ac->next = x509acerts;
146 x509acerts = x509ac;
147 }
148
149 /**
150 * verifies a X.509 attribute certificate
151 */
152 bool verify_x509acert(x509acert_t *x509ac, bool strict)
153 {
154 certificate_t *cert_ac = x509ac->ac;
155 ac_t *ac = (ac_t*)cert_ac;
156 identification_t *subject = cert_ac->get_subject(cert_ac);
157 identification_t *issuer = cert_ac->get_issuer(cert_ac);
158 chunk_t issuer_dn = issuer->get_encoding(issuer);
159 chunk_t authKeyID = ac->get_authKeyIdentifier(ac);
160 x509cert_t *aacert;
161 time_t valid_until;
162
163 DBG(DBG_CONTROL,
164 DBG_log("holder: '%Y'", subject);
165 DBG_log("issuer: '%Y'", issuer);
166 )
167
168 if (!cert_ac->get_validity(cert_ac, NULL, NULL, &valid_until))
169 {
170 return FALSE;
171 }
172 DBG(DBG_CONTROL,
173 DBG_log("attribute certificate is valid until %T", &valid_until, TRUE)
174 )
175
176 lock_authcert_list("verify_x509acert");
177 aacert = get_authcert(issuer_dn, authKeyID, X509_AA);
178 unlock_authcert_list("verify_x509acert");
179
180 if (aacert == NULL)
181 {
182 plog("issuer aacert not found");
183 return FALSE;
184 }
185 DBG(DBG_CONTROL,
186 DBG_log("issuer aacert found")
187 )
188
189 if (!cert_ac->issued_by(cert_ac, aacert->cert))
190 {
191 plog("attribute certificate signature is invalid");
192 return FALSE;
193 }
194 DBG(DBG_CONTROL,
195 DBG_log("attribute certificate signature is valid");
196 )
197
198 return verify_x509cert(aacert, strict, &valid_until);
199 }
200
201 /**
202 * Check if at least one peer attribute matches a connection attribute
203 */
204 bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn,
205 ietf_attributes_t *conn_attributes)
206 {
207 bool match;
208
209 if (conn_attributes == NULL)
210 {
211 return TRUE;
212 }
213
214 match = conn_attributes->matches(conn_attributes, peer_attributes);
215 DBG(DBG_CONTROL,
216 DBG_log("%s: peer with attributes '%s' is %sa member of the groups '%s'",
217 conn,
218 peer_attributes->get_string(peer_attributes),
219 match ? "" : "not ",
220 conn_attributes->get_string(conn_attributes))
221 )
222 return match;
223
224 }
225
226 /**
227 * Loads X.509 attribute certificates
228 */
229 void load_acerts(void)
230 {
231 u_char buf[BUF_LEN];
232
233 /* change directory to specified path */
234 u_char *save_dir = getcwd(buf, BUF_LEN);
235
236 if (!chdir(A_CERT_PATH))
237 {
238 struct dirent **filelist;
239 int n;
240
241 plog("Changing to directory '%s'",A_CERT_PATH);
242 n = scandir(A_CERT_PATH, &filelist, file_select, alphasort);
243
244 if (n > 0)
245 {
246 while (n--)
247 {
248 char *filename = filelist[n]->d_name;
249 x509acert_t *ac;
250
251 ac = lib->creds->create(lib->creds, CRED_CERTIFICATE,
252 CERT_PLUTO_AC, BUILD_FROM_FILE, filename,
253 BUILD_END);
254 if (ac)
255 {
256 plog(" loaded attribute certificate from '%s'", filename);
257 add_acert(ac);
258 }
259 free(filelist[n]);
260 }
261 free(filelist);
262 }
263 }
264 /* restore directory path */
265 ignore_result(chdir(save_dir));
266 }
267
268 /**
269 * list all X.509 attribute certificates in the chained list
270 */
271 void list_acerts(bool utc)
272 {
273 x509acert_t *x509ac = x509acerts;
274 time_t now;
275
276 /* determine the current time */
277 time(&now);
278
279 if (x509ac)
280 {
281 whack_log(RC_COMMENT, " ");
282 whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
283 whack_log(RC_COMMENT, " ");
284 }
285
286 while (x509ac)
287 {
288 certificate_t *cert_ac = x509ac->ac;
289 ac_t *ac = (ac_t*)cert_ac;
290 identification_t *entityName, *holderIssuer, *issuer;
291 chunk_t holderSerial, serial, authKeyID;
292 time_t notBefore, notAfter;
293 ietf_attributes_t *groups;
294
295
296 whack_log(RC_COMMENT, "%T", &x509ac->installed, utc);
297
298 entityName = cert_ac->get_subject(cert_ac);
299 if (entityName)
300 {
301 whack_log(RC_COMMENT, " holder: '%Y'", entityName);
302 }
303
304 holderIssuer = ac->get_holderIssuer(ac);
305 if (holderIssuer)
306 {
307 whack_log(RC_COMMENT, " hissuer: '%Y'", holderIssuer);
308 }
309
310 holderSerial = ac->get_holderSerial(ac);
311 if (holderSerial.ptr)
312 {
313 whack_log(RC_COMMENT, " hserial: %#B", &holderSerial);
314 }
315
316 groups = ac->get_groups(ac);
317 if (groups)
318 {
319 whack_log(RC_COMMENT, " groups: %s",
320 groups->get_string(groups));
321 groups->destroy(groups);
322 }
323
324 issuer = cert_ac->get_issuer(cert_ac);
325 whack_log(RC_COMMENT, " issuer: '%Y'", issuer);
326
327 serial = ac->get_serial(ac);
328 whack_log(RC_COMMENT, " serial: %#B", &serial);
329
330 cert_ac->get_validity(cert_ac, &now, &notBefore, &notAfter);
331 whack_log(RC_COMMENT, " validity: not before %T %s",
332 &notBefore, utc,
333 (notBefore < now)?"ok":"fatal (not valid yet)");
334 whack_log(RC_COMMENT, " not after %T %s",
335 &notAfter, utc,
336 check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE));
337
338 authKeyID = ac->get_authKeyIdentifier(ac);
339 if (authKeyID.ptr)
340 {
341 whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
342 }
343
344 x509ac = x509ac->next;
345 }
346 }
347