Renamed ike_cert_pre_v1 to isakmp_cert_pre
[strongswan.git] / src / libcharon / sa / tasks / isakmp_cert_pre.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "isakmp_cert_pre.h"
17
18 #include <daemon.h>
19 #include <sa/ike_sa.h>
20 #include <encoding/payloads/cert_payload.h>
21 #include <encoding/payloads/sa_payload.h>
22 #include <encoding/payloads/certreq_payload.h>
23 #include <credentials/certificates/x509.h>
24
25
26 typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
27
28 /**
29 * Private members of a isakmp_cert_pre_t task.
30 */
31 struct private_isakmp_cert_pre_t {
32
33 /**
34 * Public methods and task_t interface.
35 */
36 isakmp_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 * Send certificate requests?
50 */
51 bool send_req;
52
53 /** next message we expect */
54 enum {
55 CR_SA,
56 CR_KE,
57 CR_AUTH,
58 } state;
59 };
60
61 /**
62 * Find the CA certificate for a given certreq payload
63 */
64 static certificate_t* find_certificate(private_isakmp_cert_pre_t *this,
65 certreq_payload_t *certreq)
66 {
67 identification_t *id;
68 certificate_t *cert;
69
70 if (certreq->get_cert_type(certreq) != CERT_X509)
71 {
72 DBG1(DBG_IKE, "%N CERTREQ not supported - ignored",
73 certificate_type_names, certreq->get_cert_type(certreq));
74 return NULL;
75 }
76 id = certreq->get_dn(certreq);
77 if (!id)
78 {
79 DBG1(DBG_IKE, "ignoring certificate request without data",
80 certificate_type_names, certreq->get_cert_type(certreq));
81 return NULL;
82 }
83 cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
84 if (cert)
85 {
86 DBG1(DBG_IKE, "received cert request for '%Y'",
87 cert->get_subject(cert));
88 }
89 else
90 {
91 DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id);
92 }
93 id->destroy(id);
94
95 return cert;
96 }
97
98 /**
99 * read certificate requests
100 */
101 static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
102 {
103 enumerator_t *enumerator;
104 payload_t *payload;
105 auth_cfg_t *auth;
106
107 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
108
109 enumerator = message->create_payload_enumerator(message);
110 while (enumerator->enumerate(enumerator, &payload))
111 {
112 switch (payload->get_type(payload))
113 {
114 case CERTIFICATE_REQUEST_V1:
115 {
116 certificate_t *cert;
117
118 this->ike_sa->set_condition(this->ike_sa,
119 COND_CERTREQ_SEEN, TRUE);
120 cert = find_certificate(this, (certreq_payload_t*)payload);
121 if (cert)
122 {
123 auth->add(auth, AUTH_RULE_CA_CERT, cert);
124 }
125 break;
126 }
127 default:
128 break;
129 }
130 }
131 enumerator->destroy(enumerator);
132 }
133
134 /**
135 * Import receuved certificates
136 */
137 static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
138 {
139 enumerator_t *enumerator;
140 payload_t *payload;
141 auth_cfg_t *auth;
142 bool first = TRUE;
143
144 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
145
146 enumerator = message->create_payload_enumerator(message);
147 while (enumerator->enumerate(enumerator, &payload))
148 {
149 if (payload->get_type(payload) == CERTIFICATE_V1)
150 {
151 cert_payload_t *cert_payload;
152 cert_encoding_t encoding;
153 certificate_t *cert;
154
155 cert_payload = (cert_payload_t*)payload;
156 encoding = cert_payload->get_cert_encoding(cert_payload);
157
158 switch (encoding)
159 {
160 case ENC_X509_SIGNATURE:
161 {
162 cert = cert_payload->get_cert(cert_payload);
163 if (cert)
164 {
165 if (first)
166 { /* the first is an end entity certificate */
167 DBG1(DBG_IKE, "received end entity cert \"%Y\"",
168 cert->get_subject(cert));
169 auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
170 first = FALSE;
171 }
172 else
173 {
174 DBG1(DBG_IKE, "received issuer cert \"%Y\"",
175 cert->get_subject(cert));
176 auth->add(auth, AUTH_HELPER_IM_CERT, cert);
177 }
178 }
179 break;
180 }
181 case ENC_CRL:
182 cert = cert_payload->get_cert(cert_payload);
183 if (cert)
184 {
185 DBG1(DBG_IKE, "received CRL \"%Y\"",
186 cert->get_subject(cert));
187 auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
188 }
189 break;
190 case ENC_PKCS7_WRAPPED_X509:
191 case ENC_PGP:
192 case ENC_DNS_SIGNED_KEY:
193 case ENC_KERBEROS_TOKEN:
194 case ENC_ARL:
195 case ENC_SPKI:
196 case ENC_X509_ATTRIBUTE:
197 case ENC_RAW_RSA_KEY:
198 case ENC_X509_HASH_AND_URL_BUNDLE:
199 case ENC_OCSP_CONTENT:
200 default:
201 DBG1(DBG_ENC, "certificate encoding %N not supported",
202 cert_encoding_names, encoding);
203 }
204 }
205 }
206 enumerator->destroy(enumerator);
207 }
208
209 /**
210 * Add the subject of a CA certificate a message
211 */
212 static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message,
213 certificate_t *cert)
214 {
215 if (cert->get_type(cert) == CERT_X509)
216 {
217 x509_t *x509 = (x509_t*)cert;
218
219 if (x509->get_flags(x509) & X509_CA)
220 {
221 DBG1(DBG_IKE, "sending cert request for \"%Y\"",
222 cert->get_subject(cert));
223 message->add_payload(message, (payload_t*)
224 certreq_payload_create_dn(cert->get_subject(cert)));
225 }
226 }
227 }
228
229 /**
230 * Add auth_cfg's CA certificates to the certificate request
231 */
232 static void add_certreqs(private_isakmp_cert_pre_t *this,
233 auth_cfg_t *auth, message_t *message)
234 {
235 enumerator_t *enumerator;
236 auth_rule_t type;
237 void *value;
238
239 enumerator = auth->create_enumerator(auth);
240 while (enumerator->enumerate(enumerator, &type, &value))
241 {
242 switch (type)
243 {
244 case AUTH_RULE_CA_CERT:
245 add_certreq(this, message, (certificate_t*)value);
246 break;
247 default:
248 break;
249 }
250 }
251 enumerator->destroy(enumerator);
252 }
253
254 /**
255 * Build certificate requests
256 */
257 static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
258 {
259 enumerator_t *enumerator;
260 ike_cfg_t *ike_cfg;
261 peer_cfg_t *peer_cfg;
262 certificate_t *cert;
263 auth_cfg_t *auth;
264
265 ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
266 if (!ike_cfg->send_certreq(ike_cfg))
267 {
268 return;
269 }
270 /* check if we require a specific CA for that peer */
271 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
272 if (peer_cfg)
273 {
274 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
275 if (enumerator->enumerate(enumerator, &auth))
276 {
277 add_certreqs(this, auth, message);
278 }
279 enumerator->destroy(enumerator);
280 }
281 if (!message->get_payload(message, CERTIFICATE_REQUEST_V1))
282 {
283 /* otherwise add all trusted CA certificates */
284 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
285 CERT_ANY, KEY_ANY, NULL, TRUE);
286 while (enumerator->enumerate(enumerator, &cert))
287 {
288 add_certreq(this, message, cert);
289 }
290 enumerator->destroy(enumerator);
291 }
292 }
293
294 /**
295 * Check if we actually use certificates for authentication
296 */
297 static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message)
298 {
299 enumerator_t *enumerator;
300 payload_t *payload;
301 bool use = FALSE;
302
303 enumerator = message->create_payload_enumerator(message);
304 while (enumerator->enumerate(enumerator, &payload))
305 {
306 if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
307 {
308 sa_payload_t *sa_payload = (sa_payload_t*)payload;
309
310 switch (sa_payload->get_auth_method(sa_payload))
311 {
312 case AUTH_HYBRID_INIT_RSA:
313 case AUTH_HYBRID_RESP_RSA:
314 if (!this->initiator)
315 {
316 this->send_req = FALSE;
317 }
318 /* FALL */
319 case AUTH_RSA:
320 case AUTH_XAUTH_INIT_RSA:
321 case AUTH_XAUTH_RESP_RSA:
322 use = TRUE;
323 break;
324 default:
325 break;
326 }
327 break;
328 }
329 }
330 enumerator->destroy(enumerator);
331
332 return use;
333 }
334
335 METHOD(task_t, build_i, status_t,
336 private_isakmp_cert_pre_t *this, message_t *message)
337 {
338 switch (message->get_exchange_type(message))
339 {
340 case ID_PROT:
341 if (this->state == CR_AUTH)
342 {
343 build_certreqs(this, message);
344 }
345 return NEED_MORE;
346 case AGGRESSIVE:
347 if (this->state == CR_SA)
348 {
349 build_certreqs(this, message);
350 }
351 return NEED_MORE;
352 default:
353 return FAILED;
354 }
355 }
356
357 METHOD(task_t, process_r, status_t,
358 private_isakmp_cert_pre_t *this, message_t *message)
359 {
360 switch (message->get_exchange_type(message))
361 {
362 case ID_PROT:
363 {
364 switch (this->state)
365 {
366 case CR_SA:
367 if (!use_certs(this, message))
368 {
369 return SUCCESS;
370 }
371 return NEED_MORE;
372 case CR_KE:
373 process_certreqs(this, message);
374 return NEED_MORE;
375 case CR_AUTH:
376 process_certreqs(this, message);
377 process_certs(this, message);
378 return SUCCESS;
379 }
380 }
381 case AGGRESSIVE:
382 {
383 switch (this->state)
384 {
385 case CR_SA:
386 if (!use_certs(this, message))
387 {
388 return SUCCESS;
389 }
390 process_certreqs(this, message);
391 return NEED_MORE;
392 case CR_AUTH:
393 process_certs(this, message);
394 return SUCCESS;
395 default:
396 return FAILED;
397 }
398 }
399 default:
400 return FAILED;
401 }
402 }
403
404 METHOD(task_t, build_r, status_t,
405 private_isakmp_cert_pre_t *this, message_t *message)
406 {
407 switch (message->get_exchange_type(message))
408 {
409 case ID_PROT:
410 switch (this->state)
411 {
412 case CR_SA:
413 this->state = CR_KE;
414 return NEED_MORE;
415 case CR_KE:
416 if (this->send_req)
417 {
418 build_certreqs(this, message);
419 }
420 this->state = CR_AUTH;
421 return NEED_MORE;
422 case CR_AUTH:
423 return NEED_MORE;
424 }
425 case AGGRESSIVE:
426 switch (this->state)
427 {
428 case CR_SA:
429 this->state = CR_AUTH;
430 return NEED_MORE;
431 case CR_AUTH:
432 return SUCCESS;
433 default:
434 return FAILED;
435 }
436 default:
437 return FAILED;
438 }
439 }
440
441 METHOD(task_t, process_i, status_t,
442 private_isakmp_cert_pre_t *this, message_t *message)
443 {
444 switch (message->get_exchange_type(message))
445 {
446 case ID_PROT:
447 {
448 switch (this->state)
449 {
450 case CR_SA:
451 if (!use_certs(this, message))
452 {
453 return SUCCESS;
454 }
455 this->state = CR_KE;
456 return NEED_MORE;
457 case CR_KE:
458 process_certreqs(this, message);
459 this->state = CR_AUTH;
460 return NEED_MORE;
461 case CR_AUTH:
462 process_certs(this, message);
463 return SUCCESS;
464 default:
465 return FAILED;
466 }
467 break;
468 }
469 case AGGRESSIVE:
470 {
471 if (!use_certs(this, message))
472 {
473 return SUCCESS;
474 }
475 process_certreqs(this, message);
476 process_certs(this, message);
477 return SUCCESS;
478 }
479 default:
480 return FAILED;
481 }
482 }
483
484 METHOD(task_t, get_type, task_type_t,
485 private_isakmp_cert_pre_t *this)
486 {
487 return TASK_ISAKMP_CERT_PRE;
488 }
489
490 METHOD(task_t, migrate, void,
491 private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
492 {
493 this->ike_sa = ike_sa;
494 }
495
496 METHOD(task_t, destroy, void,
497 private_isakmp_cert_pre_t *this)
498 {
499 free(this);
500 }
501
502 /*
503 * Described in header.
504 */
505 isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
506 {
507 private_isakmp_cert_pre_t *this;
508
509 INIT(this,
510 .public = {
511 .task = {
512 .get_type = _get_type,
513 .migrate = _migrate,
514 .destroy = _destroy,
515 },
516 },
517 .ike_sa = ike_sa,
518 .initiator = initiator,
519 .state = CR_SA,
520 .send_req = TRUE,
521 );
522 if (initiator)
523 {
524 this->public.task.build = _build_i;
525 this->public.task.process = _process_i;
526 }
527 else
528 {
529 this->public.task.build = _build_r;
530 this->public.task.process = _process_r;
531 }
532 return &this->public;
533 }