]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/proposal.c
ipsec-258.90.2.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 #include "ikev2_rfc.h"
76
77 /* %%%
78 * modules for ipsec sa spec
79 */
80 struct saprop *
81 newsaprop()
82 {
83 struct saprop *new;
84
85 new = racoon_calloc(1, sizeof(*new));
86 if (new == NULL)
87 return NULL;
88
89 return new;
90 }
91
92 struct saproto *
93 newsaproto()
94 {
95 struct saproto *new;
96
97 new = racoon_calloc(1, sizeof(*new));
98 if (new == NULL)
99 return NULL;
100
101 return new;
102 }
103
104 /* set saprop to last part of the prop tree */
105 void
106 inssaprop(head, new)
107 struct saprop **head;
108 struct saprop *new;
109 {
110 struct saprop *p;
111
112 if (*head == NULL) {
113 *head = new;
114 return;
115 }
116
117 for (p = *head; p->next; p = p->next)
118 ;
119 p->next = new;
120
121 return;
122 }
123
124 /* set saproto to the end of the proto tree in saprop */
125 void
126 inssaproto(pp, new)
127 struct saprop *pp;
128 struct saproto *new;
129 {
130 struct saproto *p;
131
132 for (p = pp->head; p && p->next; p = p->next)
133 ;
134 if (p == NULL)
135 pp->head = new;
136 else
137 p->next = new;
138
139 return;
140 }
141
142 /* set saproto to the top of the proto tree in saprop */
143 void
144 inssaprotorev(pp, new)
145 struct saprop *pp;
146 struct saproto *new;
147 {
148 new->next = pp->head;
149 pp->head = new;
150
151 return;
152 }
153
154 struct satrns *
155 newsatrns()
156 {
157 struct satrns *new;
158
159 new = racoon_calloc(1, sizeof(*new));
160 if (new == NULL)
161 return NULL;
162
163 return new;
164 }
165
166 /* set saproto to last part of the proto tree in saprop */
167 void
168 inssatrns(pr, new)
169 struct saproto *pr;
170 struct satrns *new;
171 {
172 struct satrns *tr;
173
174 for (tr = pr->head; tr && tr->next; tr = tr->next)
175 ;
176 if (tr == NULL)
177 pr->head = new;
178 else
179 tr->next = new;
180
181 return;
182 }
183
184 int
185 satrns_remove_from_list(struct satrns **listptr, struct satrns *trns)
186 {
187
188 struct satrns **ptr = listptr;
189
190 if (ptr == NULL)
191 return -1;
192
193 while (*ptr) {
194 if (*ptr == trns) {
195 *ptr = trns->next;
196 ptr = &trns->next;
197 trns->next = NULL;
198 return 0;
199 }
200 ptr = &((*ptr)->next);
201 }
202 return -1;
203 }
204
205 #ifdef ENABLE_NATT
206 static void
207 saprop_udp_encap (struct saproto *pr)
208 {
209 switch (pr->encmode) {
210 case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
211 case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
212 pr->encmode = IPSECDOI_ATTR_ENC_MODE_TUNNEL;
213 pr->udp_encap = 1;
214 break;
215 case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
216 case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
217 pr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
218 pr->udp_encap = 1;
219 break;
220 }
221 }
222
223 static void
224 saprop_adjust_encmode (struct saproto *pr2, struct saproto *pr1)
225 {
226 int prev;
227
228 if (natt_udp_encap(pr2->encmode)) {
229 prev = pr2->encmode;
230 saprop_udp_encap(pr2);
231 plog(ASL_LEVEL_INFO, "Adjusting my encmode %s(%d)->%s(%d)\n",
232 s_ipsecdoi_encmode(prev),
233 prev,
234 s_ipsecdoi_encmode(pr2->encmode),
235 pr2->encmode);
236 }
237 if (natt_udp_encap(pr1->encmode)) {
238 prev = pr1->encmode;
239 saprop_udp_encap(pr1);
240 plog(ASL_LEVEL_INFO, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
241 s_ipsecdoi_encmode(prev),
242 prev,
243 s_ipsecdoi_encmode(pr1->encmode),
244 pr1->encmode);
245 }
246 }
247 #endif // ENABLE_NATT
248
249 /*
250 * take a single match between saprop. allocate a new proposal and return it
251 * for future use (like picking single proposal from a bundle).
252 * pp1: peer's proposal.
253 * pp2: my proposal.
254 * NOTE: In the case of initiator, must be ensured that there is no
255 * modification of the proposal by calling cmp_aproppair_i() before
256 * this function.
257 * XXX cannot understand the comment!
258 */
259 struct saprop *
260 cmpsaprop_alloc(ph1, pp1, pp2, side)
261 phase1_handle_t *ph1;
262 const struct saprop *pp1, *pp2;
263 int side;
264 {
265 struct saprop *newpp = NULL;
266 struct saproto *pr1, *pr2, *newpr = NULL;
267 struct satrns *tr1, *tr2, *newtr;
268 const int ordermatters = 0;
269 int npr1, npr2;
270 int spisizematch;
271
272 newpp = newsaprop();
273 if (newpp == NULL) {
274 plog(ASL_LEVEL_ERR,
275 "failed to allocate saprop.\n");
276 return NULL;
277 }
278 newpp->prop_no = pp1->prop_no;
279
280 /* see proposal.h about lifetime/key length and PFS selection. */
281
282 /* check time/bytes lifetime and PFS */
283 switch (ph1->rmconf->pcheck_level) {
284 case PROP_CHECK_OBEY:
285 newpp->lifetime = pp1->lifetime;
286 newpp->lifebyte = pp1->lifebyte;
287 newpp->pfs_group = pp1->pfs_group;
288 break;
289
290 case PROP_CHECK_STRICT:
291 if (pp1->lifetime > pp2->lifetime) {
292 plog(ASL_LEVEL_ERR,
293 "long lifetime proposed: "
294 "my:%d peer:%d\n",
295 (int)pp2->lifetime, (int)pp1->lifetime);
296 goto err;
297 }
298 if (pp1->lifebyte > pp2->lifebyte) {
299 plog(ASL_LEVEL_ERR,
300 "long lifebyte proposed: "
301 "my:%d peer:%d\n",
302 pp2->lifebyte, pp1->lifebyte);
303 goto err;
304 }
305 newpp->lifetime = pp1->lifetime;
306 newpp->lifebyte = pp1->lifebyte;
307
308 prop_pfs_check:
309 if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) {
310 plog(ASL_LEVEL_ERR,
311 "pfs group mismatched: "
312 "my:%d peer:%d\n",
313 pp2->pfs_group, pp1->pfs_group);
314 goto err;
315 }
316 newpp->pfs_group = pp1->pfs_group;
317 break;
318
319 case PROP_CHECK_CLAIM:
320 /* lifetime */
321 if (pp1->lifetime <= pp2->lifetime) {
322 newpp->lifetime = pp1->lifetime;
323 } else {
324 newpp->lifetime = pp2->lifetime;
325 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
326 plog(ASL_LEVEL_NOTICE,
327 "use own lifetime: "
328 "my:%d peer:%d\n",
329 (int)pp2->lifetime, (int)pp1->lifetime);
330 }
331
332 /* lifebyte */
333 if (pp1->lifebyte > pp2->lifebyte) {
334 newpp->lifebyte = pp2->lifebyte;
335 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
336 plog(ASL_LEVEL_NOTICE,
337 "use own lifebyte: "
338 "my:%d peer:%d\n",
339 pp2->lifebyte, pp1->lifebyte);
340 }
341 newpp->lifebyte = pp1->lifebyte;
342
343 goto prop_pfs_check;
344 break;
345
346 case PROP_CHECK_EXACT:
347 if (pp1->lifetime != pp2->lifetime) {
348 plog(ASL_LEVEL_ERR,
349 "lifetime mismatched: "
350 "my:%d peer:%d\n",
351 (int)pp2->lifetime, (int)pp1->lifetime);
352 goto err;
353 }
354
355 if (pp1->lifebyte != pp2->lifebyte) {
356 plog(ASL_LEVEL_ERR,
357 "lifebyte mismatched: "
358 "my:%d peer:%d\n",
359 pp2->lifebyte, pp1->lifebyte);
360 goto err;
361 }
362 if (pp1->pfs_group != pp2->pfs_group) {
363 plog(ASL_LEVEL_ERR,
364 "pfs group mismatched: "
365 "my:%d peer:%d\n",
366 pp2->pfs_group, pp1->pfs_group);
367 goto err;
368 }
369 newpp->lifetime = pp1->lifetime;
370 newpp->lifebyte = pp1->lifebyte;
371 newpp->pfs_group = pp1->pfs_group;
372 break;
373
374 default:
375 plog(ASL_LEVEL_ERR,
376 "invalid pcheck_level why?.\n");
377 goto err;
378 }
379
380 npr1 = npr2 = 0;
381 for (pr1 = pp1->head; pr1; pr1 = pr1->next)
382 npr1++;
383 for (pr2 = pp2->head; pr2; pr2 = pr2->next)
384 npr2++;
385 if (npr1 != npr2)
386 goto err;
387
388 /* check protocol order */
389 pr1 = pp1->head;
390 pr2 = pp2->head;
391
392 while (1) {
393 if (!ordermatters) {
394 /*
395 * XXX does not work if we have multiple proposals
396 * with the same proto_id
397 */
398 switch (side) {
399 case RESPONDER:
400 if (!pr2)
401 break;
402 for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
403 if (pr1->proto_id == pr2->proto_id)
404 break;
405 }
406 break;
407 case INITIATOR:
408 if (!pr1)
409 break;
410 for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
411 if (pr2->proto_id == pr1->proto_id)
412 break;
413 }
414 break;
415 }
416 }
417 if (!pr1 || !pr2)
418 break;
419
420 if (pr1->proto_id != pr2->proto_id) {
421 plog(ASL_LEVEL_ERR,
422 "proto_id mismatched: "
423 "my:%s peer:%s\n",
424 s_ipsecdoi_proto(pr2->proto_id),
425 s_ipsecdoi_proto(pr1->proto_id));
426 goto err;
427 }
428 spisizematch = 0;
429 if (pr1->spisize == pr2->spisize)
430 spisizematch = 1;
431 else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
432 /*
433 * draft-shacham-ippcp-rfc2393bis-05.txt:
434 * need to accept 16bit and 32bit SPI (CPI) for IPComp.
435 */
436 if (pr1->spisize == sizeof(u_int16_t) &&
437 pr2->spisize == sizeof(u_int32_t)) {
438 spisizematch = 1;
439 } else if (pr2->spisize == sizeof(u_int16_t) &&
440 pr1->spisize == sizeof(u_int32_t)) {
441 spisizematch = 1;
442 }
443 if (spisizematch) {
444 plog(ASL_LEVEL_ERR,
445 "IPComp SPI size promoted "
446 "from 16bit to 32bit\n");
447 }
448 }
449 if (!spisizematch) {
450 plog(ASL_LEVEL_ERR,
451 "spisize mismatched: "
452 "my:%d peer:%d\n",
453 (int)pr2->spisize, (int)pr1->spisize);
454 goto err;
455 }
456
457 #ifdef ENABLE_NATT
458 if (ph1->natt_flags & NAT_DETECTED) {
459 saprop_adjust_encmode(pr2, pr1);
460 }
461 #endif
462
463 if (pr1->encmode != pr2->encmode) {
464 plog(ASL_LEVEL_ERR,
465 "encmode mismatched: "
466 "my:%s peer:%s\n",
467 s_ipsecdoi_encmode(pr2->encmode),
468 s_ipsecdoi_encmode(pr1->encmode));
469 goto err;
470 }
471
472 for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
473 for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
474 if (cmpsatrns(pr1->proto_id, tr1, tr2) == 0)
475 goto found;
476 }
477 }
478
479 goto err;
480
481 found:
482 newpr = newsaproto();
483 if (newpr == NULL) {
484 plog(ASL_LEVEL_ERR,
485 "failed to allocate saproto.\n");
486 goto err;
487 }
488 newpr->proto_id = pr1->proto_id;
489 newpr->spisize = pr1->spisize;
490 newpr->encmode = pr1->encmode;
491 newpr->spi = pr2->spi; /* copy my SPI */
492 newpr->spi_p = pr1->spi; /* copy peer's SPI */
493 newpr->reqid_in = pr2->reqid_in;
494 newpr->reqid_out = pr2->reqid_out;
495 #ifdef ENABLE_NATT
496 newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
497 #endif
498
499 newtr = newsatrns();
500 if (newtr == NULL) {
501 plog(ASL_LEVEL_ERR,
502 "failed to allocate satrns.\n");
503 racoon_free(newpr);
504 goto err;
505 }
506 newtr->trns_no = tr1->trns_no;
507 newtr->trns_id = tr1->trns_id;
508 newtr->encklen = tr1->encklen;
509 newtr->authtype = tr1->authtype;
510
511 inssatrns(newpr, newtr);
512 inssaproto(newpp, newpr);
513
514 pr1 = pr1->next;
515 pr2 = pr2->next;
516 }
517
518 /* XXX should check if we have visited all items or not */
519 if (!ordermatters) {
520 switch (side) {
521 case RESPONDER:
522 if (!pr2)
523 pr1 = NULL;
524 break;
525 case INITIATOR:
526 if (!pr1)
527 pr2 = NULL;
528 break;
529 }
530 }
531
532 /* should be matched all protocols in a proposal */
533 if (pr1 != NULL || pr2 != NULL)
534 goto err;
535
536 return newpp;
537
538 err:
539 flushsaprop(newpp);
540 return NULL;
541 }
542
543 /* take a single match between saprop. returns 0 if pp1 equals to pp2. */
544 int
545 cmpsaprop(pp1, pp2)
546 const struct saprop *pp1, *pp2;
547 {
548 if (pp1->pfs_group != pp2->pfs_group) {
549 plog(ASL_LEVEL_WARNING,
550 "pfs_group mismatch. mine:%d peer:%d\n",
551 pp1->pfs_group, pp2->pfs_group);
552 /* FALLTHRU */
553 }
554
555 if (pp1->lifetime > pp2->lifetime) {
556 plog(ASL_LEVEL_WARNING,
557 "less lifetime proposed. mine:%d peer:%d\n",
558 (int)pp1->lifetime, (int)pp2->lifetime);
559 /* FALLTHRU */
560 }
561 if (pp1->lifebyte > pp2->lifebyte) {
562 plog(ASL_LEVEL_WARNING,
563 "less lifebyte proposed. mine:%d peer:%d\n",
564 pp1->lifebyte, pp2->lifebyte);
565 /* FALLTHRU */
566 }
567
568 return 0;
569 }
570
571 /*
572 * take a single match between satrns. returns 0 if tr1 equals to tr2.
573 * tr1: peer's satrns
574 * tr2: my satrns
575 */
576 int
577 cmpsatrns(proto_id, tr1, tr2)
578 int proto_id;
579 const struct satrns *tr1, *tr2;
580 {
581 if (tr1->trns_id != tr2->trns_id) {
582 plog(ASL_LEVEL_DEBUG,
583 "trns_id mismatched: "
584 "my:%s peer:%s\n",
585 s_ipsecdoi_trns(proto_id, tr2->trns_id),
586 s_ipsecdoi_trns(proto_id, tr1->trns_id));
587 return 1;
588 }
589
590 if (tr1->authtype != tr2->authtype) {
591 plog(ASL_LEVEL_DEBUG,
592 "authtype mismatched: "
593 "my:%s peer:%s\n",
594 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
595 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
596 return 1;
597 }
598
599 /* XXX
600 * At this moment for interoperability, the responder obey
601 * the initiator. It should be defined a notify message.
602 */
603 if (tr1->encklen > tr2->encklen) {
604 plog(ASL_LEVEL_WARNING,
605 "less key length proposed, "
606 "mine:%d peer:%d. Use initiaotr's one.\n",
607 tr2->encklen, tr1->encklen);
608 /* FALLTHRU */
609 }
610
611 return 0;
612 }
613
614 int
615 set_satrnsbysainfo(struct saproto *pr, struct sainfo *sainfo, u_int8_t ike_version, int pfs_group)
616 {
617 struct sainfoalg *a, *b;
618 struct satrns *newtr;
619 int t;
620
621 switch (pr->proto_id) {
622 case IPSECDOI_PROTO_IPSEC_AH:
623 if (sainfo->algs[algclass_ipsec_auth] == NULL) {
624 plog(ASL_LEVEL_ERR,
625 "no auth algorithm found\n");
626 goto err;
627 }
628 t = 1;
629 for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
630
631 if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
632 continue;
633
634 /* allocate satrns */
635 newtr = newsatrns();
636 if (newtr == NULL) {
637 plog(ASL_LEVEL_ERR,
638 "failed to allocate satrns.\n");
639 goto err;
640 }
641
642 newtr->trns_no = t++;
643 newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg); // IKEv1 only
644 newtr->authtype = a->alg;
645
646 inssatrns(pr, newtr);
647 }
648 break;
649 case IPSECDOI_PROTO_IPSEC_ESP:
650 if (sainfo->algs[algclass_ipsec_enc] == NULL) {
651 plog(ASL_LEVEL_ERR,
652 "no encryption algorithm found\n");
653 goto err;
654 }
655 t = 1;
656 if (ike_version == ISAKMP_VERSION_NUMBER_IKEV1) {
657 for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
658 for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
659 /* allocate satrns */
660 newtr = newsatrns();
661 if (newtr == NULL) {
662 plog(ASL_LEVEL_ERR,
663 "failed to allocate satrns.\n");
664 goto err;
665 }
666
667 newtr->trns_no = t++;
668 newtr->trns_id = a->alg;
669 newtr->encklen = a->encklen;
670 newtr->authtype = b->alg;
671
672 inssatrns(pr, newtr);
673 }
674 }
675 }
676 break;
677 case IPSECDOI_PROTO_IPCOMP:
678 if (sainfo->algs[algclass_ipsec_comp] == NULL) {
679 plog(ASL_LEVEL_ERR,
680 "no ipcomp algorithm found\n");
681 goto err;
682 }
683 t = 1;
684 for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
685
686 /* allocate satrns */
687 newtr = newsatrns();
688 if (newtr == NULL) {
689 plog(ASL_LEVEL_ERR,
690 "failed to allocate satrns.\n");
691 goto err;
692 }
693
694 newtr->trns_no = t++;
695 newtr->trns_id = a->alg;
696 newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
697
698 inssatrns(pr, newtr);
699 }
700 break;
701 default:
702 plog(ASL_LEVEL_ERR,
703 "unknown proto_id (%d).\n", pr->proto_id);
704 goto err;
705 }
706
707 /* no proposal found */
708 if (pr->head == NULL) {
709 plog(ASL_LEVEL_ERR, "no algorithms found.\n");
710 return -1;
711 }
712
713 return 0;
714
715 err:
716 flushsatrns(pr->head);
717 return -1;
718 }
719
720 struct saprop *
721 aproppair2saprop(p0)
722 struct prop_pair *p0;
723 {
724 struct prop_pair *p, *t;
725 struct saprop *newpp;
726 struct saproto *newpr;
727 struct satrns *newtr;
728 u_int8_t *spi;
729
730 if (p0 == NULL)
731 return NULL;
732
733 /* allocate ipsec a sa proposal */
734 newpp = newsaprop();
735 if (newpp == NULL) {
736 plog(ASL_LEVEL_ERR,
737 "failed to allocate saprop.\n");
738 return NULL;
739 }
740 newpp->prop_no = p0->prop->p_no;
741 /* lifetime & lifebyte must be updated later */
742
743 for (p = p0; p; p = p->next) {
744
745 /* allocate ipsec sa protocol */
746 newpr = newsaproto();
747 if (newpr == NULL) {
748 plog(ASL_LEVEL_ERR,
749 "failed to allocate saproto.\n");
750 goto err;
751 }
752
753 /* check spi size */
754 /* XXX should be handled isakmp cookie */
755 if (sizeof(newpr->spi) < p->prop->spi_size) {
756 plog(ASL_LEVEL_ERR,
757 "invalid spi size %d.\n", p->prop->spi_size);
758 racoon_free(newpr);
759 goto err;
760 }
761
762 /*
763 * XXX SPI bits are left-filled, for use with IPComp.
764 * we should be switching to variable-length spi field...
765 */
766 newpr->proto_id = p->prop->proto_id;
767 newpr->spisize = p->prop->spi_size;
768 memset(&newpr->spi, 0, sizeof(newpr->spi));
769 spi = (u_int8_t *)&newpr->spi;
770 spi += sizeof(newpr->spi);
771 spi -= p->prop->spi_size;
772 memcpy(spi, p->prop + 1, p->prop->spi_size);
773 newpr->reqid_in = 0;
774 newpr->reqid_out = 0;
775
776 for (t = p; t; t = t->tnext) {
777
778 plog(ASL_LEVEL_DEBUG,
779 "prop#=%d prot-id=%s spi-size=%d "
780 "#trns=%d trns#=%d trns-id=%s\n",
781 t->prop->p_no,
782 s_ipsecdoi_proto(t->prop->proto_id),
783 t->prop->spi_size, t->prop->num_t,
784 t->trns->t_no,
785 s_ipsecdoi_trns(t->prop->proto_id,
786 t->trns->t_id));
787
788 /* allocate ipsec sa transform */
789 newtr = newsatrns();
790 if (newtr == NULL) {
791 plog(ASL_LEVEL_ERR,
792 "failed to allocate satrns.\n");
793 racoon_free(newpr);
794 goto err;
795 }
796
797 if (ipsecdoi_t2satrns(t->trns,
798 newpp, newpr, newtr) < 0) {
799 flushsaprop(newpp);
800 racoon_free(newtr);
801 racoon_free(newpr);
802 return NULL;
803 }
804
805 inssatrns(newpr, newtr);
806 }
807
808 /*
809 * If the peer does not specify encryption mode, use
810 * transport mode by default. This is to conform to
811 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
812 * that unspecified == transport), as well as RFC2407
813 * (unspecified == implementation dependent default).
814 */
815 if (newpr->encmode == 0)
816 newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
817
818 inssaproto(newpp, newpr);
819 }
820
821 return newpp;
822
823 err:
824 flushsaprop(newpp);
825 return NULL;
826 }
827
828 void
829 flushsaprop(head)
830 struct saprop *head;
831 {
832 struct saprop *p, *save;
833
834 for (p = head; p != NULL; p = save) {
835 save = p->next;
836 flushsaproto(p->head);
837 racoon_free(p);
838 }
839
840 return;
841 }
842
843 void
844 flushsaproto(head)
845 struct saproto *head;
846 {
847 struct saproto *p, *save;
848
849 for (p = head; p != NULL; p = save) {
850 save = p->next;
851 flushsatrns(p->head);
852 vfree(p->keymat);
853 vfree(p->keymat_p);
854 racoon_free(p);
855 }
856
857 return;
858 }
859
860 void
861 flushsatrns(head)
862 struct satrns *head;
863 {
864 struct satrns *p, *save;
865
866 for (p = head; p != NULL; p = save) {
867 save = p->next;
868 racoon_free(p);
869 }
870
871 return;
872 }
873
874 /*
875 * print multiple proposals
876 */
877 void
878 printsaprop(pri, pp)
879 const int pri;
880 const struct saprop *pp;
881 {
882 const struct saprop *p;
883
884 if (pp == NULL) {
885 plog(pri, "(null)");
886 return;
887 }
888
889 for (p = pp; p; p = p->next) {
890 printsaprop0(pri, p);
891 }
892
893 return;
894 }
895
896 /*
897 * print one proposal.
898 */
899 void
900 printsaprop0(pri, pp)
901 int pri;
902 const struct saprop *pp;
903 {
904 const struct saproto *p;
905
906 if (pp == NULL)
907 return;
908
909 for (p = pp->head; p; p = p->next) {
910 printsaproto(pri, p);
911 }
912
913 return;
914 }
915
916 void
917 printsaproto(pri, pr)
918 const int pri;
919 const struct saproto *pr;
920 {
921 struct satrns *tr;
922
923 if (pr == NULL)
924 return;
925
926 plog(pri,
927 " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
928 "encmode=%s reqid=%d:%d)\n",
929 s_ipsecdoi_proto(pr->proto_id),
930 (int)pr->spisize,
931 (unsigned long)ntohl(pr->spi),
932 (unsigned long)ntohl(pr->spi_p),
933 s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
934 (int)pr->reqid_in, (int)pr->reqid_out);
935
936 for (tr = pr->head; tr; tr = tr->next) {
937 printsatrns(pri, pr->proto_id, tr);
938 }
939
940 return;
941 }
942
943 void
944 printsatrns(pri, proto_id, tr)
945 const int pri;
946 const int proto_id;
947 const struct satrns *tr;
948 {
949 if (tr == NULL)
950 return;
951
952 switch (proto_id) {
953 case IPSECDOI_PROTO_IPSEC_AH:
954 plog(pri,
955 " (trns_id=%s authtype=%s)\n",
956 s_ipsecdoi_trns(proto_id, tr->trns_id),
957 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
958 break;
959 case IPSECDOI_PROTO_IPSEC_ESP:
960 plog(pri,
961 " (trns_id=%s encklen=%d authtype=%s)\n",
962 s_ipsecdoi_trns(proto_id, tr->trns_id),
963 tr->encklen,
964 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
965 break;
966 case IPSECDOI_PROTO_IPCOMP:
967 plog(pri,
968 " (trns_id=%s)\n",
969 s_ipsecdoi_trns(proto_id, tr->trns_id));
970 break;
971 default:
972 plog(pri,
973 "(unknown proto_id %d)\n", proto_id);
974 }
975
976 return;
977 }
978
979 void
980 print_proppair0(pri, p, level)
981 int pri;
982 struct prop_pair *p;
983 int level;
984 {
985 char spc[21];
986
987 memset(spc, ' ', sizeof(spc));
988 spc[sizeof(spc) - 1] = '\0';
989 if (level < 20) {
990 spc[level] = '\0';
991 }
992
993 plog(pri,
994 "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
995 if (p->next)
996 print_proppair0(pri, p->next, level + 1);
997 if (p->tnext)
998 print_proppair0(pri, p->tnext, level + 1);
999 }
1000
1001 void
1002 print_proppair(pri, p)
1003 int pri;
1004 struct prop_pair *p;
1005 {
1006 print_proppair0(pri, p, 1);
1007 }
1008
1009 int
1010 set_proposal_from_policy(iph2, sp_main, sp_sub)
1011 phase2_handle_t *iph2;
1012 struct secpolicy *sp_main, *sp_sub;
1013 {
1014 struct saprop *newpp;
1015 struct ipsecrequest *req;
1016 int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */
1017
1018 newpp = newsaprop();
1019 if (newpp == NULL) {
1020 plog(ASL_LEVEL_ERR,
1021 "failed to allocate saprop.\n");
1022 goto err;
1023 }
1024 newpp->prop_no = 1;
1025 newpp->lifetime = iph2->sainfo->lifetime;
1026 newpp->lifebyte = iph2->sainfo->lifebyte;
1027 newpp->pfs_group = iph2->sainfo->pfs_group;
1028
1029 //%%%% to do - verify DH group is OK - tried that here and iphone failed to connect
1030
1031 if (lcconf->complex_bundle)
1032 goto skip1;
1033
1034 /*
1035 * decide the encryption mode of this SA bundle.
1036 * the mode becomes tunnel mode when there is even one policy
1037 * of tunnel mode in the SPD. otherwise the mode becomes
1038 * transport mode.
1039 */
1040 encmodesv = IPSEC_MODE_TRANSPORT;
1041 for (req = sp_main->req; req; req = req->next) {
1042 if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
1043 encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
1044 #ifdef ENABLE_NATT
1045 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1046 encmodesv += iph2->ph1->natt_options->mode_udp_diff;
1047 #endif
1048 break;
1049 }
1050 }
1051
1052 skip1:
1053 //%%%%%%s IKEv2 - no support for bundle - fix this - return error if bundle ???
1054 // %%%% need special handling for ipcomp
1055 for (req = sp_main->req; req; req = req->next) {
1056 struct saproto *newpr;
1057 caddr_t paddr = NULL;
1058
1059 /*
1060 * check if SA bundle ?
1061 * nested SAs negotiation is NOT supported.
1062 * me +--- SA1 ---+ peer1
1063 * me +--- SA2 --------------+ peer2
1064 */
1065 if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
1066 /* check the end of ip addresses of SA */
1067 if (iph2->side == INITIATOR)
1068 paddr = (caddr_t)&req->saidx.dst;
1069 else
1070 paddr = (caddr_t)&req->saidx.src;
1071 }
1072
1073 /* allocate ipsec sa protocol */
1074 newpr = newsaproto();
1075 if (newpr == NULL) {
1076 plog(ASL_LEVEL_ERR,
1077 "failed to allocate saproto.\n");
1078 goto err;
1079 }
1080
1081 newpr->proto_id = ipproto2doi(req->saidx.proto);
1082 if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1083 newpr->spisize = 2;
1084 else
1085 newpr->spisize = 4;
1086 if (lcconf->complex_bundle) {
1087 encmodesv = newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1088 #ifdef ENABLE_NATT
1089 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1090 newpr->encmode += iph2->ph1->natt_options->mode_udp_diff;
1091 #endif
1092 }
1093 else
1094 encmodesv = newpr->encmode = encmodesv;
1095 if (iph2->side == INITIATOR)
1096 newpr->reqid_out = req->saidx.reqid;
1097 else
1098 newpr->reqid_in = req->saidx.reqid;
1099
1100 if (set_satrnsbysainfo(newpr, iph2->sainfo, iph2->version, newpp->pfs_group) < 0) {
1101 plog(ASL_LEVEL_ERR,
1102 "failed to get algorithms.\n");
1103 racoon_free(newpr);
1104 goto err;
1105 }
1106
1107 /* set new saproto */
1108 inssaprotorev(newpp, newpr);
1109 }
1110
1111 /* get reqid_in from inbound policy */
1112 if (sp_sub) {
1113 struct saproto *pr;
1114
1115 req = sp_sub->req;
1116 pr = newpp->head;
1117 while (req && pr) {
1118 if (iph2->side == INITIATOR)
1119 pr->reqid_in = req->saidx.reqid;
1120 else
1121 pr->reqid_out = req->saidx.reqid;
1122 pr = pr->next;
1123 req = req->next;
1124 }
1125 if (pr || req) {
1126 plog(ASL_LEVEL_NOTICE,
1127 "There is a difference "
1128 "between the in/out bound policies in SPD.\n");
1129 }
1130 }
1131
1132 iph2->proposal = newpp;
1133
1134 ike_session_update_mode(iph2);
1135
1136 printsaprop0(ASL_LEVEL_DEBUG, newpp);
1137
1138 return 0;
1139 err:
1140 if (newpp)
1141 flushsaprop(newpp);
1142 return -1;
1143 }
1144
1145 /*
1146 * generate a policy from peer's proposal.
1147 * this function unconditionally chooses the first proposal the in SA payload
1148 * passed by peer.
1149 */
1150 int
1151 set_proposal_from_proposal(iph2)
1152 phase2_handle_t *iph2;
1153 {
1154 struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1155 struct saproto *newpr = NULL, *pr;
1156 struct prop_pair **pair;
1157 int error = -1;
1158 int i;
1159
1160 /* get proposal pair */
1161 if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1)
1162 pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1163 if (pair == NULL)
1164 goto end;
1165
1166 /*
1167 * make my proposal according as the client proposal.
1168 * XXX assumed there is only one proposal even if it's the SA bundle.
1169 */
1170 for (i = 0; i < MAXPROPPAIRLEN; i++) {
1171 if (pair[i] == NULL)
1172 continue;
1173
1174 if (pp_peer != NULL)
1175 flushsaprop(pp_peer);
1176
1177 pp_peer = aproppair2saprop(pair[i]);
1178 if (pp_peer == NULL)
1179 goto end;
1180
1181 pp0 = newsaprop();
1182 if (pp0 == NULL) {
1183 plog(ASL_LEVEL_ERR,
1184 "failed to allocate saprop.\n");
1185 goto end;
1186 }
1187 pp0->prop_no = 1;
1188 pp0->lifetime = iph2->sainfo->lifetime;
1189 pp0->lifebyte = iph2->sainfo->lifebyte;
1190 pp0->pfs_group = iph2->sainfo->pfs_group;
1191
1192 if (pp_peer->next != NULL) {
1193 plog(ASL_LEVEL_ERR,
1194 "pp_peer is inconsistency, ignore it.\n");
1195 /*FALLTHROUGH*/
1196 }
1197
1198 for (pr = pp_peer->head; pr; pr = pr->next) {
1199
1200 newpr = newsaproto();
1201 if (newpr == NULL) {
1202 plog(ASL_LEVEL_ERR,
1203 "failed to allocate saproto.\n");
1204 racoon_free(pp0);
1205 goto end;
1206 }
1207 newpr->proto_id = pr->proto_id;
1208 newpr->spisize = pr->spisize;
1209 newpr->encmode = pr->encmode;
1210 newpr->spi = 0;
1211 newpr->spi_p = pr->spi; /* copy peer's SPI */
1212 newpr->reqid_in = 0;
1213 newpr->reqid_out = 0;
1214
1215 if (set_satrnsbysainfo(newpr, iph2->sainfo, iph2->version, 0) < 0) {
1216 plog(ASL_LEVEL_ERR,
1217 "failed to get algorithms.\n");
1218 racoon_free(newpr);
1219 racoon_free(pp0);
1220 goto end;
1221 }
1222 inssaproto(pp0, newpr);
1223 }
1224
1225 inssaprop(&newpp, pp0);
1226 }
1227
1228 plog(ASL_LEVEL_DEBUG, "make a proposal from peer's:\n");
1229 printsaprop0(ASL_LEVEL_DEBUG, newpp);
1230
1231 iph2->proposal = newpp;
1232
1233 ike_session_update_mode(iph2);
1234
1235 error = 0;
1236
1237 end:
1238 if (error && newpp)
1239 flushsaprop(newpp);
1240
1241 if (pp_peer)
1242 flushsaprop(pp_peer);
1243 if (pair)
1244 free_proppair(pair);
1245 return error;
1246 }
1247
1248 int
1249 tunnel_mode_prop(p)
1250 struct saprop *p;
1251 {
1252 struct saproto *pr;
1253
1254 for (pr = p->head; pr; pr = pr->next)
1255 if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL)
1256 return 1;
1257 return 0;
1258 }
1259
1260 struct satrns *
1261 dupsatrns_1(struct satrns *tr)
1262 {
1263 struct satrns *newtr;
1264
1265 newtr = racoon_calloc(1, sizeof(*newtr));
1266 if (newtr == NULL)
1267 return NULL;
1268 newtr->trns_no = tr->trns_no;
1269 newtr->trns_type = tr->trns_type;
1270 newtr->trns_id = tr->trns_id;
1271 newtr->encklen = tr->encklen;
1272 newtr->authtype = tr->authtype;
1273
1274 return newtr;
1275 }
1276
1277 void
1278 dupsatrns(newpr, head)
1279 struct saproto *newpr;
1280 struct satrns *head;
1281 {
1282 struct satrns *p, *newtr;
1283
1284 for (p = head; p != NULL; p = p->next) {
1285 newtr = newsatrns();
1286 if (newtr) {
1287 newtr->trns_no = p->trns_no;
1288 newtr->trns_type = p->trns_type;
1289 newtr->trns_id = p->trns_id;
1290 newtr->encklen = p->encklen;
1291 newtr->authtype = p->authtype;
1292 inssatrns(newpr, newtr);
1293 } else {
1294 break;
1295 }
1296
1297 }
1298
1299 return;
1300 }
1301
1302 void
1303 dupsaproto(newpp, head, ignore_spis)
1304 struct saprop *newpp;
1305 struct saproto *head;
1306 int ignore_spis;
1307 {
1308 struct saproto *p, *newpr;
1309
1310 for (p = head; p != NULL; p = p->next) {
1311 newpr = newsaproto();
1312 if (newpr) {
1313 newpr->proto_id = p->proto_id;
1314 newpr->spisize = p->spisize;
1315 newpr->encmode = p->encmode;
1316 newpr->udp_encap = p->udp_encap;
1317 if (!ignore_spis) {
1318 newpr->spi = p->spi;
1319 newpr->spi_p = p->spi_p;
1320 newpr->reqid_in = p->reqid_in;
1321 newpr->reqid_out = p->reqid_out;
1322 }
1323 dupsatrns(newpr, p->head);
1324 inssaproto(newpp, newpr);
1325 } else {
1326 break;
1327 }
1328
1329 }
1330
1331 return;
1332 }
1333
1334 struct saprop *
1335 dupsaprop(head, ignore_spis)
1336 struct saprop *head;
1337 int ignore_spis;
1338 {
1339 struct saprop *p, *newpp;
1340
1341 for (p = head, newpp = NULL; p != NULL; p = p->next) {
1342 struct saprop *tmp = newsaprop();
1343 if (tmp) {
1344 tmp->prop_no = p->prop_no;
1345 tmp->lifetime = p->lifetime;
1346 tmp->lifebyte = p->lifebyte;
1347 tmp->pfs_group = p->pfs_group;
1348 tmp->claim = p->claim;
1349 dupsaproto(tmp, p->head, ignore_spis);
1350 inssaprop(&newpp, tmp);
1351 } else {
1352 break;
1353 }
1354 }
1355
1356 return newpp;
1357 }