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