1 /* $OpenBSD: isakmp_cfg.c,v 1.38 2007/04/16 13:01:39 moritz Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. 5 * Copyright (c) 2002 H�kan Olsson. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * This code was written under funding by Gatespace 30 * (http://www.gatespace.com/). 31 */ 32 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 #include <string.h> 38 #include <bitstring.h> 39 40 #include "attribute.h" 41 #include "conf.h" 42 #include "exchange.h" 43 #include "hash.h" 44 #include "ipsec.h" 45 #include "isakmp_fld.h" 46 #include "isakmp_num.h" 47 #include "log.h" 48 #include "message.h" 49 #include "prf.h" 50 #include "sa.h" 51 #include "transport.h" 52 #include "util.h" 53 54 /* 55 * Validation script used to test messages for correct content of 56 * payloads depending on the exchange type. 57 */ 58 int16_t script_transaction[] = { 59 ISAKMP_PAYLOAD_ATTRIBUTE, /* Initiator -> responder. */ 60 EXCHANGE_SCRIPT_SWITCH, 61 ISAKMP_PAYLOAD_ATTRIBUTE, /* Responder -> initiator. */ 62 EXCHANGE_SCRIPT_END 63 }; 64 65 static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); 66 static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t, 67 u_int32_t, char *, u_int8_t **, u_int16_t *); 68 static int cfg_initiator_send_ATTR(struct message *); 69 static int cfg_initiator_recv_ATTR(struct message *); 70 static int cfg_responder_recv_ATTR(struct message *); 71 static int cfg_responder_send_ATTR(struct message *); 72 73 u_int8_t *cfg_add_hash(struct message *); 74 int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *, 75 u_int16_t); 76 int cfg_verify_hash(struct message *); 77 78 /* Server: SET/ACK Client; REQ/REPLY */ 79 int (*isakmp_cfg_initiator[]) (struct message *) = { 80 cfg_initiator_send_ATTR, 81 cfg_initiator_recv_ATTR 82 }; 83 84 /* Server: REQ/REPLY Client: SET/ACK */ 85 int (*isakmp_cfg_responder[]) (struct message *) = { 86 cfg_responder_recv_ATTR, 87 cfg_responder_send_ATTR 88 }; 89 90 /* 91 * When we are "the server", this starts SET/ACK mode 92 * When we are "the client", this starts REQ/REPLY mode 93 */ 94 static int 95 cfg_initiator_send_ATTR(struct message *msg) 96 { 97 struct sa *isakmp_sa = msg->isakmp_sa; 98 struct ipsec_exch *ie = msg->exchange->data; 99 u_int8_t *hashp = 0, *attrp, *attr; 100 size_t attrlen, off; 101 char *id_string, *cfg_mode, *field; 102 struct sockaddr *sa; 103 #define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN /* XXX */ 104 bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX); 105 u_int16_t bit, length; 106 u_int32_t life; 107 108 if (msg->exchange->phase == 2) { 109 hashp = cfg_add_hash(msg); 110 if (!hashp) 111 return -1; 112 } 113 /* We initiated this exchange, check isakmp_sa for other side. */ 114 if (isakmp_sa->initiator) 115 id_string = ipsec_id_string(isakmp_sa->id_r, 116 isakmp_sa->id_r_len); 117 else 118 id_string = ipsec_id_string(isakmp_sa->id_i, 119 isakmp_sa->id_i_len); 120 if (!id_string) { 121 log_print("cfg_initiator_send_ATTR: cannot parse ID"); 122 goto fail; 123 } 124 /* Check for attribute list to send to the other side */ 125 attrlen = 0; 126 bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1); 127 128 cfg_mode = conf_get_str(id_string, "Mode"); 129 if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) { 130 /* SET/ACK mode */ 131 ie->cfg_type = ISAKMP_CFG_SET; 132 133 LOG_DBG((LOG_NEGOTIATION, 10, 134 "cfg_initiator_send_ATTR: SET/ACK mode")); 135 136 #define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \ 137 { \ 138 if ((sa = conf_get_address (id_string, STR)) != NULL) \ 139 switch (sa->sa_family) { \ 140 case AF_INET: \ 141 bit_set (attrbits, ATTR4); \ 142 attrlen += ISAKMP_ATTR_SZ + LEN4; \ 143 break; \ 144 case AF_INET6: \ 145 bit_set (attrbits, ATTR6); \ 146 attrlen += ISAKMP_ATTR_SZ + LEN6; \ 147 break; \ 148 default: \ 149 break; \ 150 } \ 151 free (sa); \ 152 } while (0) 153 154 /* 155 * XXX We don't simultaneously support IPv4 and IPv6 156 * addresses. 157 */ 158 ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4, 159 ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16); 160 ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4, 161 ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16); 162 ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4, 163 ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16); 164 ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4, 165 ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16); 166 ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4, 167 ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16); 168 #ifdef notyet 169 ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8, 170 ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17); 171 #endif 172 #undef ATTRFIND 173 174 if (conf_get_str(id_string, "Lifetime")) { 175 bit_set(attrbits, 176 ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); 177 attrlen += ISAKMP_ATTR_SZ + 4; 178 } 179 } else { 180 struct conf_list *alist; 181 struct conf_list_node *anode; 182 183 ie->cfg_type = ISAKMP_CFG_REQUEST; 184 185 LOG_DBG((LOG_NEGOTIATION, 10, 186 "cfg_initiator_send_ATTR: REQ/REPLY mode")); 187 188 alist = conf_get_list(id_string, "Attributes"); 189 if (alist) { 190 for (anode = TAILQ_FIRST(&alist->fields); anode; 191 anode = TAILQ_NEXT(anode, link)) { 192 if (strcasecmp(anode->field, "Address") == 0) { 193 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS); 194 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS); 195 attrlen += ISAKMP_ATTR_SZ * 2; 196 } else if (strcasecmp(anode->field, "Netmask") 197 == 0) { 198 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK); 199 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK); 200 attrlen += ISAKMP_ATTR_SZ * 2; 201 } else if (strcasecmp(anode->field, 202 "Nameserver") == 0) { 203 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS); 204 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS); 205 attrlen += ISAKMP_ATTR_SZ * 2; 206 } else if (strcasecmp(anode->field, 207 "WINS-server") == 0) { 208 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS); 209 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS); 210 attrlen += ISAKMP_ATTR_SZ * 2; 211 } else if (strcasecmp(anode->field, 212 "DHCP-server") == 0) { 213 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP); 214 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP); 215 attrlen += ISAKMP_ATTR_SZ * 2; 216 } else if (strcasecmp(anode->field, 217 "Lifetime") == 0) { 218 bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); 219 attrlen += ISAKMP_ATTR_SZ; 220 } else { 221 log_print("cfg_initiator_send_ATTR: " 222 "unknown attribute %.20s in " 223 "section [%s]", anode->field, 224 id_string); 225 } 226 } 227 228 conf_free_list(alist); 229 } 230 } 231 232 if (attrlen == 0) { 233 /* No data found. */ 234 log_print("cfg_initiator_send_ATTR: no IKECFG attributes " 235 "found for [%s]", id_string); 236 237 /* 238 * We can continue, but this indicates a configuration error 239 * that the user probably will want to correct. 240 */ 241 free(id_string); 242 return 0; 243 } 244 attrlen += ISAKMP_ATTRIBUTE_SZ; 245 attrp = calloc(1, attrlen); 246 if (!attrp) { 247 log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed", 248 (unsigned long)attrlen); 249 goto fail; 250 } 251 if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, 252 1)) { 253 free(attrp); 254 goto fail; 255 } 256 SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type); 257 getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id); 258 SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id); 259 260 off = ISAKMP_ATTRIBUTE_SZ; 261 262 /* 263 * Use the bitstring built previously to collect the right 264 * parameters for attrp. 265 */ 266 for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++) 267 if (bit_test(attrbits, bit)) { 268 attr = attrp + off; 269 SET_ISAKMP_ATTR_TYPE(attr, bit); 270 271 if (ie->cfg_type == ISAKMP_CFG_REQUEST) { 272 off += ISAKMP_ATTR_SZ; 273 continue; 274 } 275 /* All the other are similar, this is the odd one. */ 276 if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) { 277 life = conf_get_num(id_string, "Lifetime", 278 1200); 279 SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4); 280 encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life); 281 off += ISAKMP_ATTR_SZ + 4; 282 continue; 283 } 284 switch (bit) { 285 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 286 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 287 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 288 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 289 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 290 length = 4; 291 break; 292 293 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 294 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 295 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 296 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 297 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 298 length = 16; 299 break; 300 301 default: 302 length = 0; /* Silence gcc. */ 303 } 304 305 switch (bit) { 306 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 307 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 308 field = "Address"; 309 break; 310 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 311 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 312 field = "Netmask"; 313 break; 314 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 315 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 316 field = "Nameserver"; 317 break; 318 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 319 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 320 field = "DHCP-server"; 321 break; 322 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 323 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 324 field = "WINS-server"; 325 break; 326 default: 327 field = 0; /* Silence gcc. */ 328 } 329 330 sa = conf_get_address(id_string, field); 331 332 SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length); 333 memcpy(attr + ISAKMP_ATTR_VALUE_OFF, 334 sockaddr_addrdata(sa), length); 335 336 free(sa); 337 338 off += ISAKMP_ATTR_SZ + length; 339 } 340 if (msg->exchange->phase == 2) 341 if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) 342 goto fail; 343 344 return 0; 345 346 fail: 347 free(id_string); 348 return -1; 349 } 350 351 /* 352 * As "the server", this ends SET/ACK. 353 * As "the client", this ends REQ/REPLY. 354 */ 355 static int 356 cfg_initiator_recv_ATTR(struct message *msg) 357 { 358 struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); 359 struct ipsec_exch *ie = msg->exchange->data; 360 struct sa *isakmp_sa = msg->isakmp_sa; 361 struct isakmp_cfg_attr *attr; 362 struct sockaddr *sa; 363 const char *uk_addr = "<unknown>"; 364 char *addr; 365 366 if (msg->exchange->phase == 2) 367 if (cfg_verify_hash(msg)) 368 return -1; 369 370 /* Sanity. */ 371 if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) { 372 log_print("cfg_initiator_recv_ATTR: " 373 "cfg packet ID does not match!"); 374 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); 375 return -1; 376 } 377 switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) { 378 case ISAKMP_CFG_ACK: 379 if (ie->cfg_type != ISAKMP_CFG_SET) { 380 log_print("cfg_initiator_recv_ATTR: " 381 "bad packet type ACK"); 382 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 383 0, 1, 0); 384 return -1; 385 } 386 break; 387 case ISAKMP_CFG_REPLY: 388 if (ie->cfg_type != ISAKMP_CFG_REQUEST) { 389 log_print("cfg_initiator_recv_ATTR: " 390 "bad packet type REPLY"); 391 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 392 0, 1, 0); 393 return -1; 394 } 395 break; 396 397 default: 398 log_print("cfg_initiator_recv_ATTR: unexpected configuration " 399 "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]); 400 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); 401 return -1; 402 } 403 404 attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, 405 GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, 406 cfg_decode_attribute, ie); 407 408 switch (ie->cfg_type) { 409 case ISAKMP_CFG_ACK: { 410 /* SET/ACK -- Server side (ACK from client) */ 411 msg->transport->vtbl->get_src(isakmp_sa->transport, 412 &sa); 413 if (sockaddr2text(sa, &addr, 0) < 0) 414 addr = (char *) uk_addr; 415 416 for (attr = LIST_FIRST(&ie->attrs); attr; 417 attr = LIST_NEXT(attr, link)) 418 LOG_DBG((LOG_NEGOTIATION, 50, 419 "cfg_initiator_recv_ATTR: " 420 "client %s ACKs attribute %s", addr, 421 constant_name(isakmp_cfg_attr_cst, 422 attr->type))); 423 424 if (addr != uk_addr) 425 free(addr); 426 } 427 break; 428 429 case ISAKMP_CFG_REPLY: { 430 /* 431 * REQ/REPLY: effect attributes we've gotten 432 * responses on. 433 */ 434 msg->transport->vtbl->get_src(isakmp_sa->transport, 435 &sa); 436 if (sockaddr2text(sa, &addr, 0) < 0) 437 addr = (char *) uk_addr; 438 439 for (attr = LIST_FIRST(&ie->attrs); attr; 440 attr = LIST_NEXT(attr, link)) 441 LOG_DBG((LOG_NEGOTIATION, 50, 442 "cfg_initiator_recv_ATTR: " 443 "server %s replied with attribute %s", 444 addr, constant_name(isakmp_cfg_attr_cst, 445 attr->type))); 446 447 if (addr != uk_addr) 448 free(addr); 449 } 450 break; 451 452 default: 453 break; 454 } 455 456 attrp->flags |= PL_MARK; 457 return 0; 458 } 459 460 /* 461 * As "the server", this starts REQ/REPLY (initiated by the client). 462 * As "the client", this starts SET/ACK (initiated by the server). 463 */ 464 static int 465 cfg_responder_recv_ATTR(struct message *msg) 466 { 467 struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); 468 struct ipsec_exch *ie = msg->exchange->data; 469 struct sa *isakmp_sa = msg->isakmp_sa; 470 struct isakmp_cfg_attr *attr; 471 struct sockaddr *sa; 472 char *addr; 473 474 if (msg->exchange->phase == 2) 475 if (cfg_verify_hash(msg)) 476 return -1; 477 478 ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p); 479 ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]; 480 481 switch (ie->cfg_type) { 482 case ISAKMP_CFG_REQUEST: 483 case ISAKMP_CFG_SET: 484 break; 485 486 default: 487 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); 488 log_print("cfg_responder_recv_ATTR: " 489 "unexpected configuration message type %d", ie->cfg_type); 490 return -1; 491 } 492 493 attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, 494 GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, 495 cfg_decode_attribute, ie); 496 497 switch (ie->cfg_type) { 498 case ISAKMP_CFG_REQUEST: 499 /* We're done. */ 500 break; 501 502 case ISAKMP_CFG_SET: { 503 /* SET/ACK -- Client side (SET from server) */ 504 const char *uk_addr = "<unknown>"; 505 506 msg->transport->vtbl->get_dst(isakmp_sa->transport, 507 &sa); 508 if (sockaddr2text(sa, &addr, 0) < 0) 509 addr = (char *) uk_addr; 510 511 for (attr = LIST_FIRST(&ie->attrs); attr; 512 attr = LIST_NEXT(attr, link)) 513 LOG_DBG((LOG_NEGOTIATION, 50, 514 "cfg_responder_recv_ATTR: " 515 "server %s asks us to SET attribute %s", 516 addr, constant_name(isakmp_cfg_attr_cst, 517 attr->type))); 518 519 /* 520 * XXX Here's the place to add code to walk through 521 * XXX each attribute and send them along to dhclient 522 * XXX or whatever. Each attribute that we act upon 523 * XXX (such as setting a netmask), should be marked 524 * XXX like this for us to send the proper ACK 525 * XXX response: attr->attr_used++; 526 */ 527 528 if (addr != uk_addr) 529 free(addr); 530 } 531 break; 532 533 default: 534 break; 535 } 536 537 attrp->flags |= PL_MARK; 538 return 0; 539 } 540 541 /* 542 * As "the server", this ends REQ/REPLY mode. 543 * As "the client", this ends SET/ACK mode. 544 */ 545 static int 546 cfg_responder_send_ATTR(struct message *msg) 547 { 548 struct ipsec_exch *ie = msg->exchange->data; 549 struct sa *isakmp_sa = msg->isakmp_sa; 550 u_int8_t *hashp = 0, *attrp; 551 u_int16_t attrlen; 552 char *id_string; 553 554 if (msg->exchange->phase == 2) { 555 hashp = cfg_add_hash(msg); 556 if (!hashp) 557 return -1; 558 } 559 /* We are responder, check isakmp_sa for other side. */ 560 if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST)) 561 id_string = ipsec_id_string(isakmp_sa->id_i, 562 isakmp_sa->id_i_len); 563 else 564 id_string = ipsec_id_string(isakmp_sa->id_r, 565 isakmp_sa->id_r_len); 566 if (!id_string) { 567 log_print("cfg_responder_send_ATTR: cannot parse client's ID"); 568 return -1; 569 } 570 if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ? 571 ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp, 572 &attrlen)) { 573 free(id_string); 574 return -1; 575 } 576 free(id_string); 577 578 if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, 579 1)) { 580 free(attrp); 581 return -1; 582 } 583 if (msg->exchange->phase == 2) 584 if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) 585 return -1; 586 587 return 0; 588 } 589 590 u_int8_t * 591 cfg_add_hash(struct message *msg) 592 { 593 struct ipsec_sa *isa = msg->isakmp_sa->data; 594 struct hash *hash = hash_get(isa->hash); 595 u_int8_t *hashp; 596 597 hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize); 598 if (!hashp) { 599 log_error("cfg_add_hash: malloc (%lu) failed", 600 ISAKMP_HASH_SZ + (unsigned long)hash->hashsize); 601 return 0; 602 } 603 if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp, 604 ISAKMP_HASH_SZ + hash->hashsize, 1)) { 605 free(hashp); 606 return 0; 607 } 608 return hashp; 609 } 610 611 int 612 cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data, 613 u_int16_t length) 614 { 615 struct ipsec_sa *isa = msg->isakmp_sa->data; 616 struct prf *prf; 617 618 prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, 619 isa->skeyid_len); 620 if (!prf) 621 return -1; 622 623 prf->Init(prf->prfctx); 624 prf->Update(prf->prfctx, msg->exchange->message_id, 625 ISAKMP_HDR_MESSAGE_ID_LEN); 626 prf->Update(prf->prfctx, data, length); 627 prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx); 628 prf_free(prf); 629 return 0; 630 } 631 632 int 633 cfg_verify_hash(struct message *msg) 634 { 635 struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); 636 struct ipsec_sa *isa = msg->isakmp_sa->data; 637 struct prf *prf; 638 u_int8_t *hash, *comp_hash; 639 size_t hash_len; 640 641 if (!hashp) { 642 log_print("cfg_verify_hash: phase 2 message missing HASH"); 643 message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 644 0, 1, 0); 645 return -1; 646 } 647 hash = hashp->p; 648 hash_len = GET_ISAKMP_GEN_LENGTH(hash); 649 comp_hash = malloc(hash_len - ISAKMP_GEN_SZ); 650 if (!comp_hash) { 651 log_error("cfg_verify_hash: malloc (%lu) failed", 652 (unsigned long)hash_len - ISAKMP_GEN_SZ); 653 return -1; 654 } 655 /* Verify hash. */ 656 prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, 657 isa->skeyid_len); 658 if (!prf) { 659 free(comp_hash); 660 return -1; 661 } 662 prf->Init(prf->prfctx); 663 prf->Update(prf->prfctx, msg->exchange->message_id, 664 ISAKMP_HDR_MESSAGE_ID_LEN); 665 prf->Update(prf->prfctx, hash + hash_len, 666 msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len); 667 prf->Final(comp_hash, prf->prfctx); 668 prf_free(prf); 669 670 if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ) 671 != 0) { 672 message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 673 0, 1, 0); 674 free(comp_hash); 675 return -1; 676 } 677 free(comp_hash); 678 679 /* Mark the HASH as handled. */ 680 hashp->flags |= PL_MARK; 681 682 /* Mark message authenticated. */ 683 msg->flags |= MSG_AUTHENTICATED; 684 685 return 0; 686 } 687 688 /* 689 * Decode the attribute of type TYPE with a LEN length value pointed to by 690 * VALUE. VIE is a pointer to the IPsec exchange context holding the 691 * attributes indexed by type for easy retrieval. 692 */ 693 static int 694 cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, 695 void *vie) 696 { 697 struct ipsec_exch *ie = vie; 698 struct isakmp_cfg_attr *attr; 699 700 if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN && 701 type <= ISAKMP_CFG_ATTR_PRIVATE_MAX) 702 return 0; 703 if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) { 704 LOG_DBG((LOG_NEGOTIATION, 30, 705 "cfg_decode_attribute: invalid attr type %u", type)); 706 return -1; 707 } 708 attr = calloc(1, sizeof *attr); 709 if (!attr) { 710 log_error("cfg_decode_attribute: calloc (1, %lu) failed", 711 (unsigned long)sizeof *attr); 712 return -1; 713 } 714 attr->type = type; 715 attr->length = len; 716 if (len) { 717 attr->value = malloc(len); 718 if (!attr->value) { 719 log_error("cfg_decode_attribute: malloc (%d) failed", 720 len); 721 free(attr); 722 /* Should we also deallocate all other values? */ 723 return -1; 724 } 725 memcpy(attr->value, value, len); 726 } 727 LIST_INSERT_HEAD(&ie->attrs, attr, link); 728 return 0; 729 } 730 731 /* 732 * Encode list of attributes from ie->attrs into a attribute payload. 733 */ 734 static int 735 cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type, 736 u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len) 737 { 738 struct isakmp_cfg_attr *attr; 739 struct sockaddr *sa; 740 sa_family_t family; 741 u_int32_t value; 742 u_int16_t off; 743 char *field; 744 745 /* Compute length */ 746 *len = ISAKMP_ATTRIBUTE_SZ; 747 for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { 748 /* With ACK we only include the attrs we've actually used. */ 749 if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) 750 continue; 751 752 switch (attr->type) { 753 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 754 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 755 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 756 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 757 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 758 case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: 759 attr->length = 4; 760 break; 761 762 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: 763 attr->length = 8; 764 break; 765 766 case ISAKMP_CFG_ATTR_APPLICATION_VERSION: 767 /* XXX So far no version identifier of isakmpd here. */ 768 attr->length = 0; 769 break; 770 771 case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: 772 attr->length = 2 * 15; 773 break; 774 775 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 776 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 777 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 778 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 779 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 780 attr->length = 16; 781 break; 782 783 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: 784 attr->length = 17; 785 break; 786 787 default: 788 attr->ignore++; 789 /* XXX Log! */ 790 } 791 *len += ISAKMP_ATTR_SZ + attr->length; 792 } 793 794 /* Allocate enough space for the payload */ 795 *attrp = calloc(1, *len); 796 if (!*attrp) { 797 log_error("cfg_encode_attributes: calloc (1, %lu) failed", 798 (unsigned long)*len); 799 return -1; 800 } 801 SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type); 802 SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id); 803 804 off = ISAKMP_ATTRIBUTE_SZ; 805 for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { 806 /* With ACK we only include the attrs we've actually used. */ 807 if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) 808 continue; 809 810 switch (attr->type) { 811 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 812 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 813 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: 814 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 815 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 816 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 817 family = AF_INET; 818 break; 819 820 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 821 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 822 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: 823 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 824 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 825 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 826 family = AF_INET6; 827 break; 828 829 default: 830 family = 0; 831 break; 832 } 833 834 switch (attr->type) { 835 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 836 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 837 field = "Address"; 838 break; 839 840 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: 841 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: 842 field = "Network"; /* XXX or just "Address" */ 843 break; 844 845 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 846 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 847 field = "Netmask"; 848 break; 849 850 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 851 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 852 field = "DHCP-server"; 853 break; 854 855 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 856 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 857 field = "Nameserver"; 858 break; 859 860 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 861 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 862 field = "WINS-server"; 863 break; 864 865 default: 866 field = 0; 867 } 868 869 switch (attr->type) { 870 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: 871 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: 872 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: 873 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: 874 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: 875 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: 876 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: 877 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: 878 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: 879 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: 880 sa = conf_get_address(id_string, field); 881 if (!sa) { 882 LOG_DBG((LOG_NEGOTIATION, 10, 883 "cfg_responder_send_ATTR: " 884 "attribute not found: %s", field)); 885 attr->length = 0; 886 break; 887 } 888 if (sa->sa_family != family) { 889 log_print("cfg_responder_send_ATTR: " 890 "attribute %s - expected %s got %s data", 891 field, 892 (family == AF_INET ? "IPv4" : "IPv6"), 893 (sa->sa_family == 894 AF_INET ? "IPv4" : "IPv6")); 895 free(sa); 896 attr->length = 0; 897 break; 898 } 899 /* Temporary limit length for the _SUBNET types. */ 900 if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) 901 attr->length = 4; 902 else if (attr->type == 903 ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) 904 attr->length = 16; 905 906 memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF, 907 sockaddr_addrdata(sa), attr->length); 908 free(sa); 909 910 /* _SUBNET types need some extra work. */ 911 if (attr->type == 912 ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) { 913 sa = conf_get_address(id_string, "Netmask"); 914 if (!sa) { 915 LOG_DBG((LOG_NEGOTIATION, 10, 916 "cfg_responder_send_ATTR: " 917 "attribute not found: Netmask")); 918 attr->length = 0; 919 break; 920 } 921 if (sa->sa_family != AF_INET) { 922 log_print("cfg_responder_send_ATTR: " 923 "attribute Netmask - expected " 924 "IPv4 got IPv6 data"); 925 free(sa); 926 attr->length = 0; 927 break; 928 } 929 memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 930 attr->length, sockaddr_addrdata(sa), 931 attr->length); 932 attr->length = 8; 933 free(sa); 934 } else if (attr->type == 935 ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) { 936 int prefix = conf_get_num(id_string, "Prefix", 937 -1); 938 939 if (prefix == -1) { 940 log_print("cfg_responder_send_ATTR: " 941 "attribute not found: Prefix"); 942 attr->length = 0; 943 break; 944 } else if (prefix < -1 || prefix > 128) { 945 log_print("cfg_responder_send_ATTR: " 946 "attribute Prefix - invalid " 947 "value %d", prefix); 948 attr->length = 0; 949 break; 950 } 951 *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) = 952 (u_int8_t)prefix; 953 attr->length = 17; 954 } 955 break; 956 957 case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: 958 value = conf_get_num(id_string, "Lifetime", 1200); 959 encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value); 960 break; 961 962 case ISAKMP_CFG_ATTR_APPLICATION_VERSION: 963 /* XXX So far no version identifier of isakmpd here. */ 964 break; 965 966 case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: 967 break; 968 969 default: 970 break; 971 } 972 973 SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type); 974 SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length); 975 off += ISAKMP_ATTR_VALUE_OFF + attr->length; 976 } 977 978 return 0; 979 } 980