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