]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/proposal.c
ipsec-92.4.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 /*
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 npr1 = npr2 = 0;
315 for (pr1 = pp1->head; pr1; pr1 = pr1->next)
316 npr1++;
317 for (pr2 = pp2->head; pr2; pr2 = pr2->next)
318 npr2++;
319 if (npr1 != npr2)
320 goto err;
321
322 /* check protocol order */
323 pr1 = pp1->head;
324 pr2 = pp2->head;
325
326 while (1) {
327 if (!ordermatters) {
328 /*
329 * XXX does not work if we have multiple proposals
330 * with the same proto_id
331 */
332 switch (side) {
333 case RESPONDER:
334 if (!pr2)
335 break;
336 for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
337 if (pr1->proto_id == pr2->proto_id)
338 break;
339 }
340 break;
341 case INITIATOR:
342 if (!pr1)
343 break;
344 for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
345 if (pr2->proto_id == pr1->proto_id)
346 break;
347 }
348 break;
349 }
350 }
351 if (!pr1 || !pr2)
352 break;
353
354 if (pr1->proto_id != pr2->proto_id) {
355 plog(LLV_ERROR, LOCATION, NULL,
356 "proto_id mismatched: "
357 "my:%s peer:%s\n",
358 s_ipsecdoi_proto(pr2->proto_id),
359 s_ipsecdoi_proto(pr1->proto_id));
360 goto err;
361 }
362 spisizematch = 0;
363 if (pr1->spisize == pr2->spisize)
364 spisizematch = 1;
365 else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
366 /*
367 * draft-shacham-ippcp-rfc2393bis-05.txt:
368 * need to accept 16bit and 32bit SPI (CPI) for IPComp.
369 */
370 if (pr1->spisize == sizeof(u_int16_t) &&
371 pr2->spisize == sizeof(u_int32_t)) {
372 spisizematch = 1;
373 } else if (pr2->spisize == sizeof(u_int16_t) &&
374 pr1->spisize == sizeof(u_int32_t)) {
375 spisizematch = 1;
376 }
377 if (spisizematch) {
378 plog(LLV_ERROR, LOCATION, NULL,
379 "IPComp SPI size promoted "
380 "from 16bit to 32bit\n");
381 }
382 }
383 if (!spisizematch) {
384 plog(LLV_ERROR, LOCATION, NULL,
385 "spisize mismatched: "
386 "my:%d peer:%d\n",
387 (int)pr2->spisize, (int)pr1->spisize);
388 goto err;
389 }
390
391 #ifdef ENABLE_NATT
392 if ((ph1->natt_flags & NAT_DETECTED) &&
393 natt_udp_encap (pr2->encmode))
394 {
395 plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
396 s_ipsecdoi_encmode(pr2->encmode),
397 s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
398 pr2->encmode -= ph1->natt_options->mode_udp_diff;
399 pr2->udp_encap = 1;
400 }
401
402 if ((ph1->natt_flags & NAT_DETECTED) &&
403 natt_udp_encap (pr1->encmode))
404 {
405 plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
406 s_ipsecdoi_encmode(pr1->encmode),
407 pr1->encmode,
408 s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
409 pr1->encmode - ph1->natt_options->mode_udp_diff);
410 pr1->encmode -= ph1->natt_options->mode_udp_diff;
411 pr1->udp_encap = 1;
412 }
413 #endif
414
415 if (pr1->encmode != pr2->encmode) {
416 plog(LLV_ERROR, LOCATION, NULL,
417 "encmode mismatched: "
418 "my:%s peer:%s\n",
419 s_ipsecdoi_encmode(pr2->encmode),
420 s_ipsecdoi_encmode(pr1->encmode));
421 goto err;
422 }
423
424 for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
425 for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
426 if (cmpsatrns(pr1->proto_id, tr1, tr2) == 0)
427 goto found;
428 }
429 }
430
431 goto err;
432
433 found:
434 newpr = newsaproto();
435 if (newpr == NULL) {
436 plog(LLV_ERROR, LOCATION, NULL,
437 "failed to allocate saproto.\n");
438 goto err;
439 }
440 newpr->proto_id = pr1->proto_id;
441 newpr->spisize = pr1->spisize;
442 newpr->encmode = pr1->encmode;
443 newpr->spi = pr2->spi; /* copy my SPI */
444 newpr->spi_p = pr1->spi; /* copy peer's SPI */
445 newpr->reqid_in = pr2->reqid_in;
446 newpr->reqid_out = pr2->reqid_out;
447 #ifdef ENABLE_NATT
448 newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
449 #endif
450
451 newtr = newsatrns();
452 if (newtr == NULL) {
453 plog(LLV_ERROR, LOCATION, NULL,
454 "failed to allocate satrns.\n");
455 racoon_free(newpr);
456 goto err;
457 }
458 newtr->trns_no = tr1->trns_no;
459 newtr->trns_id = tr1->trns_id;
460 newtr->encklen = tr1->encklen;
461 newtr->authtype = tr1->authtype;
462
463 inssatrns(newpr, newtr);
464 inssaproto(newpp, newpr);
465
466 pr1 = pr1->next;
467 pr2 = pr2->next;
468 }
469
470 /* XXX should check if we have visited all items or not */
471 if (!ordermatters) {
472 switch (side) {
473 case RESPONDER:
474 if (!pr2)
475 pr1 = NULL;
476 break;
477 case INITIATOR:
478 if (!pr1)
479 pr2 = NULL;
480 break;
481 }
482 }
483
484 /* should be matched all protocols in a proposal */
485 if (pr1 != NULL || pr2 != NULL)
486 goto err;
487
488 return newpp;
489
490 err:
491 flushsaprop(newpp);
492 return NULL;
493 }
494
495 /* take a single match between saprop. returns 0 if pp1 equals to pp2. */
496 int
497 cmpsaprop(pp1, pp2)
498 const struct saprop *pp1, *pp2;
499 {
500 if (pp1->pfs_group != pp2->pfs_group) {
501 plog(LLV_WARNING, LOCATION, NULL,
502 "pfs_group mismatch. mine:%d peer:%d\n",
503 pp1->pfs_group, pp2->pfs_group);
504 /* FALLTHRU */
505 }
506
507 if (pp1->lifetime > pp2->lifetime) {
508 plog(LLV_WARNING, LOCATION, NULL,
509 "less lifetime proposed. mine:%d peer:%d\n",
510 (int)pp1->lifetime, (int)pp2->lifetime);
511 /* FALLTHRU */
512 }
513 if (pp1->lifebyte > pp2->lifebyte) {
514 plog(LLV_WARNING, LOCATION, NULL,
515 "less lifebyte proposed. mine:%d peer:%d\n",
516 pp1->lifebyte, pp2->lifebyte);
517 /* FALLTHRU */
518 }
519
520 return 0;
521 }
522
523 /*
524 * take a single match between satrns. returns 0 if tr1 equals to tr2.
525 * tr1: peer's satrns
526 * tr2: my satrns
527 */
528 int
529 cmpsatrns(proto_id, tr1, tr2)
530 int proto_id;
531 const struct satrns *tr1, *tr2;
532 {
533 if (tr1->trns_id != tr2->trns_id) {
534 plog(LLV_WARNING, LOCATION, NULL,
535 "trns_id mismatched: "
536 "my:%s peer:%s\n",
537 s_ipsecdoi_trns(proto_id, tr2->trns_id),
538 s_ipsecdoi_trns(proto_id, tr1->trns_id));
539 return 1;
540 }
541
542 if (tr1->authtype != tr2->authtype) {
543 plog(LLV_WARNING, LOCATION, NULL,
544 "authtype mismatched: "
545 "my:%s peer:%s\n",
546 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
547 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
548 return 1;
549 }
550
551 /* XXX
552 * At this moment for interoperability, the responder obey
553 * the initiator. It should be defined a notify message.
554 */
555 if (tr1->encklen > tr2->encklen) {
556 plog(LLV_WARNING, LOCATION, NULL,
557 "less key length proposed, "
558 "mine:%d peer:%d. Use initiaotr's one.\n",
559 tr2->encklen, tr1->encklen);
560 /* FALLTHRU */
561 }
562
563 return 0;
564 }
565
566 int
567 set_satrnsbysainfo(pr, sainfo)
568 struct saproto *pr;
569 struct sainfo *sainfo;
570 {
571 struct sainfoalg *a, *b;
572 struct satrns *newtr;
573 int t;
574
575 switch (pr->proto_id) {
576 case IPSECDOI_PROTO_IPSEC_AH:
577 if (sainfo->algs[algclass_ipsec_auth] == NULL) {
578 plog(LLV_ERROR, LOCATION, NULL,
579 "no auth algorithm found\n");
580 goto err;
581 }
582 t = 1;
583 for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
584
585 if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
586 continue;
587
588 /* allocate satrns */
589 newtr = newsatrns();
590 if (newtr == NULL) {
591 plog(LLV_ERROR, LOCATION, NULL,
592 "failed to allocate satrns.\n");
593 goto err;
594 }
595
596 newtr->trns_no = t++;
597 newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
598 newtr->authtype = a->alg;
599
600 inssatrns(pr, newtr);
601 }
602 break;
603 case IPSECDOI_PROTO_IPSEC_ESP:
604 if (sainfo->algs[algclass_ipsec_enc] == NULL) {
605 plog(LLV_ERROR, LOCATION, NULL,
606 "no encryption algorithm found\n");
607 goto err;
608 }
609 t = 1;
610 for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
611 for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
612 /* allocate satrns */
613 newtr = newsatrns();
614 if (newtr == NULL) {
615 plog(LLV_ERROR, LOCATION, NULL,
616 "failed to allocate satrns.\n");
617 goto err;
618 }
619
620 newtr->trns_no = t++;
621 newtr->trns_id = a->alg;
622 newtr->encklen = a->encklen;
623 newtr->authtype = b->alg;
624
625 inssatrns(pr, newtr);
626 }
627 }
628 break;
629 case IPSECDOI_PROTO_IPCOMP:
630 if (sainfo->algs[algclass_ipsec_comp] == NULL) {
631 plog(LLV_ERROR, LOCATION, NULL,
632 "no ipcomp algorithm found\n");
633 goto err;
634 }
635 t = 1;
636 for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
637
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->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
649
650 inssatrns(pr, newtr);
651 }
652 break;
653 default:
654 plog(LLV_ERROR, LOCATION, NULL,
655 "unknown proto_id (%d).\n", pr->proto_id);
656 goto err;
657 }
658
659 /* no proposal found */
660 if (pr->head == NULL) {
661 plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
662 return -1;
663 }
664
665 return 0;
666
667 err:
668 flushsatrns(pr->head);
669 return -1;
670 }
671
672 struct saprop *
673 aproppair2saprop(p0)
674 struct prop_pair *p0;
675 {
676 struct prop_pair *p, *t;
677 struct saprop *newpp;
678 struct saproto *newpr;
679 struct satrns *newtr;
680 u_int8_t *spi;
681
682 if (p0 == NULL)
683 return NULL;
684
685 /* allocate ipsec a sa proposal */
686 newpp = newsaprop();
687 if (newpp == NULL) {
688 plog(LLV_ERROR, LOCATION, NULL,
689 "failed to allocate saprop.\n");
690 return NULL;
691 }
692 newpp->prop_no = p0->prop->p_no;
693 /* lifetime & lifebyte must be updated later */
694
695 for (p = p0; p; p = p->next) {
696
697 /* allocate ipsec sa protocol */
698 newpr = newsaproto();
699 if (newpr == NULL) {
700 plog(LLV_ERROR, LOCATION, NULL,
701 "failed to allocate saproto.\n");
702 goto err;
703 }
704
705 /* check spi size */
706 /* XXX should be handled isakmp cookie */
707 if (sizeof(newpr->spi) < p->prop->spi_size) {
708 plog(LLV_ERROR, LOCATION, NULL,
709 "invalid spi size %d.\n", p->prop->spi_size);
710 racoon_free(newpr);
711 goto err;
712 }
713
714 /*
715 * XXX SPI bits are left-filled, for use with IPComp.
716 * we should be switching to variable-length spi field...
717 */
718 newpr->proto_id = p->prop->proto_id;
719 newpr->spisize = p->prop->spi_size;
720 memset(&newpr->spi, 0, sizeof(newpr->spi));
721 spi = (u_int8_t *)&newpr->spi;
722 spi += sizeof(newpr->spi);
723 spi -= p->prop->spi_size;
724 memcpy(spi, p->prop + 1, p->prop->spi_size);
725 newpr->reqid_in = 0;
726 newpr->reqid_out = 0;
727
728 for (t = p; t; t = t->tnext) {
729
730 plog(LLV_DEBUG, LOCATION, NULL,
731 "prop#=%d prot-id=%s spi-size=%d "
732 "#trns=%d trns#=%d trns-id=%s\n",
733 t->prop->p_no,
734 s_ipsecdoi_proto(t->prop->proto_id),
735 t->prop->spi_size, t->prop->num_t,
736 t->trns->t_no,
737 s_ipsecdoi_trns(t->prop->proto_id,
738 t->trns->t_id));
739
740 /* allocate ipsec sa transform */
741 newtr = newsatrns();
742 if (newtr == NULL) {
743 plog(LLV_ERROR, LOCATION, NULL,
744 "failed to allocate satrns.\n");
745 racoon_free(newpr);
746 goto err;
747 }
748
749 if (ipsecdoi_t2satrns(t->trns,
750 newpp, newpr, newtr) < 0) {
751 flushsaprop(newpp);
752 racoon_free(newtr);
753 racoon_free(newpr);
754 return NULL;
755 }
756
757 inssatrns(newpr, newtr);
758 }
759
760 /*
761 * If the peer does not specify encryption mode, use
762 * transport mode by default. This is to conform to
763 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
764 * that unspecified == transport), as well as RFC2407
765 * (unspecified == implementation dependent default).
766 */
767 if (newpr->encmode == 0)
768 newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
769
770 inssaproto(newpp, newpr);
771 }
772
773 return newpp;
774
775 err:
776 flushsaprop(newpp);
777 return NULL;
778 }
779
780 void
781 flushsaprop(head)
782 struct saprop *head;
783 {
784 struct saprop *p, *save;
785
786 for (p = head; p != NULL; p = save) {
787 save = p->next;
788 flushsaproto(p->head);
789 racoon_free(p);
790 }
791
792 return;
793 }
794
795 void
796 flushsaproto(head)
797 struct saproto *head;
798 {
799 struct saproto *p, *save;
800
801 for (p = head; p != NULL; p = save) {
802 save = p->next;
803 flushsatrns(p->head);
804 vfree(p->keymat);
805 vfree(p->keymat_p);
806 racoon_free(p);
807 }
808
809 return;
810 }
811
812 void
813 flushsatrns(head)
814 struct satrns *head;
815 {
816 struct satrns *p, *save;
817
818 for (p = head; p != NULL; p = save) {
819 save = p->next;
820 racoon_free(p);
821 }
822
823 return;
824 }
825
826 /*
827 * print multiple proposals
828 */
829 void
830 printsaprop(pri, pp)
831 const int pri;
832 const struct saprop *pp;
833 {
834 const struct saprop *p;
835
836 if (pp == NULL) {
837 plog(pri, LOCATION, NULL, "(null)");
838 return;
839 }
840
841 for (p = pp; p; p = p->next) {
842 printsaprop0(pri, p);
843 }
844
845 return;
846 }
847
848 /*
849 * print one proposal.
850 */
851 void
852 printsaprop0(pri, pp)
853 int pri;
854 const struct saprop *pp;
855 {
856 const struct saproto *p;
857
858 if (pp == NULL)
859 return;
860
861 for (p = pp->head; p; p = p->next) {
862 printsaproto(pri, p);
863 }
864
865 return;
866 }
867
868 void
869 printsaproto(pri, pr)
870 const int pri;
871 const struct saproto *pr;
872 {
873 struct satrns *tr;
874
875 if (pr == NULL)
876 return;
877
878 plog(pri, LOCATION, NULL,
879 " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
880 "encmode=%s reqid=%d:%d)\n",
881 s_ipsecdoi_proto(pr->proto_id),
882 (int)pr->spisize,
883 (unsigned long)ntohl(pr->spi),
884 (unsigned long)ntohl(pr->spi_p),
885 s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
886 (int)pr->reqid_in, (int)pr->reqid_out);
887
888 for (tr = pr->head; tr; tr = tr->next) {
889 printsatrns(pri, pr->proto_id, tr);
890 }
891
892 return;
893 }
894
895 void
896 printsatrns(pri, proto_id, tr)
897 const int pri;
898 const int proto_id;
899 const struct satrns *tr;
900 {
901 if (tr == NULL)
902 return;
903
904 switch (proto_id) {
905 case IPSECDOI_PROTO_IPSEC_AH:
906 plog(pri, LOCATION, NULL,
907 " (trns_id=%s authtype=%s)\n",
908 s_ipsecdoi_trns(proto_id, tr->trns_id),
909 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
910 break;
911 case IPSECDOI_PROTO_IPSEC_ESP:
912 plog(pri, LOCATION, NULL,
913 " (trns_id=%s encklen=%d authtype=%s)\n",
914 s_ipsecdoi_trns(proto_id, tr->trns_id),
915 tr->encklen,
916 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
917 break;
918 case IPSECDOI_PROTO_IPCOMP:
919 plog(pri, LOCATION, NULL,
920 " (trns_id=%s)\n",
921 s_ipsecdoi_trns(proto_id, tr->trns_id));
922 break;
923 default:
924 plog(pri, LOCATION, NULL,
925 "(unknown proto_id %d)\n", proto_id);
926 }
927
928 return;
929 }
930
931 void
932 print_proppair0(pri, p, level)
933 int pri;
934 struct prop_pair *p;
935 int level;
936 {
937 char spc[21];
938
939 memset(spc, ' ', sizeof(spc));
940 spc[sizeof(spc) - 1] = '\0';
941 if (level < 20) {
942 spc[level] = '\0';
943 }
944
945 plog(pri, LOCATION, NULL,
946 "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
947 if (p->next)
948 print_proppair0(pri, p->next, level + 1);
949 if (p->tnext)
950 print_proppair0(pri, p->tnext, level + 1);
951 }
952
953 void
954 print_proppair(pri, p)
955 int pri;
956 struct prop_pair *p;
957 {
958 print_proppair0(pri, p, 1);
959 }
960
961 int
962 set_proposal_from_policy(iph2, sp_main, sp_sub)
963 struct ph2handle *iph2;
964 struct secpolicy *sp_main, *sp_sub;
965 {
966 struct saprop *newpp;
967 struct ipsecrequest *req;
968 int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */
969
970 newpp = newsaprop();
971 if (newpp == NULL) {
972 plog(LLV_ERROR, LOCATION, NULL,
973 "failed to allocate saprop.\n");
974 goto err;
975 }
976 newpp->prop_no = 1;
977 newpp->lifetime = iph2->sainfo->lifetime;
978 newpp->lifebyte = iph2->sainfo->lifebyte;
979 newpp->pfs_group = iph2->sainfo->pfs_group;
980
981 if (lcconf->complex_bundle)
982 goto skip1;
983
984 /*
985 * decide the encryption mode of this SA bundle.
986 * the mode becomes tunnel mode when there is even one policy
987 * of tunnel mode in the SPD. otherwise the mode becomes
988 * transport mode.
989 */
990 encmodesv = IPSEC_MODE_TRANSPORT;
991 for (req = sp_main->req; req; req = req->next) {
992 if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
993 encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
994 #ifdef ENABLE_NATT
995 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
996 encmodesv += iph2->ph1->natt_options->mode_udp_diff;
997 #endif
998 break;
999 }
1000 }
1001
1002 skip1:
1003 for (req = sp_main->req; req; req = req->next) {
1004 struct saproto *newpr;
1005 caddr_t paddr = NULL;
1006
1007 /*
1008 * check if SA bundle ?
1009 * nested SAs negotiation is NOT supported.
1010 * me +--- SA1 ---+ peer1
1011 * me +--- SA2 --------------+ peer2
1012 */
1013 #ifdef __linux__
1014 if (req->saidx.src.ss_family && req->saidx.dst.ss_family) {
1015 #else
1016 if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
1017 #endif
1018 /* check the end of ip addresses of SA */
1019 if (iph2->side == INITIATOR)
1020 paddr = (caddr_t)&req->saidx.dst;
1021 else
1022 paddr = (caddr_t)&req->saidx.src;
1023 }
1024
1025 /* allocate ipsec sa protocol */
1026 newpr = newsaproto();
1027 if (newpr == NULL) {
1028 plog(LLV_ERROR, LOCATION, NULL,
1029 "failed to allocate saproto.\n");
1030 goto err;
1031 }
1032
1033 newpr->proto_id = ipproto2doi(req->saidx.proto);
1034 if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1035 newpr->spisize = 2;
1036 else
1037 newpr->spisize = 4;
1038 if (lcconf->complex_bundle) {
1039 newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1040 #ifdef ENABLE_NATT
1041 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1042 newpr->encmode += iph2->ph1->natt_options->mode_udp_diff;
1043 #endif
1044 }
1045 else
1046 newpr->encmode = encmodesv;
1047
1048 if (iph2->side == INITIATOR)
1049 newpr->reqid_out = req->saidx.reqid;
1050 else
1051 newpr->reqid_in = req->saidx.reqid;
1052
1053 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1054 plog(LLV_ERROR, LOCATION, NULL,
1055 "failed to get algorithms.\n");
1056 racoon_free(newpr);
1057 goto err;
1058 }
1059
1060 /* set new saproto */
1061 inssaprotorev(newpp, newpr);
1062 }
1063
1064 /* get reqid_in from inbound policy */
1065 if (sp_sub) {
1066 struct saproto *pr;
1067
1068 req = sp_sub->req;
1069 pr = newpp->head;
1070 while (req && pr) {
1071 if (iph2->side == INITIATOR)
1072 pr->reqid_in = req->saidx.reqid;
1073 else
1074 pr->reqid_out = req->saidx.reqid;
1075 pr = pr->next;
1076 req = req->next;
1077 }
1078 if (pr || req) {
1079 plog(LLV_NOTIFY, LOCATION, NULL,
1080 "There is a difference "
1081 "between the in/out bound policies in SPD.\n");
1082 }
1083 }
1084
1085 iph2->proposal = newpp;
1086
1087 ike_session_update_mode(iph2);
1088
1089 printsaprop0(LLV_DEBUG, newpp);
1090
1091 return 0;
1092 err:
1093 if (newpp)
1094 flushsaprop(newpp);
1095 return -1;
1096 }
1097
1098 /*
1099 * generate a policy from peer's proposal.
1100 * this function unconditionally chooses the first proposal the in SA payload
1101 * passed by peer.
1102 */
1103 int
1104 set_proposal_from_proposal(iph2)
1105 struct ph2handle *iph2;
1106 {
1107 struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1108 struct saproto *newpr = NULL, *pr;
1109 struct prop_pair **pair;
1110 int error = -1;
1111 int i;
1112
1113 /* get proposal pair */
1114 pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1115 if (pair == NULL)
1116 goto end;
1117
1118 /*
1119 * make my proposal according as the client proposal.
1120 * XXX assumed there is only one proposal even if it's the SA bundle.
1121 */
1122 for (i = 0; i < MAXPROPPAIRLEN; i++) {
1123 if (pair[i] == NULL)
1124 continue;
1125
1126 if (pp_peer != NULL)
1127 flushsaprop(pp_peer);
1128
1129 pp_peer = aproppair2saprop(pair[i]);
1130 if (pp_peer == NULL)
1131 goto end;
1132
1133 pp0 = newsaprop();
1134 if (pp0 == NULL) {
1135 plog(LLV_ERROR, LOCATION, NULL,
1136 "failed to allocate saprop.\n");
1137 goto end;
1138 }
1139 pp0->prop_no = 1;
1140 pp0->lifetime = iph2->sainfo->lifetime;
1141 pp0->lifebyte = iph2->sainfo->lifebyte;
1142 pp0->pfs_group = iph2->sainfo->pfs_group;
1143
1144 if (pp_peer->next != NULL) {
1145 plog(LLV_ERROR, LOCATION, NULL,
1146 "pp_peer is inconsistency, ignore it.\n");
1147 /*FALLTHROUGH*/
1148 }
1149
1150 for (pr = pp_peer->head; pr; pr = pr->next) {
1151
1152 newpr = newsaproto();
1153 if (newpr == NULL) {
1154 plog(LLV_ERROR, LOCATION, NULL,
1155 "failed to allocate saproto.\n");
1156 racoon_free(pp0);
1157 goto end;
1158 }
1159 newpr->proto_id = pr->proto_id;
1160 newpr->spisize = pr->spisize;
1161 newpr->encmode = pr->encmode;
1162 newpr->spi = 0;
1163 newpr->spi_p = pr->spi; /* copy peer's SPI */
1164 newpr->reqid_in = 0;
1165 newpr->reqid_out = 0;
1166
1167 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1168 plog(LLV_ERROR, LOCATION, NULL,
1169 "failed to get algorithms.\n");
1170 racoon_free(newpr);
1171 racoon_free(pp0);
1172 goto end;
1173 }
1174 inssaproto(pp0, newpr);
1175 }
1176
1177 inssaprop(&newpp, pp0);
1178 }
1179
1180 plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
1181 printsaprop0(LLV_DEBUG, newpp);
1182
1183 iph2->proposal = newpp;
1184
1185 ike_session_update_mode(iph2);
1186
1187 error = 0;
1188
1189 end:
1190 if (error && newpp)
1191 flushsaprop(newpp);
1192
1193 if (pp_peer)
1194 flushsaprop(pp_peer);
1195 if (pair)
1196 free_proppair(pair);
1197 return error;
1198 }
1199
1200 int
1201 tunnel_mode_prop(p)
1202 struct saprop *p;
1203 {
1204 struct saproto *pr;
1205
1206 for (pr = p->head; pr; pr = pr->next)
1207 if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL)
1208 return 1;
1209 return 0;
1210 }