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