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