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
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
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);
230		plog(ASL_LEVEL_INFO, "Adjusting my encmode %s(%d)->%s(%d)\n",
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);
239		plog(ASL_LEVEL_INFO, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
240			 s_ipsecdoi_encmode(prev),
241			 prev,
242			 s_ipsecdoi_encmode(pr1->encmode),
243			 pr1->encmode);
244	}
245}
246#endif // ENABLE_NATT
247
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)
260	phase1_handle_t *ph1;
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) {
273		plog(ASL_LEVEL_ERR,
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) {
291			plog(ASL_LEVEL_ERR,
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) {
298			plog(ASL_LEVEL_ERR,
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) {
309			plog(ASL_LEVEL_ERR,
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;
325			plog(ASL_LEVEL_NOTICE,
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;
335			plog(ASL_LEVEL_NOTICE,
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) {
347			plog(ASL_LEVEL_ERR,
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) {
355			plog(ASL_LEVEL_ERR,
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) {
362			plog(ASL_LEVEL_ERR,
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:
374		plog(ASL_LEVEL_ERR,
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) {
420			plog(ASL_LEVEL_ERR,
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) {
443				plog(ASL_LEVEL_ERR,
444				    "IPComp SPI size promoted "
445				    "from 16bit to 32bit\n");
446			}
447		}
448		if (!spisizematch) {
449			plog(ASL_LEVEL_ERR,
450				"spisize mismatched: "
451				"my:%d peer:%d\n",
452				(int)pr2->spisize, (int)pr1->spisize);
453			goto err;
454		}
455
456#ifdef ENABLE_NATT
457		if (ph1->natt_flags & NAT_DETECTED) {
458			saprop_adjust_encmode(pr2, pr1);
459		}
460#endif
461
462		if (pr1->encmode != pr2->encmode) {
463			plog(ASL_LEVEL_ERR,
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) {
483			plog(ASL_LEVEL_ERR,
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) {
500			plog(ASL_LEVEL_ERR,
501				"failed to allocate satrns.\n");
502			racoon_free(newpr);
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) {
548		plog(ASL_LEVEL_WARNING,
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) {
555		plog(ASL_LEVEL_WARNING,
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) {
561		plog(ASL_LEVEL_WARNING,
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) {
581		plog(ASL_LEVEL_DEBUG,
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) {
590		plog(ASL_LEVEL_DEBUG,
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) {
603		plog(ASL_LEVEL_WARNING,
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
614set_satrnsbysainfo(struct saproto *pr, struct sainfo *sainfo, u_int8_t ike_version, int pfs_group)
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) {
623			plog(ASL_LEVEL_ERR,
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) {
636				plog(ASL_LEVEL_ERR,
637					"failed to allocate satrns.\n");
638				goto err;
639			}
640
641			newtr->trns_no = t++;
642			newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);   // IKEv1 only
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) {
650			plog(ASL_LEVEL_ERR,
651				"no encryption algorithm found\n");
652			goto err;
653		}
654		t = 1;
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        }
675		break;
676	case IPSECDOI_PROTO_IPCOMP:
677		if (sainfo->algs[algclass_ipsec_comp] == NULL) {
678			plog(ASL_LEVEL_ERR,
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) {
688				plog(ASL_LEVEL_ERR,
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:
701		plog(ASL_LEVEL_ERR,
702			"unknown proto_id (%d).\n", pr->proto_id);
703		goto err;
704	}
705
706	/* no proposal found */
707	if (pr->head == NULL) {
708		plog(ASL_LEVEL_ERR, "no algorithms found.\n");
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) {
735		plog(ASL_LEVEL_ERR,
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) {
747			plog(ASL_LEVEL_ERR,
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) {
755			plog(ASL_LEVEL_ERR,
756				"invalid spi size %d.\n", p->prop->spi_size);
757			racoon_free(newpr);
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
777			plog(ASL_LEVEL_DEBUG,
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) {
790				plog(ASL_LEVEL_ERR,
791					"failed to allocate satrns.\n");
792				racoon_free(newpr);
793				goto err;
794			}
795
796			if (ipsecdoi_t2satrns(t->trns,
797			    newpp, newpr, newtr) < 0) {
798				flushsaprop(newpp);
799				racoon_free(newtr);
800				racoon_free(newpr);
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) {
884		plog(pri, "(null)");
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
925	plog(pri,
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:
953		plog(pri,
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:
959		plog(pri,
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:
966		plog(pri,
967			"  (trns_id=%s)\n",
968			s_ipsecdoi_trns(proto_id, tr->trns_id));
969		break;
970	default:
971		plog(pri,
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
992	plog(pri,
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)
1010	phase2_handle_t *iph2;
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) {
1019		plog(ASL_LEVEL_ERR,
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;
1026    newpp->pfs_group = iph2->sainfo->pfs_group;
1027
1028    //%%%% to do - verify DH group is OK - tried that here and iphone failed to connect
1029
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		 */
1062		if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
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) {
1073			plog(ASL_LEVEL_ERR,
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) {
1084			encmodesv = newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
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
1091			encmodesv = newpr->encmode = encmodesv;
1092		if (iph2->side == INITIATOR)
1093			newpr->reqid_out = req->saidx.reqid;
1094		else
1095			newpr->reqid_in = req->saidx.reqid;
1096
1097		if (set_satrnsbysainfo(newpr, iph2->sainfo, iph2->version, newpp->pfs_group) < 0) {
1098			plog(ASL_LEVEL_ERR,
1099				"failed to get algorithms.\n");
1100			racoon_free(newpr);
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) {
1123			plog(ASL_LEVEL_NOTICE,
1124				"There is a difference "
1125				"between the in/out bound policies in SPD.\n");
1126		}
1127	}
1128
1129	iph2->proposal = newpp;
1130
1131    ike_session_update_mode(iph2);
1132
1133	printsaprop0(ASL_LEVEL_DEBUG, newpp);
1134
1135	return 0;
1136err:
1137	if (newpp)
1138		flushsaprop(newpp);
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)
1149	phase2_handle_t *iph2;
1150{
1151        struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1152	struct saproto *newpr = NULL, *pr;
1153	struct prop_pair **pair = NULL;
1154	int error = -1;
1155	int i;
1156
1157	/* get proposal pair */
1158	if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1)
1159		pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1160
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;
1171
1172		if (pp_peer != NULL)
1173			flushsaprop(pp_peer);
1174
1175		pp_peer = aproppair2saprop(pair[i]);
1176		if (pp_peer == NULL)
1177			goto end;
1178
1179		pp0 = newsaprop();
1180		if (pp0 == NULL) {
1181			plog(ASL_LEVEL_ERR,
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) {
1191			plog(ASL_LEVEL_ERR,
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) {
1200				plog(ASL_LEVEL_ERR,
1201				    "failed to allocate saproto.\n");
1202 				racoon_free(pp0);
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;
1212
1213			if (set_satrnsbysainfo(newpr, iph2->sainfo, iph2->version, 0) < 0) {
1214				plog(ASL_LEVEL_ERR,
1215					"failed to get algorithms.\n");
1216 				racoon_free(newpr);
1217 				racoon_free(pp0);
1218				goto end;
1219			}
1220			inssaproto(pp0, newpr);
1221		}
1222
1223		inssaprop(&newpp, pp0);
1224	}
1225
1226	plog(ASL_LEVEL_DEBUG, "make a proposal from peer's:\n");
1227	printsaprop0(ASL_LEVEL_DEBUG, newpp);
1228
1229	iph2->proposal = newpp;
1230
1231	ike_session_update_mode(iph2);
1232
1233	error = 0;
1234
1235end:
1236	if (error && newpp)
1237		flushsaprop(newpp);
1238
1239	if (pp_peer)
1240		flushsaprop(pp_peer);
1241	if (pair)
1242		free_proppair(pair);
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}
1257
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;
1267    newtr->trns_id = tr->trns_id;
1268    newtr->encklen = tr->encklen;
1269    newtr->authtype = tr->authtype;
1270
1271	return newtr;
1272}
1273
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}
1354