1 |
|
|
/* $OpenBSD: ikev2_msg.c,v 1.52 2017/04/26 10:42:38 henning Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/param.h> /* roundup */ |
20 |
|
|
#include <sys/queue.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <sys/wait.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 <unistd.h> |
31 |
|
|
#include <string.h> |
32 |
|
|
#include <signal.h> |
33 |
|
|
#include <errno.h> |
34 |
|
|
#include <err.h> |
35 |
|
|
#include <pwd.h> |
36 |
|
|
#include <event.h> |
37 |
|
|
|
38 |
|
|
#include <openssl/sha.h> |
39 |
|
|
#include <openssl/evp.h> |
40 |
|
|
|
41 |
|
|
#include "iked.h" |
42 |
|
|
#include "ikev2.h" |
43 |
|
|
#include "eap.h" |
44 |
|
|
#include "dh.h" |
45 |
|
|
|
46 |
|
|
void ikev1_recv(struct iked *, struct iked_message *); |
47 |
|
|
void ikev2_msg_response_timeout(struct iked *, void *); |
48 |
|
|
void ikev2_msg_retransmit_timeout(struct iked *, void *); |
49 |
|
|
|
50 |
|
|
void |
51 |
|
|
ikev2_msg_cb(int fd, short event, void *arg) |
52 |
|
|
{ |
53 |
|
|
struct iked_socket *sock = arg; |
54 |
|
|
struct iked *env = sock->sock_env; |
55 |
|
|
struct iked_message msg; |
56 |
|
|
struct ike_header hdr; |
57 |
|
|
uint32_t natt = 0x00000000; |
58 |
|
|
uint8_t buf[IKED_MSGBUF_MAX]; |
59 |
|
|
ssize_t len; |
60 |
|
|
off_t off; |
61 |
|
|
|
62 |
|
|
bzero(&msg, sizeof(msg)); |
63 |
|
|
bzero(buf, sizeof(buf)); |
64 |
|
|
|
65 |
|
|
msg.msg_peerlen = sizeof(msg.msg_peer); |
66 |
|
|
msg.msg_locallen = sizeof(msg.msg_local); |
67 |
|
|
msg.msg_parent = &msg; |
68 |
|
|
memcpy(&msg.msg_local, &sock->sock_addr, sizeof(sock->sock_addr)); |
69 |
|
|
|
70 |
|
|
if ((len = recvfromto(fd, buf, sizeof(buf), 0, |
71 |
|
|
(struct sockaddr *)&msg.msg_peer, &msg.msg_peerlen, |
72 |
|
|
(struct sockaddr *)&msg.msg_local, &msg.msg_locallen)) < |
73 |
|
|
(ssize_t)sizeof(natt)) |
74 |
|
|
return; |
75 |
|
|
|
76 |
|
|
if (socket_getport((struct sockaddr *)&msg.msg_local) == |
77 |
|
|
IKED_NATT_PORT) { |
78 |
|
|
if (memcmp(&natt, buf, sizeof(natt)) != 0) |
79 |
|
|
return; |
80 |
|
|
msg.msg_natt = 1; |
81 |
|
|
off = sizeof(natt); |
82 |
|
|
} else |
83 |
|
|
off = 0; |
84 |
|
|
|
85 |
|
|
if ((size_t)(len - off) <= sizeof(hdr)) |
86 |
|
|
return; |
87 |
|
|
memcpy(&hdr, buf + off, sizeof(hdr)); |
88 |
|
|
|
89 |
|
|
if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL) |
90 |
|
|
return; |
91 |
|
|
|
92 |
|
|
TAILQ_INIT(&msg.msg_proposals); |
93 |
|
|
msg.msg_fd = fd; |
94 |
|
|
|
95 |
|
|
if (hdr.ike_version == IKEV1_VERSION) |
96 |
|
|
ikev1_recv(env, &msg); |
97 |
|
|
else |
98 |
|
|
ikev2_recv(env, &msg); |
99 |
|
|
|
100 |
|
|
ikev2_msg_cleanup(env, &msg); |
101 |
|
|
} |
102 |
|
|
|
103 |
|
|
void |
104 |
|
|
ikev1_recv(struct iked *env, struct iked_message *msg) |
105 |
|
|
{ |
106 |
|
|
struct ike_header *hdr; |
107 |
|
|
|
108 |
|
|
if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { |
109 |
|
|
log_debug("%s: short message", __func__); |
110 |
|
|
return; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
hdr = (struct ike_header *)ibuf_data(msg->msg_data); |
114 |
|
|
|
115 |
|
|
log_debug("%s: header ispi %s rspi %s" |
116 |
|
|
" nextpayload %u version 0x%02x exchange %u flags 0x%02x" |
117 |
|
|
" msgid %u length %u", __func__, |
118 |
|
|
print_spi(betoh64(hdr->ike_ispi), 8), |
119 |
|
|
print_spi(betoh64(hdr->ike_rspi), 8), |
120 |
|
|
hdr->ike_nextpayload, |
121 |
|
|
hdr->ike_version, |
122 |
|
|
hdr->ike_exchange, |
123 |
|
|
hdr->ike_flags, |
124 |
|
|
betoh32(hdr->ike_msgid), |
125 |
|
|
betoh32(hdr->ike_length)); |
126 |
|
|
|
127 |
|
|
log_debug("%s: IKEv1 not supported", __func__); |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
struct ibuf * |
131 |
|
|
ikev2_msg_init(struct iked *env, struct iked_message *msg, |
132 |
|
|
struct sockaddr_storage *peer, socklen_t peerlen, |
133 |
|
|
struct sockaddr_storage *local, socklen_t locallen, int response) |
134 |
|
|
{ |
135 |
|
|
bzero(msg, sizeof(*msg)); |
136 |
|
|
memcpy(&msg->msg_peer, peer, peerlen); |
137 |
|
|
msg->msg_peerlen = peerlen; |
138 |
|
|
memcpy(&msg->msg_local, local, locallen); |
139 |
|
|
msg->msg_locallen = locallen; |
140 |
|
|
msg->msg_response = response ? 1 : 0; |
141 |
|
|
msg->msg_fd = -1; |
142 |
|
|
msg->msg_data = ibuf_static(); |
143 |
|
|
msg->msg_e = 0; |
144 |
|
|
msg->msg_parent = msg; /* has to be set */ |
145 |
|
|
TAILQ_INIT(&msg->msg_proposals); |
146 |
|
|
|
147 |
|
|
return (msg->msg_data); |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
struct iked_message * |
151 |
|
|
ikev2_msg_copy(struct iked *env, struct iked_message *msg) |
152 |
|
|
{ |
153 |
|
|
struct iked_message *m = NULL; |
154 |
|
|
struct ibuf *buf; |
155 |
|
|
size_t len; |
156 |
|
|
void *ptr; |
157 |
|
|
|
158 |
|
|
if (ibuf_size(msg->msg_data) < msg->msg_offset) |
159 |
|
|
return (NULL); |
160 |
|
|
len = ibuf_size(msg->msg_data) - msg->msg_offset; |
161 |
|
|
|
162 |
|
|
if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || |
163 |
|
|
(m = malloc(sizeof(*m))) == NULL || |
164 |
|
|
(buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, |
165 |
|
|
&msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || |
166 |
|
|
ibuf_add(buf, ptr, len)) |
167 |
|
|
return (NULL); |
168 |
|
|
|
169 |
|
|
m->msg_fd = msg->msg_fd; |
170 |
|
|
m->msg_msgid = msg->msg_msgid; |
171 |
|
|
m->msg_offset = msg->msg_offset; |
172 |
|
|
m->msg_sa = msg->msg_sa; |
173 |
|
|
|
174 |
|
|
return (m); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
void |
178 |
|
|
ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) |
179 |
|
|
{ |
180 |
|
|
if (msg == msg->msg_parent) { |
181 |
|
|
ibuf_release(msg->msg_nonce); |
182 |
|
|
ibuf_release(msg->msg_ke); |
183 |
|
|
ibuf_release(msg->msg_auth.id_buf); |
184 |
|
|
ibuf_release(msg->msg_id.id_buf); |
185 |
|
|
ibuf_release(msg->msg_cert.id_buf); |
186 |
|
|
ibuf_release(msg->msg_cookie); |
187 |
|
|
|
188 |
|
|
msg->msg_nonce = NULL; |
189 |
|
|
msg->msg_ke = NULL; |
190 |
|
|
msg->msg_auth.id_buf = NULL; |
191 |
|
|
msg->msg_id.id_buf = NULL; |
192 |
|
|
msg->msg_cert.id_buf = NULL; |
193 |
|
|
msg->msg_cookie = NULL; |
194 |
|
|
|
195 |
|
|
config_free_proposals(&msg->msg_proposals, 0); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
if (msg->msg_data != NULL) { |
199 |
|
|
ibuf_release(msg->msg_data); |
200 |
|
|
msg->msg_data = NULL; |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
int |
205 |
|
|
ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, |
206 |
|
|
struct iked_message *msg) |
207 |
|
|
{ |
208 |
|
|
#if 0 |
209 |
|
|
/* XXX Disabled, see comment below */ |
210 |
|
|
struct iked_message resp; |
211 |
|
|
struct ike_header *hdr; |
212 |
|
|
struct ikev2_payload *pld; |
213 |
|
|
struct ikev2_notify *n; |
214 |
|
|
struct ibuf *buf; |
215 |
|
|
struct iked_sa sa; |
216 |
|
|
#endif |
217 |
|
|
|
218 |
|
|
if (msg->msg_sa != NULL && msg->msg_policy != NULL) { |
219 |
|
|
if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSED) |
220 |
|
|
return (-1); |
221 |
|
|
/* |
222 |
|
|
* Only permit informational requests from initiator |
223 |
|
|
* on closing SAs (for DELETE). |
224 |
|
|
*/ |
225 |
|
|
if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) { |
226 |
|
|
if (((oldhdr->ike_flags & |
227 |
|
|
(IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) == |
228 |
|
|
IKEV2_FLAG_INITIATOR) && |
229 |
|
|
(oldhdr->ike_exchange == |
230 |
|
|
IKEV2_EXCHANGE_INFORMATIONAL)) |
231 |
|
|
return (0); |
232 |
|
|
return (-1); |
233 |
|
|
} |
234 |
|
|
return (0); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
#if 0 |
238 |
|
|
/* |
239 |
|
|
* XXX Sending INVALID_IKE_SPIs notifications is disabled |
240 |
|
|
* XXX because it is not mandatory and ignored by most |
241 |
|
|
* XXX implementations. We might want to enable it in |
242 |
|
|
* XXX combination with a rate-limitation to avoid DoS situations. |
243 |
|
|
*/ |
244 |
|
|
|
245 |
|
|
/* Fail without error message */ |
246 |
|
|
if (msg->msg_response || msg->msg_policy == NULL) |
247 |
|
|
return (-1); |
248 |
|
|
|
249 |
|
|
/* Invalid IKE SA, return notification */ |
250 |
|
|
if ((buf = ikev2_msg_init(env, &resp, |
251 |
|
|
&msg->msg_peer, msg->msg_peerlen, |
252 |
|
|
&msg->msg_local, msg->msg_locallen, 1)) == NULL) |
253 |
|
|
goto done; |
254 |
|
|
|
255 |
|
|
resp.msg_fd = msg->msg_fd; |
256 |
|
|
|
257 |
|
|
bzero(&sa, sizeof(sa)); |
258 |
|
|
if ((oldhdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0) |
259 |
|
|
sa.sa_hdr.sh_initiator = 1; |
260 |
|
|
sa.sa_hdr.sh_ispi = betoh64(oldhdr->ike_ispi); |
261 |
|
|
sa.sa_hdr.sh_rspi = betoh64(oldhdr->ike_rspi); |
262 |
|
|
|
263 |
|
|
resp.msg_msgid = betoh32(oldhdr->ike_msgid); |
264 |
|
|
|
265 |
|
|
/* IKE header */ |
266 |
|
|
if ((hdr = ikev2_add_header(buf, &sa, resp.msg_msgid, |
267 |
|
|
IKEV2_PAYLOAD_NOTIFY, IKEV2_EXCHANGE_INFORMATIONAL, |
268 |
|
|
IKEV2_FLAG_RESPONSE)) == NULL) |
269 |
|
|
goto done; |
270 |
|
|
|
271 |
|
|
/* SA payload */ |
272 |
|
|
if ((pld = ikev2_add_payload(buf)) == NULL) |
273 |
|
|
goto done; |
274 |
|
|
if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) |
275 |
|
|
goto done; |
276 |
|
|
n->n_protoid = IKEV2_SAPROTO_IKE; |
277 |
|
|
n->n_spisize = 0; |
278 |
|
|
n->n_type = htobe16(IKEV2_N_INVALID_IKE_SPI); |
279 |
|
|
|
280 |
|
|
if (ikev2_next_payload(pld, sizeof(*n), IKEV2_PAYLOAD_NONE) == -1) |
281 |
|
|
goto done; |
282 |
|
|
|
283 |
|
|
if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1) |
284 |
|
|
goto done; |
285 |
|
|
|
286 |
|
|
(void)ikev2_pld_parse(env, hdr, &resp, 0); |
287 |
|
|
(void)ikev2_msg_send(env, &resp); |
288 |
|
|
|
289 |
|
|
done: |
290 |
|
|
ikev2_msg_cleanup(env, &resp); |
291 |
|
|
#endif |
292 |
|
|
|
293 |
|
|
/* Always fail */ |
294 |
|
|
return (-1); |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
int |
298 |
|
|
ikev2_msg_send(struct iked *env, struct iked_message *msg) |
299 |
|
|
{ |
300 |
|
|
struct iked_sa *sa = msg->msg_sa; |
301 |
|
|
struct ibuf *buf = msg->msg_data; |
302 |
|
|
uint32_t natt = 0x00000000; |
303 |
|
|
int isnatt = 0; |
304 |
|
|
uint8_t exchange, flags; |
305 |
|
|
struct ike_header *hdr; |
306 |
|
|
struct iked_message *m; |
307 |
|
|
|
308 |
|
|
if (buf == NULL || (hdr = ibuf_seek(msg->msg_data, |
309 |
|
|
msg->msg_offset, sizeof(*hdr))) == NULL) |
310 |
|
|
return (-1); |
311 |
|
|
|
312 |
|
|
isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); |
313 |
|
|
|
314 |
|
|
exchange = hdr->ike_exchange; |
315 |
|
|
flags = hdr->ike_flags; |
316 |
|
|
log_info("%s: %s %s from %s to %s msgid %u, %ld bytes%s", __func__, |
317 |
|
|
print_map(exchange, ikev2_exchange_map), |
318 |
|
|
(flags & IKEV2_FLAG_RESPONSE) ? "response" : "request", |
319 |
|
|
print_host((struct sockaddr *)&msg->msg_local, NULL, 0), |
320 |
|
|
print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), |
321 |
|
|
betoh32(hdr->ike_msgid), |
322 |
|
|
ibuf_length(buf), isnatt ? ", NAT-T" : ""); |
323 |
|
|
|
324 |
|
|
if (isnatt) { |
325 |
|
|
if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { |
326 |
|
|
log_debug("%s: failed to set NAT-T", __func__); |
327 |
|
|
return (-1); |
328 |
|
|
} |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
if (sendtofrom(msg->msg_fd, ibuf_data(buf), ibuf_size(buf), 0, |
332 |
|
|
(struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, |
333 |
|
|
(struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { |
334 |
|
|
if (errno == EADDRNOTAVAIL) { |
335 |
|
|
sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSING); |
336 |
|
|
timer_del(env, &msg->msg_sa->sa_timer); |
337 |
|
|
timer_set(env, &msg->msg_sa->sa_timer, |
338 |
|
|
ikev2_ike_sa_timeout, msg->msg_sa); |
339 |
|
|
timer_add(env, &msg->msg_sa->sa_timer, |
340 |
|
|
IKED_IKE_SA_DELETE_TIMEOUT); |
341 |
|
|
} |
342 |
|
|
log_warn("%s: sendtofrom", __func__); |
343 |
|
|
return (-1); |
344 |
|
|
} |
345 |
|
|
|
346 |
|
|
if (!sa) |
347 |
|
|
return (0); |
348 |
|
|
|
349 |
|
|
if ((m = ikev2_msg_copy(env, msg)) == NULL) { |
350 |
|
|
log_debug("%s: failed to copy a message", __func__); |
351 |
|
|
return (-1); |
352 |
|
|
} |
353 |
|
|
m->msg_exchange = exchange; |
354 |
|
|
|
355 |
|
|
if (flags & IKEV2_FLAG_RESPONSE) { |
356 |
|
|
TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); |
357 |
|
|
timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m); |
358 |
|
|
timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); |
359 |
|
|
} else { |
360 |
|
|
TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); |
361 |
|
|
timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); |
362 |
|
|
timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
return (0); |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
uint32_t |
369 |
|
|
ikev2_msg_id(struct iked *env, struct iked_sa *sa) |
370 |
|
|
{ |
371 |
|
|
uint32_t id = sa->sa_reqid; |
372 |
|
|
|
373 |
|
|
if (++sa->sa_reqid == UINT32_MAX) { |
374 |
|
|
/* XXX we should close and renegotiate the connection now */ |
375 |
|
|
log_debug("%s: IKEv2 message sequence overflow", __func__); |
376 |
|
|
} |
377 |
|
|
return (id); |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
struct ibuf * |
381 |
|
|
ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) |
382 |
|
|
{ |
383 |
|
|
size_t len, ivlen, encrlen, integrlen, blocklen, |
384 |
|
|
outlen; |
385 |
|
|
uint8_t *buf, pad = 0, *ptr; |
386 |
|
|
struct ibuf *encr, *dst = NULL, *out = NULL; |
387 |
|
|
|
388 |
|
|
buf = ibuf_data(src); |
389 |
|
|
len = ibuf_size(src); |
390 |
|
|
|
391 |
|
|
log_debug("%s: decrypted length %zu", __func__, len); |
392 |
|
|
print_hex(buf, 0, len); |
393 |
|
|
|
394 |
|
|
if (sa == NULL || |
395 |
|
|
sa->sa_encr == NULL || |
396 |
|
|
sa->sa_integr == NULL) { |
397 |
|
|
log_debug("%s: invalid SA", __func__); |
398 |
|
|
goto done; |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
if (sa->sa_hdr.sh_initiator) |
402 |
|
|
encr = sa->sa_key_iencr; |
403 |
|
|
else |
404 |
|
|
encr = sa->sa_key_rencr; |
405 |
|
|
|
406 |
|
|
blocklen = cipher_length(sa->sa_encr); |
407 |
|
|
ivlen = cipher_ivlength(sa->sa_encr); |
408 |
|
|
integrlen = hash_length(sa->sa_integr); |
409 |
|
|
encrlen = roundup(len + sizeof(pad), blocklen); |
410 |
|
|
pad = encrlen - (len + sizeof(pad)); |
411 |
|
|
|
412 |
|
|
/* |
413 |
|
|
* Pad the payload and encrypt it |
414 |
|
|
*/ |
415 |
|
|
if (pad) { |
416 |
|
|
if ((ptr = ibuf_advance(src, pad)) == NULL) |
417 |
|
|
goto done; |
418 |
|
|
arc4random_buf(ptr, pad); |
419 |
|
|
} |
420 |
|
|
if (ibuf_add(src, &pad, sizeof(pad)) != 0) |
421 |
|
|
goto done; |
422 |
|
|
|
423 |
|
|
log_debug("%s: padded length %zu", __func__, ibuf_size(src)); |
424 |
|
|
print_hex(ibuf_data(src), 0, ibuf_size(src)); |
425 |
|
|
|
426 |
|
|
cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); |
427 |
|
|
cipher_setiv(sa->sa_encr, NULL, 0); /* XXX ivlen */ |
428 |
|
|
cipher_init_encrypt(sa->sa_encr); |
429 |
|
|
|
430 |
|
|
if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL) |
431 |
|
|
goto done; |
432 |
|
|
|
433 |
|
|
if ((out = ibuf_new(NULL, |
434 |
|
|
cipher_outlength(sa->sa_encr, encrlen))) == NULL) |
435 |
|
|
goto done; |
436 |
|
|
|
437 |
|
|
outlen = ibuf_size(out); |
438 |
|
|
cipher_update(sa->sa_encr, |
439 |
|
|
ibuf_data(src), encrlen, ibuf_data(out), &outlen); |
440 |
|
|
|
441 |
|
|
if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0) |
442 |
|
|
goto done; |
443 |
|
|
|
444 |
|
|
if ((ptr = ibuf_advance(dst, integrlen)) == NULL) |
445 |
|
|
goto done; |
446 |
|
|
explicit_bzero(ptr, integrlen); |
447 |
|
|
|
448 |
|
|
log_debug("%s: length %zu, padding %d, output length %zu", |
449 |
|
|
__func__, len + sizeof(pad), pad, ibuf_size(dst)); |
450 |
|
|
print_hex(ibuf_data(dst), 0, ibuf_size(dst)); |
451 |
|
|
|
452 |
|
|
ibuf_release(src); |
453 |
|
|
ibuf_release(out); |
454 |
|
|
return (dst); |
455 |
|
|
done: |
456 |
|
|
ibuf_release(src); |
457 |
|
|
ibuf_release(out); |
458 |
|
|
ibuf_release(dst); |
459 |
|
|
return (NULL); |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
int |
463 |
|
|
ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) |
464 |
|
|
{ |
465 |
|
|
int ret = -1; |
466 |
|
|
size_t integrlen, tmplen; |
467 |
|
|
struct ibuf *integr, *tmp = NULL; |
468 |
|
|
uint8_t *ptr; |
469 |
|
|
|
470 |
|
|
log_debug("%s: message length %zu", __func__, ibuf_size(src)); |
471 |
|
|
print_hex(ibuf_data(src), 0, ibuf_size(src)); |
472 |
|
|
|
473 |
|
|
if (sa == NULL || |
474 |
|
|
sa->sa_integr == NULL) { |
475 |
|
|
log_debug("%s: invalid SA", __func__); |
476 |
|
|
return (-1); |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
if (sa->sa_hdr.sh_initiator) |
480 |
|
|
integr = sa->sa_key_iauth; |
481 |
|
|
else |
482 |
|
|
integr = sa->sa_key_rauth; |
483 |
|
|
|
484 |
|
|
integrlen = hash_length(sa->sa_integr); |
485 |
|
|
|
486 |
|
|
log_debug("%s: integrity checksum length %zu", __func__, |
487 |
|
|
integrlen); |
488 |
|
|
|
489 |
|
|
/* |
490 |
|
|
* Validate packet checksum |
491 |
|
|
*/ |
492 |
|
|
if ((tmp = ibuf_new(NULL, hash_keylength(sa->sa_integr))) == NULL) |
493 |
|
|
goto done; |
494 |
|
|
|
495 |
|
|
hash_setkey(sa->sa_integr, ibuf_data(integr), ibuf_size(integr)); |
496 |
|
|
hash_init(sa->sa_integr); |
497 |
|
|
hash_update(sa->sa_integr, ibuf_data(src), |
498 |
|
|
ibuf_size(src) - integrlen); |
499 |
|
|
hash_final(sa->sa_integr, ibuf_data(tmp), &tmplen); |
500 |
|
|
|
501 |
|
|
if (tmplen != integrlen) { |
502 |
|
|
log_debug("%s: hash failure", __func__); |
503 |
|
|
goto done; |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
if ((ptr = ibuf_seek(src, |
507 |
|
|
ibuf_size(src) - integrlen, integrlen)) == NULL) |
508 |
|
|
goto done; |
509 |
|
|
memcpy(ptr, ibuf_data(tmp), tmplen); |
510 |
|
|
|
511 |
|
|
print_hex(ibuf_data(tmp), 0, ibuf_size(tmp)); |
512 |
|
|
|
513 |
|
|
ret = 0; |
514 |
|
|
done: |
515 |
|
|
ibuf_release(tmp); |
516 |
|
|
|
517 |
|
|
return (ret); |
518 |
|
|
} |
519 |
|
|
|
520 |
|
|
struct ibuf * |
521 |
|
|
ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, |
522 |
|
|
struct ibuf *msg, struct ibuf *src) |
523 |
|
|
{ |
524 |
|
|
ssize_t ivlen, encrlen, integrlen, blocklen, |
525 |
|
|
outlen, tmplen; |
526 |
|
|
uint8_t pad = 0, *ptr; |
527 |
|
|
struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; |
528 |
|
|
off_t ivoff, encroff, integroff; |
529 |
|
|
|
530 |
|
|
if (sa == NULL || |
531 |
|
|
sa->sa_encr == NULL || |
532 |
|
|
sa->sa_integr == NULL) { |
533 |
|
|
log_debug("%s: invalid SA", __func__); |
534 |
|
|
print_hex(ibuf_data(src), 0, ibuf_size(src)); |
535 |
|
|
goto done; |
536 |
|
|
} |
537 |
|
|
|
538 |
|
|
if (!sa->sa_hdr.sh_initiator) { |
539 |
|
|
encr = sa->sa_key_iencr; |
540 |
|
|
integr = sa->sa_key_iauth; |
541 |
|
|
} else { |
542 |
|
|
encr = sa->sa_key_rencr; |
543 |
|
|
integr = sa->sa_key_rauth; |
544 |
|
|
} |
545 |
|
|
|
546 |
|
|
blocklen = cipher_length(sa->sa_encr); |
547 |
|
|
ivlen = cipher_ivlength(sa->sa_encr); |
548 |
|
|
ivoff = 0; |
549 |
|
|
integrlen = hash_length(sa->sa_integr); |
550 |
|
|
integroff = ibuf_size(src) - integrlen; |
551 |
|
|
encroff = ivlen; |
552 |
|
|
encrlen = ibuf_size(src) - integrlen - ivlen; |
553 |
|
|
|
554 |
|
|
if (encrlen < 0 || integroff < 0) { |
555 |
|
|
log_debug("%s: invalid integrity value", __func__); |
556 |
|
|
goto done; |
557 |
|
|
} |
558 |
|
|
|
559 |
|
|
log_debug("%s: IV length %zd", __func__, ivlen); |
560 |
|
|
print_hex(ibuf_data(src), 0, ivlen); |
561 |
|
|
log_debug("%s: encrypted payload length %zd", __func__, encrlen); |
562 |
|
|
print_hex(ibuf_data(src), encroff, encrlen); |
563 |
|
|
log_debug("%s: integrity checksum length %zd", __func__, integrlen); |
564 |
|
|
print_hex(ibuf_data(src), integroff, integrlen); |
565 |
|
|
|
566 |
|
|
/* |
567 |
|
|
* Validate packet checksum |
568 |
|
|
*/ |
569 |
|
|
if ((tmp = ibuf_new(NULL, ibuf_length(integr))) == NULL) |
570 |
|
|
goto done; |
571 |
|
|
|
572 |
|
|
hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr)); |
573 |
|
|
hash_init(sa->sa_integr); |
574 |
|
|
hash_update(sa->sa_integr, ibuf_data(msg), |
575 |
|
|
ibuf_size(msg) - integrlen); |
576 |
|
|
hash_final(sa->sa_integr, tmp->buf, &tmplen); |
577 |
|
|
|
578 |
|
|
if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) { |
579 |
|
|
log_debug("%s: integrity check failed", __func__); |
580 |
|
|
goto done; |
581 |
|
|
} |
582 |
|
|
|
583 |
|
|
log_debug("%s: integrity check succeeded", __func__); |
584 |
|
|
print_hex(tmp->buf, 0, tmplen); |
585 |
|
|
|
586 |
|
|
ibuf_release(tmp); |
587 |
|
|
tmp = NULL; |
588 |
|
|
|
589 |
|
|
/* |
590 |
|
|
* Decrypt the payload and strip any padding |
591 |
|
|
*/ |
592 |
|
|
if ((encrlen % blocklen) != 0) { |
593 |
|
|
log_debug("%s: unaligned encrypted payload", __func__); |
594 |
|
|
goto done; |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); |
598 |
|
|
cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen); |
599 |
|
|
cipher_init_decrypt(sa->sa_encr); |
600 |
|
|
|
601 |
|
|
if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr, |
602 |
|
|
encrlen))) == NULL) |
603 |
|
|
goto done; |
604 |
|
|
|
605 |
|
|
if ((outlen = ibuf_length(out)) != 0) { |
606 |
|
|
cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen, |
607 |
|
|
ibuf_data(out), &outlen); |
608 |
|
|
|
609 |
|
|
ptr = ibuf_seek(out, outlen - 1, 1); |
610 |
|
|
pad = *ptr; |
611 |
|
|
} |
612 |
|
|
|
613 |
|
|
log_debug("%s: decrypted payload length %zd/%zd padding %d", |
614 |
|
|
__func__, outlen, encrlen, pad); |
615 |
|
|
print_hex(ibuf_data(out), 0, ibuf_size(out)); |
616 |
|
|
|
617 |
|
|
if (ibuf_setsize(out, outlen) != 0) |
618 |
|
|
goto done; |
619 |
|
|
|
620 |
|
|
ibuf_release(src); |
621 |
|
|
return (out); |
622 |
|
|
done: |
623 |
|
|
ibuf_release(tmp); |
624 |
|
|
ibuf_release(out); |
625 |
|
|
ibuf_release(src); |
626 |
|
|
return (NULL); |
627 |
|
|
} |
628 |
|
|
|
629 |
|
|
int |
630 |
|
|
ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, |
631 |
|
|
uint8_t exchange, uint8_t firstpayload, int response) |
632 |
|
|
{ |
633 |
|
|
struct iked_message resp; |
634 |
|
|
struct ike_header *hdr; |
635 |
|
|
struct ikev2_payload *pld; |
636 |
|
|
struct ibuf *buf, *e = *ep; |
637 |
|
|
int ret = -1; |
638 |
|
|
|
639 |
|
|
if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, |
640 |
|
|
sa->sa_peer.addr.ss_len, &sa->sa_local.addr, |
641 |
|
|
sa->sa_local.addr.ss_len, response)) == NULL) |
642 |
|
|
goto done; |
643 |
|
|
|
644 |
|
|
resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); |
645 |
|
|
|
646 |
|
|
/* IKE header */ |
647 |
|
|
if ((hdr = ikev2_add_header(buf, sa, resp.msg_msgid, IKEV2_PAYLOAD_SK, |
648 |
|
|
exchange, response ? IKEV2_FLAG_RESPONSE : 0)) == NULL) |
649 |
|
|
goto done; |
650 |
|
|
|
651 |
|
|
if ((pld = ikev2_add_payload(buf)) == NULL) |
652 |
|
|
goto done; |
653 |
|
|
|
654 |
|
|
/* Encrypt message and add as an E payload */ |
655 |
|
|
if ((e = ikev2_msg_encrypt(env, sa, e)) == NULL) { |
656 |
|
|
log_debug("%s: encryption failed", __func__); |
657 |
|
|
goto done; |
658 |
|
|
} |
659 |
|
|
if (ibuf_cat(buf, e) != 0) |
660 |
|
|
goto done; |
661 |
|
|
if (ikev2_next_payload(pld, ibuf_size(e), firstpayload) == -1) |
662 |
|
|
goto done; |
663 |
|
|
|
664 |
|
|
if (ikev2_set_header(hdr, ibuf_size(buf) - sizeof(*hdr)) == -1) |
665 |
|
|
goto done; |
666 |
|
|
|
667 |
|
|
/* Add integrity checksum (HMAC) */ |
668 |
|
|
if (ikev2_msg_integr(env, sa, buf) != 0) { |
669 |
|
|
log_debug("%s: integrity checksum failed", __func__); |
670 |
|
|
goto done; |
671 |
|
|
} |
672 |
|
|
|
673 |
|
|
resp.msg_data = buf; |
674 |
|
|
resp.msg_sa = sa; |
675 |
|
|
resp.msg_fd = sa->sa_fd; |
676 |
|
|
TAILQ_INIT(&resp.msg_proposals); |
677 |
|
|
|
678 |
|
|
(void)ikev2_pld_parse(env, hdr, &resp, 0); |
679 |
|
|
|
680 |
|
|
ret = ikev2_msg_send(env, &resp); |
681 |
|
|
|
682 |
|
|
done: |
683 |
|
|
/* e is cleaned up by the calling function */ |
684 |
|
|
*ep = e; |
685 |
|
|
ikev2_msg_cleanup(env, &resp); |
686 |
|
|
|
687 |
|
|
return (ret); |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
struct ibuf * |
691 |
|
|
ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) |
692 |
|
|
{ |
693 |
|
|
struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; |
694 |
|
|
uint8_t *ptr; |
695 |
|
|
struct iked_id *id; |
696 |
|
|
size_t tmplen; |
697 |
|
|
|
698 |
|
|
/* |
699 |
|
|
* Create the payload to be signed/MAC'ed for AUTH |
700 |
|
|
*/ |
701 |
|
|
|
702 |
|
|
if (!response) { |
703 |
|
|
if ((nonce = sa->sa_rnonce) == NULL || |
704 |
|
|
(sa->sa_iid.id_type == 0) || |
705 |
|
|
(prfkey = sa->sa_key_iprf) == NULL || |
706 |
|
|
(buf = sa->sa_1stmsg) == NULL) |
707 |
|
|
return (NULL); |
708 |
|
|
id = &sa->sa_iid; |
709 |
|
|
} else { |
710 |
|
|
if ((nonce = sa->sa_inonce) == NULL || |
711 |
|
|
(sa->sa_rid.id_type == 0) || |
712 |
|
|
(prfkey = sa->sa_key_rprf) == NULL || |
713 |
|
|
(buf = sa->sa_2ndmsg) == NULL) |
714 |
|
|
return (NULL); |
715 |
|
|
id = &sa->sa_rid; |
716 |
|
|
} |
717 |
|
|
|
718 |
|
|
if ((authmsg = ibuf_dup(buf)) == NULL) |
719 |
|
|
return (NULL); |
720 |
|
|
if (ibuf_cat(authmsg, nonce) != 0) |
721 |
|
|
goto fail; |
722 |
|
|
|
723 |
|
|
if ((hash_setkey(sa->sa_prf, ibuf_data(prfkey), |
724 |
|
|
ibuf_size(prfkey))) == NULL) |
725 |
|
|
goto fail; |
726 |
|
|
|
727 |
|
|
if ((ptr = ibuf_advance(authmsg, |
728 |
|
|
hash_length(sa->sa_prf))) == NULL) |
729 |
|
|
goto fail; |
730 |
|
|
|
731 |
|
|
hash_init(sa->sa_prf); |
732 |
|
|
hash_update(sa->sa_prf, ibuf_data(id->id_buf), ibuf_size(id->id_buf)); |
733 |
|
|
hash_final(sa->sa_prf, ptr, &tmplen); |
734 |
|
|
|
735 |
|
|
if (tmplen != hash_length(sa->sa_prf)) |
736 |
|
|
goto fail; |
737 |
|
|
|
738 |
|
|
log_debug("%s: %s auth data length %zu", |
739 |
|
|
__func__, response ? "responder" : "initiator", |
740 |
|
|
ibuf_size(authmsg)); |
741 |
|
|
print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); |
742 |
|
|
|
743 |
|
|
return (authmsg); |
744 |
|
|
|
745 |
|
|
fail: |
746 |
|
|
ibuf_release(authmsg); |
747 |
|
|
return (NULL); |
748 |
|
|
} |
749 |
|
|
|
750 |
|
|
int |
751 |
|
|
ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, |
752 |
|
|
struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) |
753 |
|
|
{ |
754 |
|
|
uint8_t *key, *psk = NULL; |
755 |
|
|
ssize_t keylen; |
756 |
|
|
struct iked_id *id; |
757 |
|
|
struct iked_dsa *dsa = NULL; |
758 |
|
|
int ret = -1; |
759 |
|
|
uint8_t keytype; |
760 |
|
|
|
761 |
|
|
if (sa->sa_hdr.sh_initiator) |
762 |
|
|
id = &sa->sa_rcert; |
763 |
|
|
else |
764 |
|
|
id = &sa->sa_icert; |
765 |
|
|
|
766 |
|
|
if ((dsa = dsa_verify_new(auth->auth_method, sa->sa_prf)) == NULL) { |
767 |
|
|
log_debug("%s: invalid auth method", __func__); |
768 |
|
|
return (-1); |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
switch (auth->auth_method) { |
772 |
|
|
case IKEV2_AUTH_SHARED_KEY_MIC: |
773 |
|
|
if (!auth->auth_length) { |
774 |
|
|
log_debug("%s: no pre-shared key found", __func__); |
775 |
|
|
goto done; |
776 |
|
|
} |
777 |
|
|
if ((keylen = ikev2_psk(sa, auth->auth_data, |
778 |
|
|
auth->auth_length, &psk)) == -1) { |
779 |
|
|
log_debug("%s: failed to get PSK", __func__); |
780 |
|
|
goto done; |
781 |
|
|
} |
782 |
|
|
key = psk; |
783 |
|
|
keytype = 0; |
784 |
|
|
break; |
785 |
|
|
default: |
786 |
|
|
if (!id->id_type || !ibuf_length(id->id_buf)) { |
787 |
|
|
log_debug("%s: no cert found", __func__); |
788 |
|
|
goto done; |
789 |
|
|
} |
790 |
|
|
key = ibuf_data(id->id_buf); |
791 |
|
|
keylen = ibuf_size(id->id_buf); |
792 |
|
|
keytype = id->id_type; |
793 |
|
|
break; |
794 |
|
|
} |
795 |
|
|
|
796 |
|
|
log_debug("%s: method %s keylen %zd type %s", __func__, |
797 |
|
|
print_map(auth->auth_method, ikev2_auth_map), keylen, |
798 |
|
|
print_map(id->id_type, ikev2_cert_map)); |
799 |
|
|
|
800 |
|
|
if (dsa_setkey(dsa, key, keylen, keytype) == NULL || |
801 |
|
|
dsa_init(dsa, buf, len) != 0 || |
802 |
|
|
dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { |
803 |
|
|
log_debug("%s: failed to compute digital signature", __func__); |
804 |
|
|
goto done; |
805 |
|
|
} |
806 |
|
|
|
807 |
|
|
if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { |
808 |
|
|
log_debug("%s: authentication successful", __func__); |
809 |
|
|
sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); |
810 |
|
|
sa_stateflags(sa, IKED_REQ_AUTHVALID); |
811 |
|
|
} else { |
812 |
|
|
log_debug("%s: authentication failed", __func__); |
813 |
|
|
sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); |
814 |
|
|
} |
815 |
|
|
|
816 |
|
|
done: |
817 |
|
|
free(psk); |
818 |
|
|
dsa_free(dsa); |
819 |
|
|
|
820 |
|
|
return (ret); |
821 |
|
|
} |
822 |
|
|
|
823 |
|
|
int |
824 |
|
|
ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, |
825 |
|
|
struct iked_auth *auth, struct ibuf *authmsg) |
826 |
|
|
{ |
827 |
|
|
uint8_t *key, *psk = NULL; |
828 |
|
|
ssize_t keylen, siglen; |
829 |
|
|
struct iked_hash *prf = sa->sa_prf; |
830 |
|
|
struct iked_id *id; |
831 |
|
|
struct iked_dsa *dsa = NULL; |
832 |
|
|
struct ibuf *buf; |
833 |
|
|
int ret = -1; |
834 |
|
|
uint8_t keytype; |
835 |
|
|
|
836 |
|
|
if (sa->sa_hdr.sh_initiator) |
837 |
|
|
id = &sa->sa_icert; |
838 |
|
|
else |
839 |
|
|
id = &sa->sa_rcert; |
840 |
|
|
|
841 |
|
|
if ((dsa = dsa_sign_new(auth->auth_method, prf)) == NULL) { |
842 |
|
|
log_debug("%s: invalid auth method", __func__); |
843 |
|
|
return (-1); |
844 |
|
|
} |
845 |
|
|
|
846 |
|
|
switch (auth->auth_method) { |
847 |
|
|
case IKEV2_AUTH_SHARED_KEY_MIC: |
848 |
|
|
if (!auth->auth_length) { |
849 |
|
|
log_debug("%s: no pre-shared key found", __func__); |
850 |
|
|
goto done; |
851 |
|
|
} |
852 |
|
|
if ((keylen = ikev2_psk(sa, auth->auth_data, |
853 |
|
|
auth->auth_length, &psk)) == -1) { |
854 |
|
|
log_debug("%s: failed to get PSK", __func__); |
855 |
|
|
goto done; |
856 |
|
|
} |
857 |
|
|
key = psk; |
858 |
|
|
keytype = 0; |
859 |
|
|
break; |
860 |
|
|
default: |
861 |
|
|
if (id == NULL) { |
862 |
|
|
log_debug("%s: no cert found", __func__); |
863 |
|
|
goto done; |
864 |
|
|
} |
865 |
|
|
key = ibuf_data(id->id_buf); |
866 |
|
|
keylen = ibuf_size(id->id_buf); |
867 |
|
|
keytype = id->id_type; |
868 |
|
|
break; |
869 |
|
|
} |
870 |
|
|
|
871 |
|
|
if (dsa_setkey(dsa, key, keylen, keytype) == NULL || |
872 |
|
|
dsa_init(dsa, NULL, 0) != 0 || |
873 |
|
|
dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { |
874 |
|
|
log_debug("%s: failed to compute digital signature", __func__); |
875 |
|
|
goto done; |
876 |
|
|
} |
877 |
|
|
|
878 |
|
|
ibuf_release(sa->sa_localauth.id_buf); |
879 |
|
|
sa->sa_localauth.id_buf = NULL; |
880 |
|
|
|
881 |
|
|
if ((buf = ibuf_new(NULL, dsa_length(dsa))) == NULL) { |
882 |
|
|
log_debug("%s: failed to get auth buffer", __func__); |
883 |
|
|
goto done; |
884 |
|
|
} |
885 |
|
|
|
886 |
|
|
if ((siglen = dsa_sign_final(dsa, |
887 |
|
|
ibuf_data(buf), ibuf_size(buf))) < 0) { |
888 |
|
|
log_debug("%s: failed to create auth signature", __func__); |
889 |
|
|
ibuf_release(buf); |
890 |
|
|
goto done; |
891 |
|
|
} |
892 |
|
|
|
893 |
|
|
if (ibuf_setsize(buf, siglen) < 0) { |
894 |
|
|
log_debug("%s: failed to set auth signature size to %zd", |
895 |
|
|
__func__, siglen); |
896 |
|
|
ibuf_release(buf); |
897 |
|
|
goto done; |
898 |
|
|
} |
899 |
|
|
|
900 |
|
|
sa->sa_localauth.id_type = auth->auth_method; |
901 |
|
|
sa->sa_localauth.id_buf = buf; |
902 |
|
|
|
903 |
|
|
ret = 0; |
904 |
|
|
done: |
905 |
|
|
free(psk); |
906 |
|
|
dsa_free(dsa); |
907 |
|
|
|
908 |
|
|
return (ret); |
909 |
|
|
} |
910 |
|
|
|
911 |
|
|
int |
912 |
|
|
ikev2_msg_frompeer(struct iked_message *msg) |
913 |
|
|
{ |
914 |
|
|
struct iked_sa *sa = msg->msg_sa; |
915 |
|
|
struct ike_header *hdr; |
916 |
|
|
|
917 |
|
|
msg = msg->msg_parent; |
918 |
|
|
|
919 |
|
|
if (sa == NULL || |
920 |
|
|
(hdr = ibuf_seek(msg->msg_data, 0, sizeof(*hdr))) == NULL) |
921 |
|
|
return (0); |
922 |
|
|
|
923 |
|
|
if (!sa->sa_hdr.sh_initiator && |
924 |
|
|
(hdr->ike_flags & IKEV2_FLAG_INITIATOR)) |
925 |
|
|
return (1); |
926 |
|
|
else if (sa->sa_hdr.sh_initiator && |
927 |
|
|
(hdr->ike_flags & IKEV2_FLAG_INITIATOR) == 0) |
928 |
|
|
return (1); |
929 |
|
|
|
930 |
|
|
return (0); |
931 |
|
|
} |
932 |
|
|
|
933 |
|
|
struct iked_socket * |
934 |
|
|
ikev2_msg_getsocket(struct iked *env, int af, int natt) |
935 |
|
|
{ |
936 |
|
|
switch (af) { |
937 |
|
|
case AF_INET: |
938 |
|
|
return (env->sc_sock4[natt ? 1 : 0]); |
939 |
|
|
case AF_INET6: |
940 |
|
|
return (env->sc_sock6[natt ? 1 : 0]); |
941 |
|
|
} |
942 |
|
|
|
943 |
|
|
log_debug("%s: af socket %d not available", __func__, af); |
944 |
|
|
return (NULL); |
945 |
|
|
} |
946 |
|
|
|
947 |
|
|
void |
948 |
|
|
ikev2_msg_prevail(struct iked *env, struct iked_msgqueue *queue, |
949 |
|
|
struct iked_message *msg) |
950 |
|
|
{ |
951 |
|
|
struct iked_message *m, *mtmp; |
952 |
|
|
|
953 |
|
|
TAILQ_FOREACH_SAFE(m, queue, msg_entry, mtmp) { |
954 |
|
|
if (m->msg_msgid < msg->msg_msgid) |
955 |
|
|
ikev2_msg_dispose(env, queue, m); |
956 |
|
|
} |
957 |
|
|
} |
958 |
|
|
|
959 |
|
|
void |
960 |
|
|
ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, |
961 |
|
|
struct iked_message *msg) |
962 |
|
|
{ |
963 |
|
|
TAILQ_REMOVE(queue, msg, msg_entry); |
964 |
|
|
timer_del(env, &msg->msg_timer); |
965 |
|
|
ikev2_msg_cleanup(env, msg); |
966 |
|
|
free(msg); |
967 |
|
|
} |
968 |
|
|
|
969 |
|
|
void |
970 |
|
|
ikev2_msg_flushqueue(struct iked *env, struct iked_msgqueue *queue) |
971 |
|
|
{ |
972 |
|
|
struct iked_message *m = NULL; |
973 |
|
|
|
974 |
|
|
while ((m = TAILQ_FIRST(queue)) != NULL) |
975 |
|
|
ikev2_msg_dispose(env, queue, m); |
976 |
|
|
} |
977 |
|
|
|
978 |
|
|
struct iked_message * |
979 |
|
|
ikev2_msg_lookup(struct iked *env, struct iked_msgqueue *queue, |
980 |
|
|
struct iked_message *msg, struct ike_header *hdr) |
981 |
|
|
{ |
982 |
|
|
struct iked_message *m = NULL; |
983 |
|
|
|
984 |
|
|
TAILQ_FOREACH(m, queue, msg_entry) { |
985 |
|
|
if (m->msg_msgid == msg->msg_msgid && |
986 |
|
|
m->msg_exchange == hdr->ike_exchange) |
987 |
|
|
break; |
988 |
|
|
} |
989 |
|
|
|
990 |
|
|
return (m); |
991 |
|
|
} |
992 |
|
|
|
993 |
|
|
int |
994 |
|
|
ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, |
995 |
|
|
struct iked_message *msg) |
996 |
|
|
{ |
997 |
|
|
if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), |
998 |
|
|
ibuf_size(msg->msg_data), 0, |
999 |
|
|
(struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, |
1000 |
|
|
(struct sockaddr *)&msg->msg_local, msg->msg_locallen) == -1) { |
1001 |
|
|
log_warn("%s: sendtofrom", __func__); |
1002 |
|
|
return (-1); |
1003 |
|
|
} |
1004 |
|
|
|
1005 |
|
|
timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); |
1006 |
|
|
return (0); |
1007 |
|
|
} |
1008 |
|
|
|
1009 |
|
|
void |
1010 |
|
|
ikev2_msg_response_timeout(struct iked *env, void *arg) |
1011 |
|
|
{ |
1012 |
|
|
struct iked_message *msg = arg; |
1013 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1014 |
|
|
|
1015 |
|
|
ikev2_msg_dispose(env, &sa->sa_responses, msg); |
1016 |
|
|
} |
1017 |
|
|
|
1018 |
|
|
void |
1019 |
|
|
ikev2_msg_retransmit_timeout(struct iked *env, void *arg) |
1020 |
|
|
{ |
1021 |
|
|
struct iked_message *msg = arg; |
1022 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1023 |
|
|
|
1024 |
|
|
if (msg->msg_tries < IKED_RETRANSMIT_TRIES) { |
1025 |
|
|
if (sendtofrom(msg->msg_fd, ibuf_data(msg->msg_data), |
1026 |
|
|
ibuf_size(msg->msg_data), 0, |
1027 |
|
|
(struct sockaddr *)&msg->msg_peer, msg->msg_peerlen, |
1028 |
|
|
(struct sockaddr *)&msg->msg_local, |
1029 |
|
|
msg->msg_locallen) == -1) { |
1030 |
|
|
log_warn("%s: sendtofrom", __func__); |
1031 |
|
|
sa_free(env, sa); |
1032 |
|
|
return; |
1033 |
|
|
} |
1034 |
|
|
/* Exponential timeout */ |
1035 |
|
|
timer_add(env, &msg->msg_timer, |
1036 |
|
|
IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); |
1037 |
|
|
} else { |
1038 |
|
|
log_debug("%s: retransmit limit reached for msgid %u", |
1039 |
|
|
__func__, msg->msg_msgid); |
1040 |
|
|
sa_free(env, sa); |
1041 |
|
|
} |
1042 |
|
|
} |