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 */
80struct saprop *
81newsaprop()
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
92struct saproto *
93newsaproto()
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 */
105void
106inssaprop(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 */
125void
126inssaproto(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 */
143void
144inssaprotorev(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
154struct satrns *
155newsatrns()
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 */
167void
168inssatrns(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
184int
185satrns_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
206static void
207saprop_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
223static void
224saprop_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 */
259struct saprop *
260cmpsaprop_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
538err:
539	flushsaprop(newpp);
540	return NULL;
541}
542
543/* take a single match between saprop.  returns 0 if pp1 equals to pp2. */
544int
545cmpsaprop(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 */
576int
577cmpsatrns(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
614int
615set_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
715err:
716	flushsatrns(pr->head);
717	return -1;
718}
719
720struct saprop *
721aproppair2saprop(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
823err:
824	flushsaprop(newpp);
825	return NULL;
826}
827
828void
829flushsaprop(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
843void
844flushsaproto(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
860void
861flushsatrns(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 */
877void
878printsaprop(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 */
899void
900printsaprop0(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
916void
917printsaproto(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
943void
944printsatrns(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
979void
980print_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
1001void
1002print_proppair(pri, p)
1003	int pri;
1004	struct prop_pair *p;
1005{
1006	print_proppair0(pri, p, 1);
1007}
1008
1009int
1010set_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;
1139err:
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 */
1150int
1151set_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
1237end:
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
1248int
1249tunnel_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
1260struct satrns *
1261dupsatrns_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
1277void
1278dupsatrns(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
1302void
1303dupsaproto(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
1334struct saprop *
1335dupsaprop(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}
1358