Moving charon to libcharon.
[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 = charon->credentials->get_cert(charon->credentials,
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 = charon->credentials->get_cert(charon->credentials,
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_PKCS7_WRAPPED_X509:
257 case ENC_PGP:
258 case ENC_DNS_SIGNED_KEY:
259 case ENC_KERBEROS_TOKEN:
260 case ENC_CRL:
261 case ENC_ARL:
262 case ENC_SPKI:
263 case ENC_X509_ATTRIBUTE:
264 case ENC_RAW_RSA_KEY:
265 case ENC_X509_HASH_AND_URL_BUNDLE:
266 case ENC_OCSP_CONTENT:
267 default:
268 DBG1(DBG_ENC, "certificate encoding %N not supported",
269 cert_encoding_names, encoding);
270 }
271 }
272 }
273 enumerator->destroy(enumerator);
274 }
275
276 /**
277 * add the keyid of a certificate to the certificate request payload
278 */
279 static void add_certreq(certreq_payload_t **req, certificate_t *cert)
280 {
281 switch (cert->get_type(cert))
282 {
283 case CERT_X509:
284 {
285 public_key_t *public;
286 chunk_t keyid;
287 x509_t *x509 = (x509_t*)cert;
288
289 if (!(x509->get_flags(x509) & X509_CA))
290 { /* no CA cert, skip */
291 break;
292 }
293 public = cert->get_public_key(cert);
294 if (!public)
295 {
296 break;
297 }
298 if (*req == NULL)
299 {
300 *req = certreq_payload_create_type(CERT_X509);
301 }
302 if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &keyid))
303 {
304 (*req)->add_keyid(*req, keyid);
305 DBG1(DBG_IKE, "sending cert request for \"%Y\"",
306 cert->get_subject(cert));
307 }
308 public->destroy(public);
309 break;
310 }
311 default:
312 break;
313 }
314 }
315
316 /**
317 * add a auth_cfg's CA certificates to the certificate request
318 */
319 static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
320 {
321 enumerator_t *enumerator;
322 auth_rule_t type;
323 void *value;
324
325 enumerator = auth->create_enumerator(auth);
326 while (enumerator->enumerate(enumerator, &type, &value))
327 {
328 switch (type)
329 {
330 case AUTH_RULE_CA_CERT:
331 add_certreq(req, (certificate_t*)value);
332 break;
333 default:
334 break;
335 }
336 }
337 enumerator->destroy(enumerator);
338 }
339
340 /**
341 * build certificate requests
342 */
343 static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
344 {
345 enumerator_t *enumerator;
346 ike_cfg_t *ike_cfg;
347 peer_cfg_t *peer_cfg;
348 certificate_t *cert;
349 auth_cfg_t *auth;
350 certreq_payload_t *req = NULL;
351
352 ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
353 if (!ike_cfg->send_certreq(ike_cfg))
354 {
355 return;
356 }
357
358 /* check if we require a specific CA for that peer */
359 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
360 if (peer_cfg)
361 {
362 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
363 while (enumerator->enumerate(enumerator, &auth))
364 {
365 add_certreqs(&req, auth);
366 }
367 enumerator->destroy(enumerator);
368 }
369
370 if (!req)
371 {
372 /* otherwise add all trusted CA certificates */
373 enumerator = charon->credentials->create_cert_enumerator(
374 charon->credentials, CERT_ANY, KEY_ANY, NULL, TRUE);
375 while (enumerator->enumerate(enumerator, &cert))
376 {
377 add_certreq(&req, cert);
378 }
379 enumerator->destroy(enumerator);
380 }
381
382 if (req)
383 {
384 message->add_payload(message, (payload_t*)req);
385
386 if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE))
387 {
388 message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
389 chunk_empty);
390 this->do_http_lookup = TRUE;
391 }
392 }
393 }
394
395 /**
396 * Check if this is the final authentication round
397 */
398 static bool final_auth(message_t *message)
399 {
400 /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */
401 if (message->get_payload(message, AUTHENTICATION) == NULL)
402 {
403 return FALSE;
404 }
405 if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
406 {
407 return FALSE;
408 }
409 return TRUE;
410 }
411
412 /**
413 * Implementation of task_t.process for initiator
414 */
415 static status_t build_i(private_ike_cert_pre_t *this, message_t *message)
416 {
417 if (message->get_message_id(message) == 1)
418 { /* initiator sends CERTREQs in first IKE_AUTH */
419 build_certreqs(this, message);
420 }
421 return NEED_MORE;
422 }
423
424 /**
425 * Implementation of task_t.process for responder
426 */
427 static status_t process_r(private_ike_cert_pre_t *this, message_t *message)
428 {
429 if (message->get_exchange_type(message) != IKE_SA_INIT)
430 { /* handle certreqs/certs in any IKE_AUTH, just in case */
431 process_certreqs(this, message);
432 process_certs(this, message);
433 }
434 this->final = final_auth(message);
435 return NEED_MORE;
436 }
437
438 /**
439 * Implementation of task_t.build for responder
440 */
441 static status_t build_r(private_ike_cert_pre_t *this, message_t *message)
442 {
443 if (message->get_exchange_type(message) == IKE_SA_INIT)
444 {
445 build_certreqs(this, message);
446 }
447 if (this->final)
448 {
449 return SUCCESS;
450 }
451 return NEED_MORE;
452 }
453
454 /**
455 * Implementation of task_t.process for initiator
456 */
457 static status_t process_i(private_ike_cert_pre_t *this, message_t *message)
458 {
459 if (message->get_exchange_type(message) == IKE_SA_INIT)
460 {
461 process_certreqs(this, message);
462 }
463 process_certs(this, message);
464
465 if (final_auth(message))
466 {
467 return SUCCESS;
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 this->final = FALSE;
522
523 return &this->public;
524 }