File: | src/sbin/isakmpd/sa.c |
Warning: | line 1352, column 18 Value stored to 'seconds' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: sa.c,v 1.125 2022/01/28 05:24:15 guenther Exp $ */ |
2 | /* $EOM: sa.c,v 1.112 2000/12/12 00:22:52 niklas Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. |
6 | * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. |
7 | * Copyright (c) 2003, 2004 Håkan Olsson. 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 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | /* |
31 | * This code was written under funding by Ericsson Radio Systems. |
32 | */ |
33 | |
34 | #include <sys/types.h> |
35 | #include <sys/un.h> |
36 | |
37 | #include <stdlib.h> |
38 | #include <string.h> |
39 | #include <netdb.h> |
40 | |
41 | #include <regex.h> |
42 | #include <keynote.h> |
43 | |
44 | #include "attribute.h" |
45 | #include "conf.h" |
46 | #include "connection.h" |
47 | #include "cookie.h" |
48 | #include "doi.h" |
49 | #include "dpd.h" |
50 | #include "exchange.h" |
51 | #include "isakmp.h" |
52 | #include "log.h" |
53 | #include "message.h" |
54 | #include "monitor.h" |
55 | #include "sa.h" |
56 | #include "timer.h" |
57 | #include "transport.h" |
58 | #include "util.h" |
59 | #include "cert.h" |
60 | #include "policy.h" |
61 | #include "key.h" |
62 | #include "ipsec.h" |
63 | #include "ipsec_num.h" |
64 | |
65 | /* Initial number of bits from the cookies used as hash. */ |
66 | #define INITIAL_BUCKET_BITS6 6 |
67 | |
68 | /* |
69 | * Don't try to use more bits than this as a hash. |
70 | * We only XOR 16 bits so going above that means changing the code below |
71 | * too. |
72 | */ |
73 | #define MAX_BUCKET_BITS16 16 |
74 | |
75 | #if 0 |
76 | static void sa_resize(void); |
77 | #endif |
78 | static void sa_soft_expire(void *); |
79 | static void sa_hard_expire(void *); |
80 | |
81 | static int _net_addrcmp(struct sockaddr *, struct sockaddr *); |
82 | |
83 | static LIST_HEAD(sa_list, sa)struct sa_list { struct sa *lh_first; } *sa_tab; |
84 | |
85 | /* Works both as a maximum index and a mask. */ |
86 | static int bucket_mask; |
87 | |
88 | void |
89 | sa_init(void) |
90 | { |
91 | int i; |
92 | |
93 | bucket_mask = (1 << INITIAL_BUCKET_BITS6) - 1; |
94 | sa_tab = calloc(bucket_mask + 1, sizeof(struct sa_list)); |
95 | if (!sa_tab) |
96 | log_fatal("sa_init: malloc (%lu) failed", |
97 | (bucket_mask + 1) * (unsigned long)sizeof(struct sa_list)); |
98 | for (i = 0; i <= bucket_mask; i++) |
99 | LIST_INIT(&sa_tab[i])do { ((&sa_tab[i])->lh_first) = ((void *)0); } while ( 0); |
100 | } |
101 | |
102 | #if 0 |
103 | /* XXX We don't yet resize. */ |
104 | static void |
105 | sa_resize(void) |
106 | { |
107 | int new_mask = (bucket_mask + 1) * 2 - 1; |
108 | int i; |
109 | struct sa_list *new_tab; |
110 | |
111 | new_tab = reallocarray(sa_tab, new_mask + 1, sizeof(struct sa_list)); |
112 | if (!new_tab) |
113 | return; |
114 | sa_tab = new_tab; |
115 | for (i = bucket_mask + 1; i <= new_mask; i++) |
116 | LIST_INIT(&sa_tab[i])do { ((&sa_tab[i])->lh_first) = ((void *)0); } while ( 0); |
117 | bucket_mask = new_mask; |
118 | |
119 | /* XXX Rehash existing entries. */ |
120 | } |
121 | #endif |
122 | |
123 | /* Lookup an SA with the help from a user-supplied checking function. */ |
124 | struct sa * |
125 | sa_find(int (*check) (struct sa*, void *), void *arg) |
126 | { |
127 | int i; |
128 | struct sa *sa; |
129 | |
130 | for (i = 0; i <= bucket_mask; i++) |
131 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) |
132 | if (check(sa, arg)) { |
133 | LOG_DBG((LOG_SA, 90, "sa_find: return SA %p",log_debug (LOG_SA, 90, "sa_find: return SA %p", sa) |
134 | sa))log_debug (LOG_SA, 90, "sa_find: return SA %p", sa); |
135 | return sa; |
136 | } |
137 | LOG_DBG((LOG_SA, 90, "sa_find: no SA matched query"))log_debug (LOG_SA, 90, "sa_find: no SA matched query"); |
138 | return 0; |
139 | } |
140 | |
141 | /* Check if SA is an ISAKMP SA with an initiator cookie equal to ICOOKIE. */ |
142 | static int |
143 | sa_check_icookie(struct sa *sa, void *icookie) |
144 | { |
145 | return sa->phase == 1 && |
146 | memcmp(sa->cookies, icookie, ISAKMP_HDR_ICOOKIE_LEN8) == 0; |
147 | } |
148 | |
149 | /* Lookup an ISAKMP SA out of just the initiator cookie. */ |
150 | struct sa * |
151 | sa_lookup_from_icookie(u_int8_t *cookie) |
152 | { |
153 | return sa_find(sa_check_icookie, cookie); |
154 | } |
155 | |
156 | struct name_phase_arg { |
157 | char *name; |
158 | u_int8_t phase; |
159 | }; |
160 | |
161 | /* Check if SA has the name and phase given by V_ARG. */ |
162 | static int |
163 | sa_check_name_phase(struct sa *sa, void *v_arg) |
164 | { |
165 | struct name_phase_arg *arg = v_arg; |
166 | |
167 | return sa->name && strcasecmp(sa->name, arg->name) == 0 && |
168 | sa->phase == arg->phase && !(sa->flags & SA_FLAG_REPLACED0x08); |
169 | } |
170 | |
171 | /* Lookup an SA by name, case-independent, and phase. */ |
172 | struct sa * |
173 | sa_lookup_by_name(char *name, int phase) |
174 | { |
175 | struct name_phase_arg arg; |
176 | |
177 | arg.name = name; |
178 | arg.phase = phase; |
179 | return sa_find(sa_check_name_phase, &arg); |
180 | } |
181 | |
182 | struct addr_arg { |
183 | struct sockaddr *addr; |
184 | socklen_t len; |
185 | int phase; |
186 | int flags; |
187 | }; |
188 | |
189 | /* |
190 | * This function has been removed from libc and put here as this |
191 | * file is the only user for it. |
192 | */ |
193 | static int |
194 | _net_addrcmp(struct sockaddr *sa1, struct sockaddr *sa2) |
195 | { |
196 | |
197 | if (sa1->sa_len != sa2->sa_len) |
198 | return (sa1->sa_len < sa2->sa_len) ? -1 : 1; |
199 | if (sa1->sa_family != sa2->sa_family) |
200 | return (sa1->sa_family < sa2->sa_family) ? -1 : 1; |
201 | |
202 | switch(sa1->sa_family) { |
203 | case AF_INET2: |
204 | return (memcmp(&((struct sockaddr_in *)sa1)->sin_addr, |
205 | &((struct sockaddr_in *)sa2)->sin_addr, |
206 | sizeof(struct in_addr))); |
207 | case AF_INET624: |
208 | if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != |
209 | ((struct sockaddr_in6 *)sa2)->sin6_scope_id) |
210 | return (((struct sockaddr_in6 *)sa1)->sin6_scope_id < |
211 | ((struct sockaddr_in6 *)sa2)->sin6_scope_id) |
212 | ? -1 : 1; |
213 | return memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, |
214 | &((struct sockaddr_in6 *)sa2)->sin6_addr, |
215 | sizeof(struct in6_addr)); |
216 | case AF_LOCAL1: |
217 | return (strcmp(((struct sockaddr_un *)sa1)->sun_path, |
218 | ((struct sockaddr_un *)sa2)->sun_path)); |
219 | default: |
220 | return -1; |
221 | } |
222 | } |
223 | |
224 | /* |
225 | * Check if SA is ready and has a peer with an address equal the one given |
226 | * by V_ADDR. Furthermore if we are searching for a specific phase, check |
227 | * that too. |
228 | */ |
229 | static int |
230 | sa_check_peer(struct sa *sa, void *v_addr) |
231 | { |
232 | struct addr_arg *addr = v_addr; |
233 | struct sockaddr *dst; |
234 | |
235 | if (!sa->transport || (sa->flags & SA_FLAG_READY0x01) == 0 || |
236 | (addr->phase && addr->phase != sa->phase)) |
237 | return 0; |
238 | |
239 | sa->transport->vtbl->get_dst(sa->transport, &dst); |
240 | if (_net_addrcmp(dst, addr->addr) != 0) |
241 | return 0; |
242 | |
243 | /* same family, length and address, check port if inet/inet6 */ |
244 | switch (dst->sa_family) { |
245 | case AF_INET2: |
246 | return ((struct sockaddr_in *)dst)->sin_port == ((struct sockaddr_in *)addr->addr)->sin_port; |
247 | case AF_INET624: |
248 | return ((struct sockaddr_in6 *)dst)->sin6_port == ((struct sockaddr_in6 *)addr->addr)->sin6_port; |
249 | } |
250 | |
251 | return 1; |
252 | } |
253 | |
254 | struct dst_isakmpspi_arg { |
255 | struct sockaddr *dst; |
256 | u_int8_t *spi; /* must be ISAKMP_SPI_SIZE octets */ |
257 | }; |
258 | |
259 | /* |
260 | * Check if SA matches what we are asking for through V_ARG. It has to |
261 | * be a finished phase 1 (ISAKMP) SA. |
262 | */ |
263 | static int |
264 | isakmp_sa_check(struct sa *sa, void *v_arg) |
265 | { |
266 | struct dst_isakmpspi_arg *arg = v_arg; |
267 | struct sockaddr *dst, *src; |
268 | |
269 | if (sa->phase != 1 || !(sa->flags & SA_FLAG_READY0x01)) |
270 | return 0; |
271 | |
272 | /* verify address is either src or dst for this sa */ |
273 | sa->transport->vtbl->get_dst(sa->transport, &dst); |
274 | sa->transport->vtbl->get_src(sa->transport, &src); |
275 | if (memcmp(src, arg->dst, SA_LEN(src)((src)->sa_len)) && |
276 | memcmp(dst, arg->dst, SA_LEN(dst)((dst)->sa_len))) |
277 | return 0; |
278 | |
279 | /* match icookie+rcookie against spi */ |
280 | if (memcmp(sa->cookies, arg->spi, ISAKMP_HDR_COOKIES_LEN(8 + 8)) == 0) |
281 | return 1; |
282 | |
283 | return 0; |
284 | } |
285 | |
286 | /* |
287 | * Find an ISAKMP SA with a "name" of DST & SPI. |
288 | */ |
289 | struct sa * |
290 | sa_lookup_isakmp_sa(struct sockaddr *dst, u_int8_t *spi) |
291 | { |
292 | struct dst_isakmpspi_arg arg; |
293 | |
294 | arg.dst = dst; |
295 | arg.spi = spi; |
296 | |
297 | return sa_find(isakmp_sa_check, &arg); |
298 | } |
299 | |
300 | /* Lookup a ready SA by the peer's address. */ |
301 | struct sa * |
302 | sa_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen, int phase) |
303 | { |
304 | struct addr_arg arg; |
305 | |
306 | arg.addr = dst; |
307 | arg.len = dstlen; |
308 | arg.phase = phase; |
309 | |
310 | return sa_find(sa_check_peer, &arg); |
311 | } |
312 | |
313 | /* Lookup a ready ISAKMP SA given its peer address. */ |
314 | struct sa * |
315 | sa_isakmp_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) |
316 | { |
317 | struct addr_arg arg; |
318 | |
319 | arg.addr = dst; |
320 | arg.len = dstlen; |
321 | arg.phase = 1; |
322 | |
323 | return sa_find(sa_check_peer, &arg); |
324 | } |
325 | |
326 | int |
327 | sa_enter(struct sa *sa) |
328 | { |
329 | u_int16_t bucket = 0; |
330 | int i; |
331 | u_int8_t *cp; |
332 | |
333 | /* XXX We might resize if we are crossing a certain threshold */ |
334 | |
335 | for (i = 0; i < ISAKMP_HDR_COOKIES_LEN(8 + 8); i += 2) { |
336 | cp = sa->cookies + i; |
337 | /* Doing it this way avoids alignment problems. */ |
338 | bucket ^= cp[0] | cp[1] << 8; |
339 | } |
340 | for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN4; i += 2) { |
341 | cp = sa->message_id + i; |
342 | /* Doing it this way avoids alignment problems. */ |
343 | bucket ^= cp[0] | cp[1] << 8; |
344 | } |
345 | bucket &= bucket_mask; |
346 | LIST_INSERT_HEAD(&sa_tab[bucket], sa, link)do { if (((sa)->link.le_next = (&sa_tab[bucket])->lh_first ) != ((void *)0)) (&sa_tab[bucket])->lh_first->link .le_prev = &(sa)->link.le_next; (&sa_tab[bucket])-> lh_first = (sa); (sa)->link.le_prev = &(&sa_tab[bucket ])->lh_first; } while (0); |
347 | sa_reference(sa); |
348 | LOG_DBG((LOG_SA, 70, "sa_enter: SA %p added to SA list", sa))log_debug (LOG_SA, 70, "sa_enter: SA %p added to SA list", sa ); |
349 | return 1; |
350 | } |
351 | |
352 | /* |
353 | * Lookup the SA given by the header fields MSG. PHASE2 is false when |
354 | * looking for phase 1 SAa and true otherwise. |
355 | */ |
356 | struct sa * |
357 | sa_lookup_by_header(u_int8_t *msg, int phase2) |
358 | { |
359 | return sa_lookup(msg + ISAKMP_HDR_COOKIES_OFF0, |
360 | phase2 ? msg + ISAKMP_HDR_MESSAGE_ID_OFF20 : 0); |
361 | } |
362 | |
363 | /* |
364 | * Lookup the SA given by the COOKIES and possibly the MESSAGE_ID unless |
365 | * a null pointer, meaning we are looking for phase 1 SAs. |
366 | */ |
367 | struct sa * |
368 | sa_lookup(u_int8_t *cookies, u_int8_t *message_id) |
369 | { |
370 | u_int16_t bucket = 0; |
371 | int i; |
372 | struct sa *sa; |
373 | u_int8_t *cp; |
374 | |
375 | /* |
376 | * We use the cookies to get bits to use as an index into sa_tab, as at |
377 | * least one (our cookie) is a good hash, xoring all the bits, 16 at a |
378 | * time, and then masking, should do. Doing it this way means we can |
379 | * validate cookies very fast thus delimiting the effects of "Denial of |
380 | * service"-attacks using packet flooding. |
381 | */ |
382 | for (i = 0; i < ISAKMP_HDR_COOKIES_LEN(8 + 8); i += 2) { |
383 | cp = cookies + i; |
384 | /* Doing it this way avoids alignment problems. */ |
385 | bucket ^= cp[0] | cp[1] << 8; |
386 | } |
387 | if (message_id) |
388 | for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN4; i += 2) { |
389 | cp = message_id + i; |
390 | /* Doing it this way avoids alignment problems. */ |
391 | bucket ^= cp[0] | cp[1] << 8; |
392 | } |
393 | bucket &= bucket_mask; |
394 | for (sa = LIST_FIRST(&sa_tab[bucket])((&sa_tab[bucket])->lh_first); |
395 | sa && (memcmp(cookies, sa->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)) != 0 || |
396 | (message_id && memcmp(message_id, sa->message_id, |
397 | ISAKMP_HDR_MESSAGE_ID_LEN4) != 0) || |
398 | (!message_id && !zero_test(sa->message_id, ISAKMP_HDR_MESSAGE_ID_LEN4))); |
399 | sa = LIST_NEXT(sa, link)((sa)->link.le_next)) |
400 | ; |
401 | |
402 | return sa; |
403 | } |
404 | |
405 | /* Create an SA. */ |
406 | int |
407 | sa_create(struct exchange *exchange, struct transport *t) |
408 | { |
409 | struct sa *sa; |
410 | |
411 | /* |
412 | * We want the SA zeroed for sa_free to be able to find out what fields |
413 | * have been filled-in. |
414 | */ |
415 | sa = calloc(1, sizeof *sa); |
416 | if (!sa) { |
417 | log_error("sa_create: calloc (1, %lu) failed", |
418 | (unsigned long)sizeof *sa); |
419 | return -1; |
420 | } |
421 | sa->transport = t; |
422 | if (t) |
423 | transport_reference(t); |
424 | sa->phase = exchange->phase; |
425 | memcpy(sa->cookies, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); |
426 | memcpy(sa->message_id, exchange->message_id, |
427 | ISAKMP_HDR_MESSAGE_ID_LEN4); |
428 | sa->doi = exchange->doi; |
429 | sa->policy_id = -1; |
430 | |
431 | if (sa->doi->sa_size) { |
432 | /* |
433 | * Allocate the DOI-specific structure and initialize it to |
434 | * zeroes. |
435 | */ |
436 | sa->data = calloc(1, sa->doi->sa_size); |
437 | if (!sa->data) { |
438 | log_error("sa_create: calloc (1, %lu) failed", |
439 | (unsigned long)sa->doi->sa_size); |
440 | free(sa); |
441 | return -1; |
442 | } |
443 | } |
444 | TAILQ_INIT(&sa->protos)do { (&sa->protos)->tqh_first = ((void *)0); (& sa->protos)->tqh_last = &(&sa->protos)->tqh_first ; } while (0); |
445 | |
446 | sa_enter(sa); |
447 | TAILQ_INSERT_TAIL(&exchange->sa_list, sa, next)do { (sa)->next.tqe_next = ((void *)0); (sa)->next.tqe_prev = (&exchange->sa_list)->tqh_last; *(&exchange-> sa_list)->tqh_last = (sa); (&exchange->sa_list)-> tqh_last = &(sa)->next.tqe_next; } while (0); |
448 | sa_reference(sa); |
449 | |
450 | LOG_DBG((LOG_SA, 60,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") |
451 | "sa_create: sa %p phase %d added to exchange %p (%s)", sa,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") |
452 | sa->phase, exchange,log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>") |
453 | exchange->name ? exchange->name : "<unnamed>"))log_debug (LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)" , sa, sa->phase, exchange, exchange->name ? exchange-> name : "<unnamed>"); |
454 | return 0; |
455 | } |
456 | |
457 | /* |
458 | * Dump the internal state of SA to the report channel, with HEADER |
459 | * prepended to each line. |
460 | */ |
461 | void |
462 | sa_dump(int cls, int level, char *header, struct sa *sa) |
463 | { |
464 | struct proto *proto; |
465 | char spi_header[80]; |
466 | int i; |
467 | |
468 | LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header,log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags) |
469 | sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id,log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags) |
470 | sa->flags))log_debug (cls, level, "%s: %p %s phase %d doi %d flags 0x%x" , header, sa, sa->name ? sa->name : "<unnamed>", sa ->phase, sa->doi->id, sa->flags); |
471 | LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header,log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)) |
472 | decode_32(sa->cookies), decode_32(sa->cookies + 4),log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)) |
473 | decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)))log_debug (cls, level, "%s: icookie %08x%08x rcookie %08x%08x" , header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)); |
474 | LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header,log_debug (cls, level, "%s: msgid %08x refcnt %d", header, decode_32 (sa->message_id), sa->refcnt) |
475 | decode_32(sa->message_id), sa->refcnt))log_debug (cls, level, "%s: msgid %08x refcnt %d", header, decode_32 (sa->message_id), sa->refcnt); |
476 | LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds,log_debug (cls, level, "%s: life secs %llu kb %llu", header, sa ->seconds, sa->kilobytes) |
477 | sa->kilobytes))log_debug (cls, level, "%s: life secs %llu kb %llu", header, sa ->seconds, sa->kilobytes); |
478 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; |
479 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { |
480 | LOG_DBG((cls, level, "%s: suite %d proto %d", header,log_debug (cls, level, "%s: suite %d proto %d", header, proto ->no, proto->proto) |
481 | proto->no, proto->proto))log_debug (cls, level, "%s: suite %d proto %d", header, proto ->no, proto->proto); |
482 | LOG_DBG((cls, level,log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) |
483 | "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p",log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) |
484 | header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1],log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]) |
485 | proto->spi[1]))log_debug (cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p" , header, proto->spi_sz[0], proto->spi[0], proto->spi_sz [1], proto->spi[1]); |
486 | LOG_DBG((cls, level, "%s: %s, %s", header,log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
487 | !sa->doi ? "<nodoi>" :log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
488 | sa->doi->decode_ids("initiator id: %s, responder id: %s",log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
489 | sa->id_i, sa->id_i_len,log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
490 | sa->id_r, sa->id_r_len, 0),log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
491 | !sa->transport ? "<no transport>" :log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)) |
492 | sa->transport->vtbl->decode_ids(sa->transport)))log_debug (cls, level, "%s: %s, %s", header, !sa->doi ? "<nodoi>" : sa->doi->decode_ids("initiator id: %s, responder id: %s" , sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "<no transport>" : sa->transport ->vtbl->decode_ids(sa->transport)); |
493 | for (i = 0; i < 2; i++) |
494 | if (proto->spi[i]) { |
495 | snprintf(spi_header, sizeof spi_header, |
496 | "%s: spi[%d]", header, i); |
497 | LOG_DBG_BUF((cls, level, spi_header,log_debug_buf (cls, level, spi_header, proto->spi[i], proto ->spi_sz[i]) |
498 | proto->spi[i], proto->spi_sz[i]))log_debug_buf (cls, level, spi_header, proto->spi[i], proto ->spi_sz[i]); |
499 | } |
500 | } |
501 | } |
502 | |
503 | /* |
504 | * Display the SA's two SPI values. |
505 | */ |
506 | static void |
507 | report_spi(FILE *fd, const u_int8_t *buf, size_t sz, int spi) |
508 | { |
509 | #define SBUFSZ(2 * 32 + 9) (2 * 32 + 9) |
510 | char s[SBUFSZ(2 * 32 + 9)]; |
511 | size_t i, j; |
512 | |
513 | for (i = j = 0; i < sz;) { |
514 | snprintf(s + j, sizeof s - j, "%02x", buf[i++]); |
515 | j += strlen(s + j); |
516 | if (i % 4 == 0) { |
517 | if (i % 32 == 0) { |
518 | s[j] = '\0'; |
519 | fprintf(fd, "%s", s); |
520 | j = 0; |
521 | } else |
522 | s[j++] = ' '; |
523 | } |
524 | } |
525 | |
526 | if (j) { |
527 | s[j] = '\0'; |
528 | fprintf(fd, "SPI %d: %s\n", spi, s); |
529 | } |
530 | } |
531 | |
532 | /* |
533 | * Display the transform names to file. |
534 | * Structure is taken from pf_key_v2.c, pf_key_v2_set_spi. |
535 | * Transform names are taken from /usr/src/sys/crypto/xform.c. |
536 | */ |
537 | static void |
538 | report_proto(FILE *fd, struct proto *proto) |
539 | { |
540 | struct ipsec_proto *iproto; |
541 | int keylen, hashlen; |
542 | |
543 | switch (proto->proto) { |
544 | case IPSEC_PROTO_IPSEC_ESP3: |
545 | keylen = ipsec_esp_enckeylength(proto); |
546 | hashlen = ipsec_esp_authkeylength(proto); |
547 | fprintf(fd, "Transform: IPsec ESP\n"); |
548 | fprintf(fd, "Encryption key length: %d\n", keylen); |
549 | fprintf(fd, "Authentication key length: %d\n", hashlen); |
550 | |
551 | fprintf(fd, "Encryption algorithm: "); |
552 | switch (proto->id) { |
553 | case IPSEC_ESP_3DES3: |
554 | fprintf(fd, "3DES\n"); |
555 | break; |
556 | |
557 | case IPSEC_ESP_AES12: |
558 | fprintf(fd, "AES (CBC)\n"); |
559 | break; |
560 | |
561 | case IPSEC_ESP_AES_CTR13: |
562 | fprintf(fd, "AES (CTR)\n"); |
563 | break; |
564 | |
565 | case IPSEC_ESP_AES_GCM_1620: |
566 | fprintf(fd, "AES (GCM)\n"); |
567 | break; |
568 | |
569 | case IPSEC_ESP_AES_GMAC23: |
570 | fprintf(fd, "AES (GMAC)\n"); |
571 | break; |
572 | |
573 | case IPSEC_ESP_CAST6: |
574 | fprintf(fd, "Cast-128\n"); |
575 | break; |
576 | |
577 | case IPSEC_ESP_BLOWFISH7: |
578 | fprintf(fd, "Blowfish\n"); |
579 | break; |
580 | |
581 | default: |
582 | fprintf(fd, "unknown (%d)\n", proto->id); |
583 | } |
584 | |
585 | fprintf(fd, "Authentication algorithm: "); |
586 | |
587 | if (!proto->data) { |
588 | fprintf(fd, "none\n"); |
589 | break; |
590 | } |
591 | iproto = proto->data; |
592 | |
593 | switch (iproto->auth) { |
594 | case IPSEC_AUTH_HMAC_MD51: |
595 | fprintf(fd, "HMAC-MD5\n"); |
596 | break; |
597 | |
598 | case IPSEC_AUTH_HMAC_SHA2: |
599 | fprintf(fd, "HMAC-SHA1\n"); |
600 | break; |
601 | |
602 | case IPSEC_AUTH_HMAC_RIPEMD8: |
603 | fprintf(fd, "HMAC-RIPEMD-160\n"); |
604 | break; |
605 | |
606 | case IPSEC_AUTH_HMAC_SHA2_2565: |
607 | fprintf(fd, "HMAC-SHA2-256\n"); |
608 | break; |
609 | |
610 | case IPSEC_AUTH_HMAC_SHA2_3846: |
611 | fprintf(fd, "HMAC-SHA2-384\n"); |
612 | break; |
613 | |
614 | case IPSEC_AUTH_HMAC_SHA2_5127: |
615 | fprintf(fd, "HMAC-SHA2-512\n"); |
616 | break; |
617 | |
618 | case IPSEC_AUTH_DES_MAC3: |
619 | case IPSEC_AUTH_KPDK4: |
620 | /* XXX We should be supporting KPDK */ |
621 | fprintf(fd, "unknown (%d)", iproto->auth); |
622 | break; |
623 | |
624 | default: |
625 | fprintf(fd, "none\n"); |
626 | } |
627 | break; |
628 | |
629 | case IPSEC_PROTO_IPSEC_AH2: |
630 | hashlen = ipsec_ah_keylength(proto); |
631 | fprintf(fd, "Transform: IPsec AH\n"); |
632 | fprintf(fd, "Encryption not used.\n"); |
633 | fprintf(fd, "Authentication key length: %d\n", hashlen); |
634 | |
635 | fprintf(fd, "Authentication algorithm: "); |
636 | switch (proto->id) { |
637 | case IPSEC_AH_MD52: |
638 | fprintf(fd, "HMAC-MD5\n"); |
639 | break; |
640 | |
641 | case IPSEC_AH_SHA3: |
642 | fprintf(fd, "HMAC-SHA1\n"); |
643 | break; |
644 | |
645 | case IPSEC_AH_RIPEMD8: |
646 | fprintf(fd, "HMAC-RIPEMD-160\n"); |
647 | break; |
648 | |
649 | case IPSEC_AH_SHA2_2565: |
650 | fprintf(fd, "HMAC-SHA2-256\n"); |
651 | break; |
652 | |
653 | case IPSEC_AH_SHA2_3846: |
654 | fprintf(fd, "HMAC-SHA2-384\n"); |
655 | break; |
656 | |
657 | case IPSEC_AH_SHA2_5127: |
658 | fprintf(fd, "HMAC-SHA2-512\n"); |
659 | break; |
660 | |
661 | default: |
662 | fprintf(fd, "unknown (%d)", proto->id); |
663 | } |
664 | break; |
665 | |
666 | default: |
667 | fprintf(fd, "report_proto: invalid proto %d\n", proto->proto); |
668 | } |
669 | } |
670 | |
671 | /* |
672 | * Display SA lifetimes. |
673 | */ |
674 | static void |
675 | report_lifetimes(FILE *fd, struct sa *sa) |
676 | { |
677 | long timeout; |
678 | |
679 | if (sa->seconds) |
680 | fprintf(fd, "Lifetime: %llu seconds\n", sa->seconds); |
681 | |
682 | if (sa->soft_death) { |
683 | timeout = get_timeout(&sa->soft_death->expiration); |
684 | if (timeout < 0) |
685 | fprintf(fd, "<no soft timeout>\n"); |
686 | else |
687 | fprintf(fd, "Soft timeout in %ld seconds\n", timeout); |
688 | } |
689 | |
690 | if (sa->death) { |
691 | timeout = get_timeout(&sa->death->expiration); |
692 | if (timeout < 0) |
693 | fprintf(fd, "No hard timeout>\n"); |
694 | else |
695 | fprintf(fd, "Hard timeout in %ld seconds\n", timeout); |
696 | } |
697 | |
698 | if (sa->kilobytes) |
699 | fprintf(fd, "Lifetime: %llu kilobytes\n", sa->kilobytes); |
700 | } |
701 | |
702 | /* |
703 | * Print phase 1 specific information. |
704 | */ |
705 | static void |
706 | report_phase1(FILE *fd, struct sa *sa) |
707 | { |
708 | /* Cookies. */ |
709 | fprintf(fd, "icookie %08x%08x rcookie %08x%08x\n", |
710 | decode_32(sa->cookies), decode_32(sa->cookies + 4), |
711 | decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)); |
712 | } |
713 | |
714 | /* |
715 | * Print phase 2 specific information. |
716 | */ |
717 | static void |
718 | report_phase2(FILE *fd, struct sa *sa) |
719 | { |
720 | struct proto *proto; |
721 | int i; |
722 | |
723 | /* Transform information. */ |
724 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; |
725 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { |
726 | |
727 | /* SPI values. */ |
728 | for (i = 0; i < 2; i++) |
729 | if (proto->spi[i]) |
730 | report_spi(fd, proto->spi[i], |
731 | proto->spi_sz[i], i); |
732 | else |
733 | fprintf(fd, "SPI %d not defined.\n", i); |
734 | |
735 | /* Proto values. */ |
736 | report_proto(fd, proto); |
737 | } |
738 | } |
739 | |
740 | /* Report all the SAs to the report channel. */ |
741 | void |
742 | sa_report(void) |
743 | { |
744 | struct sa *sa; |
745 | int i; |
746 | |
747 | for (i = 0; i <= bucket_mask; i++) |
748 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) |
749 | sa_dump(LOG_REPORT-2, 0, "sa_report", sa); |
750 | } |
751 | |
752 | /* |
753 | * Print an SA's connection details to file SA_FILE. |
754 | */ |
755 | static void |
756 | sa_dump_all(FILE *fd, struct sa *sa) |
757 | { |
758 | /* SA name and phase. */ |
759 | fprintf(fd, "SA name: %s", sa->name ? sa->name : "<unnamed>"); |
760 | fprintf(fd, " (Phase %d%s)\n", sa->phase, sa->phase == 1 ? |
761 | (sa->initiator ? "/Initiator" : "/Responder") : ""); |
762 | |
763 | /* Source and destination IPs. */ |
764 | fprintf(fd, "%s", sa->transport == NULL((void *)0) ? "<no transport>" : |
765 | sa->transport->vtbl->decode_ids(sa->transport)); |
766 | fprintf(fd, "\n"); |
767 | |
768 | /* Lifetimes */ |
769 | report_lifetimes(fd, sa); |
770 | |
771 | fprintf(fd, "Flags 0x%08x\n", sa->flags); |
772 | |
773 | if (sa->phase == 1) |
774 | report_phase1(fd, sa); |
775 | else if (sa->phase == 2) |
776 | report_phase2(fd, sa); |
777 | else { |
778 | /* Should not happen, but... */ |
779 | fprintf(fd, "<unknown phase>\n"); |
780 | } |
781 | |
782 | /* SA separator. */ |
783 | fprintf(fd, "\n"); |
784 | } |
785 | |
786 | /* Report info of all SAs to file 'fd'. */ |
787 | void |
788 | sa_report_all(FILE *fd) |
789 | { |
790 | struct sa *sa; |
791 | int i; |
792 | |
793 | for (i = 0; i <= bucket_mask; i++) |
794 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) |
795 | sa_dump_all(fd, sa); |
796 | } |
797 | |
798 | /* Free the protocol structure pointed to by PROTO. */ |
799 | void |
800 | proto_free(struct proto *proto) |
801 | { |
802 | struct proto_attr *pa; |
803 | struct sa *sa = proto->sa; |
804 | int i; |
805 | |
806 | for (i = 0; i < 2; i++) |
807 | if (proto->spi[i]) { |
808 | if (sa->doi->delete_spi) |
809 | sa->doi->delete_spi(sa, proto, i); |
810 | free(proto->spi[i]); |
811 | } |
812 | TAILQ_REMOVE(&sa->protos, proto, link)do { if (((proto)->link.tqe_next) != ((void *)0)) (proto)-> link.tqe_next->link.tqe_prev = (proto)->link.tqe_prev; else (&sa->protos)->tqh_last = (proto)->link.tqe_prev ; *(proto)->link.tqe_prev = (proto)->link.tqe_next; ; ; } while (0); |
813 | if (proto->data) { |
814 | if (sa->doi && sa->doi->free_proto_data) |
815 | sa->doi->free_proto_data(proto->data); |
816 | free(proto->data); |
817 | } |
818 | if (proto->xf_cnt) |
819 | while ((pa = TAILQ_FIRST(&proto->xfs)((&proto->xfs)->tqh_first)) != NULL((void *)0)) { |
820 | free(pa->attrs); |
821 | TAILQ_REMOVE(&proto->xfs, pa, next)do { if (((pa)->next.tqe_next) != ((void *)0)) (pa)->next .tqe_next->next.tqe_prev = (pa)->next.tqe_prev; else (& proto->xfs)->tqh_last = (pa)->next.tqe_prev; *(pa)-> next.tqe_prev = (pa)->next.tqe_next; ; ; } while (0); |
822 | free(pa); |
823 | } |
824 | |
825 | LOG_DBG((LOG_SA, 90, "proto_free: freeing %p", proto))log_debug (LOG_SA, 90, "proto_free: freeing %p", proto); |
826 | free(proto); |
827 | } |
828 | |
829 | /* Release all resources this SA is using. */ |
830 | void |
831 | sa_free(struct sa *sa) |
832 | { |
833 | if (sa->death) { |
834 | timer_remove_event(sa->death); |
835 | sa->death = 0; |
836 | sa->refcnt--; |
837 | } |
838 | if (sa->soft_death) { |
839 | timer_remove_event(sa->soft_death); |
840 | sa->soft_death = 0; |
841 | sa->refcnt--; |
842 | } |
843 | if (sa->dpd_event) { |
844 | timer_remove_event(sa->dpd_event); |
845 | sa->dpd_event = 0; |
846 | } |
847 | sa_remove(sa); |
848 | } |
849 | |
850 | /* Remove the SA from the hash table of live SAs. */ |
851 | void |
852 | sa_remove(struct sa *sa) |
853 | { |
854 | LIST_REMOVE(sa, link)do { if ((sa)->link.le_next != ((void *)0)) (sa)->link. le_next->link.le_prev = (sa)->link.le_prev; *(sa)->link .le_prev = (sa)->link.le_next; ; ; } while (0); |
855 | LOG_DBG((LOG_SA, 70, "sa_remove: SA %p removed from SA list", sa))log_debug (LOG_SA, 70, "sa_remove: SA %p removed from SA list" , sa); |
856 | sa_release(sa); |
857 | } |
858 | |
859 | /* Raise the reference count of SA. */ |
860 | void |
861 | sa_reference(struct sa *sa) |
862 | { |
863 | sa->refcnt++; |
864 | LOG_DBG((LOG_SA, 80, "sa_reference: SA %p now has %d references",log_debug (LOG_SA, 80, "sa_reference: SA %p now has %d references" , sa, sa->refcnt) |
865 | sa, sa->refcnt))log_debug (LOG_SA, 80, "sa_reference: SA %p now has %d references" , sa, sa->refcnt); |
866 | } |
867 | |
868 | /* Release a reference to SA. */ |
869 | void |
870 | sa_release(struct sa *sa) |
871 | { |
872 | struct cert_handler *handler; |
873 | struct proto *proto; |
874 | |
875 | LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references",log_debug (LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt) |
876 | sa, sa->refcnt))log_debug (LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt); |
877 | |
878 | if (--sa->refcnt) |
879 | return; |
880 | |
881 | LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa))log_debug (LOG_SA, 60, "sa_release: freeing SA %p", sa); |
882 | |
883 | while ((proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) != 0) |
884 | proto_free(proto); |
885 | if (sa->data) { |
886 | if (sa->doi && sa->doi->free_sa_data) |
887 | sa->doi->free_sa_data(sa->data); |
888 | free(sa->data); |
889 | } |
890 | free(sa->id_i); |
891 | free(sa->id_r); |
892 | if (sa->recv_cert) { |
893 | handler = cert_get(sa->recv_certtype); |
894 | if (handler) |
895 | handler->cert_free(sa->recv_cert); |
896 | } |
897 | if (sa->sent_cert) { |
898 | handler = cert_get(sa->sent_certtype); |
899 | if (handler) |
900 | handler->cert_free(sa->sent_cert); |
901 | } |
902 | if (sa->recv_key) |
903 | key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC0, |
904 | sa->recv_key); |
905 | free(sa->keynote_key); /* This is just a string */ |
906 | if (sa->policy_id != -1) |
907 | kn_close(sa->policy_id); |
908 | free(sa->name); |
909 | free(sa->keystate); |
910 | if (sa->nat_t_keepalive) |
911 | timer_remove_event(sa->nat_t_keepalive); |
912 | if (sa->dpd_event) |
913 | timer_remove_event(sa->dpd_event); |
914 | if (sa->transport) |
915 | transport_release(sa->transport); |
916 | free(sa->tag); |
917 | free(sa); |
918 | } |
919 | |
920 | /* |
921 | * Rehash the ISAKMP SA this MSG is negotiating with the responder cookie |
922 | * filled in. |
923 | */ |
924 | void |
925 | sa_isakmp_upgrade(struct message *msg) |
926 | { |
927 | struct sa *sa = TAILQ_FIRST(&msg->exchange->sa_list)((&msg->exchange->sa_list)->tqh_first); |
928 | |
929 | sa_remove(sa); |
930 | GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base,field_get_raw (isakmp_hdr_fld + 1, msg->iov[0].iov_base, sa ->cookies + 8) |
931 | sa->cookies + ISAKMP_HDR_ICOOKIE_LEN)field_get_raw (isakmp_hdr_fld + 1, msg->iov[0].iov_base, sa ->cookies + 8); |
932 | |
933 | /* |
934 | * We don't install a transport in the initiator case as we don't know |
935 | * what local address will be chosen. Do it now instead. |
936 | */ |
937 | sa->transport = msg->transport; |
938 | transport_reference(sa->transport); |
939 | sa_enter(sa); |
940 | } |
941 | |
942 | #define ATTRS_SIZE(17 + 1) (IKE_ATTR_BLOCK_SIZE17 + 1) /* XXX Should be dynamic. */ |
943 | |
944 | struct attr_validation_state { |
945 | u_int8_t *attrp[ATTRS_SIZE(17 + 1)]; |
946 | u_int8_t checked[ATTRS_SIZE(17 + 1)]; |
947 | u_int16_t len[ATTRS_SIZE(17 + 1)]; |
948 | int phase; /* IKE (1) or IPSEC (2) attrs? */ |
949 | int mode; /* 0 = 'load', 1 = check */ |
950 | }; |
951 | |
952 | /* Validate an attribute. Return 0 on match. */ |
953 | static int |
954 | sa_validate_xf_attrs(u_int16_t type, u_int8_t *value, u_int16_t len, |
955 | void *arg) |
956 | { |
957 | int val0, val1; |
958 | |
959 | struct attr_validation_state *avs = |
960 | (struct attr_validation_state *)arg; |
961 | |
962 | LOG_DBG((LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d "log_debug (LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " "len %d", avs->phase, avs->mode, type, len) |
963 | "len %d", avs->phase, avs->mode, type, len))log_debug (LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " "len %d", avs->phase, avs->mode, type, len); |
964 | |
965 | /* Make sure the phase and type are valid. */ |
966 | if (avs->phase == 1) { |
967 | if (type < IKE_ATTR_ENCRYPTION_ALGORITHM1 || |
968 | type > IKE_ATTR_BLOCK_SIZE17) |
969 | return 1; |
970 | } else if (avs->phase == 2) { |
971 | if (type < IPSEC_ATTR_SA_LIFE_TYPE1 || |
972 | type > IPSEC_ATTR_ECN_TUNNEL10) |
973 | return 1; |
974 | } else |
975 | return 1; |
976 | |
977 | if (avs->mode == 0) { /* Load attrs. */ |
978 | avs->attrp[type] = value; |
979 | avs->len[type] = len; |
980 | return 0; |
981 | } |
982 | /* Checking for a missing attribute is an immediate failure. */ |
983 | if (!avs->attrp[type]) |
984 | return 1; |
985 | |
986 | /* Match the loaded attribute against this one, mark it as checked. */ |
987 | avs->checked[type]++; |
988 | switch (len) { |
989 | case 2: |
990 | val0 = (int)decode_16(value); |
991 | break; |
992 | case 4: |
993 | val0 = (int)decode_32(value); |
994 | break; |
995 | default: |
996 | return 1; |
997 | } |
998 | switch (avs->len[type]) { |
999 | case 2: |
1000 | val1 = (int)decode_16(avs->attrp[type]); |
1001 | break; |
1002 | case 4: |
1003 | val1 = (int)decode_32(avs->attrp[type]); |
1004 | break; |
1005 | default: |
1006 | return 1; |
1007 | } |
1008 | /* Return 0 when the values are equal. */ |
1009 | return (val0 != val1); |
1010 | } |
1011 | |
1012 | /* |
1013 | * This function is used to validate the returned proposal (protection suite) |
1014 | * we get from the responder against a proposal we sent. Only run as initiator. |
1015 | * We return 0 if a match is found (in any transform of this proposal), 1 |
1016 | * otherwise. Also see note in sa_add_transform() below. |
1017 | */ |
1018 | static int |
1019 | sa_validate_proto_xf(struct proto *match, struct payload *xf, int phase) |
1020 | { |
1021 | struct attr_validation_state *avs; |
1022 | struct proto_attr *pa; |
1023 | int found = 0; |
1024 | size_t i; |
1025 | u_int8_t xf_id; |
1026 | |
1027 | if (!match->xf_cnt) |
1028 | return 0; |
1029 | |
1030 | if (match->proto != GET_ISAKMP_PROP_PROTO(xf->context->p)field_get_num (isakmp_prop_fld + 1, xf->context->p)) { |
1031 | LOG_DBG((LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) "log_debug (LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " "protocol mismatch", match, match->no) |
1032 | "protocol mismatch", match, match->no))log_debug (LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " "protocol mismatch", match, match->no); |
1033 | return 1; |
1034 | } |
1035 | avs = calloc(1, sizeof *avs); |
1036 | if (!avs) { |
1037 | log_error("sa_validate_proto_xf: calloc (1, %lu)", |
1038 | (unsigned long)sizeof *avs); |
1039 | return 1; |
1040 | } |
1041 | avs->phase = phase; |
1042 | |
1043 | /* Load the "proposal candidate" attribute set. */ |
1044 | (void)attribute_map(xf->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, |
1045 | GET_ISAKMP_GEN_LENGTH(xf->p)field_get_num (isakmp_gen_fld + 2, xf->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, |
1046 | sa_validate_xf_attrs, avs); |
1047 | xf_id = GET_ISAKMP_TRANSFORM_ID(xf->p)field_get_num (isakmp_transform_fld + 1, xf->p); |
1048 | |
1049 | /* Check against the transforms we suggested. */ |
1050 | avs->mode++; |
1051 | for (pa = TAILQ_FIRST(&match->xfs)((&match->xfs)->tqh_first); pa && !found; |
1052 | pa = TAILQ_NEXT(pa, next)((pa)->next.tqe_next)) { |
1053 | if (xf_id != GET_ISAKMP_TRANSFORM_ID(pa->attrs)field_get_num (isakmp_transform_fld + 1, pa->attrs)) |
1054 | continue; |
1055 | |
1056 | bzero(avs->checked, sizeof avs->checked); |
1057 | if (attribute_map(pa->attrs + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, |
1058 | pa->len - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, |
1059 | sa_validate_xf_attrs, avs) == 0) |
1060 | found++; |
1061 | |
1062 | LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: attr_map "log_debug (LOG_SA, 80, "sa_validate_proto_xf: attr_map " "xf %p proto %p pa %p found %d" , xf, match, pa, found) |
1063 | "xf %p proto %p pa %p found %d", xf, match, pa, found))log_debug (LOG_SA, 80, "sa_validate_proto_xf: attr_map " "xf %p proto %p pa %p found %d" , xf, match, pa, found); |
1064 | |
1065 | if (!found) |
1066 | continue; |
1067 | |
1068 | /* |
1069 | * Require all attributes present and checked. XXX perhaps |
1070 | * not? |
1071 | */ |
1072 | for (i = 0; i < sizeof avs->checked; i++) |
1073 | if (avs->attrp[i] && !avs->checked[i]) |
1074 | found = 0; |
1075 | |
1076 | LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: req_attr "log_debug (LOG_SA, 80, "sa_validate_proto_xf: req_attr " "xf %p proto %p pa %p found %d" , xf, match, pa, found) |
1077 | "xf %p proto %p pa %p found %d", xf, match, pa, found))log_debug (LOG_SA, 80, "sa_validate_proto_xf: req_attr " "xf %p proto %p pa %p found %d" , xf, match, pa, found); |
1078 | } |
1079 | free(avs); |
1080 | return found ? 0 : 1; |
1081 | } |
1082 | |
1083 | /* |
1084 | * Register the chosen transform XF into SA. As a side effect set PROTOP |
1085 | * to point at the corresponding proto structure. INITIATOR is true if we |
1086 | * are the initiator. |
1087 | */ |
1088 | int |
1089 | sa_add_transform(struct sa *sa, struct payload *xf, int initiator, |
1090 | struct proto **protop) |
1091 | { |
1092 | struct proto *proto; |
1093 | struct payload *prop = xf->context; |
1094 | |
1095 | *protop = 0; |
1096 | if (!initiator) { |
1097 | proto = calloc(1, sizeof *proto); |
1098 | if (!proto) |
1099 | log_error("sa_add_transform: calloc (1, %lu) failed", |
1100 | (unsigned long)sizeof *proto); |
1101 | } else { |
1102 | /* |
1103 | * RFC 2408, section 4.2 states the responder SHOULD use the |
1104 | * proposal number from the initiator (i.e us), in its |
1105 | * selected proposal to make this lookup easier. Most vendors |
1106 | * follow this. One noted exception is the CiscoPIX (and |
1107 | * perhaps other Cisco products). |
1108 | * |
1109 | * We start by matching on the proposal number, as before. |
1110 | */ |
1111 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); |
1112 | proto && proto->no != GET_ISAKMP_PROP_NO(prop->p)field_get_num (isakmp_prop_fld + 0, prop->p); |
1113 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) |
1114 | ; |
1115 | /* |
1116 | * If we did not find a match, search through all proposals |
1117 | * and xforms. |
1118 | */ |
1119 | if (!proto || sa_validate_proto_xf(proto, xf, sa->phase) != 0) |
1120 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); |
1121 | proto && sa_validate_proto_xf(proto, xf, sa->phase) != 0; |
1122 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) |
1123 | ; |
1124 | } |
1125 | if (!proto) |
1126 | return -1; |
1127 | *protop = proto; |
1128 | |
1129 | /* Allocate DOI-specific part. */ |
1130 | if (!initiator) { |
1131 | proto->data = calloc(1, sa->doi->proto_size); |
1132 | if (!proto->data) { |
1133 | log_error("sa_add_transform: calloc (1, %lu) failed", |
1134 | (unsigned long)sa->doi->proto_size); |
1135 | goto cleanup; |
1136 | } |
1137 | } |
1138 | proto->no = GET_ISAKMP_PROP_NO(prop->p)field_get_num (isakmp_prop_fld + 0, prop->p); |
1139 | proto->proto = GET_ISAKMP_PROP_PROTO(prop->p)field_get_num (isakmp_prop_fld + 1, prop->p); |
1140 | proto->spi_sz[0] = GET_ISAKMP_PROP_SPI_SZ(prop->p)field_get_num (isakmp_prop_fld + 2, prop->p); |
1141 | if (proto->spi_sz[0]) { |
1142 | proto->spi[0] = malloc(proto->spi_sz[0]); |
1143 | if (!proto->spi[0]) |
1144 | goto cleanup; |
1145 | memcpy(proto->spi[0], prop->p + ISAKMP_PROP_SPI_OFF8, |
1146 | proto->spi_sz[0]); |
1147 | } |
1148 | proto->chosen = xf; |
1149 | proto->sa = sa; |
1150 | proto->id = GET_ISAKMP_TRANSFORM_ID(xf->p)field_get_num (isakmp_transform_fld + 1, xf->p); |
1151 | if (!initiator) |
1152 | TAILQ_INSERT_TAIL(&sa->protos, proto, link)do { (proto)->link.tqe_next = ((void *)0); (proto)->link .tqe_prev = (&sa->protos)->tqh_last; *(&sa-> protos)->tqh_last = (proto); (&sa->protos)->tqh_last = &(proto)->link.tqe_next; } while (0); |
1153 | |
1154 | /* Let the DOI get at proto for initializing its own data. */ |
1155 | if (sa->doi->proto_init) |
1156 | sa->doi->proto_init(proto, 0); |
1157 | |
1158 | LOG_DBG((LOG_SA, 80,log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) |
1159 | "sa_add_transform: "log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) |
1160 | "proto %p no %d proto %d chosen %p sa %p id %d",log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) |
1161 | proto, proto->no, proto->proto, proto->chosen, proto->sa,log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id) |
1162 | proto->id))log_debug (LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d" , proto, proto->no, proto->proto, proto->chosen, proto ->sa, proto->id); |
1163 | |
1164 | return 0; |
1165 | |
1166 | cleanup: |
1167 | if (!initiator) { |
1168 | free(proto->data); |
1169 | free(proto); |
1170 | } |
1171 | *protop = 0; |
1172 | return -1; |
1173 | } |
1174 | |
1175 | /* Delete an SA. Tell the peer if NOTIFY is set. */ |
1176 | void |
1177 | sa_delete(struct sa *sa, int notify) |
1178 | { |
1179 | if (notify) |
1180 | message_send_delete(sa); |
1181 | sa_free(sa); |
1182 | } |
1183 | |
1184 | |
1185 | /* Teardown all SAs. */ |
1186 | void |
1187 | sa_teardown_all(void) |
1188 | { |
1189 | int i; |
1190 | struct sa *sa, *next = 0; |
1191 | |
1192 | LOG_DBG((LOG_SA, 70, "sa_teardown_all:"))log_debug (LOG_SA, 70, "sa_teardown_all:"); |
1193 | /* Get Phase 2 SAs. */ |
1194 | for (i = 0; i <= bucket_mask; i++) |
1195 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = next) { |
1196 | next = LIST_NEXT(sa, link)((sa)->link.le_next); |
1197 | if (sa->phase == 2) { |
1198 | /* |
1199 | * Teardown the phase 2 SAs by name, similar |
1200 | * to ui_teardown. |
1201 | */ |
1202 | LOG_DBG((LOG_SA, 70,log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>") |
1203 | "sa_teardown_all: tearing down SA %s",log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>") |
1204 | sa->name ? sa->name : "<unnamed>"))log_debug (LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>"); |
1205 | if (sa->name) |
1206 | connection_teardown(sa->name); |
1207 | sa_delete(sa, 1); |
1208 | } |
1209 | } |
1210 | } |
1211 | |
1212 | /* |
1213 | * This function will get called when we are closing in on the death time of SA |
1214 | */ |
1215 | static void |
1216 | sa_soft_expire(void *v_sa) |
1217 | { |
1218 | struct sa *sa = v_sa; |
1219 | |
1220 | sa->soft_death = 0; |
1221 | sa_release(sa); |
1222 | |
1223 | if ((sa->flags & (SA_FLAG_STAYALIVE0x02 | SA_FLAG_REPLACED0x08)) == |
1224 | SA_FLAG_STAYALIVE0x02) |
1225 | exchange_establish(sa->name, 0, 0, 1); |
1226 | else |
1227 | /* |
1228 | * Start to watch the use of this SA, so a renegotiation can |
1229 | * happen as soon as it is shown to be alive. |
1230 | */ |
1231 | sa->flags |= SA_FLAG_FADING0x10; |
1232 | } |
1233 | |
1234 | /* SA has passed its best before date. */ |
1235 | static void |
1236 | sa_hard_expire(void *v_sa) |
1237 | { |
1238 | struct sa *sa = v_sa; |
1239 | |
1240 | sa->death = 0; |
1241 | sa_release(sa); |
1242 | |
1243 | if ((sa->flags & (SA_FLAG_STAYALIVE0x02 | SA_FLAG_REPLACED0x08)) == |
1244 | SA_FLAG_STAYALIVE0x02) |
1245 | exchange_establish(sa->name, 0, 0, 1); |
1246 | |
1247 | sa_delete(sa, 1); |
1248 | } |
1249 | |
1250 | void |
1251 | sa_reinit(void) |
1252 | { |
1253 | struct sa *sa; |
1254 | char *tag; |
1255 | int i; |
1256 | |
1257 | /* For now; only do this if we have the proper tag configured. */ |
1258 | tag = conf_get_str("General", "Renegotiate-on-HUP"); |
1259 | if (!tag) |
1260 | return; |
1261 | |
1262 | LOG_DBG((LOG_SA, 30, "sa_reinit: renegotiating active connections"))log_debug (LOG_SA, 30, "sa_reinit: renegotiating active connections" ); |
1263 | |
1264 | /* |
1265 | * Get phase 2 SAs. Soft expire those without active exchanges. Do |
1266 | * not touch a phase 2 SA where the soft expiration is not set, ie. |
1267 | * the SA is not yet established. |
1268 | */ |
1269 | for (i = 0; i <= bucket_mask; i++) |
1270 | for (sa = LIST_FIRST(&sa_tab[i])((&sa_tab[i])->lh_first); sa; sa = LIST_NEXT(sa, link)((sa)->link.le_next)) |
1271 | if (sa->phase == 2) |
1272 | if (exchange_lookup_by_name(sa->name, |
1273 | sa->phase) == 0 && sa->soft_death) { |
1274 | timer_remove_event(sa->soft_death); |
1275 | sa_soft_expire(sa); |
1276 | } |
1277 | } |
1278 | |
1279 | /* |
1280 | * Get an SA attribute's flag value out of textual description. |
1281 | */ |
1282 | int |
1283 | sa_flag(char *attr) |
1284 | { |
1285 | static struct sa_flag_map { |
1286 | char *name; |
1287 | int flag; |
1288 | } sa_flag_map[] = { |
1289 | { |
1290 | "active-only", SA_FLAG_ACTIVE_ONLY0x20 |
1291 | }, |
1292 | |
1293 | /* |
1294 | * Below this point are flags that are internal to the |
1295 | * implementation. |
1296 | */ |
1297 | { |
1298 | "__ondemand", SA_FLAG_ONDEMAND0x04 |
1299 | }, |
1300 | { |
1301 | "ikecfg", SA_FLAG_IKECFG0x40 |
1302 | }, |
1303 | }; |
1304 | size_t i; |
1305 | |
1306 | for (i = 0; i < sizeof sa_flag_map / sizeof sa_flag_map[0]; i++) |
1307 | if (strcasecmp(attr, sa_flag_map[i].name) == 0) |
1308 | return sa_flag_map[i].flag; |
1309 | log_print("sa_flag: attribute \"%s\" unknown", attr); |
1310 | return 0; |
1311 | } |
1312 | |
1313 | /* Mark SA as replaced. */ |
1314 | void |
1315 | sa_mark_replaced(struct sa *sa) |
1316 | { |
1317 | LOG_DBG((LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced",log_debug (LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced" , sa, sa->name ? sa->name : "unnamed") |
1318 | sa, sa->name ? sa->name : "unnamed"))log_debug (LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced" , sa, sa->name ? sa->name : "unnamed"); |
1319 | if (sa->dpd_event) { |
1320 | timer_remove_event(sa->dpd_event); |
1321 | sa->dpd_event = 0; |
1322 | } |
1323 | sa->flags |= SA_FLAG_REPLACED0x08; |
1324 | } |
1325 | |
1326 | /* Replace SA */ |
1327 | void |
1328 | sa_replace(struct sa *sa, struct sa *new_sa) |
1329 | { |
1330 | LOG_DBG((LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)",log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed") |
1331 | sa, sa->name ? sa->name : "unnamed",log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed") |
1332 | new_sa, new_sa->name ? new_sa->name : "unnamed"))log_debug (LOG_SA, 60, "sa_replace: SA %p (%s) is replaced by SA %p (%s)" , sa, sa->name ? sa->name : "unnamed", new_sa, new_sa-> name ? new_sa->name : "unnamed"); |
1333 | sa_mark_replaced(sa); |
1334 | if (new_sa->flags & SA_FLAG_REPLACED0x08) { |
1335 | /* enable the dpd */ |
1336 | if ((new_sa->flags & SA_FLAG_DPD0x80) == SA_FLAG_DPD0x80) |
1337 | dpd_start(new_sa); |
1338 | new_sa->flags &= ~SA_FLAG_REPLACED0x08; |
1339 | } |
1340 | } |
1341 | |
1342 | /* |
1343 | * Setup expiration timers for SA. This is used for ISAKMP SAs, but also |
1344 | * possible to use for application SAs if the application does not deal |
1345 | * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec |
1346 | * stack. |
1347 | */ |
1348 | int |
1349 | sa_setup_expirations(struct sa *sa) |
1350 | { |
1351 | struct timespec expiration; |
1352 | u_int64_t seconds = sa->seconds; |
Value stored to 'seconds' during its initialization is never read | |
1353 | |
1354 | /* |
1355 | * Set the soft timeout to a random percentage between 85 & 95 of |
1356 | * the negotiated lifetime to break strictly synchronized |
1357 | * renegotiations. This works better when the randomization is on the |
1358 | * order of processing plus network-roundtrip times, or larger. |
1359 | * I.e. it depends on configuration and negotiated lifetimes. |
1360 | * It is not good to do the decrease on the hard timeout, because then |
1361 | * we may drop our SA before our peer. |
1362 | * XXX Better scheme to come? |
1363 | */ |
1364 | if (!sa->soft_death) { |
1365 | clock_gettime(CLOCK_MONOTONIC3, &expiration); |
1366 | /* |
1367 | * XXX This should probably be configuration controlled |
1368 | * somehow. |
1369 | */ |
1370 | seconds = sa->seconds * (850 + arc4random_uniform(100)) / 1000; |
1371 | LOG_DBG((LOG_TIMER, 95,log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds) |
1372 | "sa_setup_expirations: SA %p soft timeout in %llu seconds",log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds) |
1373 | sa, seconds))log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds" , sa, seconds); |
1374 | expiration.tv_sec += seconds; |
1375 | sa->soft_death = timer_add_event("sa_soft_expire", |
1376 | sa_soft_expire, sa, &expiration); |
1377 | if (!sa->soft_death) { |
1378 | /* If we don't give up we might start leaking... */ |
1379 | sa_delete(sa, 1); |
1380 | return -1; |
1381 | } |
1382 | sa_reference(sa); |
1383 | } |
1384 | if (!sa->death) { |
1385 | clock_gettime(CLOCK_MONOTONIC3, &expiration); |
1386 | LOG_DBG((LOG_TIMER, 95,log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds) |
1387 | "sa_setup_expirations: SA %p hard timeout in %llu seconds",log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds) |
1388 | sa, sa->seconds))log_debug (LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds" , sa, sa->seconds); |
1389 | expiration.tv_sec += sa->seconds; |
1390 | sa->death = timer_add_event("sa_hard_expire", sa_hard_expire, |
1391 | sa, &expiration); |
1392 | if (!sa->death) { |
1393 | /* If we don't give up we might start leaking... */ |
1394 | sa_delete(sa, 1); |
1395 | return -1; |
1396 | } |
1397 | sa_reference(sa); |
1398 | } |
1399 | return 0; |
1400 | } |