1/* $Id: ipsec_doi.c,v 1.26.2.16 2006/02/02 14:37:17 vanhu 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/types.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37
38#include <netinet/in.h>
39
40#ifndef HAVE_NETINET6_IPSEC
41#include <netinet/ipsec.h>
42#else
43#include <netinet6/ipsec.h>
44#endif
45
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <errno.h>
50#include <netdb.h>
51#if TIME_WITH_SYS_TIME
52# include <sys/time.h>
53# include <time.h>
54#else
55# if HAVE_SYS_TIME_H
56#  include <sys/time.h>
57# else
58#  include <time.h>
59# endif
60#endif
61
62#include "var.h"
63#include "vmbuf.h"
64#include "misc.h"
65#include "plog.h"
66#include "debug.h"
67
68#include "cfparse_proto.h"
69#include "isakmp_var.h"
70#include "isakmp.h"
71#include "ipsec_doi.h"
72#include "oakley.h"
73#include "remoteconf.h"
74#include "localconf.h"
75#include "sockmisc.h"
76#include "handler.h"
77#include "policy.h"
78#include "algorithm.h"
79#include "sainfo.h"
80#include "proposal.h"
81#include "crypto_openssl.h"
82#include "crypto_cssm.h"
83#include "strnames.h"
84#include "gcmalloc.h"
85
86#ifdef ENABLE_NATT
87#include "nattraversal.h"
88#endif
89#include "ikev2_rfc.h"
90
91#ifdef ENABLE_HYBRID
92static int switch_authmethod(int);
93#endif
94
95int verbose_proposal_check = 1;
96
97static vchar_t *get_ph1approval (phase1_handle_t *, struct prop_pair **);
98void print_ph1mismatched (struct prop_pair *, struct isakmpsa *);
99static int t2isakmpsa (struct isakmp_pl_t *, struct isakmpsa *);
100static int cmp_aproppair_i (struct prop_pair *, struct prop_pair *);
101static struct prop_pair *get_ph2approval (phase2_handle_t *,
102	struct prop_pair **);
103static struct prop_pair *get_ph2approvalx (phase2_handle_t *,
104	struct prop_pair *);
105static void free_proppair0 (struct prop_pair *);
106
107static int get_transform (struct isakmp_pl_p *, struct prop_pair **, int *);
108static u_int32_t ipsecdoi_set_ld (vchar_t *);
109
110static int check_doi (u_int32_t);
111static int check_situation (u_int32_t);
112
113static int check_prot_main (int);
114static int check_prot_quick (int);
115static int (*check_protocol[]) (int) = {
116	check_prot_main,	/* IPSECDOI_TYPE_PH1 */
117	check_prot_quick,	/* IPSECDOI_TYPE_PH2 */
118	NULL,				/* IPSECDOI_TYPE_IKEV2_PH1 */
119	NULL,				/* IPSECDOI_TYPE_IKEV2_PH2 */
120};
121
122int check_spi_size (int, int);
123
124static int check_trns_isakmp (int);
125static int check_trns_ah (int);
126static int check_trns_esp (int);
127static int check_trns_ipcomp (int);
128static int (*check_transform[]) (int) = {
129	0,
130	check_trns_isakmp,	/* IPSECDOI_PROTO_ISAKMP */
131	check_trns_ah,		/* IPSECDOI_PROTO_IPSEC_AH */
132	check_trns_esp,		/* IPSECDOI_PROTO_IPSEC_ESP */
133	check_trns_ipcomp,	/* IPSECDOI_PROTO_IPCOMP */
134};
135
136static int check_attr_isakmp (struct isakmp_pl_t *);
137static int check_attr_ah (struct isakmp_pl_t *);
138static int check_attr_esp (struct isakmp_pl_t *);
139static int check_attr_ipsec (int, struct isakmp_pl_t *);
140static int check_attr_ipcomp (struct isakmp_pl_t *);
141static int (*check_attributes[]) (struct isakmp_pl_t *) = {
142	0,
143	check_attr_isakmp,	/* IPSECDOI_PROTO_ISAKMP */
144	check_attr_ah,		/* IPSECDOI_PROTO_IPSEC_AH */
145	check_attr_esp,		/* IPSECDOI_PROTO_IPSEC_ESP */
146	check_attr_ipcomp,	/* IPSECDOI_PROTO_IPCOMP */
147};
148
149int setph1prop (phase1_handle_t *, caddr_t);
150static int setph1trns (struct isakmpsa *, caddr_t);
151static int setph1attr (struct isakmpsa *, caddr_t);
152static vchar_t *setph2proposal0 (const phase2_handle_t *,
153	const struct saprop *, const struct saproto *);
154
155static vchar_t *getidval (int, vchar_t *);
156
157
158/*%%%*/
159/*
160 * check phase 1 SA payload.
161 * make new SA payload to be replyed not including general header.
162 * the pointer to one of isakmpsa in proposal is set into iph1->approval.
163 * OUT:
164 *	positive: the pointer to new buffer of SA payload.
165 *		  network byte order.
166 *	NULL	: error occurd.
167 */
168int
169ipsecdoi_checkph1proposal(sa, iph1)
170	vchar_t *sa;
171	phase1_handle_t *iph1;
172{
173	vchar_t *newsa;		/* new SA payload approved. */
174	struct prop_pair **pair;
175
176	/* get proposal pair */
177	pair = get_proppair(sa, IPSECDOI_TYPE_PH1);
178	if (pair == NULL)
179		return -1;
180
181	/* check and get one SA for use */
182	newsa = get_ph1approval(iph1, pair);
183
184	free_proppair(pair);
185
186	if (newsa == NULL)
187		return -1;
188
189	iph1->sa_ret = newsa;
190
191	return 0;
192}
193
194/*
195 * acceptable check for remote configuration.
196 * return a new SA payload to be reply to peer.
197 */
198static vchar_t *
199get_ph1approval(iph1, pair)
200	phase1_handle_t *iph1;
201	struct prop_pair **pair;
202{
203	vchar_t *newsa;
204	struct isakmpsa *sa, tsa;
205	struct prop_pair *s, *p;
206	int prophlen;
207	int i;
208
209	if (iph1->approval) {
210		delisakmpsa(iph1->approval);
211		iph1->approval = NULL;
212	}
213
214	for (i = 0; i < MAXPROPPAIRLEN; i++) {
215		if (pair[i] == NULL)
216			continue;
217		for (s = pair[i]; s; s = s->next) {
218			prophlen =
219			    sizeof(struct isakmp_pl_p) + s->prop->spi_size;
220
221			/* compare proposal and select one */
222			for (p = s; p; p = p->tnext) {
223				if ((sa = get_ph1approvalx(p,
224				    iph1->rmconf->proposal, &tsa,
225				    iph1->rmconf->pcheck_level)) != NULL)
226					goto found;
227			}
228		}
229	}
230
231	/*
232	 * if there is no suitable proposal, racoon complains about all of
233	 * mismatched items in those proposal.
234	 */
235	if (verbose_proposal_check) {
236		for (i = 0; i < MAXPROPPAIRLEN; i++) {
237			if (pair[i] == NULL)
238				continue;
239			for (s = pair[i]; s; s = s->next) {
240				prophlen = sizeof(struct isakmp_pl_p)
241						+ s->prop->spi_size;
242				for (p = s; p; p = p->tnext) {
243					print_ph1mismatched(p,
244						iph1->rmconf->proposal);
245				}
246			}
247		}
248	}
249	plog(ASL_LEVEL_ERR, "no suitable proposal found.\n");
250
251	return NULL;
252
253found:
254	plog(ASL_LEVEL_DEBUG, "an acceptable proposal found.\n");
255
256	/* check DH group settings */
257	if (sa->dhgrp) {
258		if (sa->dhgrp->prime && sa->dhgrp->gen1) {
259			/* it's ok */
260			goto saok;
261		}
262		plog(ASL_LEVEL_WARNING,
263			"invalid DH parameter found, use default.\n");
264		oakley_dhgrp_free(sa->dhgrp);
265		sa->dhgrp=NULL;
266	}
267
268	if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) {
269		sa->dhgrp = NULL;
270		racoon_free(sa);
271		return NULL;
272	}
273
274saok:
275	iph1->approval = sa;
276	if(iph1->approval) {
277		plog(ASL_LEVEL_DEBUG, "agreed on %s auth.\n",
278		    s_oakley_attr_method(iph1->approval->authmethod));
279	}
280
281	newsa = get_sabyproppair(p, iph1);
282	if (newsa == NULL) {
283		delisakmpsa(iph1->approval);
284		iph1->approval = NULL;
285	}
286
287	return newsa;
288}
289
290/*
291 * compare peer's single proposal and all of my proposal.
292 * and select one if suiatable.
293 * p       : one of peer's proposal.
294 * proposal: my proposals.
295 */
296struct isakmpsa *
297get_ph1approvalx(p, proposal, sap, check_level)
298	struct prop_pair *p;
299	struct isakmpsa *proposal, *sap;
300	int check_level;
301{
302	struct isakmp_pl_p *prop = p->prop;
303	struct isakmp_pl_t *trns = p->trns;
304	struct isakmpsa sa, *s, *tsap;
305	int authmethod;
306    int tsap_authmethod;
307
308	plog(ASL_LEVEL_DEBUG,
309		 "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n",
310		 prop->p_no, s_ipsecdoi_proto(prop->proto_id),
311		 prop->spi_size, prop->num_t);
312
313	plog(ASL_LEVEL_DEBUG,
314		"trns#=%d, trns-id=%s\n",
315		trns->t_no,
316		s_ipsecdoi_trns(prop->proto_id, trns->t_id));
317
318	tsap = sap != NULL ? sap : &sa;
319
320	memset(tsap, 0, sizeof(*tsap));
321	if (t2isakmpsa(trns, tsap) < 0)
322		return NULL;
323	for (s = proposal; s != NULL; s = s->next) {
324#ifdef ENABLE_HYBRID
325		authmethod = switch_authmethod(s->authmethod);
326        tsap_authmethod = switch_authmethod(tsap->authmethod);
327#else
328		authmethod = s->authmethod;
329        tsap_authmethod = tsap->authmethod;
330#endif
331		plog(ASL_LEVEL_DEBUG, "Compared: DB:Peer\n");
332		plog(ASL_LEVEL_DEBUG, "(version = %d:%d)\n",
333			 s->version, tsap->version);
334		plog(ASL_LEVEL_DEBUG, "(lifetime = %ld:%ld)\n",
335			(long)s->lifetime, (long)tsap->lifetime);
336		plog(ASL_LEVEL_DEBUG, "(lifebyte = %zu:%zu)\n",
337			s->lifebyte, tsap->lifebyte);
338		plog(ASL_LEVEL_DEBUG, "enctype = %s:%s\n",
339			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
340					s->enctype),
341			s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
342					tsap->enctype));
343		plog(ASL_LEVEL_DEBUG, "(encklen = %d:%d)\n",
344			s->encklen, tsap->encklen);
345		plog(ASL_LEVEL_DEBUG, "hashtype = %s:%s\n",
346			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
347					s->hashtype),
348			s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
349					tsap->hashtype));
350		plog(ASL_LEVEL_DEBUG, "authmethod = %s:%s\n",
351			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
352					s->authmethod),
353			s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
354					tsap->authmethod));
355		plog(ASL_LEVEL_DEBUG, "dh_group = %s:%s\n",
356			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
357					s->dh_group),
358			s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
359					tsap->dh_group));
360#if 0
361		/* XXX to be considered ? */
362		if (tsap->lifebyte > s->lifebyte) ;
363#endif
364		/*
365		 * if responder side and peer's key length in proposal
366		 * is bigger than mine, it might be accepted.
367		 */
368		if(tsap->enctype == s->enctype &&
369		    (tsap->authmethod == authmethod || tsap_authmethod == authmethod) &&
370		    tsap->hashtype == s->hashtype &&
371		    tsap->dh_group == s->dh_group &&
372		    tsap->encklen == s->encklen &&
373			tsap->version == s->version) {
374			switch(check_level) {
375			case PROP_CHECK_IKEV2:
376			case PROP_CHECK_OBEY:
377				goto found;
378				break;
379
380			case PROP_CHECK_STRICT:
381				if ((tsap->lifetime > s->lifetime) ||
382				    (tsap->lifebyte > s->lifebyte))
383					continue;
384				goto found;
385				break;
386
387			case PROP_CHECK_CLAIM:
388				if (tsap->lifetime < s->lifetime)
389					s->lifetime = tsap->lifetime;
390				if (tsap->lifebyte < s->lifebyte)
391					s->lifebyte = tsap->lifebyte;
392				goto found;
393				break;
394
395			case PROP_CHECK_EXACT:
396				if ((tsap->lifetime != s->lifetime) ||
397				    (tsap->lifebyte != s->lifebyte))
398					continue;
399				goto found;
400				break;
401
402			default:
403				plog(ASL_LEVEL_ERR,
404				    "Unexpected proposal_check value\n");
405				continue;
406				break;
407			}
408		}
409	}
410
411found:
412	if (tsap->dhgrp != NULL){
413		oakley_dhgrp_free(tsap->dhgrp);
414		tsap->dhgrp = NULL;
415	}
416
417	if ((s = dupisakmpsa(s)) != NULL) {
418		switch(check_level) {
419		case PROP_CHECK_OBEY:
420			s->lifetime = tsap->lifetime;
421			s->lifebyte = tsap->lifebyte;
422			break;
423
424		case PROP_CHECK_STRICT:
425			s->lifetime = tsap->lifetime;
426			s->lifebyte = tsap->lifebyte;
427			break;
428
429		case PROP_CHECK_CLAIM:
430			if (tsap->lifetime < s->lifetime)
431				s->lifetime = tsap->lifetime;
432			if (tsap->lifebyte < s->lifebyte)
433				s->lifebyte = tsap->lifebyte;
434			break;
435
436		default:
437			break;
438		}
439        // hack to get around cisco rekeys
440        if (tsap->authmethod != authmethod && tsap_authmethod == authmethod) {
441            s->authmethod = tsap->authmethod;
442        }
443	}
444	return s;
445}
446
447/*
448 * print all of items in peer's proposal which are mismatched to my proposal.
449 * p       : one of peer's proposal.
450 * proposal: my proposals.
451 */
452void
453print_ph1mismatched(p, proposal)
454	struct prop_pair *p;
455	struct isakmpsa *proposal;
456{
457	struct isakmpsa sa, *s;
458
459	memset(&sa, 0, sizeof(sa));
460	if (t2isakmpsa(p->trns, &sa) < 0)
461		return;
462	for (s = proposal; s ; s = s->next) {
463		if (sa.enctype != s->enctype) {
464			plog(ASL_LEVEL_ERR,
465				"rejected enctype: "
466				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
467				"%s:%s\n",
468				s->prop_no, s->trns_no,
469				p->prop->p_no, p->trns->t_no,
470				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
471					s->enctype),
472				s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG,
473					sa.enctype));
474		}
475		if (sa.authmethod != s->authmethod) {
476			plog(ASL_LEVEL_ERR,
477				"rejected authmethod: "
478				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
479				"%s:%s\n",
480				s->prop_no, s->trns_no,
481				p->prop->p_no, p->trns->t_no,
482				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
483					s->authmethod),
484				s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD,
485					sa.authmethod));
486		}
487		if (sa.hashtype != s->hashtype) {
488			plog(ASL_LEVEL_ERR,
489				"rejected hashtype: "
490				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
491				"%s:%s\n",
492				s->prop_no, s->trns_no,
493				p->prop->p_no, p->trns->t_no,
494				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
495					s->hashtype),
496				s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
497					sa.hashtype));
498		}
499		if (sa.prf != s->prf ||
500			sa.prfklen != s->prfklen) {
501			plog(ASL_LEVEL_ERR,
502				 "rejected prf: "
503				 "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
504				 "%s.%d:%s.%d\n",
505				 s->prop_no, s->trns_no,
506				 p->prop->p_no, p->trns->t_no,
507				 s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
508								 s->prf),
509				 s->prfklen,
510				 s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG,
511								 sa.prf),
512				 sa.prfklen);
513		}
514		if (sa.dh_group != s->dh_group) {
515			plog(ASL_LEVEL_ERR,
516				"rejected dh_group: "
517				"DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = "
518				"%s:%s\n",
519				s->prop_no, s->trns_no,
520				p->prop->p_no, p->trns->t_no,
521				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
522					s->dh_group),
523				s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC,
524					sa.dh_group));
525		}
526	}
527
528	if (sa.dhgrp != NULL){
529		oakley_dhgrp_free(sa.dhgrp);
530		sa.dhgrp=NULL;
531	}
532}
533
534/*
535 * get ISAKMP data attributes
536 */
537static int
538t2isakmpsa(trns, sa)
539	struct isakmp_pl_t *trns;
540	struct isakmpsa *sa;
541{
542	struct isakmp_data *d, *prev;
543	int flag, type;
544	int error = -1;
545	int life_t;
546	int keylen = 0;
547	vchar_t *val = NULL;
548	int len, tlen;
549	u_char *p;
550
551	tlen = ntohs(trns->h.len) - sizeof(*trns);
552	prev = (struct isakmp_data *)NULL;
553	d = (struct isakmp_data *)(trns + 1);
554
555	/* default */
556	life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
557	sa->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT;
558	sa->lifebyte = 0;
559	sa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup));
560	if (!sa->dhgrp)
561		goto err;
562
563	while (tlen > 0) {
564
565		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
566		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
567
568		plog(ASL_LEVEL_DEBUG,
569			"type=%s, flag=0x%04x, lorv=%s\n",
570			s_oakley_attr(type), flag,
571			s_oakley_attr_v(type, ntohs(d->lorv)));
572
573		/* get variable-sized item */
574		switch (type) {
575		case OAKLEY_ATTR_GRP_PI:
576		case OAKLEY_ATTR_GRP_GEN_ONE:
577		case OAKLEY_ATTR_GRP_GEN_TWO:
578		case OAKLEY_ATTR_GRP_CURVE_A:
579		case OAKLEY_ATTR_GRP_CURVE_B:
580		case OAKLEY_ATTR_SA_LD:
581		case OAKLEY_ATTR_GRP_ORDER:
582			if (flag) {	/*TV*/
583				len = 2;
584				p = (u_char *)&d->lorv;
585			} else {	/*TLV*/
586				len = ntohs(d->lorv);
587				if (len > tlen) {
588					plog(ASL_LEVEL_ERR,
589						 "invalid ISAKMP-SA attr, attr-len %d, overall-len %d\n",
590						 len, tlen);
591					return -1;
592				}
593				p = (u_char *)(d + 1);
594			}
595			val = vmalloc(len);
596			if (!val)
597				return -1;
598			memcpy(val->v, p, len);
599			break;
600
601		default:
602			break;
603		}
604
605		switch (type) {
606		case OAKLEY_ATTR_ENC_ALG:
607			sa->enctype = (u_int16_t)ntohs(d->lorv);
608			break;
609
610		case OAKLEY_ATTR_HASH_ALG:
611			sa->hashtype = (u_int16_t)ntohs(d->lorv);
612			break;
613
614		case OAKLEY_ATTR_AUTH_METHOD:
615			sa->authmethod = ntohs(d->lorv);
616			break;
617
618		case OAKLEY_ATTR_GRP_DESC:
619			sa->dh_group = (u_int16_t)ntohs(d->lorv);
620			break;
621
622		case OAKLEY_ATTR_GRP_TYPE:
623		{
624			int type = (int)ntohs(d->lorv);
625			if (type == OAKLEY_ATTR_GRP_TYPE_MODP)
626				sa->dhgrp->type = type;
627			else
628				return -1;
629			break;
630		}
631		case OAKLEY_ATTR_GRP_PI:
632			sa->dhgrp->prime = val;
633			break;
634
635		case OAKLEY_ATTR_GRP_GEN_ONE:
636			vfree(val);
637			if (!flag)
638				sa->dhgrp->gen1 = ntohs(d->lorv);
639			else {
640				int len = ntohs(d->lorv);
641				sa->dhgrp->gen1 = 0;
642				if (len > 4)
643					return -1;
644				memcpy(&sa->dhgrp->gen1, d + 1, len);
645				sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1);
646			}
647			break;
648
649		case OAKLEY_ATTR_GRP_GEN_TWO:
650			vfree(val);
651			if (!flag)
652				sa->dhgrp->gen2 = ntohs(d->lorv);
653			else {
654				int len = ntohs(d->lorv);
655				sa->dhgrp->gen2 = 0;
656				if (len > 4)
657					return -1;
658				memcpy(&sa->dhgrp->gen2, d + 1, len);
659				sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2);
660			}
661			break;
662
663		case OAKLEY_ATTR_GRP_CURVE_A:
664			sa->dhgrp->curve_a = val;
665			break;
666
667		case OAKLEY_ATTR_GRP_CURVE_B:
668			sa->dhgrp->curve_b = val;
669			break;
670
671		case OAKLEY_ATTR_SA_LD_TYPE:
672		{
673			int type = (int)ntohs(d->lorv);
674			switch (type) {
675			case OAKLEY_ATTR_SA_LD_TYPE_SEC:
676			case OAKLEY_ATTR_SA_LD_TYPE_KB:
677				life_t = type;
678				break;
679			default:
680				life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT;
681				break;
682			}
683			break;
684		}
685		case OAKLEY_ATTR_SA_LD:
686			if (!prev
687			 || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
688					OAKLEY_ATTR_SA_LD_TYPE) {
689				plog(ASL_LEVEL_ERR,
690				    "life duration must follow ltype\n");
691				break;
692			}
693
694			switch (life_t) {
695			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
696				sa->lifetime = ipsecdoi_set_ld(val);
697				vfree(val);
698				if (sa->lifetime == 0) {
699					plog(ASL_LEVEL_ERR,
700						"invalid life duration.\n");
701					goto err;
702				}
703				break;
704			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
705				sa->lifebyte = ipsecdoi_set_ld(val);
706				vfree(val);
707				if (sa->lifebyte == 0) {
708					plog(ASL_LEVEL_ERR,
709						"invalid life duration.\n");
710					goto err;
711				}
712				break;
713			default:
714				vfree(val);
715				plog(ASL_LEVEL_ERR,
716					"invalid life type: %d\n", life_t);
717				goto err;
718			}
719			break;
720
721		case OAKLEY_ATTR_KEY_LEN:
722		{
723			int len = ntohs(d->lorv);
724			if (len % 8 != 0) {
725				plog(ASL_LEVEL_ERR,
726					"keylen %d: not multiple of 8\n",
727					len);
728				goto err;
729			}
730			sa->encklen = (u_int16_t)len;
731			keylen++;
732			break;
733		}
734		case OAKLEY_ATTR_PRF:
735		case OAKLEY_ATTR_FIELD_SIZE:
736			/* unsupported */
737			break;
738
739		case OAKLEY_ATTR_GRP_ORDER:
740			sa->dhgrp->order = val;
741			break;
742
743		default:
744			break;
745		}
746
747		prev = d;
748		if (flag) {
749			tlen -= sizeof(*d);
750			d = (struct isakmp_data *)((char *)d + sizeof(*d));
751		} else {
752			tlen -= (sizeof(*d) + ntohs(d->lorv));
753			d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv));
754		}
755	}
756
757	/* key length must not be specified on some algorithms */
758	if (keylen) {
759		if (sa->enctype == OAKLEY_ATTR_ENC_ALG_DES
760		 || sa->enctype == OAKLEY_ATTR_ENC_ALG_3DES) {
761			plog(ASL_LEVEL_ERR,
762				"keylen must not be specified "
763				"for encryption algorithm %d\n",
764				sa->enctype);
765			return -1;
766		}
767	}
768
769	return 0;
770err:
771	return error;
772}
773
774/*%%%*/
775/*
776 * check phase 2 SA payload and select single proposal.
777 * make new SA payload to be replyed not including general header.
778 * This function is called by responder only.
779 * OUT:
780 *	0: succeed.
781 *	-1: error occured.
782 */
783int
784ipsecdoi_selectph2proposal(iph2)
785	phase2_handle_t *iph2;
786{
787	struct prop_pair **pair;
788	struct prop_pair *ret;
789
790	/* get proposal pair */
791	pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
792	if (pair == NULL)
793		return -1;
794
795	/* check and select a proposal. */
796	ret = get_ph2approval(iph2, pair);
797	free_proppair(pair);
798	if (ret == NULL)
799		return -1;
800
801	/* make a SA to be replayed. */
802	/* SPI must be updated later. */
803	iph2->sa_ret = get_sabyproppair(ret, iph2->ph1);
804	free_proppair0(ret);
805	if (iph2->sa_ret == NULL)
806		return -1;
807
808	return 0;
809}
810
811/*
812 * check phase 2 SA payload returned from responder.
813 * This function is called by initiator only.
814 * OUT:
815 *	0: valid.
816 *	-1: invalid.
817 */
818int
819ipsecdoi_checkph2proposal(iph2)
820	phase2_handle_t *iph2;
821{
822	struct prop_pair **rpair = NULL, **spair = NULL;
823	struct prop_pair *p;
824	int i, n, num;
825	int error = -1;
826	vchar_t *sa_ret = NULL;
827
828	/* get proposal pair of SA sent. */
829	spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
830	if (spair == NULL) {
831		plog(ASL_LEVEL_ERR,
832			"failed to get prop pair.\n");
833		goto end;
834	}
835
836	/* XXX should check the number of transform */
837
838	/* get proposal pair of SA replayed */
839	rpair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
840	if (rpair == NULL) {
841		plog(ASL_LEVEL_ERR,
842			"failed to get prop pair.\n");
843		goto end;
844	}
845
846	/* check proposal is only one ? */
847	n = 0;
848	num = 0;
849	for (i = 0; i < MAXPROPPAIRLEN; i++) {
850		if (rpair[i]) {
851			n = i;
852			num++;
853		}
854	}
855	if (num == 0) {
856		plog(ASL_LEVEL_ERR,
857			"no proposal received.\n");
858		goto end;
859	}
860	if (num != 1) {
861		plog(ASL_LEVEL_ERR,
862			"some proposals received.\n");
863		goto end;
864	}
865
866	if (spair[n] == NULL) {
867		plog(ASL_LEVEL_WARNING,
868			"invalid proposal number:%d received.\n", i);
869	}
870
871
872	if (rpair[n]->tnext != NULL) {
873		plog(ASL_LEVEL_ERR,
874			"multi transforms replyed.\n");
875		goto end;
876	}
877
878	if (cmp_aproppair_i(rpair[n], spair[n])) {
879		plog(ASL_LEVEL_ERR,
880			"proposal mismathed.\n");
881		goto end;
882	}
883
884	/*
885	 * check and select a proposal.
886	 * ensure that there is no modification of the proposal by
887	 * cmp_aproppair_i()
888	 */
889	p = get_ph2approval(iph2, rpair);
890	if (p == NULL)
891		goto end;
892
893	/* make a SA to be replayed. */
894	sa_ret = iph2->sa_ret;
895	iph2->sa_ret = get_sabyproppair(p, iph2->ph1);
896	free_proppair0(p);
897	if (iph2->sa_ret == NULL)
898		goto end;
899
900	error = 0;
901
902end:
903	if (rpair)
904		free_proppair(rpair);
905	if (spair)
906		free_proppair(spair);
907	if (sa_ret)
908		vfree(sa_ret);
909
910	return error;
911}
912
913/*
914 * compare two prop_pair which is assumed to have same proposal number.
915 * the case of bundle or single SA, NOT multi transforms.
916 * a: a proposal that is multi protocols and single transform, usually replyed.
917 * b: a proposal that is multi protocols and multi transform, usually sent.
918 * NOTE: this function is for initiator.
919 * OUT
920 *	0: equal
921 *	1: not equal
922 * XXX cannot understand the comment!
923 */
924static int
925cmp_aproppair_i(a, b)
926	struct prop_pair *a, *b;
927{
928	struct prop_pair *p, *q, *r;
929	int len;
930
931	for (p = a, q = b; p && q; p = p->next, q = q->next) {
932		for (r = q; r; r = r->tnext) {
933			/* compare trns */
934			if (p->trns->t_no == r->trns->t_no)
935				break;
936		}
937		if (!r) {
938			/* no suitable transform found */
939			plog(ASL_LEVEL_ERR,
940				"no suitable transform found.\n");
941			return -1;
942		}
943
944		/* compare prop */
945		if (p->prop->p_no != r->prop->p_no) {
946			plog(ASL_LEVEL_WARNING,
947				"proposal #%d mismatched, "
948				"expected #%d.\n",
949				r->prop->p_no, p->prop->p_no);
950			/*FALLTHROUGH*/
951		}
952
953		if (p->prop->proto_id != r->prop->proto_id) {
954			plog(ASL_LEVEL_ERR,
955				"proto_id mismathed: my:%d peer:%d\n",
956				r->prop->proto_id, p->prop->proto_id);
957			return -1;
958		}
959
960		if (p->prop->proto_id != r->prop->proto_id) {
961			plog(ASL_LEVEL_ERR,
962				"invalid spi size: %d.\n",
963				p->prop->proto_id);
964			return -1;
965		}
966
967		/* check #of transforms */
968		if (p->prop->num_t != 1) {
969			plog(ASL_LEVEL_WARNING,
970				"#of transform is %d, "
971				"but expected 1.\n", p->prop->num_t);
972			/*FALLTHROUGH*/
973		}
974
975		if (p->trns->t_id != r->trns->t_id) {
976			plog(ASL_LEVEL_WARNING,
977				"transform number has been modified.\n");
978			/*FALLTHROUGH*/
979		}
980		if (p->trns->reserved != r->trns->reserved) {
981			plog(ASL_LEVEL_WARNING,
982				"reserved field should be zero.\n");
983			/*FALLTHROUGH*/
984		}
985
986		/* compare attribute */
987		len = ntohs(r->trns->h.len) - sizeof(*p->trns);
988		if (memcmp(p->trns + 1, r->trns + 1, len) != 0) {
989			plog(ASL_LEVEL_WARNING,
990				"attribute has been modified.\n");
991			/*FALLTHROUGH*/
992		}
993	}
994	if ((p && !q) || (!p && q)) {
995		/* # of protocols mismatched */
996		plog(ASL_LEVEL_ERR,
997			"#of protocols mismatched.\n");
998		return -1;
999	}
1000
1001	return 0;
1002}
1003
1004/*
1005 * acceptable check for policy configuration.
1006 * return a new SA payload to be reply to peer.
1007 */
1008static struct prop_pair *
1009get_ph2approval(iph2, pair)
1010	phase2_handle_t *iph2;
1011	struct prop_pair **pair;
1012{
1013	struct prop_pair *ret;
1014	int i;
1015
1016	iph2->approval = NULL;
1017
1018	plog(ASL_LEVEL_DEBUG,
1019		"begin compare proposals.\n");
1020
1021	for (i = 0; i < MAXPROPPAIRLEN; i++) {
1022		if (pair[i] == NULL)
1023			continue;
1024		plog(ASL_LEVEL_DEBUG,
1025			"pair[%d]: %p\n", i, pair[i]);
1026		print_proppair(ASL_LEVEL_DEBUG, pair[i]);;
1027
1028		/* compare proposal and select one */
1029		ret = get_ph2approvalx(iph2, pair[i]);
1030		if (ret != NULL) {
1031			/* found */
1032			return ret;
1033		}
1034	}
1035
1036	plog(ASL_LEVEL_ERR, "no suitable policy found.\n");
1037
1038	return NULL;
1039}
1040
1041/*
1042 * compare my proposal and peers just one proposal.
1043 * set a approval.
1044 */
1045static struct prop_pair *
1046get_ph2approvalx(iph2, pp)
1047	phase2_handle_t *iph2;
1048	struct prop_pair *pp;
1049{
1050	struct prop_pair *ret = NULL;
1051	struct saprop *pr0, *pr = NULL;
1052	struct saprop *q1, *q2;
1053
1054	pr0 = aproppair2saprop(pp);
1055	if (pr0 == NULL)
1056		return NULL;
1057
1058	for (q1 = pr0; q1; q1 = q1->next) {
1059		for (q2 = iph2->proposal; q2; q2 = q2->next) {
1060			plog(ASL_LEVEL_DEBUG,
1061				"peer's single bundle:\n");
1062			printsaprop0(ASL_LEVEL_DEBUG, q1);
1063			plog(ASL_LEVEL_DEBUG,
1064				"my single bundle:\n");
1065			printsaprop0(ASL_LEVEL_DEBUG, q2);
1066
1067			pr = cmpsaprop_alloc(iph2->ph1, q1, q2, iph2->side);
1068			if (pr != NULL)
1069				goto found;
1070
1071			plog(ASL_LEVEL_ERR,
1072				"not matched\n");
1073		}
1074	}
1075	/* no proposal matching */
1076err:
1077	flushsaprop(pr0);
1078	return NULL;
1079
1080found:
1081	flushsaprop(pr0);
1082	plog(ASL_LEVEL_DEBUG, "matched\n");
1083	iph2->approval = pr;
1084
1085    {
1086	struct saproto *sp;
1087	struct prop_pair *p, *x;
1088	struct prop_pair *n = NULL;
1089
1090	ret = NULL;
1091
1092	for (p = pp; p; p = p->next) {
1093		/*
1094		 * find a proposal with matching proto_id.
1095		 * we have analyzed validity already, in cmpsaprop_alloc().
1096		 */
1097		for (sp = pr->head; sp; sp = sp->next) {
1098			if (sp->proto_id == p->prop->proto_id)
1099				break;
1100		}
1101		if (!sp)
1102			goto err;
1103		if (sp->head->next)
1104			goto err;	/* XXX */
1105
1106		for (x = p; x; x = x->tnext)
1107			if (sp->head->trns_no == x->trns->t_no)
1108				break;
1109		if (!x)
1110			goto err;	/* XXX */
1111
1112		n = racoon_calloc(1, sizeof(struct prop_pair));
1113		if (n == NULL) {
1114			plog(ASL_LEVEL_ERR,
1115				"failed to get buffer.\n");
1116			goto err;
1117		}
1118
1119		n->prop = x->prop;
1120		n->trns = x->trns;
1121
1122		/* need to preserve the order */
1123		for (x = ret; x && x->next; x = x->next)
1124			;
1125		if (x && x->prop == n->prop) {
1126			for (/*nothing*/; x && x->tnext; x = x->tnext)
1127				;
1128			x->tnext = n;
1129		} else {
1130			if (x)
1131				x->next = n;
1132			else {
1133				ret = n;
1134			}
1135		}
1136
1137		/* #of transforms should be updated ? */
1138	}
1139    }
1140
1141	return ret;
1142}
1143
1144void
1145free_proppair(pair)
1146	struct prop_pair **pair;
1147{
1148	int i;
1149
1150	for (i = 0; i < MAXPROPPAIRLEN; i++) {
1151		free_proppair0(pair[i]);
1152		pair[i] = NULL;
1153	}
1154	racoon_free(pair);
1155}
1156
1157static void
1158free_proppair0(pair)
1159	struct prop_pair *pair;
1160{
1161	struct prop_pair *p, *q, *r, *s;
1162
1163	p = pair;
1164	while (p) {
1165		q = p->next;
1166		r = p;
1167		while (r) {
1168			s = r->tnext;
1169			racoon_free(r);
1170			r = s;
1171		}
1172		p = q;
1173	}
1174}
1175
1176/*
1177 * get proposal pairs from SA payload.
1178 * tiny check for proposal payload.
1179 */
1180struct prop_pair **
1181get_proppair(sa, mode)
1182	vchar_t *sa;
1183	int mode;
1184{
1185	struct prop_pair **pair = NULL;
1186	int num_p = 0;			/* number of proposal for use */
1187	int tlen;
1188	caddr_t bp;
1189	int i;
1190
1191	//plogdump(ASL_LEVEL_DEBUG, sa->v, sa->l, "total SA len=%zu\n", sa->l);
1192
1193	if (mode == IPSECDOI_TYPE_PH1 || mode == IPSECDOI_TYPE_PH2) {
1194		// IKEv1
1195		struct ipsecdoi_sa_b *sab = ALIGNED_CAST(__typeof__(sab))sa->v;
1196
1197
1198		/* check SA payload size */
1199		if (sa->l < sizeof(*sab)) {
1200			plog(ASL_LEVEL_ERR,
1201				 "Invalid SA length = %zu.\n", sa->l);
1202			goto bad;
1203		}
1204
1205		/* check DOI */
1206		if (check_doi(ntohl(sab->doi)) < 0)
1207			goto bad;
1208
1209		/* check SITUATION */
1210		if (check_situation(ntohl(sab->sit)) < 0)
1211			goto bad;
1212
1213		bp = (caddr_t)(sab + 1);
1214		tlen = sa->l - sizeof(*sab);
1215	} else {
1216		bp = (__typeof__(bp))sa->v;
1217		tlen = sa->l;
1218	}
1219
1220	pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair));
1221	if (pair == NULL) {
1222		plog(ASL_LEVEL_ERR,
1223			"failed to get buffer.\n");
1224		goto bad;
1225	}
1226
1227    {
1228	struct isakmp_pl_p *prop;
1229	int proplen;
1230	vchar_t *pbuf = NULL;
1231	struct isakmp_parse_t *pa;
1232
1233	pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen);
1234	if (pbuf == NULL)
1235		goto bad;
1236
1237	for (pa = ALIGNED_CAST(struct isakmp_parse_t *)pbuf->v;
1238	     pa->type != ISAKMP_NPTYPE_NONE;
1239	     pa++) {
1240		/* check the value of next payload */
1241		if (pa->type != ISAKMP_NPTYPE_P) {
1242			plog(ASL_LEVEL_ERR,
1243				"Invalid payload type=%u\n", pa->type);
1244			vfree(pbuf);
1245			goto bad;
1246		}
1247
1248		prop = (struct isakmp_pl_p *)pa->ptr;
1249		proplen = pa->len;
1250
1251		plog(ASL_LEVEL_DEBUG,
1252			"proposal #%u len=%d\n", prop->p_no, proplen);
1253
1254		if (proplen == 0) {
1255			plog(ASL_LEVEL_ERR,
1256				"invalid proposal with length %d\n", proplen);
1257			vfree(pbuf);
1258			goto bad;
1259		}
1260
1261		/* check Protocol ID */
1262		if (!check_protocol[mode]) {
1263			plog(ASL_LEVEL_ERR,
1264				"unsupported mode %d\n", mode);
1265			continue;
1266		}
1267
1268		if (check_protocol[mode](prop->proto_id) < 0)
1269			continue;
1270
1271		/* check SPI length when IKE. */
1272		if (check_spi_size(prop->proto_id, prop->spi_size) < 0)
1273			continue;
1274
1275		/* get transform */
1276		if (get_transform(prop, pair, &num_p) < 0) {
1277			vfree(pbuf);
1278			goto bad;
1279		}
1280	}
1281	vfree(pbuf);
1282	pbuf = NULL;
1283    }
1284
1285    {
1286	int notrans, nprop;
1287	struct prop_pair *p, *q;
1288
1289	/* check for proposals with no transforms */
1290	for (i = 0; i < MAXPROPPAIRLEN; i++) {
1291		if (!pair[i])
1292			continue;
1293
1294		plog(ASL_LEVEL_DEBUG, "pair %d:\n", i);
1295		print_proppair(ASL_LEVEL_DEBUG, pair[i]);
1296
1297		notrans = nprop = 0;
1298		for (p = pair[i]; p; p = p->next) {
1299			if (p->trns == NULL) {
1300				notrans++;
1301				break;
1302			}
1303			for (q = p; q; q = q->tnext)
1304				nprop++;
1305		}
1306
1307#if 0
1308		/*
1309		 * XXX at this moment, we cannot accept proposal group
1310		 * with multiple proposals.  this should be fixed.
1311		 */
1312		if (pair[i]->next) {
1313			plog(ASL_LEVEL_WARNING,
1314				"proposal #%u ignored "
1315				"(multiple proposal not supported)\n",
1316				pair[i]->prop->p_no);
1317			notrans++;
1318		}
1319#endif
1320
1321		if (notrans) {
1322			for (p = pair[i]; p; p = q) {
1323				q = p->next;
1324				racoon_free(p);
1325			}
1326			pair[i] = NULL;
1327			num_p--;
1328		} else {
1329			plog(ASL_LEVEL_DEBUG,
1330				"proposal #%u: %d transform\n",
1331				pair[i]->prop->p_no, nprop);
1332		}
1333	}
1334    }
1335
1336	/* bark if no proposal is found. */
1337	if (num_p <= 0) {
1338		plog(ASL_LEVEL_ERR,
1339			"no Proposal found.\n");
1340		goto bad;
1341	}
1342
1343	return pair;
1344bad:
1345	if (pair != NULL)
1346		racoon_free(pair);
1347	return NULL;
1348}
1349
1350/*
1351 * check transform payload.
1352 * OUT:
1353 *	positive: return the pointer to the payload of valid transform.
1354 *	0	: No valid transform found.
1355 */
1356static int
1357get_transform(prop, pair, num_p)
1358	struct isakmp_pl_p *prop;
1359	struct prop_pair **pair;
1360	int *num_p;
1361{
1362	int tlen; /* total length of all transform in a proposal */
1363	caddr_t bp;
1364	struct isakmp_pl_t *trns;
1365	int trnslen;
1366	vchar_t *pbuf = NULL;
1367	struct isakmp_parse_t *pa;
1368	struct prop_pair *p = NULL, *q;
1369	int num_t;
1370
1371	bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size;
1372	tlen = ntohs(prop->h.len)
1373		- (sizeof(struct isakmp_pl_p) + prop->spi_size);
1374	pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, tlen);
1375	if (pbuf == NULL)
1376		return -1;
1377
1378	/* check and get transform for use */
1379	num_t = 0;
1380	for (pa = ALIGNED_CAST(struct isakmp_parse_t *)pbuf->v;
1381	     pa->type != ISAKMP_NPTYPE_NONE;
1382	     pa++) {
1383
1384		num_t++;
1385
1386		/* check the value of next payload */
1387		if (pa->type != ISAKMP_NPTYPE_T) {
1388			plog(ASL_LEVEL_ERR,
1389				"Invalid payload type=%u\n", pa->type);
1390			break;
1391		}
1392
1393		trns = (struct isakmp_pl_t *)pa->ptr;
1394		trnslen = pa->len;
1395
1396		plog(ASL_LEVEL_DEBUG,
1397			"transform #%u len=%u\n", trns->t_no, trnslen);
1398
1399		/* check transform ID */
1400		if (prop->proto_id >= ARRAYLEN(check_transform)) {
1401			plog(ASL_LEVEL_WARNING,
1402				"unsupported proto_id %u\n",
1403				prop->proto_id);
1404			continue;
1405		}
1406		if (prop->proto_id >= ARRAYLEN(check_attributes)) {
1407			plog(ASL_LEVEL_WARNING,
1408				"unsupported proto_id %u\n",
1409				prop->proto_id);
1410			continue;
1411		}
1412
1413		if (!check_transform[prop->proto_id]
1414		 || !check_attributes[prop->proto_id]) {
1415			plog(ASL_LEVEL_WARNING,
1416				"unsupported proto_id %u\n",
1417				prop->proto_id);
1418			continue;
1419		}
1420		if (check_transform[prop->proto_id](trns->t_id) < 0)
1421			continue;
1422
1423		/* check data attributes */
1424		if (check_attributes[prop->proto_id](trns) != 0)
1425			continue;
1426
1427		p = racoon_calloc(1, sizeof(*p));
1428		if (p == NULL) {
1429			plog(ASL_LEVEL_ERR,
1430				"failed to get buffer.\n");
1431			vfree(pbuf);
1432			return -1;
1433		}
1434		p->prop = prop;
1435		p->trns = trns;
1436
1437		/* need to preserve the order */
1438		for (q = pair[prop->p_no]; q && q->next; q = q->next)
1439			;
1440		if (q && q->prop == p->prop) {
1441			for (/*nothing*/; q && q->tnext; q = q->tnext)
1442				;
1443			q->tnext = p;
1444		} else {
1445			if (q)
1446				q->next = p;
1447			else {
1448				pair[prop->p_no] = p;
1449				(*num_p)++;
1450			}
1451		}
1452	}
1453
1454	vfree(pbuf);
1455
1456	return 0;
1457}
1458
1459/*
1460 * make a new SA payload from prop_pair.
1461 * NOTE: this function clears the spi value.
1462 */
1463vchar_t *
1464get_sabyproppair(pair, iph1)
1465	struct prop_pair *pair;
1466	phase1_handle_t *iph1;
1467{
1468	vchar_t *newsa;
1469	int newtlen;
1470	u_int8_t *np_p = NULL;
1471	struct prop_pair *p;
1472	int prophlen, trnslen;
1473	caddr_t bp;
1474
1475	if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
1476		newtlen = sizeof(struct ipsecdoi_sa_b);
1477	} else {
1478		newtlen = 0;
1479	}
1480	for (p = pair; p; p = p->next) {
1481		newtlen += sizeof(struct isakmp_pl_p);
1482		newtlen += p->prop->spi_size;
1483		newtlen += ntohs(p->trns->h.len);
1484	}
1485
1486	newsa = vmalloc(newtlen);
1487	if (newsa == NULL) {
1488		plog(ASL_LEVEL_ERR, "failed to get newsa.\n");
1489		return NULL;
1490	}
1491	bp = newsa->v;
1492
1493	((struct isakmp_gen *)bp)->len = htons(newtlen);
1494
1495	if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
1496		/* update some of values in SA header */
1497		(ALIGNED_CAST(struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype);
1498		(ALIGNED_CAST(struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype);
1499		bp += sizeof(struct ipsecdoi_sa_b);
1500	}
1501
1502	/* create proposal payloads */
1503	for (p = pair; p; p = p->next) {
1504		prophlen = sizeof(struct isakmp_pl_p)
1505				+ p->prop->spi_size;
1506		trnslen = ntohs(p->trns->h.len);
1507
1508		if (np_p)
1509			*np_p = ISAKMP_NPTYPE_P;
1510
1511		/* create proposal */
1512
1513		memcpy(bp, p->prop, prophlen);
1514		((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
1515		((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
1516		((struct isakmp_pl_p *)bp)->num_t = 1;
1517		np_p = &((struct isakmp_pl_p *)bp)->h.np;
1518		memset(bp + sizeof(struct isakmp_pl_p), 0, p->prop->spi_size);
1519		bp += prophlen;
1520
1521		/* create transform */
1522		memcpy(bp, p->trns, trnslen);
1523		((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
1524		((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
1525		bp += trnslen;
1526	}
1527
1528	return newsa;
1529}
1530
1531/*
1532 * update responder's spi
1533 */
1534int
1535ipsecdoi_updatespi(iph2)
1536	phase2_handle_t *iph2;
1537{
1538	struct prop_pair **pair, *p;
1539	struct saprop *pp;
1540	struct saproto *pr;
1541	int i;
1542	int error = -1;
1543	u_int8_t *spi;
1544
1545	pair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2);
1546	if (pair == NULL)
1547		return -1;
1548	for (i = 0; i < MAXPROPPAIRLEN; i++) {
1549		if (pair[i])
1550			break;
1551	}
1552	if (i == MAXPROPPAIRLEN || pair[i]->tnext) {
1553		/* multiple transform must be filtered by selectph2proposal.*/
1554		goto end;
1555	}
1556
1557	pp = iph2->approval;
1558
1559	/* create proposal payloads */
1560	for (p = pair[i]; p; p = p->next) {
1561		/*
1562		 * find a proposal/transform with matching proto_id/t_id.
1563		 * we have analyzed validity already, in cmpsaprop_alloc().
1564		 */
1565		for (pr = pp->head; pr; pr = pr->next) {
1566			if (p->prop->proto_id == pr->proto_id &&
1567			    p->trns->t_id == pr->head->trns_id) {
1568				break;
1569			}
1570		}
1571		if (!pr)
1572			goto end;
1573
1574		/*
1575		 * XXX SPI bits are left-filled, for use with IPComp.
1576		 * we should be switching to variable-length spi field...
1577		 */
1578		spi = (u_int8_t *)&pr->spi;
1579		spi += sizeof(pr->spi);
1580		spi -= pr->spisize;
1581		memcpy((caddr_t)p->prop + sizeof(*p->prop), spi, pr->spisize);
1582	}
1583
1584	error = 0;
1585end:
1586	free_proppair(pair);
1587	return error;
1588}
1589
1590/*
1591 * make a new SA payload from prop_pair.
1592 */
1593vchar_t *
1594get_sabysaprop(pp0, sa0)
1595	struct saprop *pp0;
1596	vchar_t *sa0;
1597{
1598	struct prop_pair **pair = NULL;
1599	vchar_t *newsa = NULL;
1600	int newtlen;
1601	u_int8_t *np_p = NULL;
1602	struct prop_pair *p = NULL;
1603	struct saprop *pp;
1604	struct saproto *pr;
1605	struct satrns *tr;
1606	int prophlen, trnslen;
1607	caddr_t bp;
1608	int error = -1;
1609
1610	/* get proposal pair */
1611	pair = get_proppair(sa0, IPSECDOI_TYPE_PH2);
1612	if (pair == NULL)
1613		goto out;
1614
1615	newtlen = sizeof(struct ipsecdoi_sa_b);
1616	for (pp = pp0; pp; pp = pp->next) {
1617
1618		if (pair[pp->prop_no] == NULL)
1619			goto out;
1620
1621		for (pr = pp->head; pr; pr = pr->next) {
1622			newtlen += (sizeof(struct isakmp_pl_p)
1623				+ pr->spisize);
1624
1625			for (tr = pr->head; tr; tr = tr->next) {
1626				for (p = pair[pp->prop_no]; p; p = p->tnext) {
1627					if (tr->trns_no == p->trns->t_no)
1628						break;
1629				}
1630				if (p == NULL)
1631					goto out;
1632
1633				newtlen += ntohs(p->trns->h.len);
1634			}
1635		}
1636	}
1637
1638	newsa = vmalloc(newtlen);
1639	if (newsa == NULL) {
1640		plog(ASL_LEVEL_ERR, "failed to get newsa.\n");
1641		goto out;
1642	}
1643	bp = newsa->v;
1644
1645	/* some of values of SA must be updated in the out of this function */
1646	((struct isakmp_gen *)bp)->len = htons(newtlen);
1647	bp += sizeof(struct ipsecdoi_sa_b);
1648
1649	/* create proposal payloads */
1650	for (pp = pp0; pp; pp = pp->next) {
1651
1652		for (pr = pp->head; pr; pr = pr->next) {
1653			prophlen = sizeof(struct isakmp_pl_p)
1654					+ p->prop->spi_size;
1655
1656			for (tr = pr->head; tr; tr = tr->next) {
1657				for (p = pair[pp->prop_no]; p; p = p->tnext) {
1658					if (tr->trns_no == p->trns->t_no)
1659						break;
1660				}
1661				if (p == NULL)
1662					goto out;
1663
1664				trnslen = ntohs(p->trns->h.len);
1665
1666				if (np_p)
1667					*np_p = ISAKMP_NPTYPE_P;
1668
1669				/* create proposal */
1670
1671				memcpy(bp, p->prop, prophlen);
1672				((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE;
1673				((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen);
1674				((struct isakmp_pl_p *)bp)->num_t = 1;
1675				np_p = &((struct isakmp_pl_p *)bp)->h.np;
1676				bp += prophlen;
1677
1678				/* create transform */
1679				memcpy(bp, p->trns, trnslen);
1680				((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE;
1681				((struct isakmp_pl_t *)bp)->h.len = htons(trnslen);
1682				bp += trnslen;
1683			}
1684		}
1685	}
1686
1687	error = 0;
1688out:
1689	if (pair != NULL)
1690		racoon_free(pair);
1691
1692	if (error != 0) {
1693		if (newsa != NULL) {
1694			vfree(newsa);
1695			newsa = NULL;
1696		}
1697	}
1698
1699	return newsa;
1700}
1701
1702/*
1703 * If some error happens then return 0.  Although 0 means that lifetime is zero,
1704 * such a value should not be accepted.
1705 * Also 0 of lifebyte should not be included in a packet although 0 means not
1706 * to care of it.
1707 */
1708static u_int32_t
1709ipsecdoi_set_ld(buf)
1710	vchar_t *buf;
1711{
1712	u_int32_t ld;
1713
1714	if (buf == 0)
1715		return 0;
1716
1717	switch (buf->l) {
1718	case 2:
1719		ld = ntohs(*ALIGNED_CAST(u_int16_t *)buf->v);
1720		break;
1721	case 4:
1722		ld = ntohl(*ALIGNED_CAST(u_int32_t *)buf->v);
1723		break;
1724	default:
1725		plog(ASL_LEVEL_ERR,
1726			"length %zu of life duration "
1727			"isn't supported.\n", buf->l);
1728		return 0;
1729	}
1730
1731	return ld;
1732}
1733
1734/*%%%*/
1735/*
1736 * check DOI
1737 */
1738static int
1739check_doi(doi)
1740	u_int32_t doi;
1741{
1742	switch (doi) {
1743	case IPSEC_DOI:
1744		return 0;
1745	default:
1746		plog(ASL_LEVEL_ERR,
1747			"invalid value of DOI 0x%08x.\n", doi);
1748		return -1;
1749	}
1750	/* NOT REACHED */
1751}
1752
1753/*
1754 * check situation
1755 */
1756static int
1757check_situation(sit)
1758	u_int32_t sit;
1759{
1760	switch (sit) {
1761	case IPSECDOI_SIT_IDENTITY_ONLY:
1762		return 0;
1763
1764	case IPSECDOI_SIT_SECRECY:
1765	case IPSECDOI_SIT_INTEGRITY:
1766		plog(ASL_LEVEL_ERR,
1767			"situation 0x%08x unsupported yet.\n", sit);
1768		return -1;
1769
1770	default:
1771		plog(ASL_LEVEL_ERR,
1772			"invalid situation 0x%08x.\n", sit);
1773		return -1;
1774	}
1775	/* NOT REACHED */
1776}
1777
1778/*
1779 * check protocol id in main mode
1780 */
1781static int
1782check_prot_main(proto_id)
1783	int proto_id;
1784{
1785	switch (proto_id) {
1786	case IPSECDOI_PROTO_ISAKMP:
1787		return 0;
1788
1789	default:
1790		plog(ASL_LEVEL_ERR,
1791			"Illegal protocol id=%u.\n", proto_id);
1792		return -1;
1793	}
1794	/* NOT REACHED */
1795}
1796
1797/*
1798 * check protocol id in quick mode
1799 */
1800static int
1801check_prot_quick(proto_id)
1802	int proto_id;
1803{
1804	switch (proto_id) {
1805	case IPSECDOI_PROTO_IPSEC_AH:
1806	case IPSECDOI_PROTO_IPSEC_ESP:
1807		return 0;
1808
1809	case IPSECDOI_PROTO_IPCOMP:
1810		return 0;
1811
1812	default:
1813		plog(ASL_LEVEL_ERR,
1814			"invalid protocol id %d.\n", proto_id);
1815		return -1;
1816	}
1817	/* NOT REACHED */
1818}
1819
1820int
1821check_spi_size(proto_id, size)
1822	int proto_id, size;
1823{
1824	switch (proto_id) {
1825	case IPSECDOI_PROTO_ISAKMP:
1826		if (size != 0) {
1827			/* WARNING */
1828			plog(ASL_LEVEL_WARNING,
1829				"SPI size isn't zero, but IKE proposal.\n");
1830		}
1831		return 0;
1832
1833	case IPSECDOI_PROTO_IPSEC_AH:
1834	case IPSECDOI_PROTO_IPSEC_ESP:
1835		if (size != 4) {
1836			plog(ASL_LEVEL_ERR,
1837				"invalid SPI size=%d for IPSEC proposal.\n",
1838				size);
1839			return -1;
1840		}
1841		return 0;
1842
1843	case IPSECDOI_PROTO_IPCOMP:
1844		if (size != 2 && size != 4) {
1845			plog(ASL_LEVEL_ERR,
1846				"invalid SPI size=%d for IPCOMP proposal.\n",
1847				size);
1848			return -1;
1849		}
1850		return 0;
1851
1852	default:
1853		/* ??? */
1854		return -1;
1855	}
1856	/* NOT REACHED */
1857}
1858
1859/*
1860 * check transform ID in ISAKMP.
1861 */
1862static int
1863check_trns_isakmp(t_id)
1864	int t_id;
1865{
1866	switch (t_id) {
1867	case IPSECDOI_KEY_IKE:
1868		return 0;
1869	default:
1870		plog(ASL_LEVEL_ERR,
1871			"invalid transform-id=%u in proto_id=%u.\n",
1872			t_id, IPSECDOI_KEY_IKE);
1873		return -1;
1874	}
1875	/* NOT REACHED */
1876}
1877
1878/*
1879 * check transform ID in AH.
1880 */
1881static int
1882check_trns_ah(t_id)
1883	int t_id;
1884{
1885	switch (t_id) {
1886	case IPSECDOI_AH_MD5:
1887	case IPSECDOI_AH_SHA:
1888	case IPSECDOI_AH_SHA256:
1889	case IPSECDOI_AH_SHA384:
1890	case IPSECDOI_AH_SHA512:
1891		return 0;
1892	case IPSECDOI_AH_DES:
1893		plog(ASL_LEVEL_ERR,
1894			"not support transform-id=%u in AH.\n", t_id);
1895		return -1;
1896	default:
1897		plog(ASL_LEVEL_ERR,
1898			"invalid transform-id=%u in AH.\n", t_id);
1899		return -1;
1900	}
1901	/* NOT REACHED */
1902}
1903
1904/*
1905 * check transform ID in ESP.
1906 */
1907static int
1908check_trns_esp(t_id)
1909	int t_id;
1910{
1911	switch (t_id) {
1912	case IPSECDOI_ESP_DES:
1913	case IPSECDOI_ESP_3DES:
1914	case IPSECDOI_ESP_NULL:
1915	case IPSECDOI_ESP_RC5:
1916	case IPSECDOI_ESP_CAST:
1917	case IPSECDOI_ESP_BLOWFISH:
1918	case IPSECDOI_ESP_AES:
1919	case IPSECDOI_ESP_TWOFISH:
1920		return 0;
1921	case IPSECDOI_ESP_DES_IV32:
1922	case IPSECDOI_ESP_DES_IV64:
1923	case IPSECDOI_ESP_IDEA:
1924	case IPSECDOI_ESP_3IDEA:
1925	case IPSECDOI_ESP_RC4:
1926		plog(ASL_LEVEL_ERR,
1927			"not support transform-id=%u in ESP.\n", t_id);
1928		return -1;
1929	default:
1930		plog(ASL_LEVEL_ERR,
1931			"invalid transform-id=%u in ESP.\n", t_id);
1932		return -1;
1933	}
1934	/* NOT REACHED */
1935}
1936
1937/*
1938 * check transform ID in IPCOMP.
1939 */
1940static int
1941check_trns_ipcomp(t_id)
1942	int t_id;
1943{
1944	switch (t_id) {
1945	case IPSECDOI_IPCOMP_OUI:
1946	case IPSECDOI_IPCOMP_DEFLATE:
1947	case IPSECDOI_IPCOMP_LZS:
1948		return 0;
1949	default:
1950		plog(ASL_LEVEL_ERR,
1951			"invalid transform-id=%u in IPCOMP.\n", t_id);
1952		return -1;
1953	}
1954	/* NOT REACHED */
1955}
1956
1957/*
1958 * check data attributes in IKE.
1959 */
1960static int
1961check_attr_isakmp(trns)
1962	struct isakmp_pl_t *trns;
1963{
1964	struct isakmp_data *d;
1965	int tlen;
1966	int flag, type;
1967	u_int16_t lorv;
1968
1969	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
1970	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
1971
1972	while (tlen > 0) {
1973		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
1974		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
1975		lorv = ntohs(d->lorv);
1976
1977		plog(ASL_LEVEL_DEBUG,
1978			"type=%s, flag=0x%04x, lorv=%s\n",
1979			s_oakley_attr(type), flag,
1980			s_oakley_attr_v(type, lorv));
1981
1982		/*
1983		 * some of the attributes must be encoded in TV.
1984		 * see RFC2409 Appendix A "Attribute Classes".
1985		 */
1986		switch (type) {
1987		case OAKLEY_ATTR_ENC_ALG:
1988		case OAKLEY_ATTR_HASH_ALG:
1989		case OAKLEY_ATTR_AUTH_METHOD:
1990		case OAKLEY_ATTR_GRP_DESC:
1991		case OAKLEY_ATTR_GRP_TYPE:
1992		case OAKLEY_ATTR_SA_LD_TYPE:
1993		case OAKLEY_ATTR_PRF:
1994		case OAKLEY_ATTR_KEY_LEN:
1995		case OAKLEY_ATTR_FIELD_SIZE:
1996			if (!flag) {	/* TLV*/
1997				plog(ASL_LEVEL_ERR,
1998					"oakley attribute %d must be TV.\n",
1999					type);
2000				return -1;
2001			}
2002			break;
2003		}
2004
2005		/* sanity check for TLV.  length must be specified. */
2006		if (!flag && lorv == 0) {	/*TLV*/
2007			plog(ASL_LEVEL_ERR,
2008				"invalid length %d for TLV attribute %d.\n",
2009				lorv, type);
2010			return -1;
2011		}
2012
2013		switch (type) {
2014		case OAKLEY_ATTR_ENC_ALG:
2015			if (!alg_oakley_encdef_ok(lorv)) {
2016				plog(ASL_LEVEL_ERR,
2017					"invalied encryption algorithm=%d.\n",
2018					lorv);
2019				return -1;
2020			}
2021			break;
2022
2023		case OAKLEY_ATTR_HASH_ALG:
2024			if (!alg_oakley_hashdef_ok(lorv)) {
2025				plog(ASL_LEVEL_ERR,
2026					"invalied hash algorithm=%d.\n",
2027					lorv);
2028				return -1;
2029			}
2030			break;
2031
2032		case OAKLEY_ATTR_AUTH_METHOD:
2033			switch (lorv) {
2034			case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
2035			case OAKLEY_ATTR_AUTH_METHOD_RSASIG:
2036#ifdef ENABLE_HYBRID
2037			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I:
2038			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I:
2039#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */
2040			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I:
2041#endif
2042            case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
2043#endif
2044			case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
2045				break;
2046			case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
2047#ifdef ENABLE_HYBRID
2048			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
2049			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
2050			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I:
2051			case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
2052			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I:
2053			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
2054			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I:
2055			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
2056			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I:
2057			case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
2058#endif
2059			case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
2060			case OAKLEY_ATTR_AUTH_METHOD_RSAREV:
2061				plog(ASL_LEVEL_ERR,
2062					"auth method %s isn't supported.\n",
2063					s_oakley_attr_method(lorv));
2064				return -1;
2065			default:
2066				plog(ASL_LEVEL_ERR,
2067					"invalid auth method %d.\n",
2068					lorv);
2069				return -1;
2070			}
2071			break;
2072
2073		case OAKLEY_ATTR_GRP_DESC:
2074			if (!alg_oakley_dhdef_ok(lorv)) {
2075				plog(ASL_LEVEL_ERR,
2076					"invalid DH group %d.\n",
2077					lorv);
2078				return -1;
2079			}
2080			break;
2081
2082		case OAKLEY_ATTR_GRP_TYPE:
2083			switch (lorv) {
2084			case OAKLEY_ATTR_GRP_TYPE_MODP:
2085				break;
2086			default:
2087				plog(ASL_LEVEL_ERR,
2088					"unsupported DH group type %d.\n",
2089					lorv);
2090				return -1;
2091			}
2092			break;
2093
2094		case OAKLEY_ATTR_GRP_PI:
2095		case OAKLEY_ATTR_GRP_GEN_ONE:
2096			/* sanity checks? */
2097			break;
2098
2099		case OAKLEY_ATTR_GRP_GEN_TWO:
2100		case OAKLEY_ATTR_GRP_CURVE_A:
2101		case OAKLEY_ATTR_GRP_CURVE_B:
2102			plog(ASL_LEVEL_ERR,
2103				"attr type=%u isn't supported.\n", type);
2104			return -1;
2105
2106		case OAKLEY_ATTR_SA_LD_TYPE:
2107			switch (lorv) {
2108			case OAKLEY_ATTR_SA_LD_TYPE_SEC:
2109			case OAKLEY_ATTR_SA_LD_TYPE_KB:
2110				break;
2111			default:
2112				plog(ASL_LEVEL_ERR,
2113					"invalid life type %d.\n", lorv);
2114				return -1;
2115			}
2116			break;
2117
2118		case OAKLEY_ATTR_SA_LD:
2119			/* should check the value */
2120			break;
2121
2122		case OAKLEY_ATTR_PRF:
2123		case OAKLEY_ATTR_KEY_LEN:
2124			break;
2125
2126		case OAKLEY_ATTR_FIELD_SIZE:
2127			plog(ASL_LEVEL_ERR,
2128				"attr type=%u isn't supported.\n", type);
2129			return -1;
2130
2131		case OAKLEY_ATTR_GRP_ORDER:
2132			break;
2133
2134		case OAKLEY_ATTR_GSS_ID:
2135			break;
2136
2137		default:
2138			plog(ASL_LEVEL_ERR,
2139				"invalid attribute type %d.\n", type);
2140			return -1;
2141		}
2142
2143		if (flag) {
2144			tlen -= sizeof(*d);
2145			d = (struct isakmp_data *)((char *)d
2146				+ sizeof(*d));
2147		} else {
2148			tlen -= (sizeof(*d) + lorv);
2149			d = (struct isakmp_data *)((char *)d
2150				+ sizeof(*d) + lorv);
2151		}
2152	}
2153
2154	return 0;
2155}
2156
2157/*
2158 * check data attributes in IPSEC AH/ESP.
2159 */
2160static int
2161check_attr_ah(trns)
2162	struct isakmp_pl_t *trns;
2163{
2164	return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_AH, trns);
2165}
2166
2167static int
2168check_attr_esp(trns)
2169	struct isakmp_pl_t *trns;
2170{
2171	return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns);
2172}
2173
2174static int
2175check_attr_ipsec(proto_id, trns)
2176	int proto_id;
2177	struct isakmp_pl_t *trns;
2178{
2179	struct isakmp_data *d;
2180	int tlen;
2181	int flag, type = 0;
2182	u_int16_t lorv;
2183	int attrseen[16];	/* XXX magic number */
2184
2185	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
2186	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
2187	memset(attrseen, 0, sizeof(attrseen));
2188
2189	while (tlen > 0) {
2190		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
2191		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
2192		lorv = ntohs(d->lorv);
2193
2194		plog(ASL_LEVEL_DEBUG,
2195			"type=%s, flag=0x%04x, lorv=%s\n",
2196			s_ipsecdoi_attr(type), flag,
2197			s_ipsecdoi_attr_v(type, lorv));
2198
2199		if (type < sizeof(attrseen)/sizeof(attrseen[0]))
2200			attrseen[type]++;
2201
2202		switch (type) {
2203		case IPSECDOI_ATTR_ENC_MODE:
2204			if (! flag) {
2205				plog(ASL_LEVEL_ERR,
2206					"must be TV when ENC_MODE.\n");
2207				return -1;
2208			}
2209
2210			switch (lorv) {
2211			case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
2212			case IPSECDOI_ATTR_ENC_MODE_TRNS:
2213				break;
2214#ifdef ENABLE_NATT
2215			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
2216			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
2217			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
2218			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
2219				plog(ASL_LEVEL_DEBUG,
2220				     "UDP encapsulation requested\n");
2221				break;
2222#endif
2223			default:
2224				plog(ASL_LEVEL_ERR,
2225					"invalid encryption mode=%u.\n",
2226					lorv);
2227				return -1;
2228			}
2229			break;
2230
2231		case IPSECDOI_ATTR_AUTH:
2232			if (! flag) {
2233				plog(ASL_LEVEL_ERR,
2234					"must be TV when AUTH.\n");
2235				return -1;
2236			}
2237
2238			switch (lorv) {
2239			case IPSECDOI_ATTR_AUTH_HMAC_MD5:
2240				if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
2241				    trns->t_id != IPSECDOI_AH_MD5) {
2242ahmismatch:
2243					plog(ASL_LEVEL_ERR,
2244						"auth algorithm %u conflicts "
2245						"with transform %u.\n",
2246						lorv, trns->t_id);
2247					return -1;
2248				}
2249				break;
2250			case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
2251				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
2252					if (trns->t_id != IPSECDOI_AH_SHA)
2253						goto ahmismatch;
2254				}
2255				break;
2256 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
2257 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
2258 					if (trns->t_id != IPSECDOI_AH_SHA256)
2259 						goto ahmismatch;
2260 				}
2261 				break;
2262 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
2263 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
2264 					if (trns->t_id != IPSECDOI_AH_SHA384)
2265 						goto ahmismatch;
2266 				}
2267 				break;
2268 			case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
2269 				if (proto_id == IPSECDOI_PROTO_IPSEC_AH) {
2270 					if (trns->t_id != IPSECDOI_AH_SHA512)
2271 					goto ahmismatch;
2272 				}
2273 				break;
2274			case IPSECDOI_ATTR_AUTH_DES_MAC:
2275			case IPSECDOI_ATTR_AUTH_KPDK:
2276				plog(ASL_LEVEL_ERR,
2277					"auth algorithm %u isn't supported.\n",
2278					lorv);
2279				return -1;
2280			default:
2281				plog(ASL_LEVEL_ERR,
2282					"invalid auth algorithm=%u.\n",
2283					lorv);
2284				return -1;
2285			}
2286			break;
2287
2288		case IPSECDOI_ATTR_SA_LD_TYPE:
2289			if (! flag) {
2290				plog(ASL_LEVEL_ERR,
2291					"must be TV when LD_TYPE.\n");
2292				return -1;
2293			}
2294
2295			switch (lorv) {
2296			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
2297			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
2298				break;
2299			default:
2300				plog(ASL_LEVEL_ERR,
2301					"invalid life type %d.\n", lorv);
2302				return -1;
2303			}
2304			break;
2305
2306		case IPSECDOI_ATTR_SA_LD:
2307			if (flag) {
2308				/* i.e. ISAKMP_GEN_TV */
2309				plog(ASL_LEVEL_DEBUG,
2310					"life duration was in TLV.\n");
2311			} else {
2312				/* i.e. ISAKMP_GEN_TLV */
2313				if (lorv == 0) {
2314					plog(ASL_LEVEL_ERR,
2315						"invalid length of LD\n");
2316					return -1;
2317				}
2318			}
2319			break;
2320
2321		case IPSECDOI_ATTR_GRP_DESC:
2322			if (! flag) {
2323				plog(ASL_LEVEL_ERR,
2324					"must be TV when GRP_DESC.\n");
2325				return -1;
2326			}
2327
2328			if (!alg_oakley_dhdef_ok(lorv)) {
2329				plog(ASL_LEVEL_ERR,
2330					"invalid group description=%u.\n",
2331					lorv);
2332				return -1;
2333			}
2334			break;
2335
2336		case IPSECDOI_ATTR_KEY_LENGTH:
2337			if (! flag) {
2338				plog(ASL_LEVEL_ERR,
2339					"must be TV when KEY_LENGTH.\n");
2340				return -1;
2341			}
2342			break;
2343
2344		case IPSECDOI_ATTR_KEY_ROUNDS:
2345		case IPSECDOI_ATTR_COMP_DICT_SIZE:
2346		case IPSECDOI_ATTR_COMP_PRIVALG:
2347			plog(ASL_LEVEL_ERR,
2348				"attr type=%u isn't supported.\n", type);
2349			return -1;
2350
2351		default:
2352			plog(ASL_LEVEL_ERR,
2353				"invalid attribute type %d.\n", type);
2354			return -1;
2355		}
2356
2357		if (flag) {
2358			tlen -= sizeof(*d);
2359			d = (struct isakmp_data *)((char *)d
2360				+ sizeof(*d));
2361		} else {
2362			tlen -= (sizeof(*d) + lorv);
2363			d = (struct isakmp_data *)((caddr_t)d
2364				+ sizeof(*d) + lorv);
2365		}
2366	}
2367
2368	if (proto_id == IPSECDOI_PROTO_IPSEC_AH &&
2369	    !attrseen[IPSECDOI_ATTR_AUTH]) {
2370		plog(ASL_LEVEL_ERR,
2371			"attr AUTH must be present for AH.\n");
2372		return -1;
2373	}
2374
2375	if (proto_id == IPSECDOI_PROTO_IPSEC_ESP &&
2376	    trns->t_id == IPSECDOI_ESP_NULL &&
2377	    !attrseen[IPSECDOI_ATTR_AUTH]) {
2378		plog(ASL_LEVEL_ERR,
2379		    "attr AUTH must be present for ESP NULL encryption.\n");
2380		return -1;
2381	}
2382
2383	return 0;
2384}
2385
2386static int
2387check_attr_ipcomp(trns)
2388	struct isakmp_pl_t *trns;
2389{
2390	struct isakmp_data *d;
2391	int tlen;
2392	int flag, type = 0;
2393	u_int16_t lorv;
2394	int attrseen[16];	/* XXX magic number */
2395
2396	tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t);
2397	d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t));
2398	memset(attrseen, 0, sizeof(attrseen));
2399
2400	while (tlen > 0) {
2401		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
2402		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
2403		lorv = ntohs(d->lorv);
2404
2405		plog(ASL_LEVEL_DEBUG,
2406			"type=%d, flag=0x%04x, lorv=0x%04x\n",
2407			type, flag, lorv);
2408
2409		if (type < sizeof(attrseen)/sizeof(attrseen[0]))
2410			attrseen[type]++;
2411
2412		switch (type) {
2413		case IPSECDOI_ATTR_ENC_MODE:
2414			if (! flag) {
2415				plog(ASL_LEVEL_ERR,
2416					"must be TV when ENC_MODE.\n");
2417				return -1;
2418			}
2419
2420			switch (lorv) {
2421			case IPSECDOI_ATTR_ENC_MODE_TUNNEL:
2422			case IPSECDOI_ATTR_ENC_MODE_TRNS:
2423				break;
2424#ifdef ENABLE_NATT
2425			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC:
2426			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC:
2427			case IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT:
2428			case IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT:
2429				plog(ASL_LEVEL_DEBUG,
2430				     "UDP encapsulation requested\n");
2431				break;
2432#endif
2433			default:
2434				plog(ASL_LEVEL_ERR,
2435					"invalid encryption mode=%u.\n",
2436					lorv);
2437				return -1;
2438			}
2439			break;
2440
2441		case IPSECDOI_ATTR_SA_LD_TYPE:
2442			if (! flag) {
2443				plog(ASL_LEVEL_ERR,
2444					"must be TV when LD_TYPE.\n");
2445				return -1;
2446			}
2447
2448			switch (lorv) {
2449			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
2450			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
2451				break;
2452			default:
2453				plog(ASL_LEVEL_ERR,
2454					"invalid life type %d.\n", lorv);
2455				return -1;
2456			}
2457			break;
2458
2459		case IPSECDOI_ATTR_SA_LD:
2460			if (flag) {
2461				/* i.e. ISAKMP_GEN_TV */
2462				plog(ASL_LEVEL_DEBUG,
2463					"life duration was in TLV.\n");
2464			} else {
2465				/* i.e. ISAKMP_GEN_TLV */
2466				if (lorv == 0) {
2467					plog(ASL_LEVEL_ERR,
2468						"invalid length of LD\n");
2469					return -1;
2470				}
2471			}
2472			break;
2473
2474		case IPSECDOI_ATTR_GRP_DESC:
2475			if (! flag) {
2476				plog(ASL_LEVEL_ERR,
2477					"must be TV when GRP_DESC.\n");
2478				return -1;
2479			}
2480
2481			if (!alg_oakley_dhdef_ok(lorv)) {
2482				plog(ASL_LEVEL_ERR,
2483					"invalid group description=%u.\n",
2484					lorv);
2485				return -1;
2486			}
2487			break;
2488
2489		case IPSECDOI_ATTR_AUTH:
2490			plog(ASL_LEVEL_ERR,
2491				"invalid attr type=%u.\n", type);
2492			return -1;
2493
2494		case IPSECDOI_ATTR_KEY_LENGTH:
2495		case IPSECDOI_ATTR_KEY_ROUNDS:
2496		case IPSECDOI_ATTR_COMP_DICT_SIZE:
2497		case IPSECDOI_ATTR_COMP_PRIVALG:
2498			plog(ASL_LEVEL_ERR,
2499				"attr type=%u isn't supported.\n", type);
2500			return -1;
2501
2502		default:
2503			plog(ASL_LEVEL_ERR,
2504				"invalid attribute type %d.\n", type);
2505			return -1;
2506		}
2507
2508		if (flag) {
2509			tlen -= sizeof(*d);
2510			d = (struct isakmp_data *)((char *)d
2511				+ sizeof(*d));
2512		} else {
2513			tlen -= (sizeof(*d) + lorv);
2514			d = (struct isakmp_data *)((caddr_t)d
2515				+ sizeof(*d) + lorv);
2516		}
2517	}
2518
2519#if 0
2520	if (proto_id == IPSECDOI_PROTO_IPCOMP &&
2521	    !attrseen[IPSECDOI_ATTR_AUTH]) {
2522		plog(ASL_LEVEL_ERR,
2523			"attr AUTH must be present for AH.\n", type);
2524		return -1;
2525	}
2526#endif
2527
2528	return 0;
2529}
2530
2531/* %%% */
2532/*
2533 * create phase1 proposal from remote configuration.
2534 * NOT INCLUDING isakmp general header of SA payload
2535 */
2536vchar_t *
2537ipsecdoi_setph1proposal (phase1_handle_t *iph1)
2538{
2539	vchar_t *mysa;
2540	int sablen;
2541
2542    if (!iph1) return NULL;
2543
2544    struct isakmpsa *props = iph1->rmconf->proposal;
2545    unsigned int version = iph1->version;
2546
2547	/* count total size of SA minus isakmp general header */
2548	/* not including isakmp general header of SA payload */
2549	if (version == ISAKMP_VERSION_NUMBER_IKEV1) {
2550		sablen = sizeof(struct ipsecdoi_sa_b);
2551	} else {
2552		sablen = 0;
2553	}
2554	sablen += setph1prop(iph1, NULL);
2555
2556	mysa = vmalloc(sablen);
2557	if (mysa == NULL) {
2558		plog(ASL_LEVEL_ERR,
2559             "failed to allocate my sa buffer\n");
2560		return NULL;
2561	}
2562
2563	/* create SA payload */
2564	if (version == ISAKMP_VERSION_NUMBER_IKEV1) {
2565		/* not including isakmp general header */
2566		(ALIGNED_CAST(struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(props->rmconf->doitype);
2567		(ALIGNED_CAST(struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype);
2568
2569		(void)setph1prop(iph1, mysa->v + sizeof(struct ipsecdoi_sa_b));
2570	} else {
2571		(void)setph1prop(iph1, mysa->v);
2572	}
2573
2574	return mysa;
2575}
2576
2577int
2578setph1prop (phase1_handle_t *iph1,
2579			caddr_t buf)
2580{
2581    struct isakmpsa *props = iph1->rmconf->proposal;
2582    unsigned int version = iph1->version;
2583
2584	struct isakmp_pl_p *prop = NULL;
2585	struct isakmpsa *s = NULL;
2586	int proplen, trnslen;
2587	u_int8_t *np_t; /* pointer next trns type in previous header */
2588	int trns_num;
2589	caddr_t p = buf;
2590	u_int16_t tmplen;
2591    int spi_size = 0;
2592    cookie_t *my_cookie = (iph1->side == INITIATOR) ? &iph1->index.i_ck : &iph1->index.r_ck;
2593
2594
2595	proplen = sizeof(*prop) + spi_size;
2596	if (buf) {
2597		/* create proposal */
2598		prop = (struct isakmp_pl_p *)p;
2599		prop->h.np = ISAKMP_NPTYPE_NONE;
2600		prop->h.reserved = 0;
2601		prop->p_no = props->prop_no;
2602		prop->proto_id = IPSECDOI_PROTO_ISAKMP;
2603        prop->spi_size = spi_size;
2604        p += sizeof(*prop);
2605	}
2606
2607	np_t = NULL;
2608	trns_num = 0;
2609
2610	for (s = props; s != NULL; s = s->next) {
2611        {
2612			if (np_t)
2613				*np_t = ISAKMP_NPTYPE_T;
2614
2615			trnslen = setph1trns(s, p);
2616			proplen += trnslen;
2617			if (buf) {
2618				/* save buffer to pre-next payload */
2619				np_t = &((struct isakmp_pl_t *)p)->h.np;
2620				p += trnslen;
2621
2622				/* count up transform length */
2623				trns_num++;
2624			}
2625		}
2626	}
2627
2628	/* update proposal length */
2629	if (buf) {
2630		prop->h.len = htons(proplen);
2631		prop->num_t = trns_num;
2632	}
2633
2634	return proplen;
2635}
2636
2637static int
2638setph1trns (struct isakmpsa *sa,
2639			caddr_t buf)
2640{
2641	struct isakmp_pl_t *trns = NULL;
2642	int trnslen, attrlen;
2643	caddr_t p = buf;
2644
2645	trnslen = sizeof(*trns);
2646	if (buf) {
2647		/* create transform */
2648		trns = (struct isakmp_pl_t *)p;
2649		trns->h.np  = ISAKMP_NPTYPE_NONE;
2650		trns->t_no  = sa->trns_no;
2651		trns->t_id  = IPSECDOI_KEY_IKE;
2652		p += sizeof(*trns);
2653	}
2654
2655	attrlen = setph1attr(sa, p);
2656	trnslen += attrlen;
2657	if (buf)
2658		p += attrlen;
2659
2660	if (buf)
2661		trns->h.len = htons(trnslen);
2662
2663	return trnslen;
2664}
2665
2666static int
2667setph1attr (struct isakmpsa *sa,
2668			caddr_t buf)
2669{
2670	caddr_t p = buf;
2671	int attrlen = 0;
2672
2673	if (sa->lifetime) {
2674		u_int32_t lifetime = htonl((u_int32_t)sa->lifetime);
2675
2676		attrlen += sizeof(struct isakmp_data)
2677			+ sizeof(struct isakmp_data);
2678		if (sa->lifetime > 0xffff)
2679			attrlen += sizeof(lifetime);
2680		if (buf) {
2681			p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
2682						OAKLEY_ATTR_SA_LD_TYPE_SEC);
2683			if (sa->lifetime > 0xffff) {
2684				p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
2685						(caddr_t)&lifetime,
2686						sizeof(lifetime));
2687			} else {
2688				p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
2689							sa->lifetime);
2690			}
2691		}
2692	}
2693
2694	if (sa->lifebyte) {
2695		u_int32_t lifebyte = htonl((u_int32_t)sa->lifebyte);
2696
2697		attrlen += sizeof(struct isakmp_data)
2698			+ sizeof(struct isakmp_data);
2699		if (sa->lifebyte > 0xffff)
2700			attrlen += sizeof(lifebyte);
2701		if (buf) {
2702			p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE,
2703						OAKLEY_ATTR_SA_LD_TYPE_KB);
2704			if (sa->lifebyte > 0xffff) {
2705				p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD,
2706							(caddr_t)&lifebyte,
2707							sizeof(lifebyte));
2708			} else {
2709				p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD,
2710							sa->lifebyte);
2711			}
2712		}
2713	}
2714
2715	if (sa->enctype) {
2716		attrlen += sizeof(struct isakmp_data);
2717		if (buf)
2718			p = isakmp_set_attr_l(p, OAKLEY_ATTR_ENC_ALG, sa->enctype);
2719	}
2720	if (sa->encklen) {
2721		attrlen += sizeof(struct isakmp_data);
2722		if (buf)
2723			p = isakmp_set_attr_l(p, OAKLEY_ATTR_KEY_LEN, sa->encklen);
2724	}
2725	if (sa->authmethod) {
2726		int authmethod;
2727
2728#ifdef ENABLE_HYBRID
2729		authmethod = switch_authmethod(sa->authmethod);
2730#else
2731		authmethod = sa->authmethod;
2732#endif
2733		attrlen += sizeof(struct isakmp_data);
2734		if (buf)
2735			p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, authmethod);
2736	}
2737	if (sa->hashtype) {
2738		attrlen += sizeof(struct isakmp_data);
2739		if (buf)
2740			p = isakmp_set_attr_l(p, OAKLEY_ATTR_HASH_ALG, sa->hashtype);
2741	}
2742	switch (sa->dh_group) {
2743	case OAKLEY_ATTR_GRP_DESC_MODP768:
2744	case OAKLEY_ATTR_GRP_DESC_MODP1024:
2745	case OAKLEY_ATTR_GRP_DESC_MODP1536:
2746	case OAKLEY_ATTR_GRP_DESC_MODP2048:
2747	case OAKLEY_ATTR_GRP_DESC_MODP3072:
2748	case OAKLEY_ATTR_GRP_DESC_MODP4096:
2749	case OAKLEY_ATTR_GRP_DESC_MODP6144:
2750	case OAKLEY_ATTR_GRP_DESC_MODP8192:
2751		/* don't attach group type for known groups */
2752		attrlen += sizeof(struct isakmp_data);
2753		if (buf) {
2754			p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_DESC,
2755				sa->dh_group);
2756		}
2757		break;
2758	case OAKLEY_ATTR_GRP_DESC_EC2N155:
2759	case OAKLEY_ATTR_GRP_DESC_EC2N185:
2760		/* don't attach group type for known groups */
2761		attrlen += sizeof(struct isakmp_data);
2762		if (buf) {
2763			p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_TYPE,
2764				OAKLEY_ATTR_GRP_TYPE_EC2N);
2765		}
2766		break;
2767	case 0:
2768	default:
2769		break;
2770	}
2771
2772	return attrlen;
2773}
2774
2775static vchar_t *
2776setph2proposal0(iph2, pp, pr)
2777	const phase2_handle_t *iph2;
2778	const struct saprop *pp;
2779	const struct saproto *pr;
2780{
2781	vchar_t *p;
2782	struct isakmp_pl_p *prop;
2783	struct isakmp_pl_t *trns;
2784	struct satrns *tr;
2785	int attrlen;
2786	size_t trnsoff;
2787	caddr_t x0, x;
2788	u_int8_t *np_t; /* pointer next trns type in previous header */
2789	const u_int8_t *spi;
2790
2791	p = vmalloc(sizeof(*prop) + sizeof(pr->spi));
2792	if (p == NULL)
2793		return NULL;
2794
2795	/* create proposal */
2796	prop = (struct isakmp_pl_p *)p->v;
2797	prop->h.np = ISAKMP_NPTYPE_NONE;
2798	prop->p_no = pp->prop_no;
2799	prop->proto_id = pr->proto_id;
2800	prop->num_t = 1;
2801
2802	spi = (const u_int8_t *)&pr->spi;
2803	switch (pr->proto_id) {
2804	case IPSECDOI_PROTO_IPCOMP:
2805		/*
2806		 * draft-shacham-ippcp-rfc2393bis-05.txt:
2807		 * construct 16bit SPI (CPI).
2808		 * XXX we may need to provide a configuration option to
2809		 * generate 32bit SPI.  otherwise we cannot interoeprate
2810		 * with nodes that uses 32bit SPI, in case we are initiator.
2811		 */
2812		prop->spi_size = sizeof(u_int16_t);
2813		spi += sizeof(pr->spi) - sizeof(u_int16_t);
2814		p->l -= sizeof(pr->spi);
2815		p->l += sizeof(u_int16_t);
2816		break;
2817	default:
2818		prop->spi_size = sizeof(pr->spi);
2819		break;
2820	}
2821	memcpy(prop + 1, spi, prop->spi_size);
2822
2823	/* create transform */
2824	trnsoff = sizeof(*prop) + prop->spi_size;
2825	np_t = NULL;
2826
2827	for (tr = pr->head; tr; tr = tr->next) {
2828
2829		switch (pr->proto_id) {
2830		case IPSECDOI_PROTO_IPSEC_ESP:
2831			/*
2832			 * don't build a null encryption
2833			 * with no authentication transform.
2834			 */
2835			if (tr->trns_id == IPSECDOI_ESP_NULL &&
2836			    tr->authtype == IPSECDOI_ATTR_AUTH_NONE)
2837				continue;
2838			break;
2839		}
2840
2841		if (np_t) {
2842			*np_t = ISAKMP_NPTYPE_T;
2843			prop->num_t++;
2844		}
2845
2846		/* get attribute length */
2847		attrlen = 0;
2848		if (pp->lifetime) {
2849			attrlen += sizeof(struct isakmp_data)
2850				+ sizeof(struct isakmp_data);
2851			if (pp->lifetime > 0xffff)
2852				attrlen += sizeof(u_int32_t);
2853		}
2854		if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
2855			attrlen += sizeof(struct isakmp_data)
2856				+ sizeof(struct isakmp_data);
2857			if (pp->lifebyte > 0xffff)
2858				attrlen += sizeof(u_int32_t);
2859		}
2860		attrlen += sizeof(struct isakmp_data);	/* enc mode */
2861		if (tr->encklen)
2862			attrlen += sizeof(struct isakmp_data);
2863
2864		switch (pr->proto_id) {
2865		case IPSECDOI_PROTO_IPSEC_ESP:
2866			/* non authentication mode ? */
2867			if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
2868				attrlen += sizeof(struct isakmp_data);
2869			break;
2870		case IPSECDOI_PROTO_IPSEC_AH:
2871			if (tr->authtype == IPSECDOI_ATTR_AUTH_NONE) {
2872				plog(ASL_LEVEL_ERR,
2873					"no authentication algorithm found "
2874					"but protocol is AH.\n");
2875				vfree(p);
2876				return NULL;
2877			}
2878			attrlen += sizeof(struct isakmp_data);
2879			break;
2880		case IPSECDOI_PROTO_IPCOMP:
2881			break;
2882		default:
2883			plog(ASL_LEVEL_ERR,
2884				"invalid protocol: %d\n", pr->proto_id);
2885			vfree(p);
2886			return NULL;
2887		}
2888
2889		if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
2890			attrlen += sizeof(struct isakmp_data);
2891
2892		p = vrealloc(p, p->l + sizeof(*trns) + attrlen);
2893		if (p == NULL)
2894			return NULL;
2895		prop = (struct isakmp_pl_p *)p->v;
2896
2897		/* set transform's values */
2898		trns = (struct isakmp_pl_t *)(p->v + trnsoff);
2899		trns->h.np  = ISAKMP_NPTYPE_NONE;
2900		trns->t_no  = tr->trns_no;
2901		trns->t_id  = tr->trns_id;
2902
2903		/* set attributes */
2904		x = x0 = p->v + trnsoff + sizeof(*trns);
2905
2906		if (pp->lifetime) {
2907			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
2908						IPSECDOI_ATTR_SA_LD_TYPE_SEC);
2909			if (pp->lifetime > 0xffff) {
2910				u_int32_t v = htonl((u_int32_t)pp->lifetime);
2911				x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
2912							(caddr_t)&v, sizeof(v));
2913			} else {
2914				x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
2915							pp->lifetime);
2916			}
2917		}
2918
2919		if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) {
2920			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE,
2921						IPSECDOI_ATTR_SA_LD_TYPE_KB);
2922			if (pp->lifebyte > 0xffff) {
2923				u_int32_t v = htonl((u_int32_t)pp->lifebyte);
2924				x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD,
2925							(caddr_t)&v, sizeof(v));
2926			} else {
2927				x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD,
2928							pp->lifebyte);
2929			}
2930		}
2931
2932		x = isakmp_set_attr_l(x, IPSECDOI_ATTR_ENC_MODE, pr->encmode);
2933
2934		if (tr->encklen)
2935			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_KEY_LENGTH, tr->encklen);
2936
2937		/* mandatory check has done above. */
2938		if ((pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP && tr->authtype != IPSECDOI_ATTR_AUTH_NONE)
2939		 || pr->proto_id == IPSECDOI_PROTO_IPSEC_AH)
2940			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_AUTH, tr->authtype);
2941
2942		if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group))
2943			x = isakmp_set_attr_l(x, IPSECDOI_ATTR_GRP_DESC,
2944				iph2->sainfo->pfs_group);
2945
2946		/* update length of this transform. */
2947		trns = (struct isakmp_pl_t *)(p->v + trnsoff);
2948		trns->h.len = htons(sizeof(*trns) + attrlen);
2949
2950		/* save buffer to pre-next payload */
2951		np_t = &trns->h.np;
2952
2953		trnsoff += (sizeof(*trns) + attrlen);
2954	}
2955
2956	if (np_t == NULL) {
2957		plog(ASL_LEVEL_ERR,
2958			"no suitable proposal was created.\n");
2959		return NULL;
2960	}
2961
2962	/* update length of this protocol. */
2963	prop->h.len = htons(p->l);
2964
2965	return p;
2966}
2967
2968
2969/*
2970 * create phase2 proposal from policy configuration.
2971 * NOT INCLUDING isakmp general header of SA payload.
2972 * This function is called by initiator only.
2973 */
2974int
2975ipsecdoi_setph2proposal(phase2_handle_t *iph2, int return_sa)
2976{
2977	struct saprop *proposal, *a;
2978	struct saproto *b = NULL;
2979	vchar_t *q, *sa = NULL;
2980	struct isakmp_pl_p *prop;
2981	size_t propoff;	/* for previous field of type of next payload. */
2982
2983    if (return_sa)
2984        proposal = iph2->approval;
2985    else
2986        proposal = iph2->proposal;
2987
2988	if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) {
2989		struct ipsecdoi_sa_b *sab;
2990
2991		sa = vmalloc(sizeof(*sab));
2992		if (sa == NULL) {
2993			plog(ASL_LEVEL_ERR,
2994				 "failed to allocate my sa buffer\n");
2995			return -1;
2996		}
2997
2998		/* create SA payload */
2999		sab = ALIGNED_CAST(struct ipsecdoi_sa_b *)sa->v;
3000		sab->doi = htonl(IPSEC_DOI);
3001		sab->sit = htonl(IPSECDOI_SIT_IDENTITY_ONLY);	/* XXX configurable ? */
3002
3003	}
3004
3005	prop = NULL;
3006	propoff = 0;
3007	for (a = proposal; a; a = a->next) {
3008		for (b = a->head; b; b = b->next) {
3009            if (b->proto_id == IPSECDOI_PROTO_IPCOMP) {
3010                // %%%%% todo - IKEv2 uses ipcomp notification
3011                // skip this - not specified in the SA
3012                // Need to set this in iph2 ???
3013                continue;
3014            }
3015            // IKEv1 sends encode mode in SA - uses diferent codes when NATT being used
3016            // IKEv2 does not send encode mode in SA
3017#ifdef ENABLE_NATT
3018            if (iph2->ph1->natt_flags & NAT_DETECTED) {
3019                plog (ASL_LEVEL_INFO, "NAT detected -> UDP encapsulation\n");
3020                b->udp_encap = 1;
3021                if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) {
3022                    int udp_diff = iph2->ph1->natt_options->mode_udp_diff;
3023                    /* Tunnel -> UDP-Tunnel, Transport -> UDP_Transport */
3024                    b->encmode += udp_diff;
3025                }
3026            }
3027#endif
3028            switch (iph2->version) {
3029                case ISAKMP_VERSION_NUMBER_IKEV1:
3030                    q = setph2proposal0(iph2, a, b);
3031                    break;
3032                default:
3033                    plog(ASL_LEVEL_ERR, "Invalid IKE version detected\n");
3034                    q = NULL;
3035                    break;
3036            }
3037			if (q == NULL) {
3038				VPTRINIT(sa);
3039				return -1;
3040			}
3041            if (sa != NULL)
3042                sa = vrealloc(sa, sa->l + q->l);
3043            else
3044                sa = vmalloc(q->l);
3045
3046			if (sa == NULL) {
3047				plog(ASL_LEVEL_ERR,
3048					"failed to allocate my sa buffer\n");
3049				if (q)
3050					vfree(q);
3051				return -1;
3052			}
3053			memcpy(sa->v + sa->l - q->l, q->v, q->l);
3054			if (propoff != 0) {
3055				prop = (struct isakmp_pl_p *)(sa->v +
3056					propoff);
3057                if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1)
3058                    prop->h.np = ISAKMP_NPTYPE_P;
3059			}
3060			propoff = sa->l - q->l;
3061
3062			vfree(q);
3063		}
3064	}
3065    if (return_sa)
3066        iph2->sa_ret = sa;
3067    else
3068        iph2->sa = sa;
3069	return 0;
3070}
3071
3072/*
3073 * return 1 if all of the given protocols are tunnel mode.
3074 */
3075int
3076ipsecdoi_tunnelmode(iph2)
3077	phase2_handle_t *iph2;
3078{
3079	struct saprop *pp;
3080	struct saproto *pr = NULL;
3081
3082	for (pp = iph2->proposal; pp; pp = pp->next) {
3083		for (pr = pp->head; pr; pr = pr->next) {
3084			if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TUNNEL &&
3085				pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_RFC &&
3086				pr->encmode != IPSECDOI_ATTR_ENC_MODE_UDPTUNNEL_DRAFT)
3087				return 0;
3088		}
3089	}
3090
3091	return 1;
3092}
3093
3094/*
3095 * return 1 if any of the given protocols are transport mode.
3096 */
3097int
3098ipsecdoi_any_transportmode(pp)
3099struct saprop *pp;
3100{
3101	struct saproto *pr = NULL;
3102
3103	for (; pp; pp = pp->next) {
3104		for (pr = pp->head; pr; pr = pr->next) {
3105			if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TRNS ||
3106				pr->encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC ||
3107				pr->encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT)
3108				return 1;
3109		}
3110	}
3111
3112	return 0;
3113}
3114
3115/*
3116 * return 1 if all of the given protocols are transport mode.
3117 */
3118int
3119ipsecdoi_transportmode(pp)
3120	struct saprop *pp;
3121{
3122	struct saproto *pr = NULL;
3123
3124	for (; pp; pp = pp->next) {
3125		for (pr = pp->head; pr; pr = pr->next) {
3126			if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS)
3127				return 0;
3128		}
3129	}
3130
3131	return 1;
3132}
3133
3134int
3135ipsecdoi_get_defaultlifetime()
3136{
3137	return IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
3138}
3139
3140int
3141ipsecdoi_checkalgtypes(proto_id, enc, auth, comp)
3142	int proto_id, enc, auth, comp;
3143{
3144#define TMPALGTYPE2STR(n) s_algtype(algclass_ipsec_##n, n)
3145	switch (proto_id) {
3146	case IPSECDOI_PROTO_IPSEC_ESP:
3147		if (enc == 0 || comp != 0) {
3148			plog(ASL_LEVEL_ERR,
3149				"illegal algorithm defined "
3150				"ESP enc=%s auth=%s comp=%s.\n",
3151				TMPALGTYPE2STR(enc),
3152				TMPALGTYPE2STR(auth),
3153				TMPALGTYPE2STR(comp));
3154			return -1;
3155		}
3156		break;
3157	case IPSECDOI_PROTO_IPSEC_AH:
3158		if (enc != 0 || auth == 0 || comp != 0) {
3159			plog(ASL_LEVEL_ERR,
3160				"illegal algorithm defined "
3161				"AH enc=%s auth=%s comp=%s.\n",
3162				TMPALGTYPE2STR(enc),
3163				TMPALGTYPE2STR(auth),
3164				TMPALGTYPE2STR(comp));
3165			return -1;
3166		}
3167		break;
3168	case IPSECDOI_PROTO_IPCOMP:
3169		if (enc != 0 || auth != 0 || comp == 0) {
3170			plog(ASL_LEVEL_ERR,
3171				"illegal algorithm defined "
3172				"IPcomp enc=%s auth=%s comp=%s.\n",
3173				TMPALGTYPE2STR(enc),
3174				TMPALGTYPE2STR(auth),
3175				TMPALGTYPE2STR(comp));
3176			return -1;
3177		}
3178		break;
3179	default:
3180		plog(ASL_LEVEL_ERR,
3181			"invalid ipsec protocol %d\n", proto_id);
3182		return -1;
3183	}
3184#undef TMPALGTYPE2STR
3185	return 0;
3186}
3187
3188int
3189ipproto2doi(proto)
3190	int proto;
3191{
3192	switch (proto) {
3193	case IPPROTO_AH:
3194		return IPSECDOI_PROTO_IPSEC_AH;
3195	case IPPROTO_ESP:
3196		return IPSECDOI_PROTO_IPSEC_ESP;
3197	case IPPROTO_IPCOMP:
3198		return IPSECDOI_PROTO_IPCOMP;
3199	}
3200	return -1;	/* XXX */
3201}
3202
3203int
3204doi2ipproto(proto)
3205	int proto;
3206{
3207	switch (proto) {
3208	case IPSECDOI_PROTO_IPSEC_AH:
3209		return IPPROTO_AH;
3210	case IPSECDOI_PROTO_IPSEC_ESP:
3211		return IPPROTO_ESP;
3212	case IPSECDOI_PROTO_IPCOMP:
3213		return IPPROTO_IPCOMP;
3214	}
3215	return -1;	/* XXX */
3216}
3217
3218/*
3219 * Check if a subnet id is valid for comparison
3220 * with an address id ( address length mask )
3221 * and compare them
3222 * Return value
3223 * =  0 for match
3224 * =  1 for mismatch
3225 */
3226
3227int
3228ipsecdoi_subnetisaddr_v4( subnet, address )
3229	const vchar_t *subnet;
3230	const vchar_t *address;
3231{
3232	struct in_addr *mask;
3233
3234	if (address->l != sizeof(struct in_addr))
3235		return 1;
3236
3237	if (subnet->l != (sizeof(struct in_addr)*2))
3238		return 1;
3239
3240	mask = ALIGNED_CAST(struct in_addr*)(subnet->v + sizeof(struct in_addr));
3241
3242	if (mask->s_addr!=0xffffffff)
3243		return 1;
3244
3245	return memcmp(subnet->v,address->v,address->l);
3246}
3247
3248#ifdef INET6
3249
3250int
3251ipsecdoi_subnetisaddr_v6( subnet, address )
3252	const vchar_t *subnet;
3253	const vchar_t *address;
3254{
3255	struct in6_addr *mask;
3256	int i;
3257
3258	if (address->l != sizeof(struct in6_addr))
3259		return 1;
3260
3261	if (subnet->l != (sizeof(struct in6_addr)*2))
3262		return 1;
3263
3264	mask = ALIGNED_CAST(struct in6_addr*)(subnet->v + sizeof(struct in6_addr));
3265
3266	for (i=0; i<16; i++)
3267		if(mask->s6_addr[i]!=0xff)
3268			return 1;
3269
3270	return memcmp(subnet->v,address->v,address->l);
3271}
3272
3273#endif
3274
3275#ifdef NOT_USED
3276/*
3277 * Check and Compare two IDs
3278 * - specify 0 for exact if wildcards are allowed
3279 * Return value
3280 * =  0 for match
3281 * =  1 for misatch
3282 * = -1 for integrity error
3283 */
3284
3285int
3286ipsecdoi_chkcmpids( idt, ids, exact )
3287	const vchar_t *idt; /* id cmp target */
3288	const vchar_t *ids; /* id cmp source */
3289	int exact;
3290{
3291	struct ipsecdoi_id_b *id_bt;
3292	struct ipsecdoi_id_b *id_bs;
3293	vchar_t ident_t;
3294	vchar_t ident_s;
3295	int result;
3296
3297	/* handle wildcard IDs */
3298
3299	if (idt == NULL || ids == NULL)
3300	{
3301		if( !exact )
3302		{
3303			plog(ASL_LEVEL_DEBUG,
3304				"check and compare ids : values matched (ANONYMOUS)\n" );
3305			return 0;
3306		}
3307		else
3308		{
3309			plog(ASL_LEVEL_DEBUG,
3310				"check and compare ids : value mismatch (ANONYMOUS)\n" );
3311			return -1;
3312		}
3313	}
3314
3315	/* make sure the ids are of the same type */
3316
3317	id_bt = (struct ipsecdoi_id_b *) idt->v;
3318	id_bs = (struct ipsecdoi_id_b *) ids->v;
3319
3320	ident_t.v = idt->v + sizeof(*id_bt);
3321	ident_t.l = idt->l - sizeof(*id_bt);
3322	ident_s.v = ids->v + sizeof(*id_bs);
3323	ident_s.l = ids->l - sizeof(*id_bs);
3324
3325	if (id_bs->type != id_bt->type)
3326	{
3327		/*
3328		 * special exception for comparing
3329                 * address to subnet id types when
3330                 * the netmask is address length
3331                 */
3332
3333		if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR)&&
3334		    (id_bt->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)) {
3335			result = ipsecdoi_subnetisaddr_v4(&ident_t,&ident_s);
3336			goto cmpid_result;
3337		}
3338
3339		if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)&&
3340		    (id_bt->type == IPSECDOI_ID_IPV4_ADDR)) {
3341			result = ipsecdoi_subnetisaddr_v4(&ident_s,&ident_t);
3342			goto cmpid_result;
3343		}
3344
3345#ifdef INET6
3346		if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR)&&
3347		    (id_bt->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
3348			result = ipsecdoi_subnetisaddr_v6(&ident_t,&ident_s);
3349			goto cmpid_result;
3350		}
3351
3352		if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)&&
3353		    (id_bt->type == IPSECDOI_ID_IPV6_ADDR)) {
3354			result = ipsecdoi_subnetisaddr_v6(&ident_s,&ident_t);
3355			goto cmpid_result;
3356		}
3357#endif
3358		plog(ASL_LEVEL_DEBUG,
3359			"check and compare ids : id type mismatch %s != %s\n",
3360			s_ipsecdoi_ident(id_bs->type),
3361			s_ipsecdoi_ident(id_bt->type));
3362
3363		return 1;
3364	}
3365
3366	if(id_bs->proto_id != id_bt->proto_id){
3367		plog(ASL_LEVEL_DEBUG,
3368			"check and compare ids : proto_id mismatch %d != %d\n",
3369			id_bs->proto_id, id_bt->proto_id);
3370
3371		return 1;
3372	}
3373
3374	/* compare the ID data. */
3375
3376	switch (id_bt->type) {
3377	        case IPSECDOI_ID_DER_ASN1_DN:
3378        	case IPSECDOI_ID_DER_ASN1_GN:
3379			/* compare asn1 ids */
3380			result = eay_cmp_asn1dn(&ident_t, &ident_s);
3381			goto cmpid_result;
3382
3383		case IPSECDOI_ID_IPV4_ADDR:
3384			/* validate lengths */
3385			if ((ident_t.l != sizeof(struct in_addr))||
3386			    (ident_s.l != sizeof(struct in_addr)))
3387				goto cmpid_invalid;
3388			break;
3389
3390		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
3391		case IPSECDOI_ID_IPV4_ADDR_RANGE:
3392			/* validate lengths */
3393			if ((ident_t.l != (sizeof(struct in_addr)*2))||
3394			    (ident_s.l != (sizeof(struct in_addr)*2)))
3395				goto cmpid_invalid;
3396			break;
3397
3398#ifdef INET6
3399		case IPSECDOI_ID_IPV6_ADDR:
3400			/* validate lengths */
3401			if ((ident_t.l != sizeof(struct in6_addr))||
3402			    (ident_s.l != sizeof(struct in6_addr)))
3403				goto cmpid_invalid;
3404			break;
3405
3406		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
3407		case IPSECDOI_ID_IPV6_ADDR_RANGE:
3408			/* validate lengths */
3409			if ((ident_t.l != (sizeof(struct in6_addr)*2))||
3410			    (ident_s.l != (sizeof(struct in6_addr)*2)))
3411				goto cmpid_invalid;
3412			break;
3413#endif
3414		case IPSECDOI_ID_FQDN:
3415		case IPSECDOI_ID_USER_FQDN:
3416		case IPSECDOI_ID_KEY_ID:
3417			break;
3418
3419		default:
3420			plog(ASL_LEVEL_ERR,
3421				"Unhandled id type %i specified for comparison\n",
3422				id_bt->type);
3423			return -1;
3424	}
3425
3426	/* validate matching data and length */
3427	if (ident_t.l == ident_s.l)
3428		result = memcmp(ident_t.v,ident_s.v,ident_t.l);
3429	else
3430		result = 1;
3431
3432cmpid_result:
3433
3434	/* debug level output */
3435	if(loglevel >= ASL_LEVEL_DEBUG) {
3436		char *idstrt = ipsecdoi_id2str(idt);
3437		char *idstrs = ipsecdoi_id2str(ids);
3438
3439		if (!result)
3440	 		plog(ASL_LEVEL_DEBUG,
3441				"check and compare ids : values matched (%s)\n",
3442				 s_ipsecdoi_ident(id_bs->type) );
3443		else
3444 			plog(ASL_LEVEL_DEBUG,
3445				"check and compare ids : value mismatch (%s)\n",
3446				 s_ipsecdoi_ident(id_bs->type));
3447
3448		plog(ASL_LEVEL_DEBUG, "cmpid target: \'%s\'\n", idstrt );
3449		plog(ASL_LEVEL_DEBUG, "cmpid source: \'%s\'\n", idstrs );
3450
3451		racoon_free(idstrs);
3452		racoon_free(idstrt);
3453	}
3454
3455	/* return result */
3456	if( !result )
3457		return 0;
3458	else
3459		return 1;
3460
3461cmpid_invalid:
3462
3463	/* id integrity error */
3464	plog(ASL_LEVEL_DEBUG, "check and compare ids : %s integrity error\n",
3465		s_ipsecdoi_ident(id_bs->type));
3466	plog(ASL_LEVEL_DEBUG, "cmpid target: length = \'%zu\'\n", ident_t.l );
3467	plog(ASL_LEVEL_DEBUG, "cmpid source: length = \'%zu\'\n", ident_s.l );
3468
3469	return -1;
3470}
3471#endif
3472
3473/*
3474 * check the following:
3475 * - In main mode with pre-shared key, only address type can be used.
3476 * - if proper type for phase 1 ?
3477 * - if phase 1 ID payload conformed RFC2407 4.6.2.
3478 *   (proto, port) must be (0, 0), (udp, 500) or (udp, [specified]).
3479 * - if ID payload sent from peer is equal to the ID expected by me.
3480 *
3481 * both of "id" and "id_p" should be ID payload without general header,
3482 */
3483int
3484ipsecdoi_checkid1(iph1)
3485	phase1_handle_t *iph1;
3486{
3487	struct ipsecdoi_id_b *id_b;
3488	struct sockaddr_storage *sa;
3489	caddr_t sa1, sa2;
3490
3491	if (iph1->id_p == NULL) {
3492		plog(ASL_LEVEL_ERR,
3493			"invalid iph1 passed id_p == NULL\n");
3494		return ISAKMP_INTERNAL_ERROR;
3495	}
3496	if (iph1->id_p->l < sizeof(*id_b)) {
3497		plog(ASL_LEVEL_ERR,
3498			"invalid value passed as \"ident\" (len=%lu)\n",
3499			(u_long)iph1->id_p->l);
3500		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
3501	}
3502
3503	id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)iph1->id_p->v;
3504
3505	/* 	In main mode with pre-shared key, only address type can be used.
3506	 *	If NAT Traversal being used and peer is behind nat and
3507	 *	natt version = 02 - allow non-address ID type.
3508	 */
3509	if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1
3510	 && iph1->etype == ISAKMP_ETYPE_IDENT
3511	 && iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY
3512#ifdef ENABLE_NATT
3513	 && (iph1->natt_flags & NAT_DETECTED_PEER) == 0
3514#endif
3515		) {
3516		 if (id_b->type != IPSECDOI_ID_IPV4_ADDR
3517		  && id_b->type != IPSECDOI_ID_IPV6_ADDR) {
3518			plog(ASL_LEVEL_ERR,
3519				"Expecting IP address type in main mode, "
3520				"but %s.\n", s_ipsecdoi_ident(id_b->type));
3521			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
3522		}
3523	}
3524
3525	/* if proper type for phase 1 ? */
3526	switch (id_b->type) {
3527	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
3528	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
3529	case IPSECDOI_ID_IPV4_ADDR_RANGE:
3530	case IPSECDOI_ID_IPV6_ADDR_RANGE:
3531		plog(ASL_LEVEL_WARNING,
3532			"such ID type %s is not proper.\n",
3533			s_ipsecdoi_ident(id_b->type));
3534		/*FALLTHROUGH*/
3535	}
3536
3537	/* if phase 1 ID payload conformed RFC2407 4.6.2. */
3538	if (id_b->type == IPSECDOI_ID_IPV4_ADDR ||
3539	    id_b->type == IPSECDOI_ID_IPV6_ADDR) {
3540
3541		if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) {
3542			plog(ASL_LEVEL_WARNING,
3543				"protocol ID and Port mismatched. "
3544				"proto_id:%d port:%d\n",
3545				id_b->proto_id, ntohs(id_b->port));
3546			/*FALLTHROUGH*/
3547
3548		} else if (id_b->proto_id == IPPROTO_UDP) {
3549			/*
3550			 * copmaring with expected port.
3551			 * always permit if port is equal to PORT_ISAKMP
3552			 */
3553			if (ntohs(id_b->port) != PORT_ISAKMP) {
3554
3555				u_int16_t port;
3556
3557				switch (iph1->remote->ss_family) {
3558				case AF_INET:
3559					port = ((struct sockaddr_in *)iph1->remote)->sin_port;
3560					break;
3561#ifdef INET6
3562				case AF_INET6:
3563					port = ((struct sockaddr_in6 *)iph1->remote)->sin6_port;
3564					break;
3565#endif
3566				default:
3567					plog(ASL_LEVEL_ERR,
3568						"invalid family: %d\n",
3569						iph1->remote->ss_family);
3570					return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
3571				}
3572				if (ntohs(id_b->port) != port) {
3573					plog(ASL_LEVEL_WARNING,
3574						"port %d expected, but %d\n",
3575						port, ntohs(id_b->port));
3576					/*FALLTHROUGH*/
3577				}
3578			}
3579		}
3580	}
3581
3582	/* compare with the ID if specified. */
3583	if (genlist_next(iph1->rmconf->idvl_p, 0)) {
3584		vchar_t *ident0 = NULL;
3585#ifdef HAVE_OPENSSL
3586		vchar_t ident;
3587#endif
3588		struct idspec *id;
3589		struct genlist_entry *gpb;
3590
3591		for (id = genlist_next (iph1->rmconf->idvl_p, &gpb); id; id = genlist_next (0, &gpb)) {
3592			/* check the type of both IDs */
3593			if (id->idtype != doi2idtype(id_b->type))
3594				continue;  /* ID type mismatch */
3595			if (id->id == 0)
3596				goto matched;
3597
3598			/* compare defined ID with the ID sent by peer. */
3599			if (ident0 != NULL)
3600				vfree(ident0);
3601			ident0 = getidval(id->idtype, id->id);
3602
3603			switch (id->idtype) {
3604			case IDTYPE_ASN1DN:
3605#ifdef HAVE_OPENSSL
3606				ident.v = iph1->id_p->v + sizeof(*id_b);
3607				ident.l = iph1->id_p->l - sizeof(*id_b);
3608				if (eay_cmp_asn1dn(ident0, &ident) == 0)
3609					goto matched;
3610#else
3611					plog(ASL_LEVEL_WARNING, "ASN1DN ID matching not implemented - passed.\n");
3612					goto matched;	//%%%%%% hack for now until we have code to do this.
3613#endif
3614				break;
3615			case IDTYPE_ADDRESS:
3616				sa = ALIGNED_CAST(struct sockaddr_storage *)ident0->v;
3617				sa2 = (caddr_t)(id_b + 1);
3618				switch (sa->ss_family) {
3619				case AF_INET:
3620					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in_addr))
3621						continue;  /* ID value mismatch */
3622					sa1 = (caddr_t)&((struct sockaddr_in *)sa)->sin_addr;
3623					if (memcmp(sa1, sa2, sizeof(struct in_addr)) == 0)
3624						goto matched;
3625					break;
3626#ifdef INET6
3627				case AF_INET6:
3628					if (iph1->id_p->l - sizeof(*id_b) != sizeof(struct in6_addr))
3629						continue;  /* ID value mismatch */
3630					sa1 = (caddr_t)&((struct sockaddr_in6 *)sa)->sin6_addr;
3631					if (memcmp(sa1, sa2, sizeof(struct in6_addr)) == 0)
3632						goto matched;
3633					break;
3634#endif
3635				default:
3636					break;
3637				}
3638				break;
3639			default:
3640				if (memcmp(ident0->v, id_b + 1, ident0->l) == 0)
3641					goto matched;
3642				break;
3643			}
3644		}
3645		if (ident0 != NULL) {
3646			vfree(ident0);
3647			ident0 = NULL;
3648		}
3649		plog(ASL_LEVEL_DEBUG, "No ID match.\n");
3650		if (iph1->rmconf->verify_identifier)
3651			return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
3652matched: /* ID value match */
3653		if (ident0 != NULL)
3654			vfree(ident0);
3655	}
3656
3657	return 0;
3658}
3659
3660/* HACK!!! - temporary until this prototype gets moved */
3661extern CFDataRef SecCertificateCopySubjectSequence( SecCertificateRef certificate);
3662
3663/*
3664 * create ID payload for phase 1 and set into iph1->id.
3665 * NOT INCLUDING isakmp general header.
3666 * see, RFC2407 4.6.2.1
3667 */
3668int
3669ipsecdoi_setid1(iph1)
3670	phase1_handle_t *iph1;
3671{
3672	vchar_t *ret = NULL;
3673	struct ipsecdoi_id_b id_b;
3674	vchar_t *ident = NULL;
3675	struct sockaddr_storage *ipid = NULL;
3676
3677	/* init */
3678    bzero(&id_b, sizeof(id_b));
3679	ident = NULL;
3680	switch (iph1->rmconf->idvtype) {
3681	case IDTYPE_FQDN:
3682		id_b.type = IPSECDOI_ID_FQDN;
3683		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
3684		break;
3685	case IDTYPE_USERFQDN:
3686		id_b.type = IPSECDOI_ID_USER_FQDN;
3687		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
3688		break;
3689	case IDTYPE_KEYID:
3690	case IDTYPE_KEYIDUSE:
3691		id_b.type = IPSECDOI_ID_KEY_ID;
3692		ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv);
3693		break;
3694	case IDTYPE_ASN1DN:
3695		id_b.type = IPSECDOI_ID_DER_ASN1_DN;
3696		if (iph1->rmconf->idv) {
3697			/* XXX it must be encoded to asn1dn. */
3698			ident = vdup(iph1->rmconf->idv);
3699		} else {
3700			if (oakley_getmycert(iph1) < 0) {
3701				plog(ASL_LEVEL_ERR,
3702					"failed to get own CERT.\n");
3703				goto err;
3704			}
3705
3706            SecCertificateRef certificate;
3707            CFDataRef subject;
3708            UInt8* namePtr;
3709            int len;
3710
3711            certificate = crypto_cssm_x509cert_CreateSecCertificateRef(&iph1->cert->cert);
3712            if (certificate == NULL) {
3713                plog(ASL_LEVEL_ERR,
3714                     "failed to get SecCertificateRef\n");
3715                break;
3716            }
3717            subject = crypto_cssm_CopySubjectSequence(certificate);
3718            if (subject == NULL) {
3719                plog(ASL_LEVEL_ERR,
3720                     "failed to get subjectName\n");
3721                CFRelease(certificate);
3722                break;
3723            }
3724            len = CFDataGetLength(subject);
3725            namePtr = (UInt8*)CFDataGetBytePtr(subject);
3726            ident = vmalloc(len);
3727            if (ident == NULL) {
3728                plog(ASL_LEVEL_ERR,
3729                     "failed to get subjectName\n");
3730                CFRelease(certificate);
3731                CFRelease(subject);
3732                break;
3733            }
3734            memcpy(ident->v, namePtr, len);
3735            CFRelease(certificate);
3736            CFRelease(subject);
3737		}
3738		break;
3739	case IDTYPE_ADDRESS:
3740		/*
3741		 * if the value of the id type was set by the configuration
3742		 * file, then use it.  otherwise the value is get from local
3743		 * ip address by using ike negotiation.
3744		 */
3745		if (iph1->rmconf->idv)
3746			ipid = ALIGNED_CAST(struct sockaddr_storage *)iph1->rmconf->idv->v;
3747		/*FALLTHROUGH*/
3748	default:
3749	    {
3750		int l;
3751		caddr_t p;
3752
3753		if (ipid == NULL)
3754			ipid = iph1->local;
3755
3756		/* use IP address */
3757		switch (ipid->ss_family) {
3758		case AF_INET:
3759			id_b.type = IPSECDOI_ID_IPV4_ADDR;
3760			l = sizeof(struct in_addr);
3761			p = (caddr_t)&((struct sockaddr_in *)ipid)->sin_addr;
3762			break;
3763#ifdef INET6
3764		case AF_INET6:
3765			id_b.type = IPSECDOI_ID_IPV6_ADDR;
3766			l = sizeof(struct in6_addr);
3767			p = (caddr_t)&((struct sockaddr_in6 *)ipid)->sin6_addr;
3768			break;
3769#endif
3770		default:
3771			plog(ASL_LEVEL_ERR,
3772				"invalid address family.\n");
3773			goto err;
3774		}
3775        if(iph1->version == ISAKMP_VERSION_NUMBER_IKEV1){
3776            id_b.proto_id = IPPROTO_UDP;
3777            id_b.port = htons(PORT_ISAKMP);
3778
3779        }
3780		ident = vmalloc(l);
3781		if (!ident) {
3782			plog(ASL_LEVEL_ERR,
3783				"failed to get ID buffer.\n");
3784			return 0;
3785		}
3786		memcpy(ident->v, p, ident->l);
3787	    }
3788	}
3789	if (!ident) {
3790		plog(ASL_LEVEL_ERR,
3791			"failed to get ID buffer.\n");
3792		return 0;
3793	}
3794
3795	ret = vmalloc(sizeof(id_b) + ident->l);
3796	if (ret == NULL) {
3797		plog(ASL_LEVEL_ERR,
3798			"failed to get ID buffer.\n");
3799		goto err;
3800	}
3801
3802	memcpy(ret->v, &id_b, sizeof(id_b));
3803	memcpy(ret->v + sizeof(id_b), ident->v, ident->l);
3804
3805	iph1->id = ret;
3806
3807	plogdump(ASL_LEVEL_DEBUG, iph1->id->v, iph1->id->l, "use ID type of %s\n", s_ipsecdoi_ident(id_b.type));
3808	if (ident)
3809		vfree(ident);
3810	return 0;
3811
3812err:
3813	if (ident)
3814		vfree(ident);
3815	plog(ASL_LEVEL_ERR, "failed get my ID\n");
3816	return -1;
3817}
3818
3819static vchar_t *
3820getidval(type, val)
3821	int type;
3822	vchar_t *val;
3823{
3824	vchar_t *new = NULL;
3825
3826	if (val)
3827		new = vdup(val);
3828	else if (lcconf->ident[type])
3829		new = vdup(lcconf->ident[type]);
3830
3831	return new;
3832}
3833
3834/* it's only called by cfparse.y. */
3835int
3836set_identifier(vpp, type, value)
3837	vchar_t **vpp, *value;
3838	int type;
3839{
3840	return set_identifier_qual(vpp, type, value, IDQUAL_UNSPEC);
3841}
3842
3843int
3844set_identifier_qual(vpp, type, value, qual)
3845	vchar_t **vpp, *value;
3846	int type;
3847	int qual;
3848{
3849	vchar_t *new = NULL;
3850
3851	/* simply return if value is null. */
3852	if (!value){
3853		if( type == IDTYPE_FQDN || type == IDTYPE_USERFQDN){
3854			plog(ASL_LEVEL_ERR,
3855				 "No %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
3856			return -1;
3857		}
3858		return 0;
3859	}
3860
3861	switch (type) {
3862	case IDTYPE_FQDN:
3863	case IDTYPE_USERFQDN:
3864		if(value->l <= 1){
3865			plog(ASL_LEVEL_ERR,
3866				 "Empty %s\n", type == IDTYPE_FQDN ? "fqdn":"user fqdn");
3867			return -1;
3868		}
3869	case IDTYPE_KEYIDUSE:
3870#ifdef ENABLE_HYBRID
3871	case IDTYPE_LOGIN:
3872#endif
3873		/* length is adjusted since QUOTEDSTRING teminates NULL. */
3874		new = vmalloc(value->l - 1);
3875		if (new == NULL)
3876			return -1;
3877		memcpy(new->v, value->v, new->l);
3878		break;
3879	case IDTYPE_KEYID:
3880		/*
3881		 * If no qualifier is specified: IDQUAL_UNSPEC. It means
3882		 * to use a file for backward compatibility sake.
3883		 */
3884		switch(qual) {
3885		case IDQUAL_FILE:
3886		case IDQUAL_UNSPEC: {
3887			FILE *fp;
3888			char b[512];
3889			int tlen, len;
3890
3891			fp = fopen(value->v, "r");
3892			if (fp == NULL) {
3893				plog(ASL_LEVEL_ERR,
3894					"can not open %s\n", value->v);
3895				return -1;
3896			}
3897			tlen = 0;
3898			while ((len = fread(b, 1, sizeof(b), fp)) != 0) {
3899				new = vrealloc(new, tlen + len);
3900				if (!new) {
3901					fclose(fp);
3902					return -1;
3903				}
3904				memcpy(new->v + tlen, b, len);
3905				tlen += len;
3906			}
3907			fclose(fp);
3908			break;
3909		}
3910
3911		case IDQUAL_TAG:
3912			new = vmalloc(value->l - 1);
3913			if (new == NULL) {
3914				plog(ASL_LEVEL_ERR,
3915					"can not allocate memory");
3916				return -1;
3917			}
3918			memcpy(new->v, value->v, new->l);
3919			break;
3920
3921		default:
3922			plog(ASL_LEVEL_ERR,
3923				"unknown qualifier");
3924			return -1;
3925		}
3926		break;
3927
3928	case IDTYPE_ADDRESS: {
3929		struct sockaddr_storage *sa;
3930
3931		/* length is adjusted since QUOTEDSTRING teminates NULL. */
3932		if (value->l == 0)
3933			break;
3934
3935		sa = str2saddr(value->v, NULL);
3936		if (sa == NULL) {
3937			plog(ASL_LEVEL_ERR,
3938				"invalid ip address %s\n", value->v);
3939			return -1;
3940		}
3941
3942		new = vmalloc(sysdep_sa_len((struct sockaddr *)sa));
3943		if (new == NULL) {
3944			racoon_free(sa);
3945			return -1;
3946		}
3947		memcpy(new->v, sa, new->l);
3948		racoon_free(sa);
3949		break;
3950	}
3951	case IDTYPE_ASN1DN:
3952        plog(ASL_LEVEL_DEBUG, "Setting ID type ASN1DN from string not supported\n");
3953        return -1;
3954
3955		break;
3956	}
3957
3958	*vpp = new;
3959
3960	return 0;
3961}
3962
3963/*
3964 * create ID payload for phase 2, and set into iph2->id and id_p.  There are
3965 * NOT INCLUDING isakmp general header.
3966 * this function is for initiator.  responder will get to copy from payload.
3967 * responder ID type is always address type.
3968 * see, RFC2407 4.6.2.1
3969 */
3970int
3971ipsecdoi_setid2(iph2)
3972	phase2_handle_t *iph2;
3973{
3974	struct secpolicy *sp;
3975
3976	/* check there is phase 2 handler ? */
3977	sp = getspbyspid(iph2->spid);
3978	if (sp == NULL) {
3979		plog(ASL_LEVEL_ERR,
3980			"no policy found for spid:%u.\n", iph2->spid);
3981		return -1;
3982	}
3983
3984	iph2->id = ipsecdoi_sockaddr2id(&sp->spidx.src,
3985					sp->spidx.prefs, sp->spidx.ul_proto);
3986	if (iph2->id == NULL) {
3987		plog(ASL_LEVEL_ERR,
3988			"failed to get ID for %s\n",
3989			spidx2str(&sp->spidx));
3990		return -1;
3991	}
3992#ifdef ENABLE_NATT
3993	if (((ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id->v)->type == IPSECDOI_ID_IPV4_ADDR ||
3994		(ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id->v)->type == IPSECDOI_ID_IPV4_ADDR_SUBNET) &&
3995		iph2->side == RESPONDER &&
3996		iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED_ME) &&
3997		lcconf->ext_nat_id) {
3998		vfree(iph2->id);
3999		if (!(iph2->id = vdup(lcconf->ext_nat_id))) {
4000			return -1;
4001		}
4002	}
4003#endif
4004	plogdump(ASL_LEVEL_DEBUG, iph2->id->v, iph2->id->l, "use local ID type %s\n",
4005			 s_ipsecdoi_ident((ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id->v)->type));
4006
4007	/* remote side */
4008	iph2->id_p = ipsecdoi_sockaddr2id(&sp->spidx.dst,
4009				sp->spidx.prefd, sp->spidx.ul_proto);
4010	if (iph2->id_p == NULL) {
4011		plog(ASL_LEVEL_ERR,
4012			"failed to get ID for %s\n",
4013			spidx2str(&sp->spidx));
4014		VPTRINIT(iph2->id);
4015		return -1;
4016	}
4017	plogdump(ASL_LEVEL_DEBUG, iph2->id->v, iph2->id->l, "use remote ID type %s\n",
4018			 s_ipsecdoi_ident((ALIGNED_CAST(struct ipsecdoi_id_b *)iph2->id_p->v)->type));
4019
4020	return 0;
4021}
4022
4023/*
4024 * set address type of ID.
4025 * NOT INCLUDING general header.
4026 */
4027vchar_t *
4028ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto)
4029	struct sockaddr_storage *saddr;
4030	u_int prefixlen;
4031	u_int ul_proto;
4032{
4033	vchar_t *new;
4034	int type, len1, len2;
4035	caddr_t sa;
4036	u_short port;
4037
4038	/*
4039	 * Q. When type is SUBNET, is it allowed to be ::1/128.
4040	 * A. Yes. (consensus at bake-off)
4041	 */
4042	switch (saddr->ss_family) {
4043	case AF_INET:
4044		len1 = sizeof(struct in_addr);
4045		if (prefixlen == (sizeof(struct in_addr) << 3)) {
4046			type = IPSECDOI_ID_IPV4_ADDR;
4047			len2 = 0;
4048		} else {
4049			type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
4050			len2 = sizeof(struct in_addr);
4051		}
4052		sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr;
4053		port = ((struct sockaddr_in *)(saddr))->sin_port;
4054		break;
4055#ifdef INET6
4056	case AF_INET6:
4057		len1 = sizeof(struct in6_addr);
4058		if (prefixlen == (sizeof(struct in6_addr) << 3)) {
4059			type = IPSECDOI_ID_IPV6_ADDR;
4060			len2 = 0;
4061		} else {
4062			type = IPSECDOI_ID_IPV6_ADDR_SUBNET;
4063			len2 = sizeof(struct in6_addr);
4064		}
4065		sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr;
4066		port = ((struct sockaddr_in6 *)(saddr))->sin6_port;
4067		break;
4068#endif
4069	default:
4070		plog(ASL_LEVEL_ERR,
4071			"invalid family: %d.\n", saddr->ss_family);
4072		return NULL;
4073	}
4074
4075	/* get ID buffer */
4076	new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2);
4077	if (new == NULL) {
4078		plog(ASL_LEVEL_ERR,
4079			"failed to get ID buffer.\n");
4080		return NULL;
4081	}
4082
4083	memset(new->v, 0, new->l);
4084
4085	/* set the part of header. */
4086	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->type = type;
4087
4088	/* set ul_proto and port */
4089	/*
4090	 * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card
4091	 * because 0 means port number of 0.  Instead of 0, we use IPSEC_*_ANY.
4092	 */
4093	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->proto_id =
4094		ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto;
4095	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->port =
4096		port == IPSEC_PORT_ANY ? 0 : port;
4097	memcpy(new->v + sizeof(struct ipsecdoi_id_b), sa, len1);
4098
4099	/* set address */
4100
4101	/* set prefix */
4102	if (len2) {
4103		u_char *p = (unsigned char *) new->v +
4104			sizeof(struct ipsecdoi_id_b) + len1;
4105		u_int bits = prefixlen;
4106
4107		while (bits >= 8) {
4108			*p++ = 0xff;
4109			bits -= 8;
4110		}
4111
4112		if (bits > 0)
4113			*p = ~((1 << (8 - bits)) - 1);
4114	}
4115
4116	return new;
4117}
4118
4119vchar_t *
4120ipsecdoi_sockrange2id(laddr, haddr, ul_proto)
4121	struct sockaddr_storage *laddr, *haddr;
4122	u_int ul_proto;
4123{
4124	vchar_t *new;
4125	int type, len1, len2;
4126	u_short port;
4127
4128	if (laddr->ss_family != haddr->ss_family) {
4129	    plog(ASL_LEVEL_ERR, "Address family mismatch\n");
4130	    return NULL;
4131	}
4132
4133	switch (laddr->ss_family) {
4134	case AF_INET:
4135	    type = IPSECDOI_ID_IPV4_ADDR_RANGE;
4136	    len1 = sizeof(struct in_addr);
4137	    len2 = sizeof(struct in_addr);
4138	    break;
4139#ifdef INET6
4140	case AF_INET6:
4141		type = IPSECDOI_ID_IPV6_ADDR_RANGE;
4142		len1 = sizeof(struct in6_addr);
4143		len2 = sizeof(struct in6_addr);
4144		break;
4145#endif
4146	default:
4147		plog(ASL_LEVEL_ERR,
4148			"invalid family: %d.\n", laddr->ss_family);
4149		return NULL;
4150	}
4151
4152	/* get ID buffer */
4153	new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2);
4154	if (new == NULL) {
4155		plog(ASL_LEVEL_ERR,
4156			"failed to get ID buffer.\n");
4157		return NULL;
4158	}
4159
4160	memset(new->v, 0, new->l);
4161	/* set the part of header. */
4162	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->type = type;
4163
4164	/* set ul_proto and port */
4165	/*
4166	 * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card
4167	 * because 0 means port number of 0.  Instead of 0, we use IPSEC_*_ANY.
4168	 */
4169	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->proto_id =
4170		ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto;
4171	port = ((struct sockaddr_in *)(laddr))->sin_port;
4172	(ALIGNED_CAST(struct ipsecdoi_id_b *)new->v)->port =
4173		port == IPSEC_PORT_ANY ? 0 : port;
4174	memcpy(new->v + sizeof(struct ipsecdoi_id_b),
4175	       (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr,
4176	       len1);
4177	memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1,
4178	       (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr,
4179	       len2);
4180	return new;
4181}
4182
4183
4184/*
4185 * create sockaddr_storage structure from ID payload (buf).
4186 * buffers (saddr, prefixlen, ul_proto) must be allocated.
4187 * see, RFC2407 4.6.2.1
4188 */
4189int
4190ipsecdoi_id2sockaddr(vchar_t *buf,
4191                    struct sockaddr_storage *saddr,
4192                    u_int8_t *prefixlen,
4193                    u_int16_t *ul_proto,
4194                    int version)
4195{
4196	struct ipsecdoi_id_b *id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)buf->v;
4197	u_int plen = 0;
4198
4199	/*
4200	 * When a ID payload of subnet type with a IP address of full bit
4201	 * masked, it has to be processed as host address.
4202	 * e.g. below 2 type are same.
4203	 *      type = ipv6 subnet, data = 2001::1/128
4204	 *      type = ipv6 address, data = 2001::1
4205	 */
4206	switch (id_b->type) {
4207	case IPSECDOI_ID_IPV4_ADDR:
4208	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4209		saddr->ss_len = sizeof(struct sockaddr_in);
4210		saddr->ss_family = AF_INET;
4211		((struct sockaddr_in *)saddr)->sin_port =
4212			(id_b->port == 0
4213				? IPSEC_PORT_ANY
4214				: id_b->port);		/* see sockaddr2id() */
4215		memcpy(&((struct sockaddr_in *)saddr)->sin_addr,
4216			buf->v + sizeof(*id_b), sizeof(struct in_addr));
4217		break;
4218#ifdef INET6
4219	case IPSECDOI_ID_IPV6_ADDR:
4220	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4221		saddr->ss_len = sizeof(struct sockaddr_in6);
4222		saddr->ss_family = AF_INET6;
4223		((struct sockaddr_in6 *)saddr)->sin6_port =
4224			(id_b->port == 0
4225				? IPSEC_PORT_ANY
4226				: id_b->port);		/* see sockaddr2id() */
4227		memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr,
4228			buf->v + sizeof(*id_b), sizeof(struct in6_addr));
4229		break;
4230#endif
4231	default:
4232		plog(ASL_LEVEL_ERR,
4233			"unsupported ID type %d\n", id_b->type);
4234		return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
4235	}
4236
4237	/* get prefix length */
4238	switch (id_b->type) {
4239	case IPSECDOI_ID_IPV4_ADDR:
4240		plen = sizeof(struct in_addr) << 3;
4241		break;
4242#ifdef INET6
4243	case IPSECDOI_ID_IPV6_ADDR:
4244		plen = sizeof(struct in6_addr) << 3;
4245		break;
4246#endif
4247	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4248#ifdef INET6
4249	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4250#endif
4251	    {
4252		u_char *p;
4253		u_int max;
4254		int alen = sizeof(struct in_addr);
4255
4256		switch (id_b->type) {
4257		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4258			alen = sizeof(struct in_addr);
4259			break;
4260#ifdef INET6
4261		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4262			alen = sizeof(struct in6_addr);
4263			break;
4264#endif
4265		}
4266
4267		/* sanity check */
4268		if (buf->l < alen)
4269			return ISAKMP_INTERNAL_ERROR;
4270
4271		/* get subnet mask length */
4272		plen = 0;
4273		max = alen <<3;
4274
4275		p = (unsigned char *) buf->v
4276			+ sizeof(struct ipsecdoi_id_b)
4277			+ alen;
4278
4279		for (; *p == 0xff; p++) {
4280			plen += 8;
4281			if (plen >= max)
4282				break;
4283		}
4284
4285		if (plen < max) {
4286			u_int l = 0;
4287			u_char b = ~(*p);
4288
4289			while (b) {
4290				b >>= 1;
4291				l++;
4292			}
4293
4294			l = 8 - l;
4295			plen += l;
4296		}
4297	    }
4298		break;
4299	}
4300
4301	*prefixlen = plen;
4302    if (version == ISAKMP_VERSION_NUMBER_IKEV1) {
4303        *ul_proto = id_b->proto_id == 0 ? IPSEC_ULPROTO_ANY : id_b->proto_id;	/* see sockaddr2id() */
4304    }
4305
4306	return 0;
4307}
4308
4309/*
4310 * make printable string from ID payload except of general header.
4311 */
4312char *
4313ipsecdoi_id2str(id)
4314	const vchar_t *id;
4315{
4316#define BUFLEN 512
4317	char * ret = NULL;
4318	int len = 0;
4319	char *dat;
4320	static char buf[BUFLEN];
4321	struct ipsecdoi_id_b *id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)id->v;
4322	struct sockaddr_storage saddr;
4323	u_int plen = 0;
4324
4325    bzero(&saddr, sizeof(saddr));
4326
4327	switch (id_b->type) {
4328	case IPSECDOI_ID_IPV4_ADDR:
4329	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4330	case IPSECDOI_ID_IPV4_ADDR_RANGE:
4331
4332		saddr.ss_len = sizeof(struct sockaddr_in);
4333		saddr.ss_family = AF_INET;
4334		((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY;
4335		memcpy(&((struct sockaddr_in *)&saddr)->sin_addr,
4336			id->v + sizeof(*id_b), sizeof(struct in_addr));
4337		break;
4338#ifdef INET6
4339	case IPSECDOI_ID_IPV6_ADDR:
4340	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4341	case IPSECDOI_ID_IPV6_ADDR_RANGE:
4342		saddr.ss_len = sizeof(struct sockaddr_in6);
4343		saddr.ss_family = AF_INET6;
4344		((struct sockaddr_in6 *)&saddr)->sin6_port = IPSEC_PORT_ANY;
4345		memcpy(&((struct sockaddr_in6 *)&saddr)->sin6_addr,
4346			id->v + sizeof(*id_b), sizeof(struct in6_addr));
4347		((struct sockaddr_in6 *)&saddr)->sin6_scope_id =
4348			(IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)&saddr)->sin6_addr)
4349			 ? (ALIGNED_CAST(struct sockaddr_in6 *)id_b)->sin6_scope_id
4350			 : 0);
4351		break;
4352#endif
4353	}
4354
4355	switch (id_b->type) {
4356	case IPSECDOI_ID_IPV4_ADDR:
4357#ifdef INET6
4358	case IPSECDOI_ID_IPV6_ADDR:
4359#endif
4360		len = snprintf( buf, sizeof(buf), "%s", saddrwop2str((struct sockaddr *)&saddr));
4361		break;
4362
4363	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4364#ifdef INET6
4365	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4366#endif
4367	    {
4368		u_char *p;
4369		u_int max;
4370		int alen = sizeof(struct in_addr);
4371
4372		switch (id_b->type) {
4373		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4374			alen = sizeof(struct in_addr);
4375			break;
4376#ifdef INET6
4377		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4378			alen = sizeof(struct in6_addr);
4379			break;
4380#endif
4381		}
4382
4383		/* sanity check */
4384		if (id->l < alen) {
4385			len = 0;
4386			break;
4387		}
4388
4389		/* get subnet mask length */
4390		plen = 0;
4391		max = alen <<3;
4392
4393		p = (unsigned char *) id->v
4394			+ sizeof(struct ipsecdoi_id_b)
4395			+ alen;
4396
4397		for (; *p == 0xff; p++) {
4398			plen += 8;
4399			if (plen >= max)
4400				break;
4401		}
4402
4403		if (plen < max) {
4404			u_int l = 0;
4405			u_char b = ~(*p);
4406
4407			while (b) {
4408				b >>= 1;
4409				l++;
4410			}
4411
4412			l = 8 - l;
4413			plen += l;
4414		}
4415
4416		len = snprintf( buf, sizeof(buf), "%s/%i", saddrwop2str((struct sockaddr *)&saddr), plen);
4417	    }
4418		break;
4419
4420	case IPSECDOI_ID_IPV4_ADDR_RANGE:
4421
4422		len = snprintf( buf, sizeof(buf), "%s-", saddrwop2str((struct sockaddr *)&saddr));
4423
4424		saddr.ss_len = sizeof(struct sockaddr_in);
4425		saddr.ss_family = AF_INET;
4426		((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY;
4427		memcpy(&((struct sockaddr_in *)&saddr)->sin_addr,
4428			id->v + sizeof(*id_b) + sizeof(struct in_addr),
4429			sizeof(struct in_addr));
4430
4431		if (len >= 0) {
4432		    len += snprintf( buf + len, sizeof(buf) - len, "%s", saddrwop2str((struct sockaddr *)&saddr));
4433		}
4434
4435		break;
4436
4437#ifdef INET6
4438	case IPSECDOI_ID_IPV6_ADDR_RANGE:
4439
4440		len = snprintf( buf, sizeof(buf), "%s-", saddrwop2str((struct sockaddr *)&saddr));
4441
4442		saddr.ss_len = sizeof(struct sockaddr_in6);
4443		saddr.ss_family = AF_INET6;
4444		((struct sockaddr_in6 *)&saddr)->sin6_port = IPSEC_PORT_ANY;
4445		memcpy(&((struct sockaddr_in6 *)&saddr)->sin6_addr,
4446			id->v + sizeof(*id_b) + sizeof(struct in6_addr),
4447			sizeof(struct in6_addr));
4448		((struct sockaddr_in6 *)&saddr)->sin6_scope_id =
4449			(IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)&saddr)->sin6_addr)
4450			 ? (ALIGNED_CAST(struct sockaddr_in6 *)id_b)->sin6_scope_id
4451			 : 0);
4452
4453		if (len >= 0) {
4454		    len += snprintf( buf + len, sizeof(buf) - len, "%s", saddrwop2str((struct sockaddr *)&saddr));
4455		}
4456
4457		break;
4458#endif
4459
4460	case IPSECDOI_ID_FQDN:
4461	case IPSECDOI_ID_USER_FQDN:
4462		len = id->l - sizeof(*id_b);
4463		if (len > BUFLEN)
4464			len = BUFLEN;
4465		memcpy(buf, id->v + sizeof(*id_b), len);
4466		break;
4467
4468	case IPSECDOI_ID_DER_ASN1_DN:
4469	case IPSECDOI_ID_DER_ASN1_GN:
4470	{
4471#ifdef HAVE_OPENSSL
4472		X509_NAME *xn = NULL;
4473#endif
4474
4475		dat = id->v + sizeof(*id_b);
4476		len = id->l - sizeof(*id_b);
4477#ifdef HAVE_OPENSSL
4478		if (d2i_X509_NAME(&xn, (void*) &dat, len) != NULL) {
4479			BIO *bio = BIO_new(BIO_s_mem());
4480			X509_NAME_print_ex(bio, xn, 0, 0);
4481			len = BIO_get_mem_data(bio, &dat);
4482			if (len > BUFLEN)
4483				len = BUFLEN;
4484			memcpy(buf,dat,len);
4485			BIO_free(bio);
4486			X509_NAME_free(xn);
4487		} else
4488#endif
4489		{
4490
4491			plog(ASL_LEVEL_ERR,
4492				"unable to extract asn1dn from id\n");
4493
4494			len = snprintf(buf, sizeof(buf), "<ASN1-DN>");
4495		}
4496
4497		break;
4498	}
4499
4500	/* currently unhandled id types */
4501	case IPSECDOI_ID_KEY_ID:
4502		len = snprintf( buf, sizeof(buf), "<KEY-ID>");
4503		break;
4504
4505	default:
4506		plog(ASL_LEVEL_ERR,
4507			"unknown ID type %d\n", id_b->type);
4508	}
4509
4510	if (!len)
4511		len = snprintf( buf, sizeof(buf), "<?>");
4512
4513	ret = racoon_malloc(len+1);
4514	if (ret != NULL) {
4515		memcpy(ret,buf,len);
4516		ret[len]=0;
4517	}
4518
4519	return ret;
4520}
4521
4522/*
4523 * set IPsec data attributes into a proposal.
4524 * NOTE: MUST called per a transform.
4525 */
4526int
4527ipsecdoi_t2satrns(t, pp, pr, tr)
4528	struct isakmp_pl_t *t;
4529	struct saprop *pp;
4530	struct saproto *pr;
4531	struct satrns *tr;
4532{
4533	struct isakmp_data *d, *prev;
4534	int flag, type;
4535	int error = -1;
4536	int life_t;
4537	int tlen;
4538
4539	tr->trns_no = t->t_no;
4540	tr->trns_id = t->t_id;
4541
4542	tlen = ntohs(t->h.len) - sizeof(*t);
4543	prev = (struct isakmp_data *)NULL;
4544	d = (struct isakmp_data *)(t + 1);
4545
4546	/* default */
4547	life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
4548	pp->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
4549	pp->lifebyte = 0;
4550	tr->authtype = IPSECDOI_ATTR_AUTH_NONE;
4551
4552	while (tlen > 0) {
4553
4554		type = ntohs(d->type) & ~ISAKMP_GEN_MASK;
4555		flag = ntohs(d->type) & ISAKMP_GEN_MASK;
4556
4557		plog(ASL_LEVEL_DEBUG,
4558			"type=%s, flag=0x%04x, lorv=%s\n",
4559			s_ipsecdoi_attr(type), flag,
4560			s_ipsecdoi_attr_v(type, ntohs(d->lorv)));
4561
4562		switch (type) {
4563		case IPSECDOI_ATTR_SA_LD_TYPE:
4564		{
4565			int type = ntohs(d->lorv);
4566			switch (type) {
4567			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
4568			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
4569				life_t = type;
4570				break;
4571			default:
4572				plog(ASL_LEVEL_WARNING,
4573					"invalid life duration type. "
4574					"use default\n");
4575				life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT;
4576				break;
4577			}
4578			break;
4579		}
4580		case IPSECDOI_ATTR_SA_LD:
4581			if (prev == NULL
4582			 || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) !=
4583					IPSECDOI_ATTR_SA_LD_TYPE) {
4584				plog(ASL_LEVEL_ERR,
4585				    "life duration must follow ltype\n");
4586				break;
4587			}
4588
4589		    {
4590			u_int32_t t;
4591			vchar_t *ld_buf = NULL;
4592
4593			if (flag) {
4594				/* i.e. ISAKMP_GEN_TV */
4595				ld_buf = vmalloc(sizeof(d->lorv));
4596				if (ld_buf == NULL) {
4597					plog(ASL_LEVEL_ERR,
4598					    "failed to get LD buffer.\n");
4599					goto end;
4600				}
4601				memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv));
4602			} else {
4603				int len = ntohs(d->lorv);
4604				/* i.e. ISAKMP_GEN_TLV */
4605				ld_buf = vmalloc(len);
4606				if (ld_buf == NULL) {
4607					plog(ASL_LEVEL_ERR,
4608					    "failed to get LD buffer.\n");
4609					goto end;
4610				}
4611				memcpy(ld_buf->v, d + 1, len);
4612			}
4613			switch (life_t) {
4614			case IPSECDOI_ATTR_SA_LD_TYPE_SEC:
4615				t = ipsecdoi_set_ld(ld_buf);
4616				vfree(ld_buf);
4617				if (t == 0) {
4618					plog(ASL_LEVEL_ERR,
4619						"invalid life duration.\n");
4620					goto end;
4621				}
4622				/* lifetime must be equal in a proposal. */
4623				if (pp->lifetime == IPSECDOI_ATTR_SA_LD_SEC_DEFAULT)
4624					pp->lifetime = t;
4625				else if (pp->lifetime != t) {
4626					plog(ASL_LEVEL_ERR,
4627						"lifetime mismatched "
4628						"in a proposal, "
4629						"prev:%ld curr:%u.\n",
4630						(long)pp->lifetime, t);
4631					goto end;
4632				}
4633				break;
4634			case IPSECDOI_ATTR_SA_LD_TYPE_KB:
4635				t = ipsecdoi_set_ld(ld_buf);
4636				vfree(ld_buf);
4637				if (t == 0) {
4638					plog(ASL_LEVEL_ERR,
4639						"invalid life duration.\n");
4640					goto end;
4641				}
4642				/* lifebyte must be equal in a proposal. */
4643				if (pp->lifebyte == 0)
4644					pp->lifebyte = t;
4645				else if (pp->lifebyte != t) {
4646					plog(ASL_LEVEL_ERR,
4647						"lifebyte mismatched "
4648						"in a proposal, "
4649						"prev:%d curr:%u.\n",
4650						pp->lifebyte, t);
4651					goto end;
4652				}
4653				break;
4654			default:
4655				vfree(ld_buf);
4656				plog(ASL_LEVEL_ERR,
4657					"invalid life type: %d\n", life_t);
4658				goto end;
4659			}
4660		    }
4661			break;
4662
4663		case IPSECDOI_ATTR_GRP_DESC:
4664			/*
4665			 * RFC2407: 4.5 IPSEC Security Association Attributes
4666			 *   Specifies the Oakley Group to be used in a PFS QM
4667			 *   negotiation.  For a list of supported values, see
4668			 *   Appendix A of [IKE].
4669			 */
4670			if (pp->pfs_group == 0)
4671				pp->pfs_group = (u_int16_t)ntohs(d->lorv);
4672			else if (pp->pfs_group != (u_int16_t)ntohs(d->lorv)) {
4673				plog(ASL_LEVEL_ERR,
4674					"pfs_group mismatched "
4675					"in a proposal.\n");
4676				goto end;
4677			}
4678			break;
4679
4680		case IPSECDOI_ATTR_ENC_MODE:
4681			if (pr->encmode &&
4682			    pr->encmode != (u_int16_t)ntohs(d->lorv)) {
4683				plog(ASL_LEVEL_ERR,
4684					"multiple encmode exist "
4685					"in a transform.\n");
4686				goto end;
4687			}
4688			pr->encmode = (u_int16_t)ntohs(d->lorv);
4689			break;
4690
4691		case IPSECDOI_ATTR_AUTH:
4692			if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) {
4693				plog(ASL_LEVEL_ERR,
4694					"multiple authtype exist "
4695					"in a transform.\n");
4696				goto end;
4697			}
4698			tr->authtype = (u_int16_t)ntohs(d->lorv);
4699			break;
4700
4701		case IPSECDOI_ATTR_KEY_LENGTH:
4702			if (pr->proto_id != IPSECDOI_PROTO_IPSEC_ESP) {
4703				plog(ASL_LEVEL_ERR,
4704					"key length defined but not ESP");
4705				goto end;
4706			}
4707			tr->encklen = ntohs(d->lorv);
4708			break;
4709
4710		case IPSECDOI_ATTR_KEY_ROUNDS:
4711		case IPSECDOI_ATTR_COMP_DICT_SIZE:
4712		case IPSECDOI_ATTR_COMP_PRIVALG:
4713		default:
4714			break;
4715		}
4716
4717		prev = d;
4718		if (flag) {
4719			tlen -= sizeof(*d);
4720			d = (struct isakmp_data *)((char *)d + sizeof(*d));
4721		} else {
4722			tlen -= (sizeof(*d) + ntohs(d->lorv));
4723			d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv));
4724		}
4725	}
4726
4727	error = 0;
4728end:
4729	return error;
4730}
4731
4732int
4733ipsecdoi_authalg2trnsid(alg)
4734	int alg;
4735{
4736	switch (alg) {
4737        case IPSECDOI_ATTR_AUTH_HMAC_MD5:
4738		return IPSECDOI_AH_MD5;
4739        case IPSECDOI_ATTR_AUTH_HMAC_SHA1:
4740		return IPSECDOI_AH_SHA;
4741	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_256:
4742		return IPSECDOI_AH_SHA256;
4743	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_384:
4744		return IPSECDOI_AH_SHA384;
4745	case IPSECDOI_ATTR_AUTH_HMAC_SHA2_512:
4746		return IPSECDOI_AH_SHA512;
4747        case IPSECDOI_ATTR_AUTH_DES_MAC:
4748		return IPSECDOI_AH_DES;
4749	case IPSECDOI_ATTR_AUTH_KPDK:
4750		return IPSECDOI_AH_MD5;	/* XXX */
4751	default:
4752		plog(ASL_LEVEL_ERR,
4753			"invalid authentication algorithm:%d\n", alg);
4754	}
4755	return -1;
4756}
4757
4758static int rm_idtype2doi[] = {
4759	255,				/* IDTYPE_UNDEFINED, 0 */
4760	IPSECDOI_ID_FQDN,		/* IDTYPE_FQDN, 1 */
4761	IPSECDOI_ID_USER_FQDN,		/* IDTYPE_USERFQDN, 2 */
4762	IPSECDOI_ID_KEY_ID,		/* IDTYPE_KEYID, 3 */
4763	255,    /*			   IDTYPE_ADDRESS, 4
4764		 * it expands into 4 types by another function. */
4765	IPSECDOI_ID_DER_ASN1_DN,	/* IDTYPE_ASN1DN, 5 */
4766};
4767
4768/*
4769 * convert idtype to DOI value.
4770 * OUT	255  : NG
4771 *	other: converted.
4772 */
4773int
4774idtype2doi(idtype)
4775	int idtype;
4776{
4777	if (ARRAYLEN(rm_idtype2doi) > idtype)
4778		return rm_idtype2doi[idtype];
4779	return 255;
4780}
4781
4782int
4783doi2idtype(doi)
4784	int doi;
4785{
4786	switch(doi) {
4787	case IPSECDOI_ID_FQDN:
4788		return(IDTYPE_FQDN);
4789	case IPSECDOI_ID_USER_FQDN:
4790		return(IDTYPE_USERFQDN);
4791	case IPSECDOI_ID_KEY_ID:
4792		return(IDTYPE_KEYID);
4793	case IPSECDOI_ID_DER_ASN1_DN:
4794		return(IDTYPE_ASN1DN);
4795	case IPSECDOI_ID_IPV4_ADDR:
4796	case IPSECDOI_ID_IPV4_ADDR_SUBNET:
4797	case IPSECDOI_ID_IPV6_ADDR:
4798	case IPSECDOI_ID_IPV6_ADDR_SUBNET:
4799		return(IDTYPE_ADDRESS);
4800	default:
4801		plog(ASL_LEVEL_WARNING,
4802			"Inproper idtype:%s in this function.\n",
4803			s_ipsecdoi_ident(doi));
4804		return(IDTYPE_ADDRESS);	/* XXX */
4805	}
4806	/*NOTREACHED*/
4807}
4808
4809#ifdef ENABLE_HYBRID
4810static int
4811switch_authmethod(authmethod)
4812	int authmethod;
4813{
4814	switch(authmethod) {
4815	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R:
4816		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I;
4817		break;
4818	case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R:
4819		authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I;
4820		break;
4821	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R:
4822		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I;
4823		break;
4824	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R:
4825		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I;
4826		break;
4827	/* Those are not implemented */
4828	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R:
4829		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I;
4830		break;
4831	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R:
4832		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I;
4833		break;
4834	case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R:
4835		authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I;
4836		break;
4837	default:
4838		break;
4839	}
4840
4841	return authmethod;
4842}
4843#endif
4844