1 /* $OpenBSD: isakmp_cfg.c,v 1.37 2005/04/08 22:32:10 cloder 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
cfg_initiator_send_ATTR(struct message * msg)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 if (id_string)
348 free(id_string);
349 return -1;
350 }
351
352 /*
353 * As "the server", this ends SET/ACK.
354 * As "the client", this ends REQ/REPLY.
355 */
356 static int
cfg_initiator_recv_ATTR(struct message * msg)357 cfg_initiator_recv_ATTR(struct message *msg)
358 {
359 struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE);
360 struct ipsec_exch *ie = msg->exchange->data;
361 struct sa *isakmp_sa = msg->isakmp_sa;
362 struct isakmp_cfg_attr *attr;
363 struct sockaddr *sa;
364 const char *uk_addr = "<unknown>";
365 char *addr;
366
367 if (msg->exchange->phase == 2)
368 if (cfg_verify_hash(msg))
369 return -1;
370
371 /* Sanity. */
372 if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) {
373 log_print("cfg_initiator_recv_ATTR: "
374 "cfg packet ID does not match!");
375 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
376 return -1;
377 }
378 switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) {
379 case ISAKMP_CFG_ACK:
380 if (ie->cfg_type != ISAKMP_CFG_SET) {
381 log_print("cfg_initiator_recv_ATTR: "
382 "bad packet type ACK");
383 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
384 0, 1, 0);
385 return -1;
386 }
387 break;
388 case ISAKMP_CFG_REPLY:
389 if (ie->cfg_type != ISAKMP_CFG_REQUEST) {
390 log_print("cfg_initiator_recv_ATTR: "
391 "bad packet type REPLY");
392 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
393 0, 1, 0);
394 return -1;
395 }
396 break;
397
398 default:
399 log_print("cfg_initiator_recv_ATTR: unexpected configuration "
400 "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]);
401 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
402 return -1;
403 }
404
405 attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF,
406 GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
407 cfg_decode_attribute, ie);
408
409 switch (ie->cfg_type) {
410 case ISAKMP_CFG_ACK: {
411 /* SET/ACK -- Server side (ACK from client) */
412 msg->transport->vtbl->get_src(isakmp_sa->transport,
413 &sa);
414 if (sockaddr2text(sa, &addr, 0) < 0)
415 addr = (char *) uk_addr;
416
417 for (attr = LIST_FIRST(&ie->attrs); attr;
418 attr = LIST_NEXT(attr, link))
419 LOG_DBG((LOG_NEGOTIATION, 50,
420 "cfg_initiator_recv_ATTR: "
421 "client %s ACKs attribute %s", addr,
422 constant_name(isakmp_cfg_attr_cst,
423 attr->type)));
424
425 if (addr != uk_addr)
426 free(addr);
427 }
428 break;
429
430 case ISAKMP_CFG_REPLY: {
431 /*
432 * REQ/REPLY: effect attributes we've gotten
433 * responses on.
434 */
435 msg->transport->vtbl->get_src(isakmp_sa->transport,
436 &sa);
437 if (sockaddr2text(sa, &addr, 0) < 0)
438 addr = (char *) uk_addr;
439
440 for (attr = LIST_FIRST(&ie->attrs); attr;
441 attr = LIST_NEXT(attr, link))
442 LOG_DBG((LOG_NEGOTIATION, 50,
443 "cfg_initiator_recv_ATTR: "
444 "server %s replied with attribute %s",
445 addr, constant_name(isakmp_cfg_attr_cst,
446 attr->type)));
447
448 if (addr != uk_addr)
449 free(addr);
450 }
451 break;
452
453 default:
454 break;
455 }
456
457 attrp->flags |= PL_MARK;
458 return 0;
459 }
460
461 /*
462 * As "the server", this starts REQ/REPLY (initiated by the client).
463 * As "the client", this starts SET/ACK (initiated by the server).
464 */
465 static int
cfg_responder_recv_ATTR(struct message * msg)466 cfg_responder_recv_ATTR(struct message *msg)
467 {
468 struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE);
469 struct ipsec_exch *ie = msg->exchange->data;
470 struct sa *isakmp_sa = msg->isakmp_sa;
471 struct isakmp_cfg_attr *attr;
472 struct sockaddr *sa;
473 char *addr;
474
475 if (msg->exchange->phase == 2)
476 if (cfg_verify_hash(msg))
477 return -1;
478
479 ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p);
480 ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF];
481
482 switch (ie->cfg_type) {
483 case ISAKMP_CFG_REQUEST:
484 case ISAKMP_CFG_SET:
485 break;
486
487 default:
488 message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
489 log_print("cfg_responder_recv_ATTR: "
490 "unexpected configuration message type %d", ie->cfg_type);
491 return -1;
492 }
493
494 attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF,
495 GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
496 cfg_decode_attribute, ie);
497
498 switch (ie->cfg_type) {
499 case ISAKMP_CFG_REQUEST:
500 /* We're done. */
501 break;
502
503 case ISAKMP_CFG_SET: {
504 /* SET/ACK -- Client side (SET from server) */
505 const char *uk_addr = "<unknown>";
506
507 msg->transport->vtbl->get_dst(isakmp_sa->transport,
508 &sa);
509 if (sockaddr2text(sa, &addr, 0) < 0)
510 addr = (char *) uk_addr;
511
512 for (attr = LIST_FIRST(&ie->attrs); attr;
513 attr = LIST_NEXT(attr, link))
514 LOG_DBG((LOG_NEGOTIATION, 50,
515 "cfg_responder_recv_ATTR: "
516 "server %s asks us to SET attribute %s",
517 addr, constant_name(isakmp_cfg_attr_cst,
518 attr->type)));
519
520 /*
521 * XXX Here's the place to add code to walk through
522 * XXX each attribute and send them along to dhclient
523 * XXX or whatever. Each attribute that we act upon
524 * XXX (such as setting a netmask), should be marked
525 * XXX like this for us to send the proper ACK
526 * XXX response: attr->attr_used++;
527 */
528
529 if (addr != uk_addr)
530 free(addr);
531 }
532 break;
533
534 default:
535 break;
536 }
537
538 attrp->flags |= PL_MARK;
539 return 0;
540 }
541
542 /*
543 * As "the server", this ends REQ/REPLY mode.
544 * As "the client", this ends SET/ACK mode.
545 */
546 static int
cfg_responder_send_ATTR(struct message * msg)547 cfg_responder_send_ATTR(struct message *msg)
548 {
549 struct ipsec_exch *ie = msg->exchange->data;
550 struct sa *isakmp_sa = msg->isakmp_sa;
551 u_int8_t *hashp = 0, *attrp;
552 u_int16_t attrlen;
553 char *id_string;
554
555 if (msg->exchange->phase == 2) {
556 hashp = cfg_add_hash(msg);
557 if (!hashp)
558 return -1;
559 }
560 /* We are responder, check isakmp_sa for other side. */
561 if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST))
562 id_string = ipsec_id_string(isakmp_sa->id_i,
563 isakmp_sa->id_i_len);
564 else
565 id_string = ipsec_id_string(isakmp_sa->id_r,
566 isakmp_sa->id_r_len);
567 if (!id_string) {
568 log_print("cfg_responder_send_ATTR: cannot parse client's ID");
569 return -1;
570 }
571 if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ?
572 ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp,
573 &attrlen)) {
574 free(id_string);
575 return -1;
576 }
577 free(id_string);
578
579 if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
580 1)) {
581 free(attrp);
582 return -1;
583 }
584 if (msg->exchange->phase == 2)
585 if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
586 return -1;
587
588 return 0;
589 }
590
591 u_int8_t *
cfg_add_hash(struct message * msg)592 cfg_add_hash(struct message *msg)
593 {
594 struct ipsec_sa *isa = msg->isakmp_sa->data;
595 struct hash *hash = hash_get(isa->hash);
596 u_int8_t *hashp;
597
598 hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize);
599 if (!hashp) {
600 log_error("cfg_add_hash: malloc (%lu) failed",
601 ISAKMP_HASH_SZ + (unsigned long)hash->hashsize);
602 return 0;
603 }
604 if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp,
605 ISAKMP_HASH_SZ + hash->hashsize, 1)) {
606 free(hashp);
607 return 0;
608 }
609 return hashp;
610 }
611
612 int
cfg_finalize_hash(struct message * msg,u_int8_t * hashp,u_int8_t * data,u_int16_t length)613 cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data,
614 u_int16_t length)
615 {
616 struct ipsec_sa *isa = msg->isakmp_sa->data;
617 struct prf *prf;
618
619 prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
620 isa->skeyid_len);
621 if (!prf)
622 return -1;
623
624 prf->Init(prf->prfctx);
625 prf->Update(prf->prfctx, msg->exchange->message_id,
626 ISAKMP_HDR_MESSAGE_ID_LEN);
627 prf->Update(prf->prfctx, data, length);
628 prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx);
629 prf_free(prf);
630 return 0;
631 }
632
633 int
cfg_verify_hash(struct message * msg)634 cfg_verify_hash(struct message *msg)
635 {
636 struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
637 struct ipsec_sa *isa = msg->isakmp_sa->data;
638 struct prf *prf;
639 u_int8_t *hash, *comp_hash;
640 size_t hash_len;
641
642 if (!hashp) {
643 log_print("cfg_verify_hash: phase 2 message missing HASH");
644 message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
645 0, 1, 0);
646 return -1;
647 }
648 hash = hashp->p;
649 hash_len = GET_ISAKMP_GEN_LENGTH(hash);
650 comp_hash = malloc(hash_len - ISAKMP_GEN_SZ);
651 if (!comp_hash) {
652 log_error("cfg_verify_hash: malloc (%lu) failed",
653 (unsigned long)hash_len - ISAKMP_GEN_SZ);
654 return -1;
655 }
656 /* Verify hash. */
657 prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
658 isa->skeyid_len);
659 if (!prf) {
660 free(comp_hash);
661 return -1;
662 }
663 prf->Init(prf->prfctx);
664 prf->Update(prf->prfctx, msg->exchange->message_id,
665 ISAKMP_HDR_MESSAGE_ID_LEN);
666 prf->Update(prf->prfctx, hash + hash_len,
667 msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
668 prf->Final(comp_hash, prf->prfctx);
669 prf_free(prf);
670
671 if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ)
672 != 0) {
673 message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
674 0, 1, 0);
675 free(comp_hash);
676 return -1;
677 }
678 free(comp_hash);
679
680 /* Mark the HASH as handled. */
681 hashp->flags |= PL_MARK;
682
683 /* Mark message authenticated. */
684 msg->flags |= MSG_AUTHENTICATED;
685
686 return 0;
687 }
688
689 /*
690 * Decode the attribute of type TYPE with a LEN length value pointed to by
691 * VALUE. VIE is a pointer to the IPsec exchange context holding the
692 * attributes indexed by type for easy retrieval.
693 */
694 static int
cfg_decode_attribute(u_int16_t type,u_int8_t * value,u_int16_t len,void * vie)695 cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len,
696 void *vie)
697 {
698 struct ipsec_exch *ie = vie;
699 struct isakmp_cfg_attr *attr;
700
701 if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN &&
702 type <= ISAKMP_CFG_ATTR_PRIVATE_MAX)
703 return 0;
704 if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) {
705 LOG_DBG((LOG_NEGOTIATION, 30,
706 "cfg_decode_attribute: invalid attr type %u", type));
707 return -1;
708 }
709 attr = calloc(1, sizeof *attr);
710 if (!attr) {
711 log_error("cfg_decode_attribute: calloc (1, %lu) failed",
712 (unsigned long)sizeof *attr);
713 return -1;
714 }
715 attr->type = type;
716 attr->length = len;
717 if (len) {
718 attr->value = malloc(len);
719 if (!attr->value) {
720 log_error("cfg_decode_attribute: malloc (%d) failed",
721 len);
722 free(attr);
723 /* Should we also deallocate all other values? */
724 return -1;
725 }
726 memcpy(attr->value, value, len);
727 }
728 LIST_INSERT_HEAD(&ie->attrs, attr, link);
729 return 0;
730 }
731
732 /*
733 * Encode list of attributes from ie->attrs into a attribute payload.
734 */
735 static int
cfg_encode_attributes(struct isakmp_cfg_attr_head * attrs,u_int32_t type,u_int32_t cfg_id,char * id_string,u_int8_t ** attrp,u_int16_t * len)736 cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type,
737 u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len)
738 {
739 struct isakmp_cfg_attr *attr;
740 struct sockaddr *sa;
741 sa_family_t family;
742 u_int32_t value;
743 u_int16_t off;
744 char *field;
745
746 /* Compute length */
747 *len = ISAKMP_ATTRIBUTE_SZ;
748 for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
749 /* With ACK we only include the attrs we've actually used. */
750 if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
751 continue;
752
753 switch (attr->type) {
754 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
755 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
756 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
757 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
758 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
759 case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
760 attr->length = 4;
761 break;
762
763 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
764 attr->length = 8;
765 break;
766
767 case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
768 /* XXX So far no version identifier of isakmpd here. */
769 attr->length = 0;
770 break;
771
772 case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
773 attr->length = 2 * 15;
774 break;
775
776 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
777 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
778 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
779 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
780 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
781 attr->length = 16;
782 break;
783
784 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
785 attr->length = 17;
786 break;
787
788 default:
789 attr->ignore++;
790 /* XXX Log! */
791 }
792 *len += ISAKMP_ATTR_SZ + attr->length;
793 }
794
795 /* Allocate enough space for the payload */
796 *attrp = calloc(1, *len);
797 if (!*attrp) {
798 log_error("cfg_encode_attributes: calloc (1, %lu) failed",
799 (unsigned long)*len);
800 return -1;
801 }
802 SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type);
803 SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id);
804
805 off = ISAKMP_ATTRIBUTE_SZ;
806 for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
807 /* With ACK we only include the attrs we've actually used. */
808 if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
809 continue;
810
811 switch (attr->type) {
812 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
813 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
814 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
815 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
816 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
817 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
818 family = AF_INET;
819 break;
820
821 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
822 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
823 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
824 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
825 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
826 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
827 family = AF_INET6;
828 break;
829
830 default:
831 family = 0;
832 break;
833 }
834
835 switch (attr->type) {
836 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
837 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
838 field = "Address";
839 break;
840
841 case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
842 case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
843 field = "Network"; /* XXX or just "Address" */
844 break;
845
846 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
847 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
848 field = "Netmask";
849 break;
850
851 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
852 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
853 field = "DHCP-server";
854 break;
855
856 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
857 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
858 field = "Nameserver";
859 break;
860
861 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
862 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
863 field = "WINS-server";
864 break;
865
866 default:
867 field = 0;
868 }
869
870 switch (attr->type) {
871 case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
872 case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
873 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
874 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
875 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
876 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
877 case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
878 case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
879 case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
880 case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
881 sa = conf_get_address(id_string, field);
882 if (!sa) {
883 LOG_DBG((LOG_NEGOTIATION, 10,
884 "cfg_responder_send_ATTR: "
885 "attribute not found: %s", field));
886 attr->length = 0;
887 break;
888 }
889 if (sa->sa_family != family) {
890 log_print("cfg_responder_send_ATTR: "
891 "attribute %s - expected %s got %s data",
892 field,
893 (family == AF_INET ? "IPv4" : "IPv6"),
894 (sa->sa_family ==
895 AF_INET ? "IPv4" : "IPv6"));
896 free(sa);
897 attr->length = 0;
898 break;
899 }
900 /* Temporary limit length for the _SUBNET types. */
901 if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET)
902 attr->length = 4;
903 else if (attr->type ==
904 ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET)
905 attr->length = 16;
906
907 memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF,
908 sockaddr_addrdata(sa), attr->length);
909 free(sa);
910
911 /* _SUBNET types need some extra work. */
912 if (attr->type ==
913 ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) {
914 sa = conf_get_address(id_string, "Netmask");
915 if (!sa) {
916 LOG_DBG((LOG_NEGOTIATION, 10,
917 "cfg_responder_send_ATTR: "
918 "attribute not found: Netmask"));
919 attr->length = 0;
920 break;
921 }
922 if (sa->sa_family != AF_INET) {
923 log_print("cfg_responder_send_ATTR: "
924 "attribute Netmask - expected "
925 "IPv4 got IPv6 data");
926 free(sa);
927 attr->length = 0;
928 break;
929 }
930 memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF +
931 attr->length, sockaddr_addrdata(sa),
932 attr->length);
933 attr->length = 8;
934 free(sa);
935 } else if (attr->type ==
936 ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) {
937 int prefix = conf_get_num(id_string, "Prefix",
938 -1);
939
940 if (prefix == -1) {
941 log_print("cfg_responder_send_ATTR: "
942 "attribute not found: Prefix");
943 attr->length = 0;
944 break;
945 } else if (prefix < -1 || prefix > 128) {
946 log_print("cfg_responder_send_ATTR: "
947 "attribute Prefix - invalid "
948 "value %d", prefix);
949 attr->length = 0;
950 break;
951 }
952 *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) =
953 (u_int8_t)prefix;
954 attr->length = 17;
955 }
956 break;
957
958 case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
959 value = conf_get_num(id_string, "Lifetime", 1200);
960 encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value);
961 break;
962
963 case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
964 /* XXX So far no version identifier of isakmpd here. */
965 break;
966
967 case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
968 break;
969
970 default:
971 break;
972 }
973
974 SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type);
975 SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length);
976 off += ISAKMP_ATTR_VALUE_OFF + attr->length;
977 }
978
979 return 0;
980 }
981