Send cert request based on peers configured authentication class
[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 /**
339 * Check if we should send a certificate request
340 */
341 static bool send_certreq(private_isakmp_cert_pre_t *this)
342 {
343 enumerator_t *enumerator;
344 peer_cfg_t *peer_cfg;
345 auth_cfg_t *auth;
346 bool req = FALSE;
347 auth_class_t class;
348
349 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
350 if (peer_cfg)
351 {
352 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
353 if (enumerator->enumerate(enumerator, &auth))
354 {
355 class = (intptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
356 if (class == AUTH_CLASS_PUBKEY)
357 {
358 req = TRUE;
359 }
360 }
361 enumerator->destroy(enumerator);
362 }
363 return req;
364 }
365
366 METHOD(task_t, build_i, status_t,
367 private_isakmp_cert_pre_t *this, message_t *message)
368 {
369 switch (message->get_exchange_type(message))
370 {
371 case ID_PROT:
372 if (this->state == CR_AUTH)
373 {
374 build_certreqs(this, message);
375 }
376 return NEED_MORE;
377 case AGGRESSIVE:
378 if (this->state == CR_SA)
379 {
380 if (send_certreq(this))
381 {
382 build_certreqs(this, message);
383 }
384 }
385 return NEED_MORE;
386 default:
387 return FAILED;
388 }
389 }
390
391 METHOD(task_t, process_r, status_t,
392 private_isakmp_cert_pre_t *this, message_t *message)
393 {
394 switch (message->get_exchange_type(message))
395 {
396 case ID_PROT:
397 {
398 switch (this->state)
399 {
400 case CR_SA:
401 if (!use_certs(this, message))
402 {
403 return SUCCESS;
404 }
405 return NEED_MORE;
406 case CR_KE:
407 process_certreqs(this, message);
408 return NEED_MORE;
409 case CR_AUTH:
410 process_certreqs(this, message);
411 process_certs(this, message);
412 return SUCCESS;
413 }
414 }
415 case AGGRESSIVE:
416 {
417 switch (this->state)
418 {
419 case CR_SA:
420 if (!use_certs(this, message))
421 {
422 return SUCCESS;
423 }
424 process_certreqs(this, message);
425 return NEED_MORE;
426 case CR_AUTH:
427 process_certs(this, message);
428 return SUCCESS;
429 default:
430 return FAILED;
431 }
432 }
433 default:
434 return FAILED;
435 }
436 }
437
438 METHOD(task_t, build_r, status_t,
439 private_isakmp_cert_pre_t *this, message_t *message)
440 {
441 switch (message->get_exchange_type(message))
442 {
443 case ID_PROT:
444 switch (this->state)
445 {
446 case CR_SA:
447 this->state = CR_KE;
448 return NEED_MORE;
449 case CR_KE:
450 if (this->send_req)
451 {
452 build_certreqs(this, message);
453 }
454 this->state = CR_AUTH;
455 return NEED_MORE;
456 case CR_AUTH:
457 return NEED_MORE;
458 }
459 case AGGRESSIVE:
460 switch (this->state)
461 {
462 case CR_SA:
463 if (this->send_req)
464 {
465 build_certreqs(this, message);
466 }
467 this->state = CR_AUTH;
468 return NEED_MORE;
469 case CR_AUTH:
470 return SUCCESS;
471 default:
472 return FAILED;
473 }
474 default:
475 return FAILED;
476 }
477 }
478
479 METHOD(task_t, process_i, status_t,
480 private_isakmp_cert_pre_t *this, message_t *message)
481 {
482 switch (message->get_exchange_type(message))
483 {
484 case ID_PROT:
485 {
486 switch (this->state)
487 {
488 case CR_SA:
489 if (!use_certs(this, message))
490 {
491 return SUCCESS;
492 }
493 this->state = CR_KE;
494 return NEED_MORE;
495 case CR_KE:
496 process_certreqs(this, message);
497 this->state = CR_AUTH;
498 return NEED_MORE;
499 case CR_AUTH:
500 process_certs(this, message);
501 return SUCCESS;
502 default:
503 return FAILED;
504 }
505 break;
506 }
507 case AGGRESSIVE:
508 {
509 if (!use_certs(this, message))
510 {
511 return SUCCESS;
512 }
513 process_certreqs(this, message);
514 process_certs(this, message);
515 this->state = CR_AUTH;
516 return SUCCESS;
517 }
518 default:
519 return FAILED;
520 }
521 }
522
523 METHOD(task_t, get_type, task_type_t,
524 private_isakmp_cert_pre_t *this)
525 {
526 return TASK_ISAKMP_CERT_PRE;
527 }
528
529 METHOD(task_t, migrate, void,
530 private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
531 {
532 this->ike_sa = ike_sa;
533 this->state = CR_SA;
534 this->send_req = TRUE;
535 }
536
537 METHOD(task_t, destroy, void,
538 private_isakmp_cert_pre_t *this)
539 {
540 free(this);
541 }
542
543 /*
544 * Described in header.
545 */
546 isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
547 {
548 private_isakmp_cert_pre_t *this;
549
550 INIT(this,
551 .public = {
552 .task = {
553 .get_type = _get_type,
554 .migrate = _migrate,
555 .destroy = _destroy,
556 },
557 },
558 .ike_sa = ike_sa,
559 .initiator = initiator,
560 .state = CR_SA,
561 .send_req = TRUE,
562 );
563 if (initiator)
564 {
565 this->public.task.build = _build_i;
566 this->public.task.process = _process_i;
567 }
568 else
569 {
570 this->public.task.build = _build_r;
571 this->public.task.process = _process_r;
572 }
573 return &this->public;
574 }