1 /* $NetBSD: proposal.c,v 1.18 2025/03/07 15:55:29 christos Exp $ */ 2 3 /* $Id: proposal.c,v 1.18 2025/03/07 15:55:29 christos Exp $ */ 4 5 /* 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "config.h" 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/queue.h> 40 41 #include <netinet/in.h> 42 #include PATH_IPSEC_H 43 44 #include <stdlib.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <errno.h> 48 49 #include "var.h" 50 #include "misc.h" 51 #include "vmbuf.h" 52 #include "plog.h" 53 #include "sockmisc.h" 54 #include "debug.h" 55 56 #include "policy.h" 57 #include "pfkey.h" 58 #include "isakmp_var.h" 59 #include "isakmp.h" 60 #include "ipsec_doi.h" 61 #include "algorithm.h" 62 #include "proposal.h" 63 #include "sainfo.h" 64 #include "localconf.h" 65 #include "remoteconf.h" 66 #include "oakley.h" 67 #include "handler.h" 68 #include "strnames.h" 69 #include "gcmalloc.h" 70 #ifdef ENABLE_NATT 71 #include "nattraversal.h" 72 #endif 73 74 static uint g_nextreqid = 1; 75 76 /* %%% 77 * modules for ipsec sa spec 78 */ 79 struct saprop * 80 newsaprop() 81 { 82 struct saprop *new; 83 84 new = racoon_calloc(1, sizeof(*new)); 85 if (new == NULL) 86 return NULL; 87 88 return new; 89 } 90 91 struct saproto * 92 newsaproto() 93 { 94 struct saproto *new; 95 96 new = racoon_calloc(1, sizeof(*new)); 97 if (new == NULL) 98 return NULL; 99 100 return new; 101 } 102 103 /* set saprop to last part of the prop tree */ 104 void 105 inssaprop(struct saprop **head, struct saprop *new) 106 { 107 struct saprop *p; 108 109 if (*head == NULL) { 110 *head = new; 111 return; 112 } 113 114 for (p = *head; p->next; p = p->next) 115 ; 116 p->next = new; 117 118 return; 119 } 120 121 /* set saproto to the end of the proto tree in saprop */ 122 void 123 inssaproto(struct saprop *pp, struct saproto *new) 124 { 125 struct saproto *p; 126 127 for (p = pp->head; p && p->next; p = p->next) 128 ; 129 if (p == NULL) 130 pp->head = new; 131 else 132 p->next = new; 133 134 return; 135 } 136 137 /* set saproto to the top of the proto tree in saprop */ 138 void 139 inssaprotorev(struct saprop *pp, struct saproto *new) 140 { 141 new->next = pp->head; 142 pp->head = new; 143 144 return; 145 } 146 147 struct satrns * 148 newsatrns(void) 149 { 150 struct satrns *new; 151 152 new = racoon_calloc(1, sizeof(*new)); 153 if (new == NULL) 154 return NULL; 155 156 return new; 157 } 158 159 /* set saproto to last part of the proto tree in saprop */ 160 void 161 inssatrns(struct saproto *pr, struct satrns *new) 162 { 163 struct satrns *tr; 164 165 for (tr = pr->head; tr && tr->next; tr = tr->next) 166 ; 167 if (tr == NULL) 168 pr->head = new; 169 else 170 tr->next = new; 171 172 return; 173 } 174 175 /* 176 * take a single match between saprop. allocate a new proposal and return it 177 * for future use (like picking single proposal from a bundle). 178 * pp1: peer's proposal. 179 * pp2: my proposal. 180 * NOTE: In the case of initiator, must be ensured that there is no 181 * modification of the proposal by calling cmp_aproppair_i() before 182 * this function. 183 * XXX cannot understand the comment! 184 */ 185 struct saprop * 186 cmpsaprop_alloc(struct ph1handle *ph1, 187 const struct saprop *pp1, 188 const struct saprop *pp2, 189 int side) 190 { 191 struct saprop *newpp = NULL; 192 struct saproto *pr1, *pr2, *newpr = NULL; 193 struct satrns *tr1, *tr2, *newtr; 194 const int ordermatters = 0; 195 int npr1, npr2; 196 int spisizematch; 197 198 newpp = newsaprop(); 199 if (newpp == NULL) { 200 plog(LLV_ERROR, LOCATION, NULL, 201 "failed to allocate saprop.\n"); 202 return NULL; 203 } 204 newpp->prop_no = pp1->prop_no; 205 206 /* see proposal.h about lifetime/key length and PFS selection. */ 207 208 /* check time/bytes lifetime and PFS */ 209 switch (ph1->rmconf->pcheck_level) { 210 case PROP_CHECK_OBEY: 211 newpp->lifetime = pp1->lifetime; 212 newpp->lifebyte = pp1->lifebyte; 213 newpp->pfs_group = pp1->pfs_group; 214 break; 215 216 case PROP_CHECK_STRICT: 217 if (pp1->lifetime > pp2->lifetime) { 218 plog(LLV_ERROR, LOCATION, NULL, 219 "long lifetime proposed: " 220 "my:%d peer:%d\n", 221 (int)pp2->lifetime, (int)pp1->lifetime); 222 goto err; 223 } 224 if (pp1->lifebyte > pp2->lifebyte) { 225 plog(LLV_ERROR, LOCATION, NULL, 226 "long lifebyte proposed: " 227 "my:%d peer:%d\n", 228 pp2->lifebyte, pp1->lifebyte); 229 goto err; 230 } 231 newpp->lifetime = pp1->lifetime; 232 newpp->lifebyte = pp1->lifebyte; 233 234 prop_pfs_check: 235 if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) { 236 plog(LLV_ERROR, LOCATION, NULL, 237 "pfs group mismatched: " 238 "my:%d peer:%d\n", 239 pp2->pfs_group, pp1->pfs_group); 240 goto err; 241 } 242 newpp->pfs_group = pp1->pfs_group; 243 break; 244 245 case PROP_CHECK_CLAIM: 246 /* lifetime */ 247 if (pp1->lifetime <= pp2->lifetime) { 248 newpp->lifetime = pp1->lifetime; 249 } else { 250 newpp->lifetime = pp2->lifetime; 251 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; 252 plog(LLV_NOTIFY, LOCATION, NULL, 253 "use own lifetime: " 254 "my:%d peer:%d\n", 255 (int)pp2->lifetime, (int)pp1->lifetime); 256 } 257 258 /* lifebyte */ 259 if (pp1->lifebyte > pp2->lifebyte) { 260 newpp->lifebyte = pp2->lifebyte; 261 newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; 262 plog(LLV_NOTIFY, LOCATION, NULL, 263 "use own lifebyte: " 264 "my:%d peer:%d\n", 265 pp2->lifebyte, pp1->lifebyte); 266 } 267 newpp->lifebyte = pp1->lifebyte; 268 269 goto prop_pfs_check; 270 271 case PROP_CHECK_EXACT: 272 if (pp1->lifetime != pp2->lifetime) { 273 plog(LLV_ERROR, LOCATION, NULL, 274 "lifetime mismatched: " 275 "my:%d peer:%d\n", 276 (int)pp2->lifetime, (int)pp1->lifetime); 277 goto err; 278 } 279 280 if (pp1->lifebyte != pp2->lifebyte) { 281 plog(LLV_ERROR, LOCATION, NULL, 282 "lifebyte mismatched: " 283 "my:%d peer:%d\n", 284 pp2->lifebyte, pp1->lifebyte); 285 goto err; 286 } 287 if (pp1->pfs_group != pp2->pfs_group) { 288 plog(LLV_ERROR, LOCATION, NULL, 289 "pfs group mismatched: " 290 "my:%d peer:%d\n", 291 pp2->pfs_group, pp1->pfs_group); 292 goto err; 293 } 294 newpp->lifetime = pp1->lifetime; 295 newpp->lifebyte = pp1->lifebyte; 296 newpp->pfs_group = pp1->pfs_group; 297 break; 298 299 default: 300 plog(LLV_ERROR, LOCATION, NULL, 301 "invalid pcheck_level why?.\n"); 302 goto err; 303 } 304 305 #ifdef HAVE_SECCTX 306 /* check the security_context properties. 307 * It is possible for one side to have a security context 308 * and the other side doesn't. If so, this is an error. 309 */ 310 311 if (*pp1->sctx.ctx_str && !(*pp2->sctx.ctx_str)) { 312 plog(LLV_ERROR, LOCATION, NULL, 313 "My proposal missing security context\n"); 314 goto err; 315 } 316 if (!(*pp1->sctx.ctx_str) && *pp2->sctx.ctx_str) { 317 plog(LLV_ERROR, LOCATION, NULL, 318 "Peer is missing security context\n"); 319 goto err; 320 } 321 322 if (*pp1->sctx.ctx_str && *pp2->sctx.ctx_str) { 323 if (pp1->sctx.ctx_doi == pp2->sctx.ctx_doi) 324 newpp->sctx.ctx_doi = pp1->sctx.ctx_doi; 325 else { 326 plog(LLV_ERROR, LOCATION, NULL, 327 "sec doi mismatched: my:%d peer:%d\n", 328 pp2->sctx.ctx_doi, pp1->sctx.ctx_doi); 329 goto err; 330 } 331 332 if (pp1->sctx.ctx_alg == pp2->sctx.ctx_alg) 333 newpp->sctx.ctx_alg = pp1->sctx.ctx_alg; 334 else { 335 plog(LLV_ERROR, LOCATION, NULL, 336 "sec alg mismatched: my:%d peer:%d\n", 337 pp2->sctx.ctx_alg, pp1->sctx.ctx_alg); 338 goto err; 339 } 340 341 if ((pp1->sctx.ctx_strlen != pp2->sctx.ctx_strlen) || 342 memcmp(pp1->sctx.ctx_str, pp2->sctx.ctx_str, 343 pp1->sctx.ctx_strlen) != 0) { 344 plog(LLV_ERROR, LOCATION, NULL, 345 "sec ctx string mismatched: my:%s peer:%s\n", 346 pp2->sctx.ctx_str, pp1->sctx.ctx_str); 347 goto err; 348 } else { 349 newpp->sctx.ctx_strlen = pp1->sctx.ctx_strlen; 350 memcpy(newpp->sctx.ctx_str, pp1->sctx.ctx_str, 351 pp1->sctx.ctx_strlen); 352 } 353 } 354 #endif /* HAVE_SECCTX */ 355 356 npr1 = npr2 = 0; 357 for (pr1 = pp1->head; pr1; pr1 = pr1->next) 358 npr1++; 359 for (pr2 = pp2->head; pr2; pr2 = pr2->next) 360 npr2++; 361 if (npr1 != npr2) 362 goto err; 363 364 /* check protocol order */ 365 pr1 = pp1->head; 366 pr2 = pp2->head; 367 368 for (;;) { 369 if (!ordermatters) { 370 /* 371 * XXX does not work if we have multiple proposals 372 * with the same proto_id 373 */ 374 switch (side) { 375 case RESPONDER: 376 if (!pr2) 377 break; 378 for (pr1 = pp1->head; pr1; pr1 = pr1->next) { 379 if (pr1->proto_id == pr2->proto_id) 380 break; 381 } 382 break; 383 case INITIATOR: 384 if (!pr1) 385 break; 386 for (pr2 = pp2->head; pr2; pr2 = pr2->next) { 387 if (pr2->proto_id == pr1->proto_id) 388 break; 389 } 390 break; 391 } 392 } 393 if (!pr1 || !pr2) 394 break; 395 396 if (pr1->proto_id != pr2->proto_id) { 397 plog(LLV_ERROR, LOCATION, NULL, 398 "proto_id mismatched: " 399 "my:%s peer:%s\n", 400 s_ipsecdoi_proto(pr2->proto_id), 401 s_ipsecdoi_proto(pr1->proto_id)); 402 goto err; 403 } 404 spisizematch = 0; 405 if (pr1->spisize == pr2->spisize) 406 spisizematch = 1; 407 else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) { 408 /* 409 * draft-shacham-ippcp-rfc2393bis-05.txt: 410 * need to accept 16bit and 32bit SPI (CPI) for IPComp. 411 */ 412 if (pr1->spisize == sizeof(uint16_t) && 413 pr2->spisize == sizeof(uint32_t)) { 414 spisizematch = 1; 415 } else if (pr2->spisize == sizeof(uint16_t) && 416 pr1->spisize == sizeof(uint32_t)) { 417 spisizematch = 1; 418 } 419 if (spisizematch) { 420 plog(LLV_ERROR, LOCATION, NULL, 421 "IPComp SPI size promoted " 422 "from 16bit to 32bit\n"); 423 } 424 } 425 if (!spisizematch) { 426 plog(LLV_ERROR, LOCATION, NULL, 427 "spisize mismatched: " 428 "my:%d peer:%d\n", 429 (int)pr2->spisize, (int)pr1->spisize); 430 goto err; 431 } 432 433 #ifdef ENABLE_NATT 434 if ((ph1->natt_flags & NAT_DETECTED) && 435 natt_udp_encap (pr2->encmode)) 436 { 437 plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n", 438 s_ipsecdoi_encmode(pr2->encmode), 439 s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff)); 440 pr2->encmode -= ph1->natt_options->mode_udp_diff; 441 pr2->udp_encap = 1; 442 } 443 444 if ((ph1->natt_flags & NAT_DETECTED) && 445 natt_udp_encap (pr1->encmode)) 446 { 447 plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n", 448 s_ipsecdoi_encmode(pr1->encmode), 449 pr1->encmode, 450 s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff), 451 pr1->encmode - ph1->natt_options->mode_udp_diff); 452 pr1->encmode -= ph1->natt_options->mode_udp_diff; 453 pr1->udp_encap = 1; 454 } 455 #endif 456 457 if (pr1->encmode != pr2->encmode) { 458 plog(LLV_ERROR, LOCATION, NULL, 459 "encmode mismatched: " 460 "my:%s peer:%s\n", 461 s_ipsecdoi_encmode(pr2->encmode), 462 s_ipsecdoi_encmode(pr1->encmode)); 463 goto err; 464 } 465 466 for (tr1 = pr1->head; tr1; tr1 = tr1->next) { 467 for (tr2 = pr2->head; tr2; tr2 = tr2->next) { 468 if (cmpsatrns(pr1->proto_id, tr1, tr2, ph1->rmconf->pcheck_level) == 0) 469 goto found; 470 } 471 } 472 473 goto err; 474 475 found: 476 newpr = newsaproto(); 477 if (newpr == NULL) { 478 plog(LLV_ERROR, LOCATION, NULL, 479 "failed to allocate saproto.\n"); 480 goto err; 481 } 482 newpr->proto_id = pr1->proto_id; 483 newpr->spisize = pr1->spisize; 484 newpr->encmode = pr1->encmode; 485 newpr->spi = pr2->spi; /* copy my SPI */ 486 newpr->spi_p = pr1->spi; /* copy peer's SPI */ 487 newpr->reqid_in = pr2->reqid_in; 488 newpr->reqid_out = pr2->reqid_out; 489 #ifdef ENABLE_NATT 490 newpr->udp_encap = pr1->udp_encap | pr2->udp_encap; 491 #endif 492 493 newtr = newsatrns(); 494 if (newtr == NULL) { 495 plog(LLV_ERROR, LOCATION, NULL, 496 "failed to allocate satrns.\n"); 497 racoon_free(newpr); 498 goto err; 499 } 500 newtr->trns_no = tr1->trns_no; 501 newtr->trns_id = tr1->trns_id; 502 newtr->encklen = tr1->encklen; 503 newtr->authtype = tr1->authtype; 504 505 inssatrns(newpr, newtr); 506 inssaproto(newpp, newpr); 507 508 pr1 = pr1->next; 509 pr2 = pr2->next; 510 } 511 512 /* XXX should check if we have visited all items or not */ 513 if (!ordermatters) { 514 switch (side) { 515 case RESPONDER: 516 if (!pr2) 517 pr1 = NULL; 518 break; 519 case INITIATOR: 520 if (!pr1) 521 pr2 = NULL; 522 break; 523 } 524 } 525 526 /* should be matched all protocols in a proposal */ 527 if (pr1 != NULL || pr2 != NULL) 528 goto err; 529 530 return newpp; 531 532 err: 533 flushsaprop(newpp); 534 return NULL; 535 } 536 537 /* take a single match between saprop. returns 0 if pp1 equals to pp2. */ 538 int 539 cmpsaprop(const struct saprop *pp1, const struct saprop *pp2) 540 { 541 if (pp1->pfs_group != pp2->pfs_group) { 542 plog(LLV_WARNING, LOCATION, NULL, 543 "pfs_group mismatch. mine:%d peer:%d\n", 544 pp1->pfs_group, pp2->pfs_group); 545 /* FALLTHRU */ 546 } 547 548 if (pp1->lifetime > pp2->lifetime) { 549 plog(LLV_WARNING, LOCATION, NULL, 550 "less lifetime proposed. mine:%d peer:%d\n", 551 (int)pp1->lifetime, (int)pp2->lifetime); 552 /* FALLTHRU */ 553 } 554 if (pp1->lifebyte > pp2->lifebyte) { 555 plog(LLV_WARNING, LOCATION, NULL, 556 "less lifebyte proposed. mine:%d peer:%d\n", 557 pp1->lifebyte, pp2->lifebyte); 558 /* FALLTHRU */ 559 } 560 561 return 0; 562 } 563 564 /* 565 * take a single match between satrns. returns 0 if tr1 equals to tr2. 566 * tr1: peer's satrns 567 * tr2: my satrns 568 */ 569 int 570 cmpsatrns( 571 int proto_id, 572 const struct satrns *tr1, 573 const struct satrns *tr2, 574 int check_level) 575 { 576 if (tr1->trns_id != tr2->trns_id) { 577 plog(LLV_WARNING, LOCATION, NULL, 578 "trns_id mismatched: " 579 "my:%s peer:%s\n", 580 s_ipsecdoi_trns(proto_id, tr2->trns_id), 581 s_ipsecdoi_trns(proto_id, tr1->trns_id)); 582 return 1; 583 } 584 585 if (tr1->authtype != tr2->authtype) { 586 plog(LLV_WARNING, LOCATION, NULL, 587 "authtype mismatched: " 588 "my:%s peer:%s\n", 589 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype), 590 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype)); 591 return 1; 592 } 593 594 /* Check key length regarding checkmode 595 * XXX Shall we send some kind of notify message when key length rejected ? 596 */ 597 switch(check_level){ 598 case PROP_CHECK_OBEY: 599 return 0; 600 601 case PROP_CHECK_STRICT: 602 /* FALLTHROUGH */ 603 case PROP_CHECK_CLAIM: 604 if (tr1->encklen < tr2->encklen) { 605 plog(LLV_WARNING, LOCATION, NULL, 606 "low key length proposed, " 607 "mine:%d peer:%d.\n", 608 tr2->encklen, tr1->encklen); 609 return 1; 610 } 611 break; 612 case PROP_CHECK_EXACT: 613 if (tr1->encklen != tr2->encklen) { 614 plog(LLV_WARNING, LOCATION, NULL, 615 "key length mismatched, " 616 "mine:%d peer:%d.\n", 617 tr2->encklen, tr1->encklen); 618 return 1; 619 } 620 break; 621 } 622 623 return 0; 624 } 625 626 int 627 set_satrnsbysainfo(struct saproto *pr, struct sainfo *sainfo) 628 { 629 struct sainfoalg *a, *b; 630 struct satrns *newtr; 631 int t; 632 633 switch (pr->proto_id) { 634 case IPSECDOI_PROTO_IPSEC_AH: 635 if (sainfo->algs[algclass_ipsec_auth] == NULL) { 636 plog(LLV_ERROR, LOCATION, NULL, 637 "no auth algorithm found\n"); 638 goto err; 639 } 640 t = 1; 641 for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) { 642 643 if (a->alg == IPSECDOI_ATTR_AUTH_NONE) 644 continue; 645 646 /* allocate satrns */ 647 newtr = newsatrns(); 648 if (newtr == NULL) { 649 plog(LLV_ERROR, LOCATION, NULL, 650 "failed to allocate satrns.\n"); 651 goto err; 652 } 653 654 newtr->trns_no = t++; 655 newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg); 656 newtr->authtype = a->alg; 657 658 inssatrns(pr, newtr); 659 } 660 break; 661 case IPSECDOI_PROTO_IPSEC_ESP: 662 if (sainfo->algs[algclass_ipsec_enc] == NULL) { 663 plog(LLV_ERROR, LOCATION, NULL, 664 "no encryption algorithm found\n"); 665 goto err; 666 } 667 t = 1; 668 for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) { 669 for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) { 670 /* allocate satrns */ 671 newtr = newsatrns(); 672 if (newtr == NULL) { 673 plog(LLV_ERROR, LOCATION, NULL, 674 "failed to allocate satrns.\n"); 675 goto err; 676 } 677 678 newtr->trns_no = t++; 679 newtr->trns_id = a->alg; 680 newtr->encklen = a->encklen; 681 newtr->authtype = b->alg; 682 683 inssatrns(pr, newtr); 684 } 685 } 686 break; 687 case IPSECDOI_PROTO_IPCOMP: 688 if (sainfo->algs[algclass_ipsec_comp] == NULL) { 689 plog(LLV_ERROR, LOCATION, NULL, 690 "no ipcomp algorithm found\n"); 691 goto err; 692 } 693 t = 1; 694 for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) { 695 696 /* allocate satrns */ 697 newtr = newsatrns(); 698 if (newtr == NULL) { 699 plog(LLV_ERROR, LOCATION, NULL, 700 "failed to allocate satrns.\n"); 701 goto err; 702 } 703 704 newtr->trns_no = t++; 705 newtr->trns_id = a->alg; 706 newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/ 707 708 inssatrns(pr, newtr); 709 } 710 break; 711 default: 712 plog(LLV_ERROR, LOCATION, NULL, 713 "unknown proto_id (%d).\n", pr->proto_id); 714 goto err; 715 } 716 717 /* no proposal found */ 718 if (pr->head == NULL) { 719 plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n"); 720 return -1; 721 } 722 723 return 0; 724 725 err: 726 flushsatrns(pr->head); 727 return -1; 728 } 729 730 struct saprop * 731 aproppair2saprop(struct prop_pair *p0) 732 { 733 struct prop_pair *p, *t; 734 struct saprop *newpp; 735 struct saproto *newpr; 736 struct satrns *newtr; 737 uint8_t *spi; 738 739 if (p0 == NULL) 740 return NULL; 741 742 /* allocate ipsec a sa proposal */ 743 newpp = newsaprop(); 744 if (newpp == NULL) { 745 plog(LLV_ERROR, LOCATION, NULL, 746 "failed to allocate saprop.\n"); 747 return NULL; 748 } 749 newpp->prop_no = p0->prop->p_no; 750 /* lifetime & lifebyte must be updated later */ 751 752 for (p = p0; p; p = p->next) { 753 754 /* allocate ipsec sa protocol */ 755 newpr = newsaproto(); 756 if (newpr == NULL) { 757 plog(LLV_ERROR, LOCATION, NULL, 758 "failed to allocate saproto.\n"); 759 goto err; 760 } 761 762 /* check spi size */ 763 /* XXX should be handled isakmp cookie */ 764 if (sizeof(newpr->spi) < p->prop->spi_size) { 765 plog(LLV_ERROR, LOCATION, NULL, 766 "invalid spi size %d.\n", p->prop->spi_size); 767 racoon_free(newpr); 768 goto err; 769 } 770 771 /* 772 * XXX SPI bits are left-filled, for use with IPComp. 773 * we should be switching to variable-length spi field... 774 */ 775 newpr->proto_id = p->prop->proto_id; 776 newpr->spisize = p->prop->spi_size; 777 memset(&newpr->spi, 0, sizeof(newpr->spi)); 778 spi = (uint8_t *)&newpr->spi; 779 spi += sizeof(newpr->spi); 780 spi -= p->prop->spi_size; 781 memcpy(spi, p->prop + 1, p->prop->spi_size); 782 newpr->reqid_in = 0; 783 newpr->reqid_out = 0; 784 785 for (t = p; t; t = t->tnext) { 786 787 plog(LLV_DEBUG, LOCATION, NULL, 788 "prop#=%d prot-id=%s spi-size=%d " 789 "#trns=%d trns#=%d trns-id=%s\n", 790 t->prop->p_no, 791 s_ipsecdoi_proto(t->prop->proto_id), 792 t->prop->spi_size, t->prop->num_t, 793 t->trns->t_no, 794 s_ipsecdoi_trns(t->prop->proto_id, 795 t->trns->t_id)); 796 797 /* allocate ipsec sa transform */ 798 newtr = newsatrns(); 799 if (newtr == NULL) { 800 plog(LLV_ERROR, LOCATION, NULL, 801 "failed to allocate satrns.\n"); 802 racoon_free(newpr); 803 goto err; 804 } 805 806 if (ipsecdoi_t2satrns(t->trns, 807 newpp, newpr, newtr) < 0) { 808 flushsaprop(newpp); 809 racoon_free(newtr); 810 racoon_free(newpr); 811 return NULL; 812 } 813 814 inssatrns(newpr, newtr); 815 } 816 817 /* 818 * If the peer does not specify encryption mode, use 819 * transport mode by default. This is to conform to 820 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies 821 * that unspecified == transport), as well as RFC2407 822 * (unspecified == implementation dependent default). 823 */ 824 if (newpr->encmode == 0) 825 newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS; 826 827 inssaproto(newpp, newpr); 828 } 829 830 return newpp; 831 832 err: 833 flushsaprop(newpp); 834 return NULL; 835 } 836 837 void 838 flushsaprop(struct saprop *head) 839 { 840 struct saprop *p, *save; 841 842 for (p = head; p != NULL; p = save) { 843 save = p->next; 844 flushsaproto(p->head); 845 racoon_free(p); 846 } 847 848 return; 849 } 850 851 void 852 flushsaproto(struct saproto *head) 853 { 854 struct saproto *p, *save; 855 856 for (p = head; p != NULL; p = save) { 857 save = p->next; 858 flushsatrns(p->head); 859 vfree(p->keymat); 860 vfree(p->keymat_p); 861 racoon_free(p); 862 } 863 864 return; 865 } 866 867 void 868 flushsatrns(struct satrns *head) 869 { 870 struct satrns *p, *save; 871 872 for (p = head; p != NULL; p = save) { 873 save = p->next; 874 racoon_free(p); 875 } 876 877 return; 878 } 879 880 /* 881 * print multiple proposals 882 */ 883 void 884 printsaprop(const int pri, const struct saprop *pp) 885 { 886 const struct saprop *p; 887 888 if (pp == NULL) { 889 plog(pri, LOCATION, NULL, "(null)"); 890 return; 891 } 892 893 for (p = pp; p; p = p->next) { 894 printsaprop0(pri, p); 895 } 896 897 return; 898 } 899 900 /* 901 * print one proposal. 902 */ 903 void 904 printsaprop0(int pri, const struct saprop *pp) 905 { 906 const struct saproto *p; 907 908 if (pp == NULL) 909 return; 910 911 for (p = pp->head; p; p = p->next) { 912 printsaproto(pri, p); 913 } 914 915 return; 916 } 917 918 void 919 printsaproto(const int pri, const struct saproto *pr) 920 { 921 struct satrns *tr; 922 923 if (pr == NULL) 924 return; 925 926 plog(pri, LOCATION, NULL, 927 " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx " 928 "encmode=%s reqid=%d:%d)\n", 929 s_ipsecdoi_proto(pr->proto_id), 930 (int)pr->spisize, 931 (unsigned long)ntohl(pr->spi), 932 (unsigned long)ntohl(pr->spi_p), 933 s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode), 934 (int)pr->reqid_in, (int)pr->reqid_out); 935 936 for (tr = pr->head; tr; tr = tr->next) { 937 printsatrns(pri, pr->proto_id, tr); 938 } 939 940 return; 941 } 942 943 void 944 printsatrns(const int pri, const int proto_id, const struct satrns *tr) 945 { 946 if (tr == NULL) 947 return; 948 949 switch (proto_id) { 950 case IPSECDOI_PROTO_IPSEC_AH: 951 plog(pri, LOCATION, NULL, 952 " (trns_id=%s authtype=%s)\n", 953 s_ipsecdoi_trns(proto_id, tr->trns_id), 954 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); 955 break; 956 case IPSECDOI_PROTO_IPSEC_ESP: 957 plog(pri, LOCATION, NULL, 958 " (trns_id=%s encklen=%d authtype=%s)\n", 959 s_ipsecdoi_trns(proto_id, tr->trns_id), 960 tr->encklen, 961 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); 962 break; 963 case IPSECDOI_PROTO_IPCOMP: 964 plog(pri, LOCATION, NULL, 965 " (trns_id=%s)\n", 966 s_ipsecdoi_trns(proto_id, tr->trns_id)); 967 break; 968 default: 969 plog(pri, LOCATION, NULL, 970 "(unknown proto_id %d)\n", proto_id); 971 } 972 973 return; 974 } 975 976 void 977 print_proppair0(int pri, struct prop_pair *p, int level) 978 { 979 char spc[21]; 980 981 memset(spc, ' ', sizeof(spc)); 982 spc[sizeof(spc) - 1] = '\0'; 983 if (level < 20) { 984 spc[level] = '\0'; 985 } 986 987 plog(pri, LOCATION, NULL, 988 "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext); 989 if (p->next) 990 print_proppair0(pri, p->next, level + 1); 991 if (p->tnext) 992 print_proppair0(pri, p->tnext, level + 1); 993 } 994 995 void 996 print_proppair(int pri, struct prop_pair *p) 997 { 998 print_proppair0(pri, p, 1); 999 } 1000 1001 int 1002 set_proposal_from_policy(struct ph2handle *iph2, 1003 struct secpolicy *sp_main, 1004 struct secpolicy *sp_sub) 1005 { 1006 struct saprop *newpp; 1007 struct ipsecrequest *req; 1008 int encmodesv = IPSECDOI_ATTR_ENC_MODE_TRNS; /* use only when complex_bundle */ 1009 1010 newpp = newsaprop(); 1011 if (newpp == NULL) { 1012 plog(LLV_ERROR, LOCATION, NULL, 1013 "failed to allocate saprop.\n"); 1014 goto err; 1015 } 1016 newpp->prop_no = 1; 1017 newpp->lifetime = iph2->sainfo->lifetime; 1018 newpp->lifebyte = iph2->sainfo->lifebyte; 1019 newpp->pfs_group = iph2->sainfo->pfs_group; 1020 1021 if (lcconf->complex_bundle) 1022 goto skip1; 1023 1024 /* 1025 * decide the encryption mode of this SA bundle. 1026 * the mode becomes tunnel mode when there is even one policy 1027 * of tunnel mode in the SPD. otherwise the mode becomes 1028 * transport mode. 1029 */ 1030 for (req = sp_main->req; req; req = req->next) { 1031 if (req->saidx.mode == IPSEC_MODE_TUNNEL) { 1032 encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode); 1033 #ifdef ENABLE_NATT 1034 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED)) 1035 encmodesv += iph2->ph1->natt_options->mode_udp_diff; 1036 #endif 1037 break; 1038 } 1039 } 1040 1041 skip1: 1042 for (req = sp_main->req; req; req = req->next) { 1043 struct saproto *newpr; 1044 1045 /* 1046 * check if SA bundle ? 1047 * nested SAs negotiation is NOT supported. 1048 * me +--- SA1 ---+ peer1 1049 * me +--- SA2 --------------+ peer2 1050 */ 1051 /* allocate ipsec sa protocol */ 1052 newpr = newsaproto(); 1053 if (newpr == NULL) { 1054 plog(LLV_ERROR, LOCATION, NULL, 1055 "failed to allocate saproto.\n"); 1056 goto err; 1057 } 1058 1059 newpr->proto_id = ipproto2doi(req->saidx.proto); 1060 if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP) 1061 newpr->spisize = 2; 1062 else 1063 newpr->spisize = 4; 1064 if (lcconf->complex_bundle) { 1065 newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode); 1066 #ifdef ENABLE_NATT 1067 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED)) 1068 newpr->encmode += 1069 iph2->ph1->natt_options->mode_udp_diff; 1070 #endif 1071 } 1072 else 1073 newpr->encmode = encmodesv; 1074 1075 if (iph2->side == INITIATOR) 1076 newpr->reqid_out = req->saidx.reqid; 1077 else 1078 newpr->reqid_in = req->saidx.reqid; 1079 1080 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) { 1081 plog(LLV_ERROR, LOCATION, NULL, 1082 "failed to get algorithms.\n"); 1083 racoon_free(newpr); 1084 goto err; 1085 } 1086 1087 /* set new saproto */ 1088 inssaprotorev(newpp, newpr); 1089 } 1090 1091 /* get reqid_in from inbound policy */ 1092 if (sp_sub) { 1093 struct saproto *pr; 1094 1095 req = sp_sub->req; 1096 pr = newpp->head; 1097 while (req && pr) { 1098 if (iph2->side == INITIATOR) 1099 pr->reqid_in = req->saidx.reqid; 1100 else 1101 pr->reqid_out = req->saidx.reqid; 1102 pr = pr->next; 1103 req = req->next; 1104 } 1105 if (pr || req) { 1106 plog(LLV_NOTIFY, LOCATION, NULL, 1107 "There is a difference " 1108 "between the in/out bound policies in SPD.\n"); 1109 } 1110 } 1111 1112 iph2->proposal = newpp; 1113 1114 printsaprop0(LLV_DEBUG, newpp); 1115 1116 return 0; 1117 err: 1118 flushsaprop(newpp); 1119 return -1; 1120 } 1121 1122 /* 1123 * generate a policy from peer's proposal. 1124 * this function unconditionally choices first proposal in SA payload 1125 * passed by peer. 1126 */ 1127 int 1128 set_proposal_from_proposal(struct ph2handle *iph2) 1129 { 1130 struct saprop *newpp = NULL, *pp0, *pp_peer = NULL; 1131 struct saproto *newpr = NULL, *pr; 1132 struct prop_pair **pair; 1133 int error = -1; 1134 int i; 1135 1136 /* get proposal pair */ 1137 pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); 1138 if (pair == NULL) 1139 goto end; 1140 1141 /* 1142 * make my proposal according as the client proposal. 1143 * XXX assumed there is only one proposal even if it's the SA bundle. 1144 */ 1145 for (i = 0; i < MAXPROPPAIRLEN; i++) { 1146 if (pair[i] == NULL) 1147 continue; 1148 1149 if (pp_peer != NULL) 1150 flushsaprop(pp_peer); 1151 1152 pp_peer = aproppair2saprop(pair[i]); 1153 if (pp_peer == NULL) 1154 goto end; 1155 1156 pp0 = newsaprop(); 1157 if (pp0 == NULL) { 1158 plog(LLV_ERROR, LOCATION, NULL, 1159 "failed to allocate saprop.\n"); 1160 goto end; 1161 } 1162 pp0->prop_no = 1; 1163 pp0->lifetime = iph2->sainfo->lifetime; 1164 pp0->lifebyte = iph2->sainfo->lifebyte; 1165 pp0->pfs_group = iph2->sainfo->pfs_group; 1166 1167 #ifdef HAVE_SECCTX 1168 if (*pp_peer->sctx.ctx_str) { 1169 pp0->sctx.ctx_doi = pp_peer->sctx.ctx_doi; 1170 pp0->sctx.ctx_alg = pp_peer->sctx.ctx_alg; 1171 pp0->sctx.ctx_strlen = pp_peer->sctx.ctx_strlen; 1172 memcpy(pp0->sctx.ctx_str, pp_peer->sctx.ctx_str, 1173 pp_peer->sctx.ctx_strlen); 1174 } 1175 #endif /* HAVE_SECCTX */ 1176 1177 if (pp_peer->next != NULL) { 1178 plog(LLV_ERROR, LOCATION, NULL, 1179 "pp_peer is inconsistency, ignore it.\n"); 1180 /*FALLTHROUGH*/ 1181 } 1182 1183 for (pr = pp_peer->head; pr; pr = pr->next) 1184 { 1185 newpr = newsaproto(); 1186 if (newpr == NULL) 1187 { 1188 plog(LLV_ERROR, LOCATION, NULL, 1189 "failed to allocate saproto.\n"); 1190 racoon_free(pp0); 1191 goto end; 1192 } 1193 newpr->proto_id = pr->proto_id; 1194 newpr->spisize = pr->spisize; 1195 newpr->encmode = pr->encmode; 1196 newpr->spi = 0; 1197 newpr->spi_p = pr->spi; /* copy peer's SPI */ 1198 newpr->reqid_in = 0; 1199 newpr->reqid_out = 0; 1200 1201 if (iph2->ph1->rmconf->gen_policy == GENERATE_POLICY_UNIQUE){ 1202 newpr->reqid_in = g_nextreqid ; 1203 newpr->reqid_out = g_nextreqid ++; 1204 /* 1205 * XXX there is a (very limited) 1206 * risk of reusing the same reqid 1207 * as another SP entry for the same peer 1208 */ 1209 if(g_nextreqid >= IPSEC_MANUAL_REQID_MAX) 1210 g_nextreqid = 1; 1211 }else{ 1212 newpr->reqid_in = 0; 1213 newpr->reqid_out = 0; 1214 } 1215 1216 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) 1217 { 1218 plog(LLV_ERROR, LOCATION, NULL, 1219 "failed to get algorithms.\n"); 1220 racoon_free(newpr); 1221 racoon_free(pp0); 1222 goto end; 1223 } 1224 inssaproto(pp0, newpr); 1225 } 1226 1227 inssaprop(&newpp, pp0); 1228 } 1229 1230 plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n"); 1231 printsaprop0(LLV_DEBUG, newpp); 1232 1233 iph2->proposal = newpp; 1234 1235 error = 0; 1236 1237 end: 1238 if (error && newpp) 1239 flushsaprop(newpp); 1240 1241 if (pp_peer) 1242 flushsaprop(pp_peer); 1243 if (pair) 1244 free_proppair(pair); 1245 return error; 1246 } 1247