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