renamed multi-level-pathlen scenario to multi-level-ca-pathlen
[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 acerts->destroy_offset(acerts, offsetof(certificate_t, destroy));
50 }
51
52 /**
53 * Get a X.509 attribute certificate for a given holder
54 */
55 certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial)
56 {
57 enumerator_t *enumerator;
58 certificate_t *cert, *found = NULL;
59
60 enumerator = acerts->create_enumerator(acerts);
61 while (enumerator->enumerate(enumerator, &cert))
62 {
63 ac_t *ac = (ac_t*)cert;
64
65 if (issuer->equals(issuer, ac->get_holderIssuer(ac)) &&
66 chunk_equals(serial, ac->get_holderSerial(ac)))
67 {
68 found = cert;
69 break;
70 }
71 }
72 enumerator->destroy(enumerator);
73 return found;
74 }
75
76 /**
77 * Verifies a X.509 attribute certificate
78 */
79 bool ac_verify_cert(certificate_t *cert, bool strict)
80 {
81 ac_t *ac = (ac_t*)cert;
82 identification_t *subject = cert->get_subject(cert);
83 identification_t *issuer = cert->get_issuer(cert);
84 chunk_t authKeyID = ac->get_authKeyIdentifier(ac);
85 x509cert_t *aacert;
86 time_t notBefore, valid_until;
87
88 DBG1("holder: '%Y'", subject);
89 DBG1("issuer: '%Y'", issuer);
90
91 if (!cert->get_validity(cert, NULL, NULL, &valid_until))
92 {
93 DBG1("attribute certificate is invalid (valid from %T to %T)",
94 &notBefore, FALSE, &valid_until, FALSE);
95 return FALSE;
96 }
97 DBG1("attribute certificate is valid until %T", &valid_until, FALSE);
98
99 lock_authcert_list("verify_x509acert");
100 aacert = get_authcert(issuer, authKeyID, X509_AA);
101 unlock_authcert_list("verify_x509acert");
102
103 if (aacert == NULL)
104 {
105 DBG1("issuer aacert not found");
106 return FALSE;
107 }
108 DBG2("issuer aacert found");
109
110 if (!cert->issued_by(cert, aacert->cert))
111 {
112 DBG1("attribute certificate signature is invalid");
113 return FALSE;
114 }
115 DBG1("attribute certificate signature is valid");
116
117 return verify_x509cert(aacert, strict, &valid_until);
118 }
119
120 /**
121 * Add a X.509 attribute certificate to the chained list
122 */
123 static void ac_add_cert(certificate_t *cert)
124 {
125 ac_t *ac = (ac_t*)cert;
126 identification_t *hIssuer = ac->get_holderIssuer(ac);
127 chunk_t hSerial = ac->get_holderSerial(ac);
128
129 enumerator_t *enumerator;
130 certificate_t *cert_old;
131
132 enumerator = acerts->create_enumerator(acerts);
133 while (enumerator->enumerate(enumerator, &cert_old))
134 {
135 ac_t *ac_old = (ac_t*)cert_old;
136
137 if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) &&
138 chunk_equals(hSerial, ac_old->get_holderSerial(ac_old)))
139 {
140 if (cert->is_newer(cert, cert_old))
141 {
142 acerts->remove_at(acerts, enumerator);
143 cert_old->destroy(cert_old);
144 }
145 else
146 {
147 cert->destroy(cert);
148 cert = NULL;
149 }
150 break;
151 }
152 }
153 enumerator->destroy(enumerator);
154
155 if (cert)
156 {
157 acerts->insert_last(acerts, cert);
158 }
159 }
160
161 /**
162 * Check if at least one peer attribute matches a connection attribute
163 */
164 bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn,
165 ietf_attributes_t *conn_attributes)
166 {
167 bool match;
168
169 if (conn_attributes == NULL)
170 {
171 return TRUE;
172 }
173
174 match = conn_attributes->matches(conn_attributes, peer_attributes);
175 DBG1("%s: peer with attributes '%s' is %sa member of the groups '%s'",
176 conn, peer_attributes->get_string(peer_attributes),
177 match ? "" : "not ", conn_attributes->get_string(conn_attributes));
178
179 return match;
180 }
181
182 /**
183 * Loads X.509 attribute certificates
184 */
185 void ac_load_certs(void)
186 {
187 enumerator_t *enumerator;
188 struct stat st;
189 char *file;
190
191 DBG1("loading attribute certificates from '%s'", A_CERT_PATH);
192
193 enumerator = enumerator_create_directory(A_CERT_PATH);
194 if (!enumerator)
195 {
196 return;
197 }
198
199 while (enumerator->enumerate(enumerator, NULL, &file, &st))
200 {
201 certificate_t *cert;
202
203 if (!S_ISREG(st.st_mode))
204 {
205 /* skip special file */
206 continue;
207 }
208 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
209 BUILD_FROM_FILE, file, BUILD_END);
210 if (cert)
211 {
212 DBG1(" loaded attribute certificate from '%s'", file);
213 ac_add_cert(cert);
214 }
215 }
216 enumerator->destroy(enumerator);
217 }
218
219 /**
220 * List all X.509 attribute certificates in the chained list
221 */
222 void ac_list_certs(bool utc)
223 {
224 enumerator_t *enumerator;
225 certificate_t *cert;
226 time_t now;
227
228 /* determine the current time */
229 time(&now);
230
231 if (acerts->get_count(acerts) > 0)
232 {
233 whack_log(RC_COMMENT, " ");
234 whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
235 }
236
237 enumerator = acerts->create_enumerator(acerts);
238 while (enumerator->enumerate(enumerator, &cert))
239 {
240 ac_t *ac = (ac_t*)cert;
241 identification_t *entityName, *holderIssuer, *issuer;
242 chunk_t holderSerial, serial, authKeyID;
243 time_t notBefore, notAfter;
244 ietf_attributes_t *groups;
245
246 whack_log(RC_COMMENT, " ");
247
248 entityName = cert->get_subject(cert);
249 if (entityName)
250 {
251 whack_log(RC_COMMENT, " holder: \"%Y\"", entityName);
252 }
253
254 holderIssuer = ac->get_holderIssuer(ac);
255 if (holderIssuer)
256 {
257 whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer);
258 }
259
260 holderSerial = ac->get_holderSerial(ac);
261 if (holderSerial.ptr)
262 {
263 whack_log(RC_COMMENT, " hserial: %#B", &holderSerial);
264 }
265
266 groups = ac->get_groups(ac);
267 if (groups)
268 {
269 whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups));
270 groups->destroy(groups);
271 }
272
273 issuer = cert->get_issuer(cert);
274 whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer);
275
276 serial = ac->get_serial(ac);
277 whack_log(RC_COMMENT, " serial: %#B", &serial);
278
279 cert->get_validity(cert, &now, &notBefore, &notAfter);
280 whack_log(RC_COMMENT, " validity: not before %T %s",
281 &notBefore, utc,
282 (notBefore < now)?"ok":"fatal (not valid yet)");
283 whack_log(RC_COMMENT, " not after %T %s", &notAfter, utc,
284 check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE));
285
286 authKeyID = ac->get_authKeyIdentifier(ac);
287 if (authKeyID.ptr)
288 {
289 whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
290 }
291 }
292 enumerator->destroy(enumerator);
293 }
294