payload: Use common prefixes for all payload type identifiers
[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 /*
17 * Copyright (C) 2013 Volker RĂ¼melin
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * THE SOFTWARE.
36 */
37
38 #include "isakmp_cert_pre.h"
39
40 #include <daemon.h>
41 #include <sa/ike_sa.h>
42 #include <encoding/payloads/cert_payload.h>
43 #include <encoding/payloads/sa_payload.h>
44 #include <encoding/payloads/certreq_payload.h>
45 #include <credentials/certificates/x509.h>
46 #include <credentials/containers/pkcs7.h>
47
48
49 typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
50
51 /**
52 * Private members of a isakmp_cert_pre_t task.
53 */
54 struct private_isakmp_cert_pre_t {
55
56 /**
57 * Public methods and task_t interface.
58 */
59 isakmp_cert_pre_t public;
60
61 /**
62 * Assigned IKE_SA.
63 */
64 ike_sa_t *ike_sa;
65
66 /**
67 * Are we the initiator?
68 */
69 bool initiator;
70
71 /**
72 * Send certificate requests?
73 */
74 bool send_req;
75
76 /** next message we expect */
77 enum {
78 CR_SA,
79 CR_KE,
80 CR_AUTH,
81 } state;
82 };
83
84 /**
85 * Find the CA certificate for a given certreq payload
86 */
87 static certificate_t* find_certificate(private_isakmp_cert_pre_t *this,
88 certreq_payload_t *certreq)
89 {
90 identification_t *id;
91 certificate_t *cert;
92
93 if (certreq->get_cert_type(certreq) != CERT_X509)
94 {
95 DBG1(DBG_IKE, "%N CERTREQ not supported - ignored",
96 certificate_type_names, certreq->get_cert_type(certreq));
97 return NULL;
98 }
99 id = certreq->get_dn(certreq);
100 if (!id)
101 {
102 DBG1(DBG_IKE, "ignoring certificate request without data",
103 certificate_type_names, certreq->get_cert_type(certreq));
104 return NULL;
105 }
106 cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
107 if (cert)
108 {
109 DBG1(DBG_IKE, "received cert request for '%Y'",
110 cert->get_subject(cert));
111 }
112 else
113 {
114 DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id);
115 }
116 id->destroy(id);
117
118 return cert;
119 }
120
121 /**
122 * read certificate requests
123 */
124 static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
125 {
126 enumerator_t *enumerator;
127 payload_t *payload;
128 auth_cfg_t *auth;
129
130 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
131
132 enumerator = message->create_payload_enumerator(message);
133 while (enumerator->enumerate(enumerator, &payload))
134 {
135 switch (payload->get_type(payload))
136 {
137 case PLV1_CERTREQ:
138 {
139 certificate_t *cert;
140
141 this->ike_sa->set_condition(this->ike_sa,
142 COND_CERTREQ_SEEN, TRUE);
143 cert = find_certificate(this, (certreq_payload_t*)payload);
144 if (cert)
145 {
146 auth->add(auth, AUTH_RULE_CA_CERT, cert);
147 }
148 break;
149 }
150 default:
151 break;
152 }
153 }
154 enumerator->destroy(enumerator);
155 }
156
157 /**
158 * Process an X509 certificate payload
159 */
160 static void process_x509(cert_payload_t *payload, auth_cfg_t *auth, bool *first)
161 {
162 certificate_t *cert;
163
164 cert = payload->get_cert(payload);
165 if (cert)
166 {
167 if (*first)
168 { /* the first is an end entity certificate */
169 DBG1(DBG_IKE, "received end entity cert \"%Y\"",
170 cert->get_subject(cert));
171 auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
172 *first = FALSE;
173 }
174 else
175 {
176 DBG1(DBG_IKE, "received issuer cert \"%Y\"",
177 cert->get_subject(cert));
178 auth->add(auth, AUTH_HELPER_IM_CERT, cert);
179 }
180 }
181 }
182
183 /**
184 * Process a CRL certificate payload
185 */
186 static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
187 {
188 certificate_t *cert;
189
190 cert = payload->get_cert(payload);
191 if (cert)
192 {
193 DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
194 auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
195 }
196 }
197
198 /**
199 * Process a PKCS7 certificate payload
200 */
201 static void process_pkcs7(cert_payload_t *payload, auth_cfg_t *auth)
202 {
203 enumerator_t *enumerator;
204 container_t *container;
205 certificate_t *cert;
206 pkcs7_t *pkcs7;
207
208 container = payload->get_container(payload);
209 if (!container)
210 {
211 return;
212 }
213 switch (container->get_type(container))
214 {
215 case CONTAINER_PKCS7_DATA:
216 case CONTAINER_PKCS7_SIGNED_DATA:
217 case CONTAINER_PKCS7_ENVELOPED_DATA:
218 break;
219 default:
220 container->destroy(container);
221 return;
222 }
223
224 pkcs7 = (pkcs7_t *)container;
225 enumerator = pkcs7->create_cert_enumerator(pkcs7);
226 while (enumerator->enumerate(enumerator, &cert))
227 {
228 if (cert->get_type(cert) == CERT_X509)
229 {
230 x509_t *x509 = (x509_t*)cert;
231
232 if (x509->get_flags(x509) & X509_CA)
233 {
234 DBG1(DBG_IKE, "received issuer cert \"%Y\"",
235 cert->get_subject(cert));
236 auth->add(auth, AUTH_HELPER_IM_CERT, cert->get_ref(cert));
237 }
238 else
239 {
240 DBG1(DBG_IKE, "received end entity cert \"%Y\"",
241 cert->get_subject(cert));
242 auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert->get_ref(cert));
243 }
244 }
245 else
246 {
247 DBG1(DBG_IKE, "received unsupported cert type %N",
248 certificate_type_names, cert->get_type(cert));
249 }
250 }
251 enumerator->destroy(enumerator);
252
253 container->destroy(container);
254 }
255
256 /**
257 * Import received certificates
258 */
259 static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
260 {
261 enumerator_t *enumerator;
262 payload_t *payload;
263 auth_cfg_t *auth;
264 bool first = TRUE;
265
266 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
267
268 enumerator = message->create_payload_enumerator(message);
269 while (enumerator->enumerate(enumerator, &payload))
270 {
271 if (payload->get_type(payload) == PLV1_CERTIFICATE)
272 {
273 cert_payload_t *cert_payload;
274 cert_encoding_t encoding;
275
276 cert_payload = (cert_payload_t*)payload;
277 encoding = cert_payload->get_cert_encoding(cert_payload);
278
279 switch (encoding)
280 {
281 case ENC_X509_SIGNATURE:
282 process_x509(cert_payload, auth, &first);
283 break;
284 case ENC_CRL:
285 process_crl(cert_payload, auth);
286 break;
287 case ENC_PKCS7_WRAPPED_X509:
288 process_pkcs7(cert_payload, auth);
289 break;
290 case ENC_PGP:
291 case ENC_DNS_SIGNED_KEY:
292 case ENC_KERBEROS_TOKEN:
293 case ENC_ARL:
294 case ENC_SPKI:
295 case ENC_X509_ATTRIBUTE:
296 case ENC_RAW_RSA_KEY:
297 case ENC_X509_HASH_AND_URL_BUNDLE:
298 case ENC_OCSP_CONTENT:
299 default:
300 DBG1(DBG_ENC, "certificate encoding %N not supported",
301 cert_encoding_names, encoding);
302 }
303 }
304 }
305 enumerator->destroy(enumerator);
306 }
307
308 /**
309 * Add the subject of a CA certificate a message
310 */
311 static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message,
312 certificate_t *cert)
313 {
314 if (cert->get_type(cert) == CERT_X509)
315 {
316 x509_t *x509 = (x509_t*)cert;
317
318 if (x509->get_flags(x509) & X509_CA)
319 {
320 DBG1(DBG_IKE, "sending cert request for \"%Y\"",
321 cert->get_subject(cert));
322 message->add_payload(message, (payload_t*)
323 certreq_payload_create_dn(cert->get_subject(cert)));
324 }
325 }
326 }
327
328 /**
329 * Add auth_cfg's CA certificates to the certificate request
330 */
331 static void add_certreqs(private_isakmp_cert_pre_t *this,
332 auth_cfg_t *auth, message_t *message)
333 {
334 enumerator_t *enumerator;
335 auth_rule_t type;
336 void *value;
337
338 enumerator = auth->create_enumerator(auth);
339 while (enumerator->enumerate(enumerator, &type, &value))
340 {
341 switch (type)
342 {
343 case AUTH_RULE_CA_CERT:
344 add_certreq(this, message, (certificate_t*)value);
345 break;
346 default:
347 break;
348 }
349 }
350 enumerator->destroy(enumerator);
351 }
352
353 /**
354 * Build certificate requests
355 */
356 static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
357 {
358 enumerator_t *enumerator;
359 ike_cfg_t *ike_cfg;
360 peer_cfg_t *peer_cfg;
361 certificate_t *cert;
362 auth_cfg_t *auth;
363
364 ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
365 if (!ike_cfg->send_certreq(ike_cfg))
366 {
367 return;
368 }
369 /* check if we require a specific CA for that peer */
370 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
371 if (peer_cfg)
372 {
373 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
374 if (enumerator->enumerate(enumerator, &auth))
375 {
376 add_certreqs(this, auth, message);
377 }
378 enumerator->destroy(enumerator);
379 }
380 if (!message->get_payload(message, PLV1_CERTREQ))
381 {
382 /* otherwise add all trusted CA certificates */
383 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
384 CERT_ANY, KEY_ANY, NULL, TRUE);
385 while (enumerator->enumerate(enumerator, &cert))
386 {
387 add_certreq(this, message, cert);
388 }
389 enumerator->destroy(enumerator);
390 }
391 }
392
393 /**
394 * Check if we actually use certificates for authentication
395 */
396 static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message)
397 {
398 enumerator_t *enumerator;
399 payload_t *payload;
400 bool use = FALSE;
401
402 enumerator = message->create_payload_enumerator(message);
403 while (enumerator->enumerate(enumerator, &payload))
404 {
405 if (payload->get_type(payload) == PLV1_SECURITY_ASSOCIATION)
406 {
407 sa_payload_t *sa_payload = (sa_payload_t*)payload;
408
409 switch (sa_payload->get_auth_method(sa_payload))
410 {
411 case AUTH_HYBRID_INIT_RSA:
412 case AUTH_HYBRID_RESP_RSA:
413 if (!this->initiator)
414 {
415 this->send_req = FALSE;
416 }
417 /* FALL */
418 case AUTH_RSA:
419 case AUTH_ECDSA_256:
420 case AUTH_ECDSA_384:
421 case AUTH_ECDSA_521:
422 case AUTH_XAUTH_INIT_RSA:
423 case AUTH_XAUTH_RESP_RSA:
424 use = TRUE;
425 break;
426 default:
427 break;
428 }
429 break;
430 }
431 }
432 enumerator->destroy(enumerator);
433
434 return use;
435 }
436
437 /**
438 * Check if we should send a certificate request
439 */
440 static bool send_certreq(private_isakmp_cert_pre_t *this)
441 {
442 enumerator_t *enumerator;
443 peer_cfg_t *peer_cfg;
444 auth_cfg_t *auth;
445 bool req = FALSE;
446 auth_class_t class;
447
448 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
449 if (peer_cfg)
450 {
451 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
452 if (enumerator->enumerate(enumerator, &auth))
453 {
454 class = (intptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
455 if (class == AUTH_CLASS_PUBKEY)
456 {
457 req = TRUE;
458 }
459 }
460 enumerator->destroy(enumerator);
461 }
462 return req;
463 }
464
465 METHOD(task_t, build_i, status_t,
466 private_isakmp_cert_pre_t *this, message_t *message)
467 {
468 switch (message->get_exchange_type(message))
469 {
470 case ID_PROT:
471 if (this->state == CR_AUTH)
472 {
473 build_certreqs(this, message);
474 }
475 return NEED_MORE;
476 case AGGRESSIVE:
477 if (this->state == CR_SA)
478 {
479 if (send_certreq(this))
480 {
481 build_certreqs(this, message);
482 }
483 }
484 return NEED_MORE;
485 default:
486 return FAILED;
487 }
488 }
489
490 METHOD(task_t, process_r, status_t,
491 private_isakmp_cert_pre_t *this, message_t *message)
492 {
493 switch (message->get_exchange_type(message))
494 {
495 case ID_PROT:
496 {
497 switch (this->state)
498 {
499 case CR_SA:
500 if (!use_certs(this, message))
501 {
502 return SUCCESS;
503 }
504 return NEED_MORE;
505 case CR_KE:
506 process_certreqs(this, message);
507 return NEED_MORE;
508 case CR_AUTH:
509 process_certreqs(this, message);
510 process_certs(this, message);
511 return SUCCESS;
512 default:
513 return FAILED;
514 }
515 }
516 case AGGRESSIVE:
517 {
518 switch (this->state)
519 {
520 case CR_SA:
521 if (!use_certs(this, message))
522 {
523 return SUCCESS;
524 }
525 process_certreqs(this, message);
526 return NEED_MORE;
527 case CR_AUTH:
528 process_certs(this, message);
529 return SUCCESS;
530 default:
531 return FAILED;
532 }
533 }
534 default:
535 return FAILED;
536 }
537 }
538
539 METHOD(task_t, build_r, status_t,
540 private_isakmp_cert_pre_t *this, message_t *message)
541 {
542 switch (message->get_exchange_type(message))
543 {
544 case ID_PROT:
545 switch (this->state)
546 {
547 case CR_SA:
548 this->state = CR_KE;
549 return NEED_MORE;
550 case CR_KE:
551 if (this->send_req)
552 {
553 build_certreqs(this, message);
554 }
555 this->state = CR_AUTH;
556 return NEED_MORE;
557 case CR_AUTH:
558 return NEED_MORE;
559 default:
560 return FAILED;
561 }
562 case AGGRESSIVE:
563 switch (this->state)
564 {
565 case CR_SA:
566 if (this->send_req)
567 {
568 build_certreqs(this, message);
569 }
570 this->state = CR_AUTH;
571 return NEED_MORE;
572 case CR_AUTH:
573 return SUCCESS;
574 default:
575 return FAILED;
576 }
577 default:
578 return FAILED;
579 }
580 }
581
582 METHOD(task_t, process_i, status_t,
583 private_isakmp_cert_pre_t *this, message_t *message)
584 {
585 switch (message->get_exchange_type(message))
586 {
587 case ID_PROT:
588 {
589 switch (this->state)
590 {
591 case CR_SA:
592 if (!use_certs(this, message))
593 {
594 return SUCCESS;
595 }
596 this->state = CR_KE;
597 return NEED_MORE;
598 case CR_KE:
599 process_certreqs(this, message);
600 this->state = CR_AUTH;
601 return NEED_MORE;
602 case CR_AUTH:
603 process_certs(this, message);
604 return SUCCESS;
605 default:
606 return FAILED;
607 }
608 break;
609 }
610 case AGGRESSIVE:
611 {
612 if (!use_certs(this, message))
613 {
614 return SUCCESS;
615 }
616 process_certreqs(this, message);
617 process_certs(this, message);
618 this->state = CR_AUTH;
619 return SUCCESS;
620 }
621 default:
622 return FAILED;
623 }
624 }
625
626 METHOD(task_t, get_type, task_type_t,
627 private_isakmp_cert_pre_t *this)
628 {
629 return TASK_ISAKMP_CERT_PRE;
630 }
631
632 METHOD(task_t, migrate, void,
633 private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
634 {
635 this->ike_sa = ike_sa;
636 this->state = CR_SA;
637 this->send_req = TRUE;
638 }
639
640 METHOD(task_t, destroy, void,
641 private_isakmp_cert_pre_t *this)
642 {
643 free(this);
644 }
645
646 /*
647 * Described in header.
648 */
649 isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
650 {
651 private_isakmp_cert_pre_t *this;
652
653 INIT(this,
654 .public = {
655 .task = {
656 .get_type = _get_type,
657 .migrate = _migrate,
658 .destroy = _destroy,
659 },
660 },
661 .ike_sa = ike_sa,
662 .initiator = initiator,
663 .state = CR_SA,
664 .send_req = TRUE,
665 );
666 if (initiator)
667 {
668 this->public.task.build = _build_i;
669 this->public.task.process = _process_i;
670 }
671 else
672 {
673 this->public.task.build = _build_r;
674 this->public.task.process = _process_r;
675 }
676 return &this->public;
677 }