ea5da4ebc6ebd029c03d4434225efecefeb7aa57
[strongswan.git] / src / libcharon / sa / ikev1 / 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_ECDSA_256:
321 case AUTH_ECDSA_384:
322 case AUTH_ECDSA_521:
323 case AUTH_XAUTH_INIT_RSA:
324 case AUTH_XAUTH_RESP_RSA:
325 use = TRUE;
326 break;
327 default:
328 break;
329 }
330 break;
331 }
332 }
333 enumerator->destroy(enumerator);
334
335 return use;
336 }
337
338 METHOD(task_t, build_i, status_t,
339 private_isakmp_cert_pre_t *this, message_t *message)
340 {
341 switch (message->get_exchange_type(message))
342 {
343 case ID_PROT:
344 if (this->state == CR_AUTH)
345 {
346 build_certreqs(this, message);
347 }
348 return NEED_MORE;
349 case AGGRESSIVE:
350 if (this->state == CR_SA)
351 {
352 if (!use_certs(this, message))
353 {
354 return SUCCESS;
355 }
356 build_certreqs(this, message);
357 }
358 return NEED_MORE;
359 default:
360 return FAILED;
361 }
362 }
363
364 METHOD(task_t, process_r, status_t,
365 private_isakmp_cert_pre_t *this, message_t *message)
366 {
367 switch (message->get_exchange_type(message))
368 {
369 case ID_PROT:
370 {
371 switch (this->state)
372 {
373 case CR_SA:
374 if (!use_certs(this, message))
375 {
376 return SUCCESS;
377 }
378 return NEED_MORE;
379 case CR_KE:
380 process_certreqs(this, message);
381 return NEED_MORE;
382 case CR_AUTH:
383 process_certreqs(this, message);
384 process_certs(this, message);
385 return SUCCESS;
386 }
387 }
388 case AGGRESSIVE:
389 {
390 switch (this->state)
391 {
392 case CR_SA:
393 if (!use_certs(this, message))
394 {
395 return SUCCESS;
396 }
397 process_certreqs(this, message);
398 return NEED_MORE;
399 case CR_AUTH:
400 process_certs(this, message);
401 return SUCCESS;
402 default:
403 return FAILED;
404 }
405 }
406 default:
407 return FAILED;
408 }
409 }
410
411 METHOD(task_t, build_r, status_t,
412 private_isakmp_cert_pre_t *this, message_t *message)
413 {
414 switch (message->get_exchange_type(message))
415 {
416 case ID_PROT:
417 switch (this->state)
418 {
419 case CR_SA:
420 this->state = CR_KE;
421 return NEED_MORE;
422 case CR_KE:
423 if (this->send_req)
424 {
425 build_certreqs(this, message);
426 }
427 this->state = CR_AUTH;
428 return NEED_MORE;
429 case CR_AUTH:
430 return NEED_MORE;
431 }
432 case AGGRESSIVE:
433 switch (this->state)
434 {
435 case CR_SA:
436 if (this->send_req)
437 {
438 build_certreqs(this, message);
439 }
440 this->state = CR_AUTH;
441 return NEED_MORE;
442 case CR_AUTH:
443 return SUCCESS;
444 default:
445 return FAILED;
446 }
447 default:
448 return FAILED;
449 }
450 }
451
452 METHOD(task_t, process_i, status_t,
453 private_isakmp_cert_pre_t *this, message_t *message)
454 {
455 switch (message->get_exchange_type(message))
456 {
457 case ID_PROT:
458 {
459 switch (this->state)
460 {
461 case CR_SA:
462 if (!use_certs(this, message))
463 {
464 return SUCCESS;
465 }
466 this->state = CR_KE;
467 return NEED_MORE;
468 case CR_KE:
469 process_certreqs(this, message);
470 this->state = CR_AUTH;
471 return NEED_MORE;
472 case CR_AUTH:
473 process_certs(this, message);
474 return SUCCESS;
475 default:
476 return FAILED;
477 }
478 break;
479 }
480 case AGGRESSIVE:
481 {
482 if (!use_certs(this, message))
483 {
484 return SUCCESS;
485 }
486 process_certreqs(this, message);
487 process_certs(this, message);
488 this->state = CR_AUTH;
489 return SUCCESS;
490 }
491 default:
492 return FAILED;
493 }
494 }
495
496 METHOD(task_t, get_type, task_type_t,
497 private_isakmp_cert_pre_t *this)
498 {
499 return TASK_ISAKMP_CERT_PRE;
500 }
501
502 METHOD(task_t, migrate, void,
503 private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
504 {
505 this->ike_sa = ike_sa;
506 this->state = CR_SA;
507 this->send_req = TRUE;
508 }
509
510 METHOD(task_t, destroy, void,
511 private_isakmp_cert_pre_t *this)
512 {
513 free(this);
514 }
515
516 /*
517 * Described in header.
518 */
519 isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
520 {
521 private_isakmp_cert_pre_t *this;
522
523 INIT(this,
524 .public = {
525 .task = {
526 .get_type = _get_type,
527 .migrate = _migrate,
528 .destroy = _destroy,
529 },
530 },
531 .ike_sa = ike_sa,
532 .initiator = initiator,
533 .state = CR_SA,
534 .send_req = TRUE,
535 );
536 if (initiator)
537 {
538 this->public.task.build = _build_i;
539 this->public.task.process = _process_i;
540 }
541 else
542 {
543 this->public.task.build = _build_r;
544 this->public.task.process = _process_r;
545 }
546 return &this->public;
547 }