File: | src/sbin/iked/ikev2_msg.c |
Warning: | line 1257, column 3 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ikev2_msg.c,v 1.100 2023/08/04 19:06:25 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> | |||
5 | * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> | |||
6 | * | |||
7 | * Permission to use, copy, modify, and distribute this software for any | |||
8 | * purpose with or without fee is hereby granted, provided that the above | |||
9 | * copyright notice and this permission notice appear in all copies. | |||
10 | * | |||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
18 | */ | |||
19 | ||||
20 | #include <sys/types.h> | |||
21 | #include <sys/queue.h> | |||
22 | #include <sys/socket.h> | |||
23 | #include <sys/uio.h> | |||
24 | ||||
25 | #include <netinet/in.h> | |||
26 | #include <arpa/inet.h> | |||
27 | ||||
28 | #include <stdlib.h> | |||
29 | #include <stdio.h> | |||
30 | #include <syslog.h> | |||
31 | #include <unistd.h> | |||
32 | #include <string.h> | |||
33 | #include <signal.h> | |||
34 | #include <endian.h> | |||
35 | #include <errno(*__errno()).h> | |||
36 | #include <err.h> | |||
37 | #include <event.h> | |||
38 | ||||
39 | #include <openssl/sha.h> | |||
40 | #include <openssl/evp.h> | |||
41 | ||||
42 | #include "iked.h" | |||
43 | #include "ikev2.h" | |||
44 | #include "eap.h" | |||
45 | #include "dh.h" | |||
46 | ||||
47 | void ikev1_recv(struct iked *, struct iked_message *); | |||
48 | void ikev2_msg_response_timeout(struct iked *, void *); | |||
49 | void ikev2_msg_retransmit_timeout(struct iked *, void *); | |||
50 | int ikev2_check_frag_oversize(struct iked_sa *, struct ibuf *); | |||
51 | int ikev2_send_encrypted_fragments(struct iked *, struct iked_sa *, | |||
52 | struct ibuf *, uint8_t, uint8_t, int); | |||
53 | int ikev2_msg_encrypt_prepare(struct iked_sa *, struct ikev2_payload *, | |||
54 | struct ibuf*, struct ibuf *, struct ike_header *, uint8_t, int); | |||
55 | ||||
56 | void | |||
57 | ikev2_msg_cb(int fd, short event, void *arg) | |||
58 | { | |||
59 | struct iked_socket *sock = arg; | |||
60 | struct iked *env = sock->sock_env; | |||
61 | struct iked_message msg; | |||
62 | struct ike_header hdr; | |||
63 | uint32_t natt = 0x00000000; | |||
64 | uint8_t buf[IKED_MSGBUF_MAX8192]; | |||
65 | ssize_t len; | |||
66 | off_t off; | |||
67 | ||||
68 | bzero(&msg, sizeof(msg)); | |||
69 | bzero(buf, sizeof(buf)); | |||
70 | ||||
71 | msg.msg_peerlen = sizeof(msg.msg_peer); | |||
72 | msg.msg_locallen = sizeof(msg.msg_local); | |||
73 | msg.msg_parent = &msg; | |||
74 | memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr)); | |||
75 | ||||
76 | if ((len = recvfromto(fd, buf, sizeof(buf), 0, | |||
77 | (struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen, | |||
78 | (struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) < | |||
79 | (ssize_t)sizeof(natt)) | |||
80 | return; | |||
81 | ||||
82 | if (socket_getport((struct sockaddr *)&msg.msg_local) == | |||
83 | env->sc_nattportsc_static.st_nattport) { | |||
84 | if (memcmp(&natt, buf, sizeof(natt)) != 0) | |||
85 | return; | |||
86 | msg.msg_natt = 1; | |||
87 | off = sizeof(natt); | |||
88 | } else | |||
89 | off = 0; | |||
90 | ||||
91 | if ((size_t)(len - off) <= sizeof(hdr)) | |||
92 | return; | |||
93 | memcpy(&hdr, buf + off, sizeof(hdr)); | |||
94 | ||||
95 | if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL((void *)0)) | |||
96 | return; | |||
97 | ||||
98 | TAILQ_INIT(&msg.msg_proposals)do { (&msg.msg_proposals)->tqh_first = ((void *)0); (& msg.msg_proposals)->tqh_last = &(&msg.msg_proposals )->tqh_first; } while (0); | |||
99 | SIMPLEQ_INIT(&msg.msg_certreqs)do { (&msg.msg_certreqs)->sqh_first = ((void *)0); (& msg.msg_certreqs)->sqh_last = &(&msg.msg_certreqs) ->sqh_first; } while (0); | |||
100 | msg.msg_fd = fd; | |||
101 | ||||
102 | if (hdr.ike_version == IKEV1_VERSION0x10) | |||
103 | ikev1_recv(env, &msg); | |||
104 | else | |||
105 | ikev2_recv(env, &msg); | |||
106 | ||||
107 | ikev2_msg_cleanup(env, &msg); | |||
108 | } | |||
109 | ||||
110 | void | |||
111 | ikev1_recv(struct iked *env, struct iked_message *msg) | |||
112 | { | |||
113 | struct ike_header *hdr; | |||
114 | ||||
115 | if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { | |||
116 | log_debug("%s: short message", __func__); | |||
117 | return; | |||
118 | } | |||
119 | ||||
120 | hdr = (struct ike_header *)ibuf_data(msg->msg_data); | |||
121 | ||||
122 | log_debug("%s: header ispi %s rspi %s" | |||
123 | " nextpayload %u version 0x%02x exchange %u flags 0x%02x" | |||
124 | " msgid %u length %u", __func__, | |||
125 | print_spi(betoh64(hdr->ike_ispi)(__uint64_t)(__builtin_constant_p(hdr->ike_ispi) ? (__uint64_t )((((__uint64_t)(hdr->ike_ispi) & 0xff) << 56) | ((__uint64_t)(hdr->ike_ispi) & 0xff00ULL) << 40 | ((__uint64_t)(hdr->ike_ispi) & 0xff0000ULL) << 24 | ((__uint64_t)(hdr->ike_ispi) & 0xff000000ULL) << 8 | ((__uint64_t)(hdr->ike_ispi) & 0xff00000000ULL) >> 8 | ((__uint64_t)(hdr->ike_ispi) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(hdr->ike_ispi) & 0xff000000000000ULL ) >> 40 | ((__uint64_t)(hdr->ike_ispi) & 0xff00000000000000ULL ) >> 56) : __swap64md(hdr->ike_ispi)), 8), | |||
126 | print_spi(betoh64(hdr->ike_rspi)(__uint64_t)(__builtin_constant_p(hdr->ike_rspi) ? (__uint64_t )((((__uint64_t)(hdr->ike_rspi) & 0xff) << 56) | ((__uint64_t)(hdr->ike_rspi) & 0xff00ULL) << 40 | ((__uint64_t)(hdr->ike_rspi) & 0xff0000ULL) << 24 | ((__uint64_t)(hdr->ike_rspi) & 0xff000000ULL) << 8 | ((__uint64_t)(hdr->ike_rspi) & 0xff00000000ULL) >> 8 | ((__uint64_t)(hdr->ike_rspi) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(hdr->ike_rspi) & 0xff000000000000ULL ) >> 40 | ((__uint64_t)(hdr->ike_rspi) & 0xff00000000000000ULL ) >> 56) : __swap64md(hdr->ike_rspi)), 8), | |||
127 | hdr->ike_nextpayload, | |||
128 | hdr->ike_version, | |||
129 | hdr->ike_exchange, | |||
130 | hdr->ike_flags, | |||
131 | betoh32(hdr->ike_msgid)(__uint32_t)(__builtin_constant_p(hdr->ike_msgid) ? (__uint32_t )(((__uint32_t)(hdr->ike_msgid) & 0xff) << 24 | ( (__uint32_t)(hdr->ike_msgid) & 0xff00) << 8 | (( __uint32_t)(hdr->ike_msgid) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->ike_msgid) & 0xff000000) >> 24 ) : __swap32md(hdr->ike_msgid)), | |||
132 | betoh32(hdr->ike_length)(__uint32_t)(__builtin_constant_p(hdr->ike_length) ? (__uint32_t )(((__uint32_t)(hdr->ike_length) & 0xff) << 24 | ((__uint32_t)(hdr->ike_length) & 0xff00) << 8 | ((__uint32_t)(hdr->ike_length) & 0xff0000) >> 8 | ((__uint32_t)(hdr->ike_length) & 0xff000000) >> 24) : __swap32md(hdr->ike_length))); | |||
133 | ||||
134 | log_debug("%s: IKEv1 not supported", __func__); | |||
135 | } | |||
136 | ||||
137 | struct ibuf * | |||
138 | ikev2_msg_init(struct iked *env, struct iked_message *msg, | |||
139 | struct sockaddr_storage *peer, socklen_t peerlen, | |||
140 | struct sockaddr_storage *local, socklen_t locallen, int response) | |||
141 | { | |||
142 | bzero(msg, sizeof(*msg)); | |||
143 | memcpy(&msg->msg_peer, peer, peerlen); | |||
144 | msg->msg_peerlen = peerlen; | |||
145 | memcpy(&msg->msg_local, local, locallen); | |||
146 | msg->msg_locallen = locallen; | |||
147 | msg->msg_response = response ? 1 : 0; | |||
148 | msg->msg_fd = -1; | |||
149 | msg->msg_data = ibuf_static(); | |||
150 | msg->msg_e = 0; | |||
151 | msg->msg_parent = msg; /* has to be set */ | |||
152 | TAILQ_INIT(&msg->msg_proposals)do { (&msg->msg_proposals)->tqh_first = ((void *)0) ; (&msg->msg_proposals)->tqh_last = &(&msg-> msg_proposals)->tqh_first; } while (0); | |||
153 | ||||
154 | return (msg->msg_data); | |||
155 | } | |||
156 | ||||
157 | struct iked_message * | |||
158 | ikev2_msg_copy(struct iked *env, struct iked_message *msg) | |||
159 | { | |||
160 | struct iked_message *m = NULL((void *)0); | |||
161 | struct ibuf *buf; | |||
162 | size_t len; | |||
163 | void *ptr; | |||
164 | ||||
165 | if (ibuf_size(msg->msg_data) < msg->msg_offset) | |||
166 | return (NULL((void *)0)); | |||
167 | len = ibuf_size(msg->msg_data) - msg->msg_offset; | |||
168 | ||||
169 | if ((m = malloc(sizeof(*m))) == NULL((void *)0)) | |||
170 | return (NULL((void *)0)); | |||
171 | ||||
172 | if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL((void *)0) || | |||
173 | (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, | |||
174 | &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL((void *)0) || | |||
175 | ibuf_add(buf, ptr, len)) { | |||
176 | free(m); | |||
177 | return (NULL((void *)0)); | |||
178 | } | |||
179 | ||||
180 | m->msg_fd = msg->msg_fd; | |||
181 | m->msg_msgid = msg->msg_msgid; | |||
182 | m->msg_offset = msg->msg_offset; | |||
183 | m->msg_sa = msg->msg_sa; | |||
184 | ||||
185 | return (m); | |||
186 | } | |||
187 | ||||
188 | void | |||
189 | ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) | |||
190 | { | |||
191 | struct iked_certreq *cr; | |||
192 | int i; | |||
193 | ||||
194 | if (msg == msg->msg_parent) { | |||
195 | ibuf_free(msg->msg_nonce); | |||
196 | ibuf_free(msg->msg_ke); | |||
197 | ibuf_free(msg->msg_auth.id_buf); | |||
198 | ibuf_free(msg->msg_peerid.id_buf); | |||
199 | ibuf_free(msg->msg_localid.id_buf); | |||
200 | ibuf_free(msg->msg_cert.id_buf); | |||
201 | for (i = 0; i < IKED_SCERT_MAX3; i++) | |||
202 | ibuf_free(msg->msg_scert[i].id_buf); | |||
203 | ibuf_free(msg->msg_cookie); | |||
204 | ibuf_free(msg->msg_cookie2); | |||
205 | ibuf_free(msg->msg_del_buf); | |||
206 | free(msg->msg_eap.eam_user); | |||
207 | free(msg->msg_cp_addr); | |||
208 | free(msg->msg_cp_addr6); | |||
209 | free(msg->msg_cp_dns); | |||
210 | ||||
211 | msg->msg_nonce = NULL((void *)0); | |||
212 | msg->msg_ke = NULL((void *)0); | |||
213 | msg->msg_auth.id_buf = NULL((void *)0); | |||
214 | msg->msg_peerid.id_buf = NULL((void *)0); | |||
215 | msg->msg_localid.id_buf = NULL((void *)0); | |||
216 | msg->msg_cert.id_buf = NULL((void *)0); | |||
217 | for (i = 0; i < IKED_SCERT_MAX3; i++) | |||
218 | msg->msg_scert[i].id_buf = NULL((void *)0); | |||
219 | msg->msg_cookie = NULL((void *)0); | |||
220 | msg->msg_cookie2 = NULL((void *)0); | |||
221 | msg->msg_del_buf = NULL((void *)0); | |||
222 | msg->msg_eap.eam_user = NULL((void *)0); | |||
223 | msg->msg_cp_addr = NULL((void *)0); | |||
224 | msg->msg_cp_addr6 = NULL((void *)0); | |||
225 | msg->msg_cp_dns = NULL((void *)0); | |||
226 | ||||
227 | config_free_proposals(&msg->msg_proposals, 0); | |||
228 | while ((cr = SIMPLEQ_FIRST(&msg->msg_certreqs)((&msg->msg_certreqs)->sqh_first))) { | |||
229 | ibuf_free(cr->cr_data); | |||
230 | SIMPLEQ_REMOVE_HEAD(&msg->msg_certreqs, cr_entry)do { if (((&msg->msg_certreqs)->sqh_first = (&msg ->msg_certreqs)->sqh_first->cr_entry.sqe_next) == (( void *)0)) (&msg->msg_certreqs)->sqh_last = &(& msg->msg_certreqs)->sqh_first; } while (0); | |||
231 | free(cr); | |||
232 | } | |||
233 | } | |||
234 | ||||
235 | if (msg->msg_data != NULL((void *)0)) { | |||
236 | ibuf_free(msg->msg_data); | |||
237 | msg->msg_data = NULL((void *)0); | |||
238 | } | |||
239 | } | |||
240 | ||||
241 | int | |||
242 | ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, | |||
243 | struct iked_message *msg) | |||
244 | { | |||
245 | if (msg->msg_sa != NULL((void *)0) && msg->msg_policy != NULL((void *)0)) { | |||
246 | if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSED11) | |||
247 | return (-1); | |||
248 | /* | |||
249 | * Only permit informational requests from initiator | |||
250 | * on closing SAs (for DELETE). | |||
251 | */ | |||
252 | if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING10) { | |||
253 | if (((oldhdr->ike_flags & | |||
254 | (IKEV2_FLAG_INITIATOR0x08|IKEV2_FLAG_RESPONSE0x20)) == | |||
255 | IKEV2_FLAG_INITIATOR0x08) && | |||
256 | (oldhdr->ike_exchange == | |||
257 | IKEV2_EXCHANGE_INFORMATIONAL37)) | |||
258 | return (0); | |||
259 | return (-1); | |||
260 | } | |||
261 | return (0); | |||
262 | } | |||
263 | ||||
264 | /* Always fail */ | |||
265 | return (-1); | |||
266 | } | |||
267 | ||||
268 | int | |||
269 | ikev2_msg_send(struct iked *env, struct iked_message *msg) | |||
270 | { | |||
271 | struct iked_sa *sa = msg->msg_sa; | |||
272 | struct ibuf *buf = msg->msg_data; | |||
273 | uint32_t natt = 0x00000000; | |||
274 | int isnatt = 0; | |||
275 | uint8_t exchange, flags; | |||
276 | struct ike_header *hdr; | |||
277 | struct iked_message *m; | |||
278 | ||||
279 | if (buf == NULL((void *)0) || (hdr = ibuf_seek(msg->msg_data, | |||
280 | msg->msg_offset, sizeof(*hdr))) == NULL((void *)0)) | |||
281 | return (-1); | |||
282 | ||||
283 | isnatt = (msg->msg_natt || (sa && sa->sa_natt)); | |||
284 | ||||
285 | exchange = hdr->ike_exchange; | |||
286 | flags = hdr->ike_flags; | |||
287 | logit(exchange == IKEV2_EXCHANGE_INFORMATIONAL37 ? LOG_DEBUG7 : LOG_INFO6, | |||
288 | "%ssend %s %s %u peer %s local %s, %zu bytes%s", | |||
289 | SPI_IH(hdr)ikev2_ikesa_info((__uint64_t)(__builtin_constant_p((hdr)-> ike_ispi) ? (__uint64_t)((((__uint64_t)((hdr)->ike_ispi) & 0xff) << 56) | ((__uint64_t)((hdr)->ike_ispi) & 0xff00ULL) << 40 | ((__uint64_t)((hdr)->ike_ispi) & 0xff0000ULL) << 24 | ((__uint64_t)((hdr)->ike_ispi) & 0xff000000ULL) << 8 | ((__uint64_t)((hdr)->ike_ispi ) & 0xff00000000ULL) >> 8 | ((__uint64_t)((hdr)-> ike_ispi) & 0xff0000000000ULL) >> 24 | ((__uint64_t )((hdr)->ike_ispi) & 0xff000000000000ULL) >> 40 | ((__uint64_t)((hdr)->ike_ispi) & 0xff00000000000000ULL ) >> 56) : __swap64md((hdr)->ike_ispi)), ((void *)0) ), | |||
290 | print_map(exchange, ikev2_exchange_map), | |||
291 | (flags & IKEV2_FLAG_RESPONSE0x20) ? "res" : "req", | |||
292 | betoh32(hdr->ike_msgid)(__uint32_t)(__builtin_constant_p(hdr->ike_msgid) ? (__uint32_t )(((__uint32_t)(hdr->ike_msgid) & 0xff) << 24 | ( (__uint32_t)(hdr->ike_msgid) & 0xff00) << 8 | (( __uint32_t)(hdr->ike_msgid) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->ike_msgid) & 0xff000000) >> 24 ) : __swap32md(hdr->ike_msgid)), | |||
293 | print_addr(&msg->msg_peer), | |||
294 | print_addr(&msg->msg_local), | |||
295 | ibuf_size(buf), isnatt ? ", NAT-T" : ""); | |||
296 | ||||
297 | if (isnatt) { | |||
298 | struct ibuf *new; | |||
299 | if ((new = ibuf_new(&natt, sizeof(natt))) == NULL((void *)0)) { | |||
300 | log_debug("%s: failed to set NAT-T", __func__); | |||
301 | return (-1); | |||
302 | } | |||
303 | if (ibuf_add_buf(new, buf) == -1) { | |||
304 | ibuf_free(new); | |||
305 | log_debug("%s: failed to set NAT-T", __func__); | |||
306 | return (-1); | |||
307 | } | |||
308 | ibuf_free(buf); | |||
309 | buf = msg->msg_data = new; | |||
310 | } | |||
311 | ||||
312 | if (sendtofrom(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, | |||
313 | (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, | |||
314 | (struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { | |||
315 | log_warn("%s: sendtofrom", __func__); | |||
316 | if (sa != NULL((void *)0) && errno(*__errno()) == EADDRNOTAVAIL49) { | |||
317 | sa_state(env, sa, IKEV2_STATE_CLOSING10); | |||
318 | timer_del(env, &sa->sa_timer); | |||
319 | timer_set(env, &sa->sa_timer, | |||
320 | ikev2_ike_sa_timeout, sa); | |||
321 | timer_add(env, &sa->sa_timer, | |||
322 | IKED_IKE_SA_DELETE_TIMEOUT120); | |||
323 | } | |||
324 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
325 | } else | |||
326 | ikestat_inc(env, ikes_msg_sent)do { env->sc_stats.ikes_msg_sent += (1); } while(0); | |||
327 | ||||
328 | if (sa == NULL((void *)0)) | |||
329 | return (0); | |||
330 | ||||
331 | if ((m = ikev2_msg_copy(env, msg)) == NULL((void *)0)) { | |||
332 | log_debug("%s: failed to copy a message", __func__); | |||
333 | return (-1); | |||
334 | } | |||
335 | m->msg_exchange = exchange; | |||
336 | ||||
337 | if (flags & IKEV2_FLAG_RESPONSE0x20) { | |||
338 | if (ikev2_msg_enqueue(env, &sa->sa_responses, m, | |||
339 | IKED_RESPONSE_TIMEOUT120) != 0) { | |||
340 | ikev2_msg_cleanup(env, m); | |||
341 | free(m); | |||
342 | return (-1); | |||
343 | } | |||
344 | } else { | |||
345 | if (ikev2_msg_enqueue(env, &sa->sa_requests, m, | |||
346 | IKED_RETRANSMIT_TIMEOUT2) != 0) { | |||
347 | ikev2_msg_cleanup(env, m); | |||
348 | free(m); | |||
349 | return (-1); | |||
350 | } | |||
351 | } | |||
352 | ||||
353 | return (0); | |||
354 | } | |||
355 | ||||
356 | uint32_t | |||
357 | ikev2_msg_id(struct iked *env, struct iked_sa *sa) | |||
358 | { | |||
359 | uint32_t id = sa->sa_reqid; | |||
360 | ||||
361 | if (++sa->sa_reqid == UINT32_MAX0xffffffffU) { | |||
362 | /* XXX we should close and renegotiate the connection now */ | |||
363 | log_debug("%s: IKEv2 message sequence overflow", __func__); | |||
364 | } | |||
365 | return (id); | |||
366 | } | |||
367 | ||||
368 | /* | |||
369 | * Calculate the final sizes of the IKEv2 header and the encrypted payload | |||
370 | * header. This must be done before encryption to make sure the correct | |||
371 | * headers are authenticated. | |||
372 | */ | |||
373 | int | |||
374 | ikev2_msg_encrypt_prepare(struct iked_sa *sa, struct ikev2_payload *pld, | |||
375 | struct ibuf *buf, struct ibuf *e, struct ike_header *hdr, | |||
376 | uint8_t firstpayload, int fragmentation) | |||
377 | { | |||
378 | size_t len, ivlen, encrlen, integrlen, blocklen, pldlen, outlen; | |||
379 | ||||
380 | if (sa == NULL((void *)0) || | |||
381 | sa->sa_encr == NULL((void *)0) || | |||
382 | sa->sa_integr == NULL((void *)0)) { | |||
383 | log_debug("%s: invalid SA", __func__); | |||
384 | return (-1); | |||
385 | } | |||
386 | ||||
387 | len = ibuf_size(e); | |||
388 | blocklen = cipher_length(sa->sa_encr); | |||
389 | integrlen = hash_length(sa->sa_integr); | |||
390 | ivlen = cipher_ivlength(sa->sa_encr); | |||
391 | encrlen = roundup(len + 1, blocklen)((((len + 1)+((blocklen)-1))/(blocklen))*(blocklen)); | |||
392 | outlen = cipher_outlength(sa->sa_encr, encrlen); | |||
393 | pldlen = ivlen + outlen + integrlen; | |||
394 | ||||
395 | if (ikev2_next_payload(pld, | |||
396 | pldlen + (fragmentation ? sizeof(struct ikev2_frag_payload) : 0), | |||
397 | firstpayload) == -1) | |||
398 | return (-1); | |||
399 | if (ikev2_set_header(hdr, ibuf_size(buf) + pldlen - sizeof(*hdr)) == -1) | |||
400 | return (-1); | |||
401 | ||||
402 | return (0); | |||
403 | } | |||
404 | ||||
405 | struct ibuf * | |||
406 | ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src, | |||
407 | struct ibuf *aad) | |||
408 | { | |||
409 | size_t len, encrlen, integrlen, blocklen, | |||
410 | outlen; | |||
411 | uint8_t *buf, pad = 0, *ptr; | |||
412 | struct ibuf *encr, *dst = NULL((void *)0), *out = NULL((void *)0); | |||
413 | ||||
414 | buf = ibuf_data(src); | |||
415 | len = ibuf_size(src); | |||
416 | ||||
417 | log_debug("%s: decrypted length %zu", __func__, len); | |||
418 | print_hex(buf, 0, len); | |||
419 | ||||
420 | if (sa == NULL((void *)0) || | |||
421 | sa->sa_encr == NULL((void *)0) || | |||
422 | sa->sa_integr == NULL((void *)0)) { | |||
423 | log_debug("%s: invalid SA", __func__); | |||
424 | goto done; | |||
425 | } | |||
426 | ||||
427 | if (sa->sa_hdr.sh_initiator) | |||
428 | encr = sa->sa_key_iencr; | |||
429 | else | |||
430 | encr = sa->sa_key_rencr; | |||
431 | ||||
432 | blocklen = cipher_length(sa->sa_encr); | |||
433 | integrlen = hash_length(sa->sa_integr); | |||
434 | encrlen = roundup(len + sizeof(pad), blocklen)((((len + sizeof(pad))+((blocklen)-1))/(blocklen))*(blocklen) ); | |||
435 | pad = encrlen - (len + sizeof(pad)); | |||
436 | ||||
437 | /* | |||
438 | * Pad the payload and encrypt it | |||
439 | */ | |||
440 | if (pad) { | |||
441 | if ((ptr = ibuf_reserve(src, pad)) == NULL((void *)0)) | |||
442 | goto done; | |||
443 | arc4random_buf(ptr, pad); | |||
444 | } | |||
445 | if (ibuf_add(src, &pad, sizeof(pad)) != 0) | |||
446 | goto done; | |||
447 | ||||
448 | log_debug("%s: padded length %zu", __func__, ibuf_size(src)); | |||
449 | print_hexbuf(src); | |||
450 | ||||
451 | cipher_setkey(sa->sa_encr, ibuf_data(encr), ibuf_size(encr)); | |||
452 | cipher_setiv(sa->sa_encr, NULL((void *)0), 0); /* XXX ivlen */ | |||
453 | if (cipher_init_encrypt(sa->sa_encr) == -1) { | |||
454 | log_info("%s: error initiating cipher.", __func__); | |||
455 | goto done; | |||
456 | } | |||
457 | ||||
458 | if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL((void *)0)) | |||
459 | goto done; | |||
460 | ||||
461 | if ((out = ibuf_new(NULL((void *)0), | |||
462 | cipher_outlength(sa->sa_encr, encrlen))) == NULL((void *)0)) | |||
463 | goto done; | |||
464 | ||||
465 | outlen = ibuf_size(out); | |||
466 | ||||
467 | /* Add AAD for AEAD ciphers */ | |||
468 | if (sa->sa_integr->hash_isaead) | |||
469 | cipher_aad(sa->sa_encr, ibuf_data(aad), ibuf_size(aad), | |||
470 | &outlen); | |||
471 | ||||
472 | if (cipher_update(sa->sa_encr, ibuf_data(src), encrlen, | |||
473 | ibuf_data(out), &outlen) == -1) { | |||
474 | log_info("%s: error updating cipher.", __func__); | |||
475 | goto done; | |||
476 | } | |||
477 | ||||
478 | if (cipher_final(sa->sa_encr) == -1) { | |||
479 | log_info("%s: encryption failed.", __func__); | |||
480 | goto done; | |||
481 | } | |||
482 | ||||
483 | if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0) | |||
484 | goto done; | |||
485 | ||||
486 | if ((ptr = ibuf_reserve(dst, integrlen)) == NULL((void *)0)) | |||
487 | goto done; | |||
488 | explicit_bzero(ptr, integrlen); | |||
489 | ||||
490 | log_debug("%s: length %zu, padding %d, output length %zu", | |||
491 | __func__, len + sizeof(pad), pad, ibuf_size(dst)); | |||
492 | print_hexbuf(dst); | |||
493 | ||||
494 | ibuf_free(src); | |||
495 | ibuf_free(out); | |||
496 | return (dst); | |||
497 | done: | |||
498 | ibuf_free(src); | |||
499 | ibuf_free(out); | |||
500 | ibuf_free(dst); | |||
501 | return (NULL((void *)0)); | |||
502 | } | |||
503 | ||||
504 | int | |||
505 | ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) | |||
506 | { | |||
507 | int ret = -1; | |||
508 | size_t integrlen, tmplen; | |||
509 | struct ibuf *integr, *tmp = NULL((void *)0); | |||
510 | uint8_t *ptr; | |||
511 | ||||
512 | log_debug("%s: message length %zu", __func__, ibuf_size(src)); | |||
513 | print_hexbuf(src); | |||
514 | ||||
515 | if (sa == NULL((void *)0) || | |||
516 | sa->sa_encr == NULL((void *)0) || | |||
517 | sa->sa_integr == NULL((void *)0)) { | |||
518 | log_debug("%s: invalid SA", __func__); | |||
519 | return (-1); | |||
520 | } | |||
521 | ||||
522 | integrlen = hash_length(sa->sa_integr); | |||
523 | log_debug("%s: integrity checksum length %zu", __func__, | |||
524 | integrlen); | |||
525 | ||||
526 | /* | |||
527 | * Validate packet checksum | |||
528 | */ | |||
529 | if ((tmp = ibuf_new(NULL((void *)0), hash_keylength(sa->sa_integr))) == NULL((void *)0)) | |||
530 | goto done; | |||
531 | ||||
532 | if (!sa->sa_integr->hash_isaead) { | |||
533 | if (sa->sa_hdr.sh_initiator) | |||
534 | integr = sa->sa_key_iauth; | |||
535 | else | |||
536 | integr = sa->sa_key_rauth; | |||
537 | ||||
538 | hash_setkey(sa->sa_integr, ibuf_data(integr), | |||
539 | ibuf_size(integr)); | |||
540 | hash_init(sa->sa_integr); | |||
541 | hash_update(sa->sa_integr, ibuf_data(src), | |||
542 | ibuf_size(src) - integrlen); | |||
543 | hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); | |||
544 | ||||
545 | if (tmplen != integrlen) { | |||
546 | log_debug("%s: hash failure", __func__); | |||
547 | goto done; | |||
548 | } | |||
549 | } else { | |||
550 | /* Append AEAD tag */ | |||
551 | if (cipher_gettag(sa->sa_encr, ibuf_data(tmp), ibuf_size(tmp))) | |||
552 | goto done; | |||
553 | } | |||
554 | ||||
555 | if ((ptr = ibuf_seek(src, | |||
556 | ibuf_size(src) - integrlen, integrlen)) == NULL((void *)0)) | |||
557 | goto done; | |||
558 | memcpy(ptr, ibuf_data(tmp), integrlen); | |||
559 | ||||
560 | print_hexbuf(tmp); | |||
561 | ||||
562 | ret = 0; | |||
563 | done: | |||
564 | ibuf_free(tmp); | |||
565 | ||||
566 | return (ret); | |||
567 | } | |||
568 | ||||
569 | struct ibuf * | |||
570 | ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, | |||
571 | struct ibuf *msg, struct ibuf *src) | |||
572 | { | |||
573 | ssize_t ivlen, encrlen, integrlen, blocklen, | |||
574 | outlen, tmplen; | |||
575 | uint8_t pad = 0, *ptr, *integrdata; | |||
576 | struct ibuf *integr, *encr, *tmp = NULL((void *)0), *out = NULL((void *)0); | |||
577 | off_t ivoff, encroff, integroff; | |||
578 | ||||
579 | if (sa == NULL((void *)0) || | |||
580 | sa->sa_encr == NULL((void *)0) || | |||
581 | sa->sa_integr == NULL((void *)0)) { | |||
582 | log_debug("%s: invalid SA", __func__); | |||
583 | print_hexbuf(src); | |||
584 | goto done; | |||
585 | } | |||
586 | ||||
587 | if (!sa->sa_hdr.sh_initiator) { | |||
588 | encr = sa->sa_key_iencr; | |||
589 | integr = sa->sa_key_iauth; | |||
590 | } else { | |||
591 | encr = sa->sa_key_rencr; | |||
592 | integr = sa->sa_key_rauth; | |||
593 | } | |||
594 | ||||
595 | blocklen = cipher_length(sa->sa_encr); | |||
596 | ivlen = cipher_ivlength(sa->sa_encr); | |||
597 | ivoff = 0; | |||
598 | integrlen = hash_length(sa->sa_integr); | |||
599 | integroff = ibuf_size(src) - integrlen; | |||
600 | encroff = ivlen; | |||
601 | encrlen = ibuf_size(src) - integrlen - ivlen; | |||
602 | ||||
603 | if (encrlen < 0 || integroff < 0) { | |||
604 | log_debug("%s: invalid integrity value", __func__); | |||
605 | goto done; | |||
606 | } | |||
607 | ||||
608 | log_debug("%s: IV length %zd", __func__, ivlen); | |||
609 | print_hex(ibuf_data(src), 0, ivlen); | |||
610 | log_debug("%s: encrypted payload length %zd", __func__, encrlen); | |||
611 | print_hex(ibuf_data(src), encroff, encrlen); | |||
612 | log_debug("%s: integrity checksum length %zd", __func__, integrlen); | |||
613 | print_hex(ibuf_data(src), integroff, integrlen); | |||
614 | ||||
615 | /* | |||
616 | * Validate packet checksum | |||
617 | */ | |||
618 | if (!sa->sa_integr->hash_isaead) { | |||
619 | if ((tmp = ibuf_new(NULL((void *)0), hash_keylength(sa->sa_integr))) == NULL((void *)0)) | |||
620 | goto done; | |||
621 | ||||
622 | hash_setkey(sa->sa_integr, ibuf_data(integr), | |||
623 | ibuf_size(integr)); | |||
624 | hash_init(sa->sa_integr); | |||
625 | hash_update(sa->sa_integr, ibuf_data(msg), | |||
626 | ibuf_size(msg) - integrlen); | |||
627 | hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); | |||
628 | ||||
629 | integrdata = ibuf_seek(src, integroff, integrlen); | |||
630 | if (integrdata == NULL((void *)0)) | |||
631 | goto done; | |||
632 | if (memcmp(ibuf_data(tmp), integrdata, integrlen) != 0) { | |||
633 | log_debug("%s: integrity check failed", __func__); | |||
634 | goto done; | |||
635 | } | |||
636 | ||||
637 | log_debug("%s: integrity check succeeded", __func__); | |||
638 | print_hex(ibuf_data(tmp), 0, tmplen); | |||
639 | ||||
640 | ibuf_free(tmp); | |||
641 | tmp = NULL((void *)0); | |||
642 | } | |||
643 | ||||
644 | /* | |||
645 | * Decrypt the payload and strip any padding | |||
646 | */ | |||
647 | if ((encrlen % blocklen) != 0) { | |||
648 | log_debug("%s: unaligned encrypted payload", __func__); | |||
649 | goto done; | |||
650 | } | |||
651 | ||||
652 | cipher_setkey(sa->sa_encr, ibuf_data(encr), ibuf_size(encr)); | |||
653 | cipher_setiv(sa->sa_encr, ibuf_seek(src, ivoff, ivlen), ivlen); | |||
654 | if (cipher_init_decrypt(sa->sa_encr) == -1) { | |||
655 | log_info("%s: error initiating cipher.", __func__); | |||
656 | goto done; | |||
657 | } | |||
658 | ||||
659 | /* Set AEAD tag */ | |||
660 | if (sa->sa_integr->hash_isaead) { | |||
661 | integrdata = ibuf_seek(src, integroff, integrlen); | |||
662 | if (integrdata == NULL((void *)0)) | |||
663 | goto done; | |||
664 | if (cipher_settag(sa->sa_encr, integrdata, integrlen)) { | |||
665 | log_info("%s: failed to set tag.", __func__); | |||
666 | goto done; | |||
667 | } | |||
668 | } | |||
669 | ||||
670 | if ((out = ibuf_new(NULL((void *)0), cipher_outlength(sa->sa_encr, | |||
671 | encrlen))) == NULL((void *)0)) | |||
672 | goto done; | |||
673 | ||||
674 | /* | |||
675 | * Add additional authenticated data for AEAD ciphers | |||
676 | */ | |||
677 | if (sa->sa_integr->hash_isaead) { | |||
678 | log_debug("%s: AAD length %zu", __func__, | |||
679 | ibuf_size(msg) - ibuf_size(src)); | |||
680 | print_hex(ibuf_data(msg), 0, ibuf_size(msg) - ibuf_size(src)); | |||
681 | cipher_aad(sa->sa_encr, ibuf_data(msg), | |||
682 | ibuf_size(msg) - ibuf_size(src), &outlen); | |||
683 | } | |||
684 | ||||
685 | if ((outlen = ibuf_size(out)) != 0) { | |||
686 | if (cipher_update(sa->sa_encr, ibuf_seek(src, encroff, encrlen), | |||
687 | encrlen, ibuf_data(out), &outlen) == -1) { | |||
688 | log_info("%s: error updating cipher.", __func__); | |||
689 | goto done; | |||
690 | } | |||
691 | ||||
692 | ptr = ibuf_seek(out, outlen - 1, 1); | |||
693 | pad = *ptr; | |||
694 | } | |||
695 | ||||
696 | if (cipher_final(sa->sa_encr) == -1) { | |||
697 | log_info("%s: decryption failed.", __func__); | |||
698 | goto done; | |||
699 | } | |||
700 | ||||
701 | log_debug("%s: decrypted payload length %zd/%zd padding %d", | |||
702 | __func__, outlen, encrlen, pad); | |||
703 | print_hexbuf(out); | |||
704 | ||||
705 | /* Strip padding and padding length */ | |||
706 | if (ibuf_setsize(out, outlen - pad - 1) != 0) | |||
707 | goto done; | |||
708 | ||||
709 | ibuf_free(src); | |||
710 | return (out); | |||
711 | done: | |||
712 | ibuf_free(tmp); | |||
713 | ibuf_free(out); | |||
714 | ibuf_free(src); | |||
715 | return (NULL((void *)0)); | |||
716 | } | |||
717 | ||||
718 | int | |||
719 | ikev2_check_frag_oversize(struct iked_sa *sa, struct ibuf *buf) { | |||
720 | size_t len = ibuf_length(buf); | |||
721 | sa_family_t sa_fam; | |||
722 | size_t max; | |||
723 | size_t ivlen, integrlen, blocklen; | |||
724 | ||||
725 | if (sa == NULL((void *)0) || | |||
726 | sa->sa_encr == NULL((void *)0) || | |||
727 | sa->sa_integr == NULL((void *)0)) { | |||
728 | log_debug("%s: invalid SA", __func__); | |||
729 | return (-1); | |||
730 | } | |||
731 | ||||
732 | sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; | |||
733 | ||||
734 | max = sa_fam == AF_INET2 ? IKEV2_MAXLEN_IPV4_FRAG(576 - (20 + 8 + 28)) | |||
735 | : IKEV2_MAXLEN_IPV6_FRAG(1280 - (40 + 8 + 28)); | |||
736 | ||||
737 | blocklen = cipher_length(sa->sa_encr); | |||
738 | ivlen = cipher_ivlength(sa->sa_encr); | |||
739 | integrlen = hash_length(sa->sa_integr); | |||
740 | ||||
741 | /* Estimated maximum packet size (with 0 < padding < blocklen) */ | |||
742 | return ((len + ivlen + blocklen + integrlen) >= max) && sa->sa_frag; | |||
743 | } | |||
744 | ||||
745 | int | |||
746 | ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, | |||
747 | uint8_t exchange, uint8_t firstpayload, int response) | |||
748 | { | |||
749 | struct iked_message resp; | |||
750 | struct ike_header *hdr; | |||
751 | struct ikev2_payload *pld; | |||
752 | struct ibuf *buf, *e = *ep; | |||
753 | int ret = -1; | |||
754 | ||||
755 | /* Check if msg needs to be fragmented */ | |||
756 | if (ikev2_check_frag_oversize(sa, e)) { | |||
757 | return ikev2_send_encrypted_fragments(env, sa, e, exchange, | |||
758 | firstpayload, response); | |||
759 | } | |||
760 | ||||
761 | if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, | |||
762 | sa->sa_peer.addr.ss_len, &sa->sa_local.addr, | |||
763 | sa->sa_local.addr.ss_len, response)) == NULL((void *)0)) | |||
764 | goto done; | |||
765 | ||||
766 | resp.msg_msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); | |||
767 | ||||
768 | /* IKE header */ | |||
769 | if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK46, | |||
770 | exchange, response ? IKEV2_FLAG_RESPONSE0x20 : 0)) == NULL((void *)0)) | |||
771 | goto done; | |||
772 | ||||
773 | if ((pld = ikev2_add_payload(buf)) == NULL((void *)0)) | |||
774 | goto done; | |||
775 | ||||
776 | if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, firstpayload, 0) == -1) | |||
777 | goto done; | |||
778 | ||||
779 | /* Encrypt message and add as an E payload */ | |||
780 | if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL((void *)0)) { | |||
781 | log_debug("%s: encryption failed", __func__); | |||
782 | goto done; | |||
783 | } | |||
784 | if (ibuf_add_buf(buf, e) != 0) | |||
785 | goto done; | |||
786 | ||||
787 | /* Add integrity checksum (HMAC) */ | |||
788 | if (ikev2_msg_integr(env, sa, buf) != 0) { | |||
789 | log_debug("%s: integrity checksum failed", __func__); | |||
790 | goto done; | |||
791 | } | |||
792 | ||||
793 | resp.msg_data = buf; | |||
794 | resp.msg_sa = sa; | |||
795 | resp.msg_fd = sa->sa_fd; | |||
796 | TAILQ_INIT(&resp.msg_proposals)do { (&resp.msg_proposals)->tqh_first = ((void *)0); ( &resp.msg_proposals)->tqh_last = &(&resp.msg_proposals )->tqh_first; } while (0); | |||
797 | ||||
798 | (void)ikev2_pld_parse(env, hdr, &resp, 0); | |||
799 | ||||
800 | ret = ikev2_msg_send(env, &resp); | |||
801 | ||||
802 | done: | |||
803 | /* e is cleaned up by the calling function */ | |||
804 | *ep = e; | |||
805 | ikev2_msg_cleanup(env, &resp); | |||
806 | ||||
807 | return (ret); | |||
808 | } | |||
809 | ||||
810 | int | |||
811 | ikev2_send_encrypted_fragments(struct iked *env, struct iked_sa *sa, | |||
812 | struct ibuf *in, uint8_t exchange, uint8_t firstpayload, int response) { | |||
813 | struct iked_message resp; | |||
814 | struct ibuf *buf, *e = NULL((void *)0); | |||
815 | struct ike_header *hdr; | |||
816 | struct ikev2_payload *pld; | |||
817 | struct ikev2_frag_payload *frag; | |||
818 | sa_family_t sa_fam; | |||
819 | size_t ivlen, integrlen, blocklen; | |||
820 | size_t max_len, left, offset=0; | |||
821 | size_t frag_num = 1, frag_total; | |||
822 | uint8_t *data; | |||
823 | uint32_t msgid; | |||
824 | int ret = -1; | |||
825 | ||||
826 | if (sa == NULL((void *)0) || | |||
827 | sa->sa_encr == NULL((void *)0) || | |||
828 | sa->sa_integr == NULL((void *)0)) { | |||
829 | log_debug("%s: invalid SA", __func__); | |||
830 | ikestat_inc(env, ikes_frag_send_failures)do { env->sc_stats.ikes_frag_send_failures += (1); } while (0); | |||
831 | return ret; | |||
832 | } | |||
833 | ||||
834 | sa_fam = ((struct sockaddr *)&sa->sa_local.addr)->sa_family; | |||
835 | ||||
836 | left = ibuf_length(in); | |||
837 | ||||
838 | /* Calculate max allowed size of a fragments payload */ | |||
839 | blocklen = cipher_length(sa->sa_encr); | |||
840 | ivlen = cipher_ivlength(sa->sa_encr); | |||
841 | integrlen = hash_length(sa->sa_integr); | |||
842 | max_len = (sa_fam == AF_INET2 ? IKEV2_MAXLEN_IPV4_FRAG(576 - (20 + 8 + 28)) | |||
843 | : IKEV2_MAXLEN_IPV6_FRAG(1280 - (40 + 8 + 28))) | |||
844 | - ivlen - blocklen - integrlen; | |||
845 | ||||
846 | /* Total number of fragments to send */ | |||
847 | frag_total = (left / max_len) + 1; | |||
848 | ||||
849 | msgid = response ? sa->sa_msgid_current : ikev2_msg_id(env, sa); | |||
850 | ||||
851 | while (frag_num <= frag_total) { | |||
852 | if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, | |||
853 | sa->sa_peer.addr.ss_len, &sa->sa_local.addr, | |||
854 | sa->sa_local.addr.ss_len, response)) == NULL((void *)0)) | |||
855 | goto done; | |||
856 | ||||
857 | resp.msg_msgid = msgid; | |||
858 | ||||
859 | /* IKE header */ | |||
860 | if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, | |||
861 | IKEV2_PAYLOAD_SKF53, exchange, response ? IKEV2_FLAG_RESPONSE0x20 | |||
862 | : 0)) == NULL((void *)0)) | |||
863 | goto done; | |||
864 | ||||
865 | /* Payload header */ | |||
866 | if ((pld = ikev2_add_payload(buf)) == NULL((void *)0)) | |||
867 | goto done; | |||
868 | ||||
869 | /* Fragment header */ | |||
870 | if ((frag = ibuf_reserve(buf, sizeof(*frag))) == NULL((void *)0)) { | |||
871 | log_debug("%s: failed to add SKF fragment header", | |||
872 | __func__); | |||
873 | goto done; | |||
874 | } | |||
875 | frag->frag_num = htobe16(frag_num)(__uint16_t)(__builtin_constant_p(frag_num) ? (__uint16_t)((( __uint16_t)(frag_num) & 0xffU) << 8 | ((__uint16_t) (frag_num) & 0xff00U) >> 8) : __swap16md(frag_num)); | |||
876 | frag->frag_total = htobe16(frag_total)(__uint16_t)(__builtin_constant_p(frag_total) ? (__uint16_t)( ((__uint16_t)(frag_total) & 0xffU) << 8 | ((__uint16_t )(frag_total) & 0xff00U) >> 8) : __swap16md(frag_total )); | |||
877 | ||||
878 | /* Encrypt message and add as an E payload */ | |||
879 | data = ibuf_seek(in, offset, 0); | |||
880 | if ((e = ibuf_new(data, MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)))) == NULL((void *)0)) { | |||
881 | goto done; | |||
882 | } | |||
883 | ||||
884 | if (ikev2_msg_encrypt_prepare(sa, pld, buf, e, hdr, | |||
885 | firstpayload, 1) == -1) | |||
886 | goto done; | |||
887 | ||||
888 | if ((e = ikev2_msg_encrypt(env, sa, e, buf)) == NULL((void *)0)) { | |||
889 | log_debug("%s: encryption failed", __func__); | |||
890 | goto done; | |||
891 | } | |||
892 | if (ibuf_add_buf(buf, e) != 0) | |||
893 | goto done; | |||
894 | ||||
895 | /* Add integrity checksum (HMAC) */ | |||
896 | if (ikev2_msg_integr(env, sa, buf) != 0) { | |||
897 | log_debug("%s: integrity checksum failed", __func__); | |||
898 | goto done; | |||
899 | } | |||
900 | ||||
901 | log_debug("%s: Fragment %zu of %zu has size of %zu bytes.", | |||
902 | __func__, frag_num, frag_total, | |||
903 | ibuf_size(buf) - sizeof(*hdr)); | |||
904 | print_hexbuf(buf); | |||
905 | ||||
906 | resp.msg_data = buf; | |||
907 | resp.msg_sa = sa; | |||
908 | resp.msg_fd = sa->sa_fd; | |||
909 | TAILQ_INIT(&resp.msg_proposals)do { (&resp.msg_proposals)->tqh_first = ((void *)0); ( &resp.msg_proposals)->tqh_last = &(&resp.msg_proposals )->tqh_first; } while (0); | |||
910 | ||||
911 | if (ikev2_msg_send(env, &resp) == -1) | |||
912 | goto done; | |||
913 | ||||
914 | ikestat_inc(env, ikes_frag_sent)do { env->sc_stats.ikes_frag_sent += (1); } while(0); | |||
915 | ||||
916 | offset += MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)); | |||
917 | left -= MINIMUM(left, max_len)(((left)<(max_len))?(left):(max_len)); | |||
918 | frag_num++; | |||
919 | ||||
920 | /* MUST be zero after first fragment */ | |||
921 | firstpayload = 0; | |||
922 | ||||
923 | ikev2_msg_cleanup(env, &resp); | |||
924 | ibuf_free(e); | |||
925 | e = NULL((void *)0); | |||
926 | } | |||
927 | ||||
928 | return 0; | |||
929 | done: | |||
930 | ikev2_msg_cleanup(env, &resp); | |||
931 | ibuf_free(e); | |||
932 | ikestat_inc(env, ikes_frag_send_failures)do { env->sc_stats.ikes_frag_send_failures += (1); } while (0); | |||
933 | return ret; | |||
934 | } | |||
935 | ||||
936 | struct ibuf * | |||
937 | ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) | |||
938 | { | |||
939 | struct ibuf *authmsg = NULL((void *)0), *nonce, *prfkey, *buf; | |||
940 | uint8_t *ptr; | |||
941 | struct iked_id *id; | |||
942 | size_t tmplen; | |||
943 | ||||
944 | /* | |||
945 | * Create the payload to be signed/MAC'ed for AUTH | |||
946 | */ | |||
947 | ||||
948 | if (!response) { | |||
949 | if ((nonce = sa->sa_rnoncesa_kex.kex_rnonce) == NULL((void *)0) || | |||
950 | (sa->sa_iid.id_type == 0) || | |||
951 | (prfkey = sa->sa_key_iprf) == NULL((void *)0) || | |||
952 | (buf = sa->sa_1stmsg) == NULL((void *)0)) | |||
953 | return (NULL((void *)0)); | |||
954 | id = &sa->sa_iid; | |||
955 | } else { | |||
956 | if ((nonce = sa->sa_inoncesa_kex.kex_inonce) == NULL((void *)0) || | |||
957 | (sa->sa_rid.id_type == 0) || | |||
958 | (prfkey = sa->sa_key_rprf) == NULL((void *)0) || | |||
959 | (buf = sa->sa_2ndmsg) == NULL((void *)0)) | |||
960 | return (NULL((void *)0)); | |||
961 | id = &sa->sa_rid; | |||
962 | } | |||
963 | ||||
964 | if ((authmsg = ibuf_dup(buf)) == NULL((void *)0)) | |||
965 | return (NULL((void *)0)); | |||
966 | if (ibuf_add_buf(authmsg, nonce) != 0) | |||
967 | goto fail; | |||
968 | ||||
969 | if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), | |||
970 | ibuf_size(prfkey))) == NULL((void *)0)) | |||
971 | goto fail; | |||
972 | ||||
973 | /* require non-truncating hash */ | |||
974 | if (hash_keylength(sa->sa_prf) != hash_length(sa->sa_prf)) | |||
975 | goto fail; | |||
976 | ||||
977 | if ((ptr = ibuf_reserve(authmsg, hash_keylength(sa->sa_prf))) == NULL((void *)0)) | |||
978 | goto fail; | |||
979 | ||||
980 | hash_init(sa->sa_prf); | |||
981 | hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); | |||
982 | hash_final(sa->sa_prf, ptr, &tmplen); | |||
983 | ||||
984 | if (tmplen != hash_length(sa->sa_prf)) | |||
985 | goto fail; | |||
986 | ||||
987 | log_debug("%s: %s auth data length %zu", | |||
988 | __func__, response ? "responder" : "initiator", | |||
989 | ibuf_size(authmsg)); | |||
990 | print_hexbuf(authmsg); | |||
991 | ||||
992 | return (authmsg); | |||
993 | ||||
994 | fail: | |||
995 | ibuf_free(authmsg); | |||
996 | return (NULL((void *)0)); | |||
997 | } | |||
998 | ||||
999 | int | |||
1000 | ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, | |||
1001 | struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) | |||
1002 | { | |||
1003 | uint8_t *key, *psk = NULL((void *)0); | |||
1004 | ssize_t keylen; | |||
1005 | struct iked_id *id; | |||
1006 | struct iked_dsa *dsa = NULL((void *)0); | |||
1007 | int ret = -1; | |||
1008 | uint8_t keytype; | |||
1009 | ||||
1010 | if (sa->sa_hdr.sh_initiator) | |||
1011 | id = &sa->sa_rcert; | |||
1012 | else | |||
1013 | id = &sa->sa_icert; | |||
1014 | ||||
1015 | if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL((void *)0)) { | |||
1016 | log_debug("%s: invalid auth method", __func__); | |||
1017 | return (-1); | |||
1018 | } | |||
1019 | ||||
1020 | switch (auth->auth_method) { | |||
1021 | case IKEV2_AUTH_SHARED_KEY_MIC2: | |||
1022 | if (!auth->auth_length) { | |||
1023 | log_debug("%s: no pre-shared key found", __func__); | |||
1024 | goto done; | |||
1025 | } | |||
1026 | if ((keylen = ikev2_psk(sa, auth->auth_data, | |||
1027 | auth->auth_length, &psk)) == -1) { | |||
1028 | log_debug("%s: failed to get PSK", __func__); | |||
1029 | goto done; | |||
1030 | } | |||
1031 | key = psk; | |||
1032 | keytype = 0; | |||
1033 | break; | |||
1034 | default: | |||
1035 | if (!id->id_type || !ibuf_length(id->id_buf)) { | |||
1036 | log_debug("%s: no cert found", __func__); | |||
1037 | goto done; | |||
1038 | } | |||
1039 | key = ibuf_data(id->id_buf); | |||
1040 | keylen = ibuf_size(id->id_buf); | |||
1041 | keytype = id->id_type; | |||
1042 | break; | |||
1043 | } | |||
1044 | ||||
1045 | log_debug("%s: method %s keylen %zd type %s", __func__, | |||
1046 | print_map(auth->auth_method, ikev2_auth_map), keylen, | |||
1047 | print_map(id->id_type, ikev2_cert_map)); | |||
1048 | ||||
1049 | if (dsa_setkey(dsa, key, keylen, keytype) == NULL((void *)0) || | |||
1050 | dsa_init(dsa, buf, len) != 0 || | |||
1051 | dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { | |||
1052 | log_debug("%s: failed to compute digital signature", __func__); | |||
1053 | goto done; | |||
1054 | } | |||
1055 | ||||
1056 | if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { | |||
1057 | log_debug("%s: authentication successful", __func__); | |||
1058 | sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS6); | |||
1059 | sa_stateflags(sa, IKED_REQ_AUTHVALID0x0010); | |||
1060 | } else { | |||
1061 | log_debug("%s: authentication failed", __func__); | |||
1062 | sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST5); | |||
1063 | } | |||
1064 | ||||
1065 | done: | |||
1066 | free(psk); | |||
1067 | dsa_free(dsa); | |||
1068 | ||||
1069 | return (ret); | |||
1070 | } | |||
1071 | ||||
1072 | int | |||
1073 | ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, | |||
1074 | struct iked_auth *auth, struct ibuf *authmsg) | |||
1075 | { | |||
1076 | uint8_t *key, *psk = NULL((void *)0); | |||
1077 | ssize_t keylen, siglen; | |||
1078 | struct iked_hash *prf = sa->sa_prf; | |||
1079 | struct iked_id *id; | |||
1080 | struct iked_dsa *dsa = NULL((void *)0); | |||
1081 | struct ibuf *buf; | |||
1082 | int ret = -1; | |||
1083 | uint8_t keytype; | |||
1084 | ||||
1085 | if (sa->sa_hdr.sh_initiator) | |||
1086 | id = &sa->sa_icert; | |||
1087 | else | |||
1088 | id = &sa->sa_rcert; | |||
1089 | ||||
1090 | if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL((void *)0)) { | |||
1091 | log_debug("%s: invalid auth method", __func__); | |||
1092 | return (-1); | |||
1093 | } | |||
1094 | ||||
1095 | switch (auth->auth_method) { | |||
1096 | case IKEV2_AUTH_SHARED_KEY_MIC2: | |||
1097 | if (!auth->auth_length) { | |||
1098 | log_debug("%s: no pre-shared key found", __func__); | |||
1099 | goto done; | |||
1100 | } | |||
1101 | if ((keylen = ikev2_psk(sa, auth->auth_data, | |||
1102 | auth->auth_length, &psk)) == -1) { | |||
1103 | log_debug("%s: failed to get PSK", __func__); | |||
1104 | goto done; | |||
1105 | } | |||
1106 | key = psk; | |||
1107 | keytype = 0; | |||
1108 | break; | |||
1109 | default: | |||
1110 | if (id == NULL((void *)0)) { | |||
1111 | log_debug("%s: no cert found", __func__); | |||
1112 | goto done; | |||
1113 | } | |||
1114 | key = ibuf_data(id->id_buf); | |||
1115 | keylen = ibuf_size(id->id_buf); | |||
1116 | keytype = id->id_type; | |||
1117 | break; | |||
1118 | } | |||
1119 | ||||
1120 | if (dsa_setkey(dsa, key, keylen, keytype) == NULL((void *)0) || | |||
1121 | dsa_init(dsa, NULL((void *)0), 0) != 0 || | |||
1122 | dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { | |||
1123 | log_debug("%s: failed to compute digital signature", __func__); | |||
1124 | goto done; | |||
1125 | } | |||
1126 | ||||
1127 | ibuf_free(sa->sa_localauth.id_buf); | |||
1128 | sa->sa_localauth.id_buf = NULL((void *)0); | |||
1129 | ||||
1130 | if ((buf = ibuf_new(NULL((void *)0), dsa_length(dsa))) == NULL((void *)0)) { | |||
1131 | log_debug("%s: failed to get auth buffer", __func__); | |||
1132 | goto done; | |||
1133 | } | |||
1134 | ||||
1135 | if ((siglen = dsa_sign_final(dsa, | |||
1136 | ibuf_data(buf), ibuf_size(buf))) < 0) { | |||
1137 | log_debug("%s: failed to create auth signature", __func__); | |||
1138 | ibuf_free(buf); | |||
1139 | goto done; | |||
1140 | } | |||
1141 | ||||
1142 | if (ibuf_setsize(buf, siglen) < 0) { | |||
1143 | log_debug("%s: failed to set auth signature size to %zd", | |||
1144 | __func__, siglen); | |||
1145 | ibuf_free(buf); | |||
1146 | goto done; | |||
1147 | } | |||
1148 | ||||
1149 | sa->sa_localauth.id_type = auth->auth_method; | |||
1150 | sa->sa_localauth.id_buf = buf; | |||
1151 | ||||
1152 | ret = 0; | |||
1153 | done: | |||
1154 | free(psk); | |||
1155 | dsa_free(dsa); | |||
1156 | ||||
1157 | return (ret); | |||
1158 | } | |||
1159 | ||||
1160 | int | |||
1161 | ikev2_msg_frompeer(struct iked_message *msg) | |||
1162 | { | |||
1163 | struct iked_sa *sa = msg->msg_sa; | |||
1164 | struct ike_header *hdr; | |||
1165 | ||||
1166 | msg = msg->msg_parent; | |||
1167 | ||||
1168 | if (sa == NULL((void *)0) || | |||
1169 | (hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL((void *)0)) | |||
1170 | return (0); | |||
1171 | ||||
1172 | if (!sa->sa_hdr.sh_initiator && | |||
1173 | (hdr->ike_flags & IKEV2_FLAG_INITIATOR0x08)) | |||
1174 | return (1); | |||
1175 | else if (sa->sa_hdr.sh_initiator && | |||
1176 | (hdr->ike_flags & IKEV2_FLAG_INITIATOR0x08) == 0) | |||
1177 | return (1); | |||
1178 | ||||
1179 | return (0); | |||
1180 | } | |||
1181 | ||||
1182 | struct iked_socket * | |||
1183 | ikev2_msg_getsocket(struct iked *env, int af, int natt) | |||
1184 | { | |||
1185 | switch (af) { | |||
1186 | case AF_INET2: | |||
1187 | return (env->sc_sock4[natt ? 1 : 0]); | |||
1188 | case AF_INET624: | |||
1189 | return (env->sc_sock6[natt ? 1 : 0]); | |||
1190 | } | |||
1191 | ||||
1192 | log_debug("%s: af socket %d not available", __func__, af); | |||
1193 | return (NULL((void *)0)); | |||
1194 | } | |||
1195 | ||||
1196 | int | |||
1197 | ikev2_msg_enqueue(struct iked *env, struct iked_msgqueue *queue, | |||
1198 | struct iked_message *msg, int timeout) | |||
1199 | { | |||
1200 | struct iked_msg_retransmit *mr; | |||
1201 | ||||
1202 | if ((mr = ikev2_msg_lookup(env, queue, msg, msg->msg_exchange)) == | |||
1203 | NULL((void *)0)) { | |||
1204 | if ((mr = calloc(1, sizeof(*mr))) == NULL((void *)0)) | |||
1205 | return (-1); | |||
1206 | TAILQ_INIT(&mr->mrt_frags)do { (&mr->mrt_frags)->tqh_first = ((void *)0); (& mr->mrt_frags)->tqh_last = &(&mr->mrt_frags) ->tqh_first; } while (0); | |||
1207 | mr->mrt_tries = 0; | |||
1208 | ||||
1209 | timer_set(env, &mr->mrt_timer, msg->msg_response ? | |||
1210 | ikev2_msg_response_timeout : ikev2_msg_retransmit_timeout, | |||
1211 | mr); | |||
1212 | timer_add(env, &mr->mrt_timer, timeout); | |||
1213 | ||||
1214 | TAILQ_INSERT_TAIL(queue, mr, mrt_entry)do { (mr)->mrt_entry.tqe_next = ((void *)0); (mr)->mrt_entry .tqe_prev = (queue)->tqh_last; *(queue)->tqh_last = (mr ); (queue)->tqh_last = &(mr)->mrt_entry.tqe_next; } while (0); | |||
1215 | } | |||
1216 | ||||
1217 | TAILQ_INSERT_TAIL(&mr->mrt_frags, msg, msg_entry)do { (msg)->msg_entry.tqe_next = ((void *)0); (msg)->msg_entry .tqe_prev = (&mr->mrt_frags)->tqh_last; *(&mr-> mrt_frags)->tqh_last = (msg); (&mr->mrt_frags)-> tqh_last = &(msg)->msg_entry.tqe_next; } while (0); | |||
1218 | ||||
1219 | return 0; | |||
1220 | } | |||
1221 | ||||
1222 | void | |||
1223 | ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue, | |||
1224 | struct iked_message *msg) | |||
1225 | { | |||
1226 | struct iked_msg_retransmit *mr, *mrtmp; | |||
1227 | ||||
1228 | TAILQ_FOREACH_SAFE(mr, queue, mrt_entry, mrtmp)for ((mr) = ((queue)->tqh_first); (mr) != ((void *)0) && ((mrtmp) = ((mr)->mrt_entry.tqe_next), 1); (mr) = (mrtmp) ) { | |||
1229 | if (TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_msgid < msg->msg_msgid) | |||
1230 | ikev2_msg_dispose(env, queue, mr); | |||
1231 | } | |||
1232 | } | |||
1233 | ||||
1234 | void | |||
1235 | ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, | |||
1236 | struct iked_msg_retransmit *mr) | |||
1237 | { | |||
1238 | struct iked_message *m; | |||
1239 | ||||
1240 | while ((m = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)) != NULL((void *)0)) { | |||
1241 | TAILQ_REMOVE(&mr->mrt_frags, m, msg_entry)do { if (((m)->msg_entry.tqe_next) != ((void *)0)) (m)-> msg_entry.tqe_next->msg_entry.tqe_prev = (m)->msg_entry .tqe_prev; else (&mr->mrt_frags)->tqh_last = (m)-> msg_entry.tqe_prev; *(m)->msg_entry.tqe_prev = (m)->msg_entry .tqe_next; ; ; } while (0); | |||
1242 | ikev2_msg_cleanup(env, m); | |||
1243 | free(m); | |||
1244 | } | |||
1245 | ||||
1246 | timer_del(env, &mr->mrt_timer); | |||
1247 | TAILQ_REMOVE(queue, mr, mrt_entry)do { if (((mr)->mrt_entry.tqe_next) != ((void *)0)) (mr)-> mrt_entry.tqe_next->mrt_entry.tqe_prev = (mr)->mrt_entry .tqe_prev; else (queue)->tqh_last = (mr)->mrt_entry.tqe_prev ; *(mr)->mrt_entry.tqe_prev = (mr)->mrt_entry.tqe_next; ; ; } while (0); | |||
1248 | free(mr); | |||
1249 | } | |||
1250 | ||||
1251 | void | |||
1252 | ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue) | |||
1253 | { | |||
1254 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
1255 | ||||
1256 | while ((mr = TAILQ_FIRST(queue)((queue)->tqh_first)) != NULL((void *)0)) | |||
| ||||
1257 | ikev2_msg_dispose(env, queue, mr); | |||
| ||||
1258 | } | |||
1259 | ||||
1260 | struct iked_msg_retransmit * | |||
1261 | ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue, | |||
1262 | struct iked_message *msg, uint8_t exchange) | |||
1263 | { | |||
1264 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
1265 | ||||
1266 | TAILQ_FOREACH(mr, queue, mrt_entry)for((mr) = ((queue)->tqh_first); (mr) != ((void *)0); (mr) = ((mr)->mrt_entry.tqe_next)) { | |||
1267 | if (TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_msgid == | |||
1268 | msg->msg_msgid && | |||
1269 | TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_exchange == exchange) | |||
1270 | break; | |||
1271 | } | |||
1272 | ||||
1273 | return (mr); | |||
1274 | } | |||
1275 | ||||
1276 | int | |||
1277 | ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, | |||
1278 | struct iked_message *msg, uint8_t exchange) | |||
1279 | { | |||
1280 | struct iked_msg_retransmit *mr = NULL((void *)0); | |||
1281 | struct iked_message *m = NULL((void *)0); | |||
1282 | ||||
1283 | if ((mr = ikev2_msg_lookup(env, &sa->sa_responses, msg, exchange)) | |||
1284 | == NULL((void *)0)) | |||
1285 | return (-2); /* not found */ | |||
1286 | ||||
1287 | TAILQ_FOREACH(m, &mr->mrt_frags, msg_entry)for((m) = ((&mr->mrt_frags)->tqh_first); (m) != ((void *)0); (m) = ((m)->msg_entry.tqe_next)) { | |||
1288 | if (sendtofrom(m->msg_fd, ibuf_data(m->msg_data), | |||
1289 | ibuf_size(m->msg_data), 0, | |||
1290 | (struct sockaddr *)&m->msg_peer, m->msg_peerlen, | |||
1291 | (struct sockaddr *)&m->msg_local, m->msg_locallen) == -1) { | |||
1292 | log_warn("%s: sendtofrom", __func__); | |||
1293 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
1294 | return (-1); | |||
1295 | } | |||
1296 | log_info("%sretransmit %s res %u local %s peer %s", | |||
1297 | SPI_SA(sa, NULL)ikev2_ikesa_info((&(sa)->sa_hdr)->sh_ispi, ((((void *)0)))), | |||
1298 | print_map(exchange, ikev2_exchange_map), | |||
1299 | m->msg_msgid, | |||
1300 | print_addr(&m->msg_local), | |||
1301 | print_addr(&m->msg_peer)); | |||
1302 | } | |||
1303 | ||||
1304 | timer_add(env, &mr->mrt_timer, IKED_RESPONSE_TIMEOUT120); | |||
1305 | ikestat_inc(env, ikes_retransmit_response)do { env->sc_stats.ikes_retransmit_response += (1); } while (0); | |||
1306 | return (0); | |||
1307 | } | |||
1308 | ||||
1309 | void | |||
1310 | ikev2_msg_response_timeout(struct iked *env, void *arg) | |||
1311 | { | |||
1312 | struct iked_msg_retransmit *mr = arg; | |||
1313 | struct iked_sa *sa; | |||
1314 | ||||
1315 | sa = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first)->msg_sa; | |||
1316 | ikev2_msg_dispose(env, &sa->sa_responses, mr); | |||
1317 | } | |||
1318 | ||||
1319 | void | |||
1320 | ikev2_msg_retransmit_timeout(struct iked *env, void *arg) | |||
1321 | { | |||
1322 | struct iked_msg_retransmit *mr = arg; | |||
1323 | struct iked_message *msg = TAILQ_FIRST(&mr->mrt_frags)((&mr->mrt_frags)->tqh_first); | |||
1324 | struct iked_sa *sa = msg->msg_sa; | |||
1325 | ||||
1326 | if (mr->mrt_tries < IKED_RETRANSMIT_TRIES5) { | |||
1327 | TAILQ_FOREACH(msg, &mr->mrt_frags, msg_entry)for((msg) = ((&mr->mrt_frags)->tqh_first); (msg) != ((void *)0); (msg) = ((msg)->msg_entry.tqe_next)) { | |||
1328 | if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), | |||
1329 | ibuf_size(msg->msg_data), 0, | |||
1330 | (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, | |||
1331 | (struct sockaddr *)&msg->msg_local, | |||
1332 | msg->msg_locallen) == -1) { | |||
1333 | log_warn("%s: sendtofrom", __func__); | |||
1334 | ikev2_ike_sa_setreason(sa, "retransmit failed"); | |||
1335 | sa_free(env, sa); | |||
1336 | ikestat_inc(env, ikes_msg_send_failures)do { env->sc_stats.ikes_msg_send_failures += (1); } while( 0); | |||
1337 | return; | |||
1338 | } | |||
1339 | log_info("%sretransmit %d %s req %u peer %s " | |||
1340 | "local %s", SPI_SA(sa, NULL)ikev2_ikesa_info((&(sa)->sa_hdr)->sh_ispi, ((((void *)0)))), mr->mrt_tries + 1, | |||
1341 | print_map(msg->msg_exchange, ikev2_exchange_map), | |||
1342 | msg->msg_msgid, | |||
1343 | print_addr(&msg->msg_peer), | |||
1344 | print_addr(&msg->msg_local)); | |||
1345 | } | |||
1346 | /* Exponential timeout */ | |||
1347 | timer_add(env, &mr->mrt_timer, | |||
1348 | IKED_RETRANSMIT_TIMEOUT2 * (2 << (mr->mrt_tries++))); | |||
1349 | ikestat_inc(env, ikes_retransmit_request)do { env->sc_stats.ikes_retransmit_request += (1); } while (0); | |||
1350 | } else { | |||
1351 | log_debug("%s: retransmit limit reached for req %u", | |||
1352 | __func__, msg->msg_msgid); | |||
1353 | ikev2_ike_sa_setreason(sa, "retransmit limit reached"); | |||
1354 | ikestat_inc(env, ikes_retransmit_limit)do { env->sc_stats.ikes_retransmit_limit += (1); } while(0 ); | |||
1355 | sa_free(env, sa); | |||
1356 | } | |||
1357 | } |