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