Provide CRLs received in CERT payloads to trustchain verification
[strongswan.git] / src / libcharon / sa / tasks / ike_cert_pre.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2006-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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 "ike_cert_pre.h"
18
19 #include <daemon.h>
20 #include <sa/ike_sa.h>
21 #include <encoding/payloads/cert_payload.h>
22 #include <encoding/payloads/certreq_payload.h>
23 #include <credentials/certificates/x509.h>
24
25
26 typedef struct private_ike_cert_pre_t private_ike_cert_pre_t;
27
28 /**
29 * Private members of a ike_cert_pre_t task.
30 */
31 struct private_ike_cert_pre_t {
32
33 /**
34 * Public methods and task_t interface.
35 */
36 ike_cert_pre_t public;
37
38 /**
39 * Assigned IKE_SA.
40 */
41 ike_sa_t *ike_sa;
42
43 /**
44 * Are we the initiator?
45 */
46 bool initiator;
47
48 /**
49 * Do we accept HTTP certificate lookup requests
50 */
51 bool do_http_lookup;
52
53 /**
54 * wheter this is the final authentication round
55 */
56 bool final;
57 };
58
59 /**
60 * read certificate requests
61 */
62 static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
63 {
64 enumerator_t *enumerator;
65 payload_t *payload;
66 auth_cfg_t *auth;
67
68 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
69
70 enumerator = message->create_payload_enumerator(message);
71 while (enumerator->enumerate(enumerator, &payload))
72 {
73 switch (payload->get_type(payload))
74 {
75 case CERTIFICATE_REQUEST:
76 {
77 certreq_payload_t *certreq = (certreq_payload_t*)payload;
78 enumerator_t *enumerator;
79 chunk_t keyid;
80
81 this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
82
83 if (certreq->get_cert_type(certreq) != CERT_X509)
84 {
85 DBG1(DBG_IKE, "cert payload %N not supported - ignored",
86 certificate_type_names, certreq->get_cert_type(certreq));
87 break;
88 }
89 enumerator = certreq->create_keyid_enumerator(certreq);
90 while (enumerator->enumerate(enumerator, &keyid))
91 {
92 identification_t *id;
93 certificate_t *cert;
94
95 id = identification_create_from_encoding(ID_KEY_ID, keyid);
96 cert = lib->credmgr->get_cert(lib->credmgr,
97 CERT_X509, KEY_ANY, id, TRUE);
98 if (cert)
99 {
100 DBG1(DBG_IKE, "received cert request for \"%Y\"",
101 cert->get_subject(cert));
102 auth->add(auth, AUTH_RULE_CA_CERT, cert);
103 }
104 else
105 {
106 DBG1(DBG_IKE, "received cert request for unknown ca "
107 "with keyid %Y", id);
108 }
109 id->destroy(id);
110 }
111 enumerator->destroy(enumerator);
112 break;
113 }
114 case NOTIFY:
115 {
116 notify_payload_t *notify = (notify_payload_t*)payload;
117
118 /* we only handle one type of notify here */
119 if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED)
120 {
121 this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
122 }
123 break;
124 }
125 default:
126 /* ignore other payloads here, these are handled elsewhere */
127 break;
128 }
129 }
130 enumerator->destroy(enumerator);
131 }
132
133 /**
134 * tries to extract a certificate from the cert payload or the credential
135 * manager (based on the hash of a "Hash and URL" encoded cert).
136 * Note: the returned certificate (if any) has to be destroyed
137 */
138 static certificate_t *try_get_cert(cert_payload_t *cert_payload)
139 {
140 certificate_t *cert = NULL;
141
142 switch (cert_payload->get_cert_encoding(cert_payload))
143 {
144 case ENC_X509_SIGNATURE:
145 {
146 cert = cert_payload->get_cert(cert_payload);
147 break;
148 }
149 case ENC_X509_HASH_AND_URL:
150 {
151 identification_t *id;
152 chunk_t hash = cert_payload->get_hash(cert_payload);
153 if (!hash.ptr)
154 {
155 /* invalid "Hash and URL" data (logged elsewhere) */
156 break;
157 }
158 id = identification_create_from_encoding(ID_KEY_ID, hash);
159 cert = lib->credmgr->get_cert(lib->credmgr,
160 CERT_X509, KEY_ANY, id, FALSE);
161 id->destroy(id);
162 break;
163 }
164 default:
165 {
166 break;
167 }
168 }
169 return cert;
170 }
171
172 /**
173 * import certificates
174 */
175 static void process_certs(private_ike_cert_pre_t *this, message_t *message)
176 {
177 enumerator_t *enumerator;
178 payload_t *payload;
179 auth_cfg_t *auth;
180 bool first = TRUE;
181
182 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
183
184 enumerator = message->create_payload_enumerator(message);
185 while (enumerator->enumerate(enumerator, &payload))
186 {
187 if (payload->get_type(payload) == CERTIFICATE)
188 {
189 cert_payload_t *cert_payload;
190 cert_encoding_t encoding;
191 certificate_t *cert;
192 char *url;
193
194 cert_payload = (cert_payload_t*)payload;
195 encoding = cert_payload->get_cert_encoding(cert_payload);
196
197 switch (encoding)
198 {
199 case ENC_X509_HASH_AND_URL:
200 {
201 if (!this->do_http_lookup)
202 {
203 DBG1(DBG_IKE, "received hash-and-url encoded cert, but"
204 " we don't accept them, ignore");
205 break;
206 }
207 /* FALL */
208 }
209 case ENC_X509_SIGNATURE:
210 {
211 cert = try_get_cert(cert_payload);
212 if (cert)
213 {
214 if (first)
215 { /* the first is an end entity certificate */
216 DBG1(DBG_IKE, "received end entity cert \"%Y\"",
217 cert->get_subject(cert));
218 auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
219 first = FALSE;
220 }
221 else
222 {
223 DBG1(DBG_IKE, "received issuer cert \"%Y\"",
224 cert->get_subject(cert));
225 auth->add(auth, AUTH_HELPER_IM_CERT, cert);
226 }
227 }
228 else if (encoding == ENC_X509_HASH_AND_URL)
229 {
230 /* we fetch the certificate not yet, but only if
231 * it is really needed during authentication */
232 url = cert_payload->get_url(cert_payload);
233 if (!url)
234 {
235 DBG1(DBG_IKE, "received invalid hash-and-url "
236 "encoded cert, ignore");
237 break;
238 }
239 url = strdup(url);
240 if (first)
241 { /* first URL is for an end entity certificate */
242 DBG1(DBG_IKE, "received hash-and-url for end"
243 " entity cert \"%s\"", url);
244 auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url);
245 first = FALSE;
246 }
247 else
248 {
249 DBG1(DBG_IKE, "received hash-and-url for issuer"
250 " cert \"%s\"", url);
251 auth->add(auth, AUTH_HELPER_IM_HASH_URL, url);
252 }
253 }
254 break;
255 }
256 case ENC_CRL:
257 cert = cert_payload->get_cert(cert_payload);
258 if (cert)
259 {
260 DBG1(DBG_IKE, "received CRL \"%Y\"",
261 cert->get_subject(cert));
262 auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
263 }
264 break;
265 case ENC_PKCS7_WRAPPED_X509:
266 case ENC_PGP:
267 case ENC_DNS_SIGNED_KEY:
268 case ENC_KERBEROS_TOKEN:
269 case ENC_ARL:
270 case ENC_SPKI:
271 case ENC_X509_ATTRIBUTE:
272 case ENC_RAW_RSA_KEY:
273 case ENC_X509_HASH_AND_URL_BUNDLE:
274 case ENC_OCSP_CONTENT:
275 default:
276 DBG1(DBG_ENC, "certificate encoding %N not supported",
277 cert_encoding_names, encoding);
278 }
279 }
280 }
281 enumerator->destroy(enumerator);
282 }
283
284 /**
285 * add the keyid of a certificate to the certificate request payload
286 */
287 static void add_certreq(certreq_payload_t **req, certificate_t *cert)
288 {
289 switch (cert->get_type(cert))
290 {
291 case CERT_X509:
292 {
293 public_key_t *public;
294 chunk_t keyid;
295 x509_t *x509 = (x509_t*)cert;
296
297 if (!(x509->get_flags(x509) & X509_CA))
298 { /* no CA cert, skip */
299 break;
300 }
301 public = cert->get_public_key(cert);
302 if (!public)
303 {
304 break;
305 }
306 if (*req == NULL)
307 {
308 *req = certreq_payload_create_type(CERT_X509);
309 }
310 if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
311 {
312 (*req)->add_keyid(*req, keyid);
313 DBG1(DBG_IKE, "sending cert request for \"%Y\"",
314 cert->get_subject(cert));
315 }
316 public->destroy(public);
317 break;
318 }
319 default:
320 break;
321 }
322 }
323
324 /**
325 * add a auth_cfg's CA certificates to the certificate request
326 */
327 static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
328 {
329 enumerator_t *enumerator;
330 auth_rule_t type;
331 void *value;
332
333 enumerator = auth->create_enumerator(auth);
334 while (enumerator->enumerate(enumerator, &type, &value))
335 {
336 switch (type)
337 {
338 case AUTH_RULE_CA_CERT:
339 add_certreq(req, (certificate_t*)value);
340 break;
341 default:
342 break;
343 }
344 }
345 enumerator->destroy(enumerator);
346 }
347
348 /**
349 * build certificate requests
350 */
351 static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
352 {
353 enumerator_t *enumerator;
354 ike_cfg_t *ike_cfg;
355 peer_cfg_t *peer_cfg;
356 certificate_t *cert;
357 auth_cfg_t *auth;
358 certreq_payload_t *req = NULL;
359
360 ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
361 if (!ike_cfg->send_certreq(ike_cfg))
362 {
363 return;
364 }
365
366 /* check if we require a specific CA for that peer */
367 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
368 if (peer_cfg)
369 {
370 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
371 while (enumerator->enumerate(enumerator, &auth))
372 {
373 add_certreqs(&req, auth);
374 }
375 enumerator->destroy(enumerator);
376 }
377
378 if (!req)
379 {
380 /* otherwise add all trusted CA certificates */
381 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
382 CERT_ANY, KEY_ANY, NULL, TRUE);
383 while (enumerator->enumerate(enumerator, &cert))
384 {
385 add_certreq(&req, cert);
386 }
387 enumerator->destroy(enumerator);
388 }
389
390 if (req)
391 {
392 message->add_payload(message, (payload_t*)req);
393
394 if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE))
395 {
396 message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
397 chunk_empty);
398 this->do_http_lookup = TRUE;
399 }
400 }
401 }
402
403 /**
404 * Check if this is the final authentication round
405 */
406 static bool final_auth(message_t *message)
407 {
408 /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */
409 if (message->get_payload(message, AUTHENTICATION) == NULL)
410 {
411 return FALSE;
412 }
413 if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
414 {
415 return FALSE;
416 }
417 return TRUE;
418 }
419
420 /**
421 * Implementation of task_t.process for initiator
422 */
423 static status_t build_i(private_ike_cert_pre_t *this, message_t *message)
424 {
425 if (message->get_message_id(message) == 1)
426 { /* initiator sends CERTREQs in first IKE_AUTH */
427 build_certreqs(this, message);
428 }
429 return NEED_MORE;
430 }
431
432 /**
433 * Implementation of task_t.process for responder
434 */
435 static status_t process_r(private_ike_cert_pre_t *this, message_t *message)
436 {
437 if (message->get_exchange_type(message) != IKE_SA_INIT)
438 { /* handle certreqs/certs in any IKE_AUTH, just in case */
439 process_certreqs(this, message);
440 process_certs(this, message);
441 }
442 this->final = final_auth(message);
443 return NEED_MORE;
444 }
445
446 /**
447 * Implementation of task_t.build for responder
448 */
449 static status_t build_r(private_ike_cert_pre_t *this, message_t *message)
450 {
451 if (message->get_exchange_type(message) == IKE_SA_INIT)
452 {
453 build_certreqs(this, message);
454 }
455 if (this->final)
456 {
457 return SUCCESS;
458 }
459 return NEED_MORE;
460 }
461
462 /**
463 * Implementation of task_t.process for initiator
464 */
465 static status_t process_i(private_ike_cert_pre_t *this, message_t *message)
466 {
467 if (message->get_exchange_type(message) == IKE_SA_INIT)
468 {
469 process_certreqs(this, message);
470 }
471 process_certs(this, message);
472
473 if (final_auth(message))
474 {
475 return SUCCESS;
476 }
477 return NEED_MORE;
478 }
479
480 /**
481 * Implementation of task_t.get_type
482 */
483 static task_type_t get_type(private_ike_cert_pre_t *this)
484 {
485 return IKE_CERT_PRE;
486 }
487
488 /**
489 * Implementation of task_t.migrate
490 */
491 static void migrate(private_ike_cert_pre_t *this, ike_sa_t *ike_sa)
492 {
493 this->ike_sa = ike_sa;
494 }
495
496 /**
497 * Implementation of task_t.destroy
498 */
499 static void destroy(private_ike_cert_pre_t *this)
500 {
501 free(this);
502 }
503
504 /*
505 * Described in header.
506 */
507 ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
508 {
509 private_ike_cert_pre_t *this = malloc_thing(private_ike_cert_pre_t);
510
511 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
512 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
513 this->public.task.destroy = (void(*)(task_t*))destroy;
514
515 if (initiator)
516 {
517 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
518 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
519 }
520 else
521 {
522 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
523 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
524 }
525
526 this->ike_sa = ike_sa;
527 this->initiator = initiator;
528 this->do_http_lookup = FALSE;
529 this->final = FALSE;
530
531 return &this->public;
532 }