Annotation of embedaddon/ipsec-tools/src/racoon/proposal.c, revision 1.1.1.1
1.1 misho 1: /* $NetBSD: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $ */
2:
3: /* $Id: proposal.c,v 1.17 2008/09/19 11:14:49 tteras Exp $ */
4:
5: /*
6: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. Neither the name of the project nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #include "config.h"
35:
36: #include <sys/param.h>
37: #include <sys/types.h>
38: #include <sys/socket.h>
39: #include <sys/queue.h>
40:
41: #include <netinet/in.h>
42: #include PATH_IPSEC_H
43:
44: #include <stdlib.h>
45: #include <stdio.h>
46: #include <string.h>
47: #include <errno.h>
48:
49: #include "var.h"
50: #include "misc.h"
51: #include "vmbuf.h"
52: #include "plog.h"
53: #include "sockmisc.h"
54: #include "debug.h"
55:
56: #include "policy.h"
57: #include "pfkey.h"
58: #include "isakmp_var.h"
59: #include "isakmp.h"
60: #include "ipsec_doi.h"
61: #include "algorithm.h"
62: #include "proposal.h"
63: #include "sainfo.h"
64: #include "localconf.h"
65: #include "remoteconf.h"
66: #include "oakley.h"
67: #include "handler.h"
68: #include "strnames.h"
69: #include "gcmalloc.h"
70: #ifdef ENABLE_NATT
71: #include "nattraversal.h"
72: #endif
73:
74: static uint g_nextreqid = 1;
75:
76: /* %%%
77: * modules for ipsec sa spec
78: */
79: struct saprop *
80: newsaprop()
81: {
82: struct saprop *new;
83:
84: new = racoon_calloc(1, sizeof(*new));
85: if (new == NULL)
86: return NULL;
87:
88: return new;
89: }
90:
91: struct saproto *
92: newsaproto()
93: {
94: struct saproto *new;
95:
96: new = racoon_calloc(1, sizeof(*new));
97: if (new == NULL)
98: return NULL;
99:
100: return new;
101: }
102:
103: /* set saprop to last part of the prop tree */
104: void
105: inssaprop(head, new)
106: struct saprop **head;
107: struct saprop *new;
108: {
109: struct saprop *p;
110:
111: if (*head == NULL) {
112: *head = new;
113: return;
114: }
115:
116: for (p = *head; p->next; p = p->next)
117: ;
118: p->next = new;
119:
120: return;
121: }
122:
123: /* set saproto to the end of the proto tree in saprop */
124: void
125: inssaproto(pp, new)
126: struct saprop *pp;
127: struct saproto *new;
128: {
129: struct saproto *p;
130:
131: for (p = pp->head; p && p->next; p = p->next)
132: ;
133: if (p == NULL)
134: pp->head = new;
135: else
136: p->next = new;
137:
138: return;
139: }
140:
141: /* set saproto to the top of the proto tree in saprop */
142: void
143: inssaprotorev(pp, new)
144: struct saprop *pp;
145: struct saproto *new;
146: {
147: new->next = pp->head;
148: pp->head = new;
149:
150: return;
151: }
152:
153: struct satrns *
154: newsatrns()
155: {
156: struct satrns *new;
157:
158: new = racoon_calloc(1, sizeof(*new));
159: if (new == NULL)
160: return NULL;
161:
162: return new;
163: }
164:
165: /* set saproto to last part of the proto tree in saprop */
166: void
167: inssatrns(pr, new)
168: struct saproto *pr;
169: struct satrns *new;
170: {
171: struct satrns *tr;
172:
173: for (tr = pr->head; tr && tr->next; tr = tr->next)
174: ;
175: if (tr == NULL)
176: pr->head = new;
177: else
178: tr->next = new;
179:
180: return;
181: }
182:
183: /*
184: * take a single match between saprop. allocate a new proposal and return it
185: * for future use (like picking single proposal from a bundle).
186: * pp1: peer's proposal.
187: * pp2: my proposal.
188: * NOTE: In the case of initiator, must be ensured that there is no
189: * modification of the proposal by calling cmp_aproppair_i() before
190: * this function.
191: * XXX cannot understand the comment!
192: */
193: struct saprop *
194: cmpsaprop_alloc(ph1, pp1, pp2, side)
195: struct ph1handle *ph1;
196: const struct saprop *pp1, *pp2;
197: int side;
198: {
199: struct saprop *newpp = NULL;
200: struct saproto *pr1, *pr2, *newpr = NULL;
201: struct satrns *tr1, *tr2, *newtr;
202: const int ordermatters = 0;
203: int npr1, npr2;
204: int spisizematch;
205:
206: newpp = newsaprop();
207: if (newpp == NULL) {
208: plog(LLV_ERROR, LOCATION, NULL,
209: "failed to allocate saprop.\n");
210: return NULL;
211: }
212: newpp->prop_no = pp1->prop_no;
213:
214: /* see proposal.h about lifetime/key length and PFS selection. */
215:
216: /* check time/bytes lifetime and PFS */
217: switch (ph1->rmconf->pcheck_level) {
218: case PROP_CHECK_OBEY:
219: newpp->lifetime = pp1->lifetime;
220: newpp->lifebyte = pp1->lifebyte;
221: newpp->pfs_group = pp1->pfs_group;
222: break;
223:
224: case PROP_CHECK_STRICT:
225: if (pp1->lifetime > pp2->lifetime) {
226: plog(LLV_ERROR, LOCATION, NULL,
227: "long lifetime proposed: "
228: "my:%d peer:%d\n",
229: (int)pp2->lifetime, (int)pp1->lifetime);
230: goto err;
231: }
232: if (pp1->lifebyte > pp2->lifebyte) {
233: plog(LLV_ERROR, LOCATION, NULL,
234: "long lifebyte proposed: "
235: "my:%d peer:%d\n",
236: pp2->lifebyte, pp1->lifebyte);
237: goto err;
238: }
239: newpp->lifetime = pp1->lifetime;
240: newpp->lifebyte = pp1->lifebyte;
241:
242: prop_pfs_check:
243: if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) {
244: plog(LLV_ERROR, LOCATION, NULL,
245: "pfs group mismatched: "
246: "my:%d peer:%d\n",
247: pp2->pfs_group, pp1->pfs_group);
248: goto err;
249: }
250: newpp->pfs_group = pp1->pfs_group;
251: break;
252:
253: case PROP_CHECK_CLAIM:
254: /* lifetime */
255: if (pp1->lifetime <= pp2->lifetime) {
256: newpp->lifetime = pp1->lifetime;
257: } else {
258: newpp->lifetime = pp2->lifetime;
259: newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
260: plog(LLV_NOTIFY, LOCATION, NULL,
261: "use own lifetime: "
262: "my:%d peer:%d\n",
263: (int)pp2->lifetime, (int)pp1->lifetime);
264: }
265:
266: /* lifebyte */
267: if (pp1->lifebyte > pp2->lifebyte) {
268: newpp->lifebyte = pp2->lifebyte;
269: newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
270: plog(LLV_NOTIFY, LOCATION, NULL,
271: "use own lifebyte: "
272: "my:%d peer:%d\n",
273: pp2->lifebyte, pp1->lifebyte);
274: }
275: newpp->lifebyte = pp1->lifebyte;
276:
277: goto prop_pfs_check;
278: break;
279:
280: case PROP_CHECK_EXACT:
281: if (pp1->lifetime != pp2->lifetime) {
282: plog(LLV_ERROR, LOCATION, NULL,
283: "lifetime mismatched: "
284: "my:%d peer:%d\n",
285: (int)pp2->lifetime, (int)pp1->lifetime);
286: goto err;
287: }
288:
289: if (pp1->lifebyte != pp2->lifebyte) {
290: plog(LLV_ERROR, LOCATION, NULL,
291: "lifebyte mismatched: "
292: "my:%d peer:%d\n",
293: pp2->lifebyte, pp1->lifebyte);
294: goto err;
295: }
296: if (pp1->pfs_group != pp2->pfs_group) {
297: plog(LLV_ERROR, LOCATION, NULL,
298: "pfs group mismatched: "
299: "my:%d peer:%d\n",
300: pp2->pfs_group, pp1->pfs_group);
301: goto err;
302: }
303: newpp->lifetime = pp1->lifetime;
304: newpp->lifebyte = pp1->lifebyte;
305: newpp->pfs_group = pp1->pfs_group;
306: break;
307:
308: default:
309: plog(LLV_ERROR, LOCATION, NULL,
310: "invalid pcheck_level why?.\n");
311: goto err;
312: }
313:
314: #ifdef HAVE_SECCTX
315: /* check the security_context properties.
316: * It is possible for one side to have a security context
317: * and the other side doesn't. If so, this is an error.
318: */
319:
320: if (*pp1->sctx.ctx_str && !(*pp2->sctx.ctx_str)) {
321: plog(LLV_ERROR, LOCATION, NULL,
322: "My proposal missing security context\n");
323: goto err;
324: }
325: if (!(*pp1->sctx.ctx_str) && *pp2->sctx.ctx_str) {
326: plog(LLV_ERROR, LOCATION, NULL,
327: "Peer is missing security context\n");
328: goto err;
329: }
330:
331: if (*pp1->sctx.ctx_str && *pp2->sctx.ctx_str) {
332: if (pp1->sctx.ctx_doi == pp2->sctx.ctx_doi)
333: newpp->sctx.ctx_doi = pp1->sctx.ctx_doi;
334: else {
335: plog(LLV_ERROR, LOCATION, NULL,
336: "sec doi mismatched: my:%d peer:%d\n",
337: pp2->sctx.ctx_doi, pp1->sctx.ctx_doi);
338: goto err;
339: }
340:
341: if (pp1->sctx.ctx_alg == pp2->sctx.ctx_alg)
342: newpp->sctx.ctx_alg = pp1->sctx.ctx_alg;
343: else {
344: plog(LLV_ERROR, LOCATION, NULL,
345: "sec alg mismatched: my:%d peer:%d\n",
346: pp2->sctx.ctx_alg, pp1->sctx.ctx_alg);
347: goto err;
348: }
349:
350: if ((pp1->sctx.ctx_strlen != pp2->sctx.ctx_strlen) ||
351: memcmp(pp1->sctx.ctx_str, pp2->sctx.ctx_str,
352: pp1->sctx.ctx_strlen) != 0) {
353: plog(LLV_ERROR, LOCATION, NULL,
354: "sec ctx string mismatched: my:%s peer:%s\n",
355: pp2->sctx.ctx_str, pp1->sctx.ctx_str);
356: goto err;
357: } else {
358: newpp->sctx.ctx_strlen = pp1->sctx.ctx_strlen;
359: memcpy(newpp->sctx.ctx_str, pp1->sctx.ctx_str,
360: pp1->sctx.ctx_strlen);
361: }
362: }
363: #endif /* HAVE_SECCTX */
364:
365: npr1 = npr2 = 0;
366: for (pr1 = pp1->head; pr1; pr1 = pr1->next)
367: npr1++;
368: for (pr2 = pp2->head; pr2; pr2 = pr2->next)
369: npr2++;
370: if (npr1 != npr2)
371: goto err;
372:
373: /* check protocol order */
374: pr1 = pp1->head;
375: pr2 = pp2->head;
376:
377: while (1) {
378: if (!ordermatters) {
379: /*
380: * XXX does not work if we have multiple proposals
381: * with the same proto_id
382: */
383: switch (side) {
384: case RESPONDER:
385: if (!pr2)
386: break;
387: for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
388: if (pr1->proto_id == pr2->proto_id)
389: break;
390: }
391: break;
392: case INITIATOR:
393: if (!pr1)
394: break;
395: for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
396: if (pr2->proto_id == pr1->proto_id)
397: break;
398: }
399: break;
400: }
401: }
402: if (!pr1 || !pr2)
403: break;
404:
405: if (pr1->proto_id != pr2->proto_id) {
406: plog(LLV_ERROR, LOCATION, NULL,
407: "proto_id mismatched: "
408: "my:%s peer:%s\n",
409: s_ipsecdoi_proto(pr2->proto_id),
410: s_ipsecdoi_proto(pr1->proto_id));
411: goto err;
412: }
413: spisizematch = 0;
414: if (pr1->spisize == pr2->spisize)
415: spisizematch = 1;
416: else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
417: /*
418: * draft-shacham-ippcp-rfc2393bis-05.txt:
419: * need to accept 16bit and 32bit SPI (CPI) for IPComp.
420: */
421: if (pr1->spisize == sizeof(u_int16_t) &&
422: pr2->spisize == sizeof(u_int32_t)) {
423: spisizematch = 1;
424: } else if (pr2->spisize == sizeof(u_int16_t) &&
425: pr1->spisize == sizeof(u_int32_t)) {
426: spisizematch = 1;
427: }
428: if (spisizematch) {
429: plog(LLV_ERROR, LOCATION, NULL,
430: "IPComp SPI size promoted "
431: "from 16bit to 32bit\n");
432: }
433: }
434: if (!spisizematch) {
435: plog(LLV_ERROR, LOCATION, NULL,
436: "spisize mismatched: "
437: "my:%d peer:%d\n",
438: (int)pr2->spisize, (int)pr1->spisize);
439: goto err;
440: }
441:
442: #ifdef ENABLE_NATT
443: if ((ph1->natt_flags & NAT_DETECTED) &&
444: natt_udp_encap (pr2->encmode))
445: {
446: plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
447: s_ipsecdoi_encmode(pr2->encmode),
448: s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
449: pr2->encmode -= ph1->natt_options->mode_udp_diff;
450: pr2->udp_encap = 1;
451: }
452:
453: if ((ph1->natt_flags & NAT_DETECTED) &&
454: natt_udp_encap (pr1->encmode))
455: {
456: plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
457: s_ipsecdoi_encmode(pr1->encmode),
458: pr1->encmode,
459: s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
460: pr1->encmode - ph1->natt_options->mode_udp_diff);
461: pr1->encmode -= ph1->natt_options->mode_udp_diff;
462: pr1->udp_encap = 1;
463: }
464: #endif
465:
466: if (pr1->encmode != pr2->encmode) {
467: plog(LLV_ERROR, LOCATION, NULL,
468: "encmode mismatched: "
469: "my:%s peer:%s\n",
470: s_ipsecdoi_encmode(pr2->encmode),
471: s_ipsecdoi_encmode(pr1->encmode));
472: goto err;
473: }
474:
475: for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
476: for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
477: if (cmpsatrns(pr1->proto_id, tr1, tr2, ph1->rmconf->pcheck_level) == 0)
478: goto found;
479: }
480: }
481:
482: goto err;
483:
484: found:
485: newpr = newsaproto();
486: if (newpr == NULL) {
487: plog(LLV_ERROR, LOCATION, NULL,
488: "failed to allocate saproto.\n");
489: goto err;
490: }
491: newpr->proto_id = pr1->proto_id;
492: newpr->spisize = pr1->spisize;
493: newpr->encmode = pr1->encmode;
494: newpr->spi = pr2->spi; /* copy my SPI */
495: newpr->spi_p = pr1->spi; /* copy peer's SPI */
496: newpr->reqid_in = pr2->reqid_in;
497: newpr->reqid_out = pr2->reqid_out;
498: #ifdef ENABLE_NATT
499: newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
500: #endif
501:
502: newtr = newsatrns();
503: if (newtr == NULL) {
504: plog(LLV_ERROR, LOCATION, NULL,
505: "failed to allocate satrns.\n");
506: racoon_free(newpr);
507: goto err;
508: }
509: newtr->trns_no = tr1->trns_no;
510: newtr->trns_id = tr1->trns_id;
511: newtr->encklen = tr1->encklen;
512: newtr->authtype = tr1->authtype;
513:
514: inssatrns(newpr, newtr);
515: inssaproto(newpp, newpr);
516:
517: pr1 = pr1->next;
518: pr2 = pr2->next;
519: }
520:
521: /* XXX should check if we have visited all items or not */
522: if (!ordermatters) {
523: switch (side) {
524: case RESPONDER:
525: if (!pr2)
526: pr1 = NULL;
527: break;
528: case INITIATOR:
529: if (!pr1)
530: pr2 = NULL;
531: break;
532: }
533: }
534:
535: /* should be matched all protocols in a proposal */
536: if (pr1 != NULL || pr2 != NULL)
537: goto err;
538:
539: return newpp;
540:
541: err:
542: flushsaprop(newpp);
543: return NULL;
544: }
545:
546: /* take a single match between saprop. returns 0 if pp1 equals to pp2. */
547: int
548: cmpsaprop(pp1, pp2)
549: const struct saprop *pp1, *pp2;
550: {
551: if (pp1->pfs_group != pp2->pfs_group) {
552: plog(LLV_WARNING, LOCATION, NULL,
553: "pfs_group mismatch. mine:%d peer:%d\n",
554: pp1->pfs_group, pp2->pfs_group);
555: /* FALLTHRU */
556: }
557:
558: if (pp1->lifetime > pp2->lifetime) {
559: plog(LLV_WARNING, LOCATION, NULL,
560: "less lifetime proposed. mine:%d peer:%d\n",
561: (int)pp1->lifetime, (int)pp2->lifetime);
562: /* FALLTHRU */
563: }
564: if (pp1->lifebyte > pp2->lifebyte) {
565: plog(LLV_WARNING, LOCATION, NULL,
566: "less lifebyte proposed. mine:%d peer:%d\n",
567: pp1->lifebyte, pp2->lifebyte);
568: /* FALLTHRU */
569: }
570:
571: return 0;
572: }
573:
574: /*
575: * take a single match between satrns. returns 0 if tr1 equals to tr2.
576: * tr1: peer's satrns
577: * tr2: my satrns
578: */
579: int
580: cmpsatrns(proto_id, tr1, tr2, check_level)
581: int proto_id;
582: const struct satrns *tr1, *tr2;
583: int check_level;
584: {
585: if (tr1->trns_id != tr2->trns_id) {
586: plog(LLV_WARNING, LOCATION, NULL,
587: "trns_id mismatched: "
588: "my:%s peer:%s\n",
589: s_ipsecdoi_trns(proto_id, tr2->trns_id),
590: s_ipsecdoi_trns(proto_id, tr1->trns_id));
591: return 1;
592: }
593:
594: if (tr1->authtype != tr2->authtype) {
595: plog(LLV_WARNING, LOCATION, NULL,
596: "authtype mismatched: "
597: "my:%s peer:%s\n",
598: s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
599: s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
600: return 1;
601: }
602:
603: /* Check key length regarding checkmode
604: * XXX Shall we send some kind of notify message when key length rejected ?
605: */
606: switch(check_level){
607: case PROP_CHECK_OBEY:
608: return 0;
609: break;
610:
611: case PROP_CHECK_STRICT:
612: /* FALLTHROUGH */
613: case PROP_CHECK_CLAIM:
614: if (tr1->encklen < tr2->encklen) {
615: plog(LLV_WARNING, LOCATION, NULL,
616: "low key length proposed, "
617: "mine:%d peer:%d.\n",
618: tr2->encklen, tr1->encklen);
619: return 1;
620: }
621: break;
622: case PROP_CHECK_EXACT:
623: if (tr1->encklen != tr2->encklen) {
624: plog(LLV_WARNING, LOCATION, NULL,
625: "key length mismatched, "
626: "mine:%d peer:%d.\n",
627: tr2->encklen, tr1->encklen);
628: return 1;
629: }
630: break;
631: }
632:
633: return 0;
634: }
635:
636: int
637: set_satrnsbysainfo(pr, sainfo)
638: struct saproto *pr;
639: struct sainfo *sainfo;
640: {
641: struct sainfoalg *a, *b;
642: struct satrns *newtr;
643: int t;
644:
645: switch (pr->proto_id) {
646: case IPSECDOI_PROTO_IPSEC_AH:
647: if (sainfo->algs[algclass_ipsec_auth] == NULL) {
648: plog(LLV_ERROR, LOCATION, NULL,
649: "no auth algorithm found\n");
650: goto err;
651: }
652: t = 1;
653: for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
654:
655: if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
656: continue;
657:
658: /* allocate satrns */
659: newtr = newsatrns();
660: if (newtr == NULL) {
661: plog(LLV_ERROR, LOCATION, NULL,
662: "failed to allocate satrns.\n");
663: goto err;
664: }
665:
666: newtr->trns_no = t++;
667: newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
668: newtr->authtype = a->alg;
669:
670: inssatrns(pr, newtr);
671: }
672: break;
673: case IPSECDOI_PROTO_IPSEC_ESP:
674: if (sainfo->algs[algclass_ipsec_enc] == NULL) {
675: plog(LLV_ERROR, LOCATION, NULL,
676: "no encryption algorithm found\n");
677: goto err;
678: }
679: t = 1;
680: for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
681: for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
682: /* allocate satrns */
683: newtr = newsatrns();
684: if (newtr == NULL) {
685: plog(LLV_ERROR, LOCATION, NULL,
686: "failed to allocate satrns.\n");
687: goto err;
688: }
689:
690: newtr->trns_no = t++;
691: newtr->trns_id = a->alg;
692: newtr->encklen = a->encklen;
693: newtr->authtype = b->alg;
694:
695: inssatrns(pr, newtr);
696: }
697: }
698: break;
699: case IPSECDOI_PROTO_IPCOMP:
700: if (sainfo->algs[algclass_ipsec_comp] == NULL) {
701: plog(LLV_ERROR, LOCATION, NULL,
702: "no ipcomp algorithm found\n");
703: goto err;
704: }
705: t = 1;
706: for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
707:
708: /* allocate satrns */
709: newtr = newsatrns();
710: if (newtr == NULL) {
711: plog(LLV_ERROR, LOCATION, NULL,
712: "failed to allocate satrns.\n");
713: goto err;
714: }
715:
716: newtr->trns_no = t++;
717: newtr->trns_id = a->alg;
718: newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
719:
720: inssatrns(pr, newtr);
721: }
722: break;
723: default:
724: plog(LLV_ERROR, LOCATION, NULL,
725: "unknown proto_id (%d).\n", pr->proto_id);
726: goto err;
727: }
728:
729: /* no proposal found */
730: if (pr->head == NULL) {
731: plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
732: return -1;
733: }
734:
735: return 0;
736:
737: err:
738: flushsatrns(pr->head);
739: return -1;
740: }
741:
742: struct saprop *
743: aproppair2saprop(p0)
744: struct prop_pair *p0;
745: {
746: struct prop_pair *p, *t;
747: struct saprop *newpp;
748: struct saproto *newpr;
749: struct satrns *newtr;
750: u_int8_t *spi;
751:
752: if (p0 == NULL)
753: return NULL;
754:
755: /* allocate ipsec a sa proposal */
756: newpp = newsaprop();
757: if (newpp == NULL) {
758: plog(LLV_ERROR, LOCATION, NULL,
759: "failed to allocate saprop.\n");
760: return NULL;
761: }
762: newpp->prop_no = p0->prop->p_no;
763: /* lifetime & lifebyte must be updated later */
764:
765: for (p = p0; p; p = p->next) {
766:
767: /* allocate ipsec sa protocol */
768: newpr = newsaproto();
769: if (newpr == NULL) {
770: plog(LLV_ERROR, LOCATION, NULL,
771: "failed to allocate saproto.\n");
772: goto err;
773: }
774:
775: /* check spi size */
776: /* XXX should be handled isakmp cookie */
777: if (sizeof(newpr->spi) < p->prop->spi_size) {
778: plog(LLV_ERROR, LOCATION, NULL,
779: "invalid spi size %d.\n", p->prop->spi_size);
780: racoon_free(newpr);
781: goto err;
782: }
783:
784: /*
785: * XXX SPI bits are left-filled, for use with IPComp.
786: * we should be switching to variable-length spi field...
787: */
788: newpr->proto_id = p->prop->proto_id;
789: newpr->spisize = p->prop->spi_size;
790: memset(&newpr->spi, 0, sizeof(newpr->spi));
791: spi = (u_int8_t *)&newpr->spi;
792: spi += sizeof(newpr->spi);
793: spi -= p->prop->spi_size;
794: memcpy(spi, p->prop + 1, p->prop->spi_size);
795: newpr->reqid_in = 0;
796: newpr->reqid_out = 0;
797:
798: for (t = p; t; t = t->tnext) {
799:
800: plog(LLV_DEBUG, LOCATION, NULL,
801: "prop#=%d prot-id=%s spi-size=%d "
802: "#trns=%d trns#=%d trns-id=%s\n",
803: t->prop->p_no,
804: s_ipsecdoi_proto(t->prop->proto_id),
805: t->prop->spi_size, t->prop->num_t,
806: t->trns->t_no,
807: s_ipsecdoi_trns(t->prop->proto_id,
808: t->trns->t_id));
809:
810: /* allocate ipsec sa transform */
811: newtr = newsatrns();
812: if (newtr == NULL) {
813: plog(LLV_ERROR, LOCATION, NULL,
814: "failed to allocate satrns.\n");
815: racoon_free(newpr);
816: goto err;
817: }
818:
819: if (ipsecdoi_t2satrns(t->trns,
820: newpp, newpr, newtr) < 0) {
821: flushsaprop(newpp);
822: racoon_free(newtr);
823: racoon_free(newpr);
824: return NULL;
825: }
826:
827: inssatrns(newpr, newtr);
828: }
829:
830: /*
831: * If the peer does not specify encryption mode, use
832: * transport mode by default. This is to conform to
833: * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
834: * that unspecified == transport), as well as RFC2407
835: * (unspecified == implementation dependent default).
836: */
837: if (newpr->encmode == 0)
838: newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
839:
840: inssaproto(newpp, newpr);
841: }
842:
843: return newpp;
844:
845: err:
846: flushsaprop(newpp);
847: return NULL;
848: }
849:
850: void
851: flushsaprop(head)
852: struct saprop *head;
853: {
854: struct saprop *p, *save;
855:
856: for (p = head; p != NULL; p = save) {
857: save = p->next;
858: flushsaproto(p->head);
859: racoon_free(p);
860: }
861:
862: return;
863: }
864:
865: void
866: flushsaproto(head)
867: struct saproto *head;
868: {
869: struct saproto *p, *save;
870:
871: for (p = head; p != NULL; p = save) {
872: save = p->next;
873: flushsatrns(p->head);
874: vfree(p->keymat);
875: vfree(p->keymat_p);
876: racoon_free(p);
877: }
878:
879: return;
880: }
881:
882: void
883: flushsatrns(head)
884: struct satrns *head;
885: {
886: struct satrns *p, *save;
887:
888: for (p = head; p != NULL; p = save) {
889: save = p->next;
890: racoon_free(p);
891: }
892:
893: return;
894: }
895:
896: /*
897: * print multiple proposals
898: */
899: void
900: printsaprop(pri, pp)
901: const int pri;
902: const struct saprop *pp;
903: {
904: const struct saprop *p;
905:
906: if (pp == NULL) {
907: plog(pri, LOCATION, NULL, "(null)");
908: return;
909: }
910:
911: for (p = pp; p; p = p->next) {
912: printsaprop0(pri, p);
913: }
914:
915: return;
916: }
917:
918: /*
919: * print one proposal.
920: */
921: void
922: printsaprop0(pri, pp)
923: int pri;
924: const struct saprop *pp;
925: {
926: const struct saproto *p;
927:
928: if (pp == NULL)
929: return;
930:
931: for (p = pp->head; p; p = p->next) {
932: printsaproto(pri, p);
933: }
934:
935: return;
936: }
937:
938: void
939: printsaproto(pri, pr)
940: const int pri;
941: const struct saproto *pr;
942: {
943: struct satrns *tr;
944:
945: if (pr == NULL)
946: return;
947:
948: plog(pri, LOCATION, NULL,
949: " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
950: "encmode=%s reqid=%d:%d)\n",
951: s_ipsecdoi_proto(pr->proto_id),
952: (int)pr->spisize,
953: (unsigned long)ntohl(pr->spi),
954: (unsigned long)ntohl(pr->spi_p),
955: s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
956: (int)pr->reqid_in, (int)pr->reqid_out);
957:
958: for (tr = pr->head; tr; tr = tr->next) {
959: printsatrns(pri, pr->proto_id, tr);
960: }
961:
962: return;
963: }
964:
965: void
966: printsatrns(pri, proto_id, tr)
967: const int pri;
968: const int proto_id;
969: const struct satrns *tr;
970: {
971: if (tr == NULL)
972: return;
973:
974: switch (proto_id) {
975: case IPSECDOI_PROTO_IPSEC_AH:
976: plog(pri, LOCATION, NULL,
977: " (trns_id=%s authtype=%s)\n",
978: s_ipsecdoi_trns(proto_id, tr->trns_id),
979: s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
980: break;
981: case IPSECDOI_PROTO_IPSEC_ESP:
982: plog(pri, LOCATION, NULL,
983: " (trns_id=%s encklen=%d authtype=%s)\n",
984: s_ipsecdoi_trns(proto_id, tr->trns_id),
985: tr->encklen,
986: s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
987: break;
988: case IPSECDOI_PROTO_IPCOMP:
989: plog(pri, LOCATION, NULL,
990: " (trns_id=%s)\n",
991: s_ipsecdoi_trns(proto_id, tr->trns_id));
992: break;
993: default:
994: plog(pri, LOCATION, NULL,
995: "(unknown proto_id %d)\n", proto_id);
996: }
997:
998: return;
999: }
1000:
1001: void
1002: print_proppair0(pri, p, level)
1003: int pri;
1004: struct prop_pair *p;
1005: int level;
1006: {
1007: char spc[21];
1008:
1009: memset(spc, ' ', sizeof(spc));
1010: spc[sizeof(spc) - 1] = '\0';
1011: if (level < 20) {
1012: spc[level] = '\0';
1013: }
1014:
1015: plog(pri, LOCATION, NULL,
1016: "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
1017: if (p->next)
1018: print_proppair0(pri, p->next, level + 1);
1019: if (p->tnext)
1020: print_proppair0(pri, p->tnext, level + 1);
1021: }
1022:
1023: void
1024: print_proppair(pri, p)
1025: int pri;
1026: struct prop_pair *p;
1027: {
1028: print_proppair0(pri, p, 1);
1029: }
1030:
1031: int
1032: set_proposal_from_policy(iph2, sp_main, sp_sub)
1033: struct ph2handle *iph2;
1034: struct secpolicy *sp_main, *sp_sub;
1035: {
1036: struct saprop *newpp;
1037: struct ipsecrequest *req;
1038: int encmodesv = IPSECDOI_ATTR_ENC_MODE_TRNS; /* use only when complex_bundle */
1039:
1040: newpp = newsaprop();
1041: if (newpp == NULL) {
1042: plog(LLV_ERROR, LOCATION, NULL,
1043: "failed to allocate saprop.\n");
1044: goto err;
1045: }
1046: newpp->prop_no = 1;
1047: newpp->lifetime = iph2->sainfo->lifetime;
1048: newpp->lifebyte = iph2->sainfo->lifebyte;
1049: newpp->pfs_group = iph2->sainfo->pfs_group;
1050:
1051: if (lcconf->complex_bundle)
1052: goto skip1;
1053:
1054: /*
1055: * decide the encryption mode of this SA bundle.
1056: * the mode becomes tunnel mode when there is even one policy
1057: * of tunnel mode in the SPD. otherwise the mode becomes
1058: * transport mode.
1059: */
1060: for (req = sp_main->req; req; req = req->next) {
1061: if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
1062: encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
1063: #ifdef ENABLE_NATT
1064: if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1065: encmodesv += iph2->ph1->natt_options->mode_udp_diff;
1066: #endif
1067: break;
1068: }
1069: }
1070:
1071: skip1:
1072: for (req = sp_main->req; req; req = req->next) {
1073: struct saproto *newpr;
1074: caddr_t paddr = NULL;
1075:
1076: /*
1077: * check if SA bundle ?
1078: * nested SAs negotiation is NOT supported.
1079: * me +--- SA1 ---+ peer1
1080: * me +--- SA2 --------------+ peer2
1081: */
1082: #ifdef __linux__
1083: if (req->saidx.src.ss_family && req->saidx.dst.ss_family) {
1084: #else
1085: if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
1086: #endif
1087: /* check the end of ip addresses of SA */
1088: if (iph2->side == INITIATOR)
1089: paddr = (caddr_t)&req->saidx.dst;
1090: else
1091: paddr = (caddr_t)&req->saidx.src;
1092: }
1093:
1094: /* allocate ipsec sa protocol */
1095: newpr = newsaproto();
1096: if (newpr == NULL) {
1097: plog(LLV_ERROR, LOCATION, NULL,
1098: "failed to allocate saproto.\n");
1099: goto err;
1100: }
1101:
1102: newpr->proto_id = ipproto2doi(req->saidx.proto);
1103: if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1104: newpr->spisize = 2;
1105: else
1106: newpr->spisize = 4;
1107: if (lcconf->complex_bundle) {
1108: newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1109: #ifdef ENABLE_NATT
1110: if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1111: newpr->encmode +=
1112: iph2->ph1->natt_options->mode_udp_diff;
1113: #endif
1114: }
1115: else
1116: newpr->encmode = encmodesv;
1117:
1118: if (iph2->side == INITIATOR)
1119: newpr->reqid_out = req->saidx.reqid;
1120: else
1121: newpr->reqid_in = req->saidx.reqid;
1122:
1123: if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1124: plog(LLV_ERROR, LOCATION, NULL,
1125: "failed to get algorithms.\n");
1126: racoon_free(newpr);
1127: goto err;
1128: }
1129:
1130: /* set new saproto */
1131: inssaprotorev(newpp, newpr);
1132: }
1133:
1134: /* get reqid_in from inbound policy */
1135: if (sp_sub) {
1136: struct saproto *pr;
1137:
1138: req = sp_sub->req;
1139: pr = newpp->head;
1140: while (req && pr) {
1141: if (iph2->side == INITIATOR)
1142: pr->reqid_in = req->saidx.reqid;
1143: else
1144: pr->reqid_out = req->saidx.reqid;
1145: pr = pr->next;
1146: req = req->next;
1147: }
1148: if (pr || req) {
1149: plog(LLV_NOTIFY, LOCATION, NULL,
1150: "There is a difference "
1151: "between the in/out bound policies in SPD.\n");
1152: }
1153: }
1154:
1155: iph2->proposal = newpp;
1156:
1157: printsaprop0(LLV_DEBUG, newpp);
1158:
1159: return 0;
1160: err:
1161: flushsaprop(newpp);
1162: return -1;
1163: }
1164:
1165: /*
1166: * generate a policy from peer's proposal.
1167: * this function unconditionally choices first proposal in SA payload
1168: * passed by peer.
1169: */
1170: int
1171: set_proposal_from_proposal(iph2)
1172: struct ph2handle *iph2;
1173: {
1174: struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1175: struct saproto *newpr = NULL, *pr;
1176: struct prop_pair **pair;
1177: int error = -1;
1178: int i;
1179:
1180: /* get proposal pair */
1181: pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1182: if (pair == NULL)
1183: goto end;
1184:
1185: /*
1186: * make my proposal according as the client proposal.
1187: * XXX assumed there is only one proposal even if it's the SA bundle.
1188: */
1189: for (i = 0; i < MAXPROPPAIRLEN; i++) {
1190: if (pair[i] == NULL)
1191: continue;
1192:
1193: if (pp_peer != NULL)
1194: flushsaprop(pp_peer);
1195:
1196: pp_peer = aproppair2saprop(pair[i]);
1197: if (pp_peer == NULL)
1198: goto end;
1199:
1200: pp0 = newsaprop();
1201: if (pp0 == NULL) {
1202: plog(LLV_ERROR, LOCATION, NULL,
1203: "failed to allocate saprop.\n");
1204: goto end;
1205: }
1206: pp0->prop_no = 1;
1207: pp0->lifetime = iph2->sainfo->lifetime;
1208: pp0->lifebyte = iph2->sainfo->lifebyte;
1209: pp0->pfs_group = iph2->sainfo->pfs_group;
1210:
1211: #ifdef HAVE_SECCTX
1212: if (*pp_peer->sctx.ctx_str) {
1213: pp0->sctx.ctx_doi = pp_peer->sctx.ctx_doi;
1214: pp0->sctx.ctx_alg = pp_peer->sctx.ctx_alg;
1215: pp0->sctx.ctx_strlen = pp_peer->sctx.ctx_strlen;
1216: memcpy(pp0->sctx.ctx_str, pp_peer->sctx.ctx_str,
1217: pp_peer->sctx.ctx_strlen);
1218: }
1219: #endif /* HAVE_SECCTX */
1220:
1221: if (pp_peer->next != NULL) {
1222: plog(LLV_ERROR, LOCATION, NULL,
1223: "pp_peer is inconsistency, ignore it.\n");
1224: /*FALLTHROUGH*/
1225: }
1226:
1227: for (pr = pp_peer->head; pr; pr = pr->next)
1228: {
1229: newpr = newsaproto();
1230: if (newpr == NULL)
1231: {
1232: plog(LLV_ERROR, LOCATION, NULL,
1233: "failed to allocate saproto.\n");
1234: racoon_free(pp0);
1235: goto end;
1236: }
1237: newpr->proto_id = pr->proto_id;
1238: newpr->spisize = pr->spisize;
1239: newpr->encmode = pr->encmode;
1240: newpr->spi = 0;
1241: newpr->spi_p = pr->spi; /* copy peer's SPI */
1242: newpr->reqid_in = 0;
1243: newpr->reqid_out = 0;
1244:
1245: if (iph2->ph1->rmconf->gen_policy == GENERATE_POLICY_UNIQUE){
1246: newpr->reqid_in = g_nextreqid ;
1247: newpr->reqid_out = g_nextreqid ++;
1248: /*
1249: * XXX there is a (very limited)
1250: * risk of reusing the same reqid
1251: * as another SP entry for the same peer
1252: */
1253: if(g_nextreqid >= IPSEC_MANUAL_REQID_MAX)
1254: g_nextreqid = 1;
1255: }else{
1256: newpr->reqid_in = 0;
1257: newpr->reqid_out = 0;
1258: }
1259:
1260: if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0)
1261: {
1262: plog(LLV_ERROR, LOCATION, NULL,
1263: "failed to get algorithms.\n");
1264: racoon_free(newpr);
1265: racoon_free(pp0);
1266: goto end;
1267: }
1268: inssaproto(pp0, newpr);
1269: }
1270:
1271: inssaprop(&newpp, pp0);
1272: }
1273:
1274: plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
1275: printsaprop0(LLV_DEBUG, newpp);
1276:
1277: iph2->proposal = newpp;
1278:
1279: error = 0;
1280:
1281: end:
1282: if (error && newpp)
1283: flushsaprop(newpp);
1284:
1285: if (pp_peer)
1286: flushsaprop(pp_peer);
1287: if (pair)
1288: free_proppair(pair);
1289: return error;
1290: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>