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