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