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