1 |
|
|
/* $OpenBSD: message.c,v 1.129 2016/04/04 17:35:07 yasuoka Exp $ */ |
2 |
|
|
/* $EOM: message.c,v 1.156 2000/10/10 12:36:39 provos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. |
6 |
|
|
* Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. |
7 |
|
|
* Copyright (c) 1999, 2000, 2001, 2004 Håkan Olsson. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
|
* modification, are permitted provided that the following conditions |
11 |
|
|
* are met: |
12 |
|
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
|
* documentation and/or other materials provided with the distribution. |
17 |
|
|
* |
18 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 |
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 |
|
|
*/ |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* This code was written under funding by Ericsson Radio Systems. |
32 |
|
|
*/ |
33 |
|
|
|
34 |
|
|
#include <sys/types.h> |
35 |
|
|
#include <sys/socket.h> |
36 |
|
|
#include <netinet/in.h> |
37 |
|
|
#include <arpa/inet.h> |
38 |
|
|
#include <stdlib.h> |
39 |
|
|
#include <string.h> |
40 |
|
|
|
41 |
|
|
#include "attribute.h" |
42 |
|
|
#include "cert.h" |
43 |
|
|
#include "constants.h" |
44 |
|
|
#include "crypto.h" |
45 |
|
|
#include "doi.h" |
46 |
|
|
#include "dpd.h" |
47 |
|
|
#include "exchange.h" |
48 |
|
|
#include "field.h" |
49 |
|
|
#include "hash.h" |
50 |
|
|
#include "ipsec.h" |
51 |
|
|
#include "ipsec_num.h" |
52 |
|
|
#include "isakmp.h" |
53 |
|
|
#include "log.h" |
54 |
|
|
#include "message.h" |
55 |
|
|
#include "nat_traversal.h" |
56 |
|
|
#include "prf.h" |
57 |
|
|
#include "sa.h" |
58 |
|
|
#include "timer.h" |
59 |
|
|
#include "transport.h" |
60 |
|
|
#include "util.h" |
61 |
|
|
#include "vendor.h" |
62 |
|
|
#include "virtual.h" |
63 |
|
|
|
64 |
|
|
/* A local set datatype, coincidentally fd_set suits our purpose fine. */ |
65 |
|
|
typedef fd_set set; |
66 |
|
|
#define ISSET FD_ISSET |
67 |
|
|
#define SET FD_SET |
68 |
|
|
#define ZERO FD_ZERO |
69 |
|
|
|
70 |
|
|
static int message_check_duplicate(struct message *); |
71 |
|
|
static int message_encrypt(struct message *); |
72 |
|
|
static int message_index_payload(struct message *, struct payload *, |
73 |
|
|
u_int8_t ,u_int8_t *); |
74 |
|
|
static int message_parse_transform(struct message *, struct payload *, |
75 |
|
|
u_int8_t, u_int8_t *); |
76 |
|
|
static struct field *message_get_field(u_int8_t); |
77 |
|
|
static int message_validate_payload(struct message *, struct payload *, |
78 |
|
|
u_int8_t); |
79 |
|
|
static u_int16_t message_payload_sz(u_int8_t); |
80 |
|
|
static int message_validate_attribute(struct message *, struct payload *); |
81 |
|
|
static int message_validate_cert(struct message *, struct payload *); |
82 |
|
|
static int message_validate_cert_req(struct message *, struct payload *); |
83 |
|
|
static int message_validate_delete(struct message *, struct payload *); |
84 |
|
|
static int message_validate_hash(struct message *, struct payload *); |
85 |
|
|
static int message_validate_id(struct message *, struct payload *); |
86 |
|
|
static int message_validate_key_exch(struct message *, struct payload *); |
87 |
|
|
static int message_validate_nat_d(struct message *, struct payload *); |
88 |
|
|
static int message_validate_nat_oa(struct message *, struct payload *); |
89 |
|
|
static int message_validate_nonce(struct message *, struct payload *); |
90 |
|
|
static int message_validate_notify(struct message *, struct payload *); |
91 |
|
|
static int message_validate_proposal(struct message *, struct payload *); |
92 |
|
|
static int message_validate_sa(struct message *, struct payload *); |
93 |
|
|
static int message_validate_sig(struct message *, struct payload *); |
94 |
|
|
static int message_validate_transform(struct message *, struct payload *); |
95 |
|
|
static int message_validate_vendor(struct message *, struct payload *); |
96 |
|
|
|
97 |
|
|
static void message_packet_log(struct message *); |
98 |
|
|
|
99 |
|
|
/* |
100 |
|
|
* Fields used for checking monotonic increasing of proposal and transform |
101 |
|
|
* numbers. |
102 |
|
|
*/ |
103 |
|
|
static u_int8_t *last_sa = 0; |
104 |
|
|
static u_int32_t last_prop_no; |
105 |
|
|
static u_int8_t *last_prop = 0; |
106 |
|
|
static u_int32_t last_xf_no; |
107 |
|
|
|
108 |
|
|
/* |
109 |
|
|
* Allocate a message structure bound to transport T, and with a first |
110 |
|
|
* segment buffer sized SZ, copied from BUF if given. |
111 |
|
|
*/ |
112 |
|
|
struct message * |
113 |
|
|
message_alloc(struct transport *t, u_int8_t *buf, size_t sz) |
114 |
|
|
{ |
115 |
|
|
struct message *msg; |
116 |
|
|
int i; |
117 |
|
|
|
118 |
|
|
/* |
119 |
|
|
* We use calloc(3) because it zeroes the structure which we rely on in |
120 |
|
|
* message_free when determining what sub-allocations to free. |
121 |
|
|
*/ |
122 |
|
|
msg = calloc(1, sizeof *msg); |
123 |
|
|
if (!msg) |
124 |
|
|
return 0; |
125 |
|
|
msg->iov = calloc(1, sizeof *msg->iov); |
126 |
|
|
if (!msg->iov) { |
127 |
|
|
message_free(msg); |
128 |
|
|
return 0; |
129 |
|
|
} |
130 |
|
|
msg->iov[0].iov_len = sz; |
131 |
|
|
msg->iov[0].iov_base = malloc(sz); |
132 |
|
|
if (!msg->iov[0].iov_base) { |
133 |
|
|
message_free(msg); |
134 |
|
|
return 0; |
135 |
|
|
} |
136 |
|
|
msg->iovlen = 1; |
137 |
|
|
if (buf) |
138 |
|
|
memcpy(msg->iov[0].iov_base, buf, sz); |
139 |
|
|
msg->nextp = (u_int8_t *)msg->iov[0].iov_base + |
140 |
|
|
ISAKMP_HDR_NEXT_PAYLOAD_OFF; |
141 |
|
|
msg->transport = t; |
142 |
|
|
transport_reference(t); |
143 |
|
|
msg->payload = calloc(ISAKMP_PAYLOAD_MAX, sizeof *msg->payload); |
144 |
|
|
if (!msg->payload) { |
145 |
|
|
message_free(msg); |
146 |
|
|
return 0; |
147 |
|
|
} |
148 |
|
|
for (i = 0; i < ISAKMP_PAYLOAD_MAX; i++) |
149 |
|
|
TAILQ_INIT(&msg->payload[i]); |
150 |
|
|
TAILQ_INIT(&msg->post_send); |
151 |
|
|
LOG_DBG((LOG_MESSAGE, 90, "message_alloc: allocated %p", msg)); |
152 |
|
|
return msg; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
/* |
156 |
|
|
* Allocate a message suitable for a reply to MSG. Just allocate an empty |
157 |
|
|
* ISAKMP header as the first segment. |
158 |
|
|
*/ |
159 |
|
|
struct message * |
160 |
|
|
message_alloc_reply(struct message *msg) |
161 |
|
|
{ |
162 |
|
|
struct message *reply; |
163 |
|
|
|
164 |
|
|
reply = message_alloc(msg->transport, 0, ISAKMP_HDR_SZ); |
165 |
|
|
reply->exchange = msg->exchange; |
166 |
|
|
reply->isakmp_sa = msg->isakmp_sa; |
167 |
|
|
reply->flags = msg->flags; |
168 |
|
|
if (msg->isakmp_sa) |
169 |
|
|
sa_reference(msg->isakmp_sa); |
170 |
|
|
return reply; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
/* Free up all resources used by the MSG message. */ |
174 |
|
|
void |
175 |
|
|
message_free(struct message *msg) |
176 |
|
|
{ |
177 |
|
|
u_int32_t i; |
178 |
|
|
struct payload *payload; |
179 |
|
|
struct post_send *node; |
180 |
|
|
|
181 |
|
|
LOG_DBG((LOG_MESSAGE, 20, "message_free: freeing %p", msg)); |
182 |
|
|
if (!msg) |
183 |
|
|
return; |
184 |
|
|
if (msg->iov) { |
185 |
|
|
if (msg->orig && msg->orig != (u_int8_t *)msg->iov[0].iov_base) |
186 |
|
|
free(msg->orig); |
187 |
|
|
for (i = 0; i < msg->iovlen; i++) |
188 |
|
|
free(msg->iov[i].iov_base); |
189 |
|
|
free(msg->iov); |
190 |
|
|
} |
191 |
|
|
if (msg->retrans) |
192 |
|
|
timer_remove_event(msg->retrans); |
193 |
|
|
if (msg->payload) { |
194 |
|
|
for (i = 0; i < ISAKMP_PAYLOAD_MAX; i++) |
195 |
|
|
while ((payload = TAILQ_FIRST(&msg->payload[i]))) { |
196 |
|
|
TAILQ_REMOVE(&msg->payload[i], payload, link); |
197 |
|
|
free(payload); |
198 |
|
|
} |
199 |
|
|
free(msg->payload); |
200 |
|
|
} |
201 |
|
|
while ((node = TAILQ_FIRST(&msg->post_send))) |
202 |
|
|
TAILQ_REMOVE(&msg->post_send, node, link); |
203 |
|
|
if (msg->transport) { |
204 |
|
|
/* If we are on the send queue, remove us from there. */ |
205 |
|
|
if (msg->flags & MSG_IN_TRANSIT) |
206 |
|
|
TAILQ_REMOVE(msg->transport->vtbl->get_queue(msg), |
207 |
|
|
msg, link); |
208 |
|
|
|
209 |
|
|
transport_release(msg->transport); |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
if (msg->isakmp_sa) |
213 |
|
|
sa_release(msg->isakmp_sa); |
214 |
|
|
|
215 |
|
|
free(msg); |
216 |
|
|
} |
217 |
|
|
|
218 |
|
|
/* |
219 |
|
|
* Generic ISAKMP parser. |
220 |
|
|
* MSG is the ISAKMP message to be parsed. NEXT is the type of the first |
221 |
|
|
* payload to be parsed, and it's pointed to by BUF. ACCEPTED_PAYLOADS |
222 |
|
|
* tells what payloads are accepted and FUNC is a pointer to a function |
223 |
|
|
* to be called for each payload found, which is also responsible for |
224 |
|
|
* freeing the passed ISAKMP message in the failure case. |
225 |
|
|
* Returns the total length of the parsed payloads. |
226 |
|
|
*/ |
227 |
|
|
static int |
228 |
|
|
message_parse_payloads(struct message *msg, struct payload *p, u_int8_t next, |
229 |
|
|
u_int8_t *buf, set *accepted_payloads, int (*func)(struct message *, |
230 |
|
|
struct payload *, u_int8_t, u_int8_t *)) |
231 |
|
|
{ |
232 |
|
|
u_int8_t payload; |
233 |
|
|
u_int16_t len; |
234 |
|
|
int sz = 0; |
235 |
|
|
|
236 |
|
|
do { |
237 |
|
|
LOG_DBG((LOG_MESSAGE, 50, |
238 |
|
|
"message_parse_payloads: offset %ld payload %s", |
239 |
|
|
(long)(buf - (u_int8_t *) msg->iov[0].iov_base), |
240 |
|
|
constant_name(isakmp_payload_cst, next))); |
241 |
|
|
|
242 |
|
|
/* Does this payload's header fit? */ |
243 |
|
|
if (buf + ISAKMP_GEN_SZ > (u_int8_t *)msg->iov[0].iov_base + |
244 |
|
|
msg->iov[0].iov_len) { |
245 |
|
|
log_print("message_parse_payloads: short message"); |
246 |
|
|
message_drop(msg, |
247 |
|
|
ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 1, 1); |
248 |
|
|
return -1; |
249 |
|
|
} |
250 |
|
|
/* Ponder on the payload that is at BUF... */ |
251 |
|
|
payload = next; |
252 |
|
|
|
253 |
|
|
/* Look at the next payload's type. */ |
254 |
|
|
next = GET_ISAKMP_GEN_NEXT_PAYLOAD(buf); |
255 |
|
|
if (next >= ISAKMP_PAYLOAD_RESERVED_MIN && |
256 |
|
|
next <= ISAKMP_PAYLOAD_RESERVED_MAX) { |
257 |
|
|
log_print("message_parse_payloads: invalid next " |
258 |
|
|
"payload type %s in payload of type %d", |
259 |
|
|
constant_name(isakmp_payload_cst, next), payload); |
260 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, |
261 |
|
|
0, 1, 1); |
262 |
|
|
return -1; |
263 |
|
|
} |
264 |
|
|
/* Reserved fields in ISAKMP messages should be zero. */ |
265 |
|
|
if (GET_ISAKMP_GEN_RESERVED(buf) != 0) { |
266 |
|
|
log_print("message_parse_payloads: reserved field " |
267 |
|
|
"non-zero: %x", GET_ISAKMP_GEN_RESERVED(buf)); |
268 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, |
269 |
|
|
0, 1, 1); |
270 |
|
|
return -1; |
271 |
|
|
} |
272 |
|
|
/* |
273 |
|
|
* Decode and validate the payload length field. |
274 |
|
|
*/ |
275 |
|
|
len = GET_ISAKMP_GEN_LENGTH(buf); |
276 |
|
|
|
277 |
|
|
if (message_payload_sz(payload) == 0) { |
278 |
|
|
log_print("message_parse_payloads: unknown minimum " |
279 |
|
|
"payload size for payload type %s", |
280 |
|
|
constant_name(isakmp_payload_cst, payload)); |
281 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, |
282 |
|
|
0, 1, 1); |
283 |
|
|
return -1; |
284 |
|
|
} |
285 |
|
|
if (len < message_payload_sz(payload)) { |
286 |
|
|
log_print("message_parse_payloads: payload too " |
287 |
|
|
"short: %u", len); |
288 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, |
289 |
|
|
0, 1, 1); |
290 |
|
|
return -1; |
291 |
|
|
} |
292 |
|
|
if (buf + len > (u_int8_t *)msg->iov[0].iov_base + |
293 |
|
|
msg->iov[0].iov_len) { |
294 |
|
|
log_print("message_parse_payloads: payload too " |
295 |
|
|
"long: %u", len); |
296 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, |
297 |
|
|
0, 1, 1); |
298 |
|
|
return -1; |
299 |
|
|
} |
300 |
|
|
/* Ignore most private payloads. */ |
301 |
|
|
if (next >= ISAKMP_PAYLOAD_PRIVATE_MIN && |
302 |
|
|
next != ISAKMP_PAYLOAD_NAT_D_DRAFT && |
303 |
|
|
next != ISAKMP_PAYLOAD_NAT_OA_DRAFT) { |
304 |
|
|
LOG_DBG((LOG_MESSAGE, 30, "message_parse_payloads: " |
305 |
|
|
"private next payload type %s in payload of " |
306 |
|
|
"type %d ignored", |
307 |
|
|
constant_name(isakmp_payload_cst, next), payload)); |
308 |
|
|
goto next_payload; |
309 |
|
|
} |
310 |
|
|
/* |
311 |
|
|
* Check if the current payload is one of the accepted ones at |
312 |
|
|
* this stage. |
313 |
|
|
*/ |
314 |
|
|
if (!ISSET(payload, accepted_payloads)) { |
315 |
|
|
log_print("message_parse_payloads: payload type %s " |
316 |
|
|
"unexpected", constant_name(isakmp_payload_cst, |
317 |
|
|
payload)); |
318 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, |
319 |
|
|
0, 1, 1); |
320 |
|
|
return -1; |
321 |
|
|
} |
322 |
|
|
/* Call the payload handler specified by the caller. */ |
323 |
|
|
if (func(msg, p, payload, buf)) |
324 |
|
|
return -1; |
325 |
|
|
|
326 |
|
|
next_payload: |
327 |
|
|
/* Advance to next payload. */ |
328 |
|
|
buf += len; |
329 |
|
|
sz += len; |
330 |
|
|
} while (next != ISAKMP_PAYLOAD_NONE); |
331 |
|
|
return sz; |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
/* |
335 |
|
|
* Parse a proposal payload found in message MSG. PAYLOAD is always |
336 |
|
|
* ISAKMP_PAYLOAD_PROPOSAL and ignored in here. It's needed as the API for |
337 |
|
|
* message_parse_payloads requires it. BUF points to the proposal's |
338 |
|
|
* generic payload header. |
339 |
|
|
*/ |
340 |
|
|
static int |
341 |
|
|
message_parse_proposal(struct message *msg, struct payload *p, |
342 |
|
|
u_int8_t payload, u_int8_t *buf) |
343 |
|
|
{ |
344 |
|
|
set payload_set; |
345 |
|
|
|
346 |
|
|
/* Put the proposal into the proposal bucket. */ |
347 |
|
|
if (message_index_payload(msg, p, payload, buf) == -1) |
348 |
|
|
return -1; |
349 |
|
|
|
350 |
|
|
ZERO(&payload_set); |
351 |
|
|
SET(ISAKMP_PAYLOAD_TRANSFORM, &payload_set); |
352 |
|
|
if (message_parse_payloads(msg, |
353 |
|
|
TAILQ_LAST(&msg->payload[ISAKMP_PAYLOAD_PROPOSAL], payload_head), |
354 |
|
|
ISAKMP_PAYLOAD_TRANSFORM, buf + ISAKMP_PROP_SPI_OFF + |
355 |
|
|
GET_ISAKMP_PROP_SPI_SZ(buf), &payload_set, message_parse_transform) |
356 |
|
|
== -1) |
357 |
|
|
return -1; |
358 |
|
|
|
359 |
|
|
return 0; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
static int |
363 |
|
|
message_parse_transform(struct message *msg, struct payload *p, |
364 |
|
|
u_int8_t payload, u_int8_t *buf) |
365 |
|
|
{ |
366 |
|
|
/* Put the transform into the transform bucket. */ |
367 |
|
|
if (message_index_payload(msg, p, payload, buf) == -1) |
368 |
|
|
return -1; |
369 |
|
|
|
370 |
|
|
LOG_DBG((LOG_MESSAGE, 50, "Transform %d's attributes", |
371 |
|
|
GET_ISAKMP_TRANSFORM_NO(buf))); |
372 |
|
|
attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
373 |
|
|
GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
374 |
|
|
msg->exchange->doi->debug_attribute, msg); |
375 |
|
|
|
376 |
|
|
return 0; |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
static struct field * |
380 |
|
|
message_get_field(u_int8_t payload) |
381 |
|
|
{ |
382 |
|
|
switch (payload) { |
383 |
|
|
case ISAKMP_PAYLOAD_SA: |
384 |
|
|
return isakmp_sa_fld; |
385 |
|
|
case ISAKMP_PAYLOAD_PROPOSAL: |
386 |
|
|
return isakmp_prop_fld; |
387 |
|
|
case ISAKMP_PAYLOAD_TRANSFORM: |
388 |
|
|
return isakmp_transform_fld; |
389 |
|
|
case ISAKMP_PAYLOAD_KEY_EXCH: |
390 |
|
|
return isakmp_ke_fld; |
391 |
|
|
case ISAKMP_PAYLOAD_ID: |
392 |
|
|
return isakmp_id_fld; |
393 |
|
|
case ISAKMP_PAYLOAD_CERT: |
394 |
|
|
return isakmp_cert_fld; |
395 |
|
|
case ISAKMP_PAYLOAD_CERT_REQ: |
396 |
|
|
return isakmp_certreq_fld; |
397 |
|
|
case ISAKMP_PAYLOAD_HASH: |
398 |
|
|
return isakmp_hash_fld; |
399 |
|
|
case ISAKMP_PAYLOAD_SIG: |
400 |
|
|
return isakmp_sig_fld; |
401 |
|
|
case ISAKMP_PAYLOAD_NONCE: |
402 |
|
|
return isakmp_nonce_fld; |
403 |
|
|
case ISAKMP_PAYLOAD_NOTIFY: |
404 |
|
|
return isakmp_notify_fld; |
405 |
|
|
case ISAKMP_PAYLOAD_DELETE: |
406 |
|
|
return isakmp_delete_fld; |
407 |
|
|
case ISAKMP_PAYLOAD_VENDOR: |
408 |
|
|
return isakmp_vendor_fld; |
409 |
|
|
case ISAKMP_PAYLOAD_ATTRIBUTE: |
410 |
|
|
return isakmp_attribute_fld; |
411 |
|
|
case ISAKMP_PAYLOAD_NAT_D: |
412 |
|
|
case ISAKMP_PAYLOAD_NAT_D_DRAFT: |
413 |
|
|
return isakmp_nat_d_fld; |
414 |
|
|
case ISAKMP_PAYLOAD_NAT_OA: |
415 |
|
|
case ISAKMP_PAYLOAD_NAT_OA_DRAFT: |
416 |
|
|
return isakmp_nat_oa_fld; |
417 |
|
|
/* Not yet supported and any other unknown payloads. */ |
418 |
|
|
case ISAKMP_PAYLOAD_SAK: |
419 |
|
|
case ISAKMP_PAYLOAD_SAT: |
420 |
|
|
case ISAKMP_PAYLOAD_KD: |
421 |
|
|
case ISAKMP_PAYLOAD_SEQ: |
422 |
|
|
case ISAKMP_PAYLOAD_POP: |
423 |
|
|
default: |
424 |
|
|
break; |
425 |
|
|
} |
426 |
|
|
return NULL; |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
static int |
430 |
|
|
message_validate_payload(struct message *m, struct payload *p, u_int8_t payload) |
431 |
|
|
{ |
432 |
|
|
switch (payload) { |
433 |
|
|
case ISAKMP_PAYLOAD_SA: |
434 |
|
|
return message_validate_sa(m, p); |
435 |
|
|
case ISAKMP_PAYLOAD_PROPOSAL: |
436 |
|
|
return message_validate_proposal(m, p); |
437 |
|
|
case ISAKMP_PAYLOAD_TRANSFORM: |
438 |
|
|
return message_validate_transform(m, p); |
439 |
|
|
case ISAKMP_PAYLOAD_KEY_EXCH: |
440 |
|
|
return message_validate_key_exch(m, p); |
441 |
|
|
case ISAKMP_PAYLOAD_ID: |
442 |
|
|
return message_validate_id(m, p); |
443 |
|
|
case ISAKMP_PAYLOAD_CERT: |
444 |
|
|
return message_validate_cert(m, p); |
445 |
|
|
case ISAKMP_PAYLOAD_CERT_REQ: |
446 |
|
|
return message_validate_cert_req(m, p); |
447 |
|
|
case ISAKMP_PAYLOAD_HASH: |
448 |
|
|
return message_validate_hash(m, p); |
449 |
|
|
case ISAKMP_PAYLOAD_SIG: |
450 |
|
|
return message_validate_sig(m, p); |
451 |
|
|
case ISAKMP_PAYLOAD_NONCE: |
452 |
|
|
return message_validate_nonce(m, p); |
453 |
|
|
case ISAKMP_PAYLOAD_NOTIFY: |
454 |
|
|
return message_validate_notify(m, p); |
455 |
|
|
case ISAKMP_PAYLOAD_DELETE: |
456 |
|
|
return message_validate_delete(m, p); |
457 |
|
|
case ISAKMP_PAYLOAD_VENDOR: |
458 |
|
|
return message_validate_vendor(m, p); |
459 |
|
|
case ISAKMP_PAYLOAD_ATTRIBUTE: |
460 |
|
|
return message_validate_attribute(m, p); |
461 |
|
|
case ISAKMP_PAYLOAD_NAT_D: |
462 |
|
|
case ISAKMP_PAYLOAD_NAT_D_DRAFT: |
463 |
|
|
return message_validate_nat_d(m, p); |
464 |
|
|
case ISAKMP_PAYLOAD_NAT_OA: |
465 |
|
|
case ISAKMP_PAYLOAD_NAT_OA_DRAFT: |
466 |
|
|
return message_validate_nat_oa(m, p); |
467 |
|
|
/* Not yet supported and any other unknown payloads. */ |
468 |
|
|
case ISAKMP_PAYLOAD_SAK: |
469 |
|
|
case ISAKMP_PAYLOAD_SAT: |
470 |
|
|
case ISAKMP_PAYLOAD_KD: |
471 |
|
|
case ISAKMP_PAYLOAD_SEQ: |
472 |
|
|
case ISAKMP_PAYLOAD_POP: |
473 |
|
|
default: |
474 |
|
|
break; |
475 |
|
|
} |
476 |
|
|
message_drop(m, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); |
477 |
|
|
return -1; |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
/* Check payloads for their required minimum size. */ |
481 |
|
|
static u_int16_t |
482 |
|
|
message_payload_sz(u_int8_t payload) |
483 |
|
|
{ |
484 |
|
|
switch (payload) { |
485 |
|
|
case ISAKMP_PAYLOAD_SA: |
486 |
|
|
return ISAKMP_SA_SZ; |
487 |
|
|
case ISAKMP_PAYLOAD_PROPOSAL: |
488 |
|
|
return ISAKMP_PROP_SZ; |
489 |
|
|
case ISAKMP_PAYLOAD_TRANSFORM: |
490 |
|
|
return ISAKMP_TRANSFORM_SZ; |
491 |
|
|
case ISAKMP_PAYLOAD_KEY_EXCH: |
492 |
|
|
return ISAKMP_KE_SZ; |
493 |
|
|
case ISAKMP_PAYLOAD_ID: |
494 |
|
|
return ISAKMP_ID_SZ; |
495 |
|
|
case ISAKMP_PAYLOAD_CERT: |
496 |
|
|
return ISAKMP_CERT_SZ; |
497 |
|
|
case ISAKMP_PAYLOAD_CERT_REQ: |
498 |
|
|
return ISAKMP_CERTREQ_SZ; |
499 |
|
|
case ISAKMP_PAYLOAD_HASH: |
500 |
|
|
return ISAKMP_HASH_SZ; |
501 |
|
|
case ISAKMP_PAYLOAD_SIG: |
502 |
|
|
return ISAKMP_SIG_SZ; |
503 |
|
|
case ISAKMP_PAYLOAD_NONCE: |
504 |
|
|
return ISAKMP_NONCE_SZ; |
505 |
|
|
case ISAKMP_PAYLOAD_NOTIFY: |
506 |
|
|
return ISAKMP_NOTIFY_SZ; |
507 |
|
|
case ISAKMP_PAYLOAD_DELETE: |
508 |
|
|
return ISAKMP_DELETE_SZ; |
509 |
|
|
case ISAKMP_PAYLOAD_VENDOR: |
510 |
|
|
return ISAKMP_VENDOR_SZ; |
511 |
|
|
case ISAKMP_PAYLOAD_ATTRIBUTE: |
512 |
|
|
return ISAKMP_ATTRIBUTE_SZ; |
513 |
|
|
case ISAKMP_PAYLOAD_NAT_D: |
514 |
|
|
case ISAKMP_PAYLOAD_NAT_D_DRAFT: |
515 |
|
|
return ISAKMP_NAT_D_SZ; |
516 |
|
|
case ISAKMP_PAYLOAD_NAT_OA: |
517 |
|
|
case ISAKMP_PAYLOAD_NAT_OA_DRAFT: |
518 |
|
|
return ISAKMP_NAT_OA_SZ; |
519 |
|
|
/* Not yet supported and any other unknown payloads. */ |
520 |
|
|
case ISAKMP_PAYLOAD_SAK: |
521 |
|
|
case ISAKMP_PAYLOAD_SAT: |
522 |
|
|
case ISAKMP_PAYLOAD_KD: |
523 |
|
|
case ISAKMP_PAYLOAD_SEQ: |
524 |
|
|
case ISAKMP_PAYLOAD_POP: |
525 |
|
|
default: |
526 |
|
|
return 0; |
527 |
|
|
} |
528 |
|
|
} |
529 |
|
|
|
530 |
|
|
/* Validate the attribute payload P in message MSG. */ |
531 |
|
|
static int |
532 |
|
|
message_validate_attribute(struct message *msg, struct payload *p) |
533 |
|
|
{ |
534 |
|
|
/* If we don't have an exchange yet, create one. */ |
535 |
|
|
if (!msg->exchange) { |
536 |
|
|
if (zero_test((u_int8_t *) msg->iov[0].iov_base + |
537 |
|
|
ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) |
538 |
|
|
msg->exchange = exchange_setup_p1(msg, |
539 |
|
|
IPSEC_DOI_IPSEC); |
540 |
|
|
else |
541 |
|
|
msg->exchange = exchange_setup_p2(msg, |
542 |
|
|
IPSEC_DOI_IPSEC); |
543 |
|
|
if (!msg->exchange) { |
544 |
|
|
log_print("message_validate_attribute: can not " |
545 |
|
|
"create exchange"); |
546 |
|
|
message_free(msg); |
547 |
|
|
return -1; |
548 |
|
|
} |
549 |
|
|
} |
550 |
|
|
return 0; |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
/* Validate the certificate payload P in message MSG. */ |
554 |
|
|
static int |
555 |
|
|
message_validate_cert(struct message *msg, struct payload *p) |
556 |
|
|
{ |
557 |
|
|
if (GET_ISAKMP_CERT_ENCODING(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) { |
558 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1, |
559 |
|
|
1); |
560 |
|
|
return -1; |
561 |
|
|
} |
562 |
|
|
return 0; |
563 |
|
|
} |
564 |
|
|
|
565 |
|
|
/* Validate the certificate request payload P in message MSG. */ |
566 |
|
|
static int |
567 |
|
|
message_validate_cert_req(struct message *msg, struct payload *p) |
568 |
|
|
{ |
569 |
|
|
struct cert_handler *cert; |
570 |
|
|
size_t len = |
571 |
|
|
GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERTREQ_AUTHORITY_OFF; |
572 |
|
|
|
573 |
|
|
if (GET_ISAKMP_CERTREQ_TYPE(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) { |
574 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1, |
575 |
|
|
1); |
576 |
|
|
return -1; |
577 |
|
|
} |
578 |
|
|
/* |
579 |
|
|
* Check the certificate types we support and if an acceptable |
580 |
|
|
* authority is included in the payload check if it can be decoded |
581 |
|
|
*/ |
582 |
|
|
cert = cert_get(GET_ISAKMP_CERTREQ_TYPE(p->p)); |
583 |
|
|
if (!cert || (len && !cert->certreq_validate(p->p + |
584 |
|
|
ISAKMP_CERTREQ_AUTHORITY_OFF, len))) { |
585 |
|
|
message_drop(msg, ISAKMP_NOTIFY_CERT_TYPE_UNSUPPORTED, 0, 1, |
586 |
|
|
1); |
587 |
|
|
return -1; |
588 |
|
|
} |
589 |
|
|
return 0; |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
/* |
593 |
|
|
* Validate the delete payload P in message MSG. As a side-effect, create |
594 |
|
|
* an exchange if we do not have one already. |
595 |
|
|
*/ |
596 |
|
|
static int |
597 |
|
|
message_validate_delete(struct message *msg, struct payload *p) |
598 |
|
|
{ |
599 |
|
|
u_int8_t proto = GET_ISAKMP_DELETE_PROTO(p->p); |
600 |
|
|
struct doi *doi; |
601 |
|
|
struct sa *sa, *isakmp_sa; |
602 |
|
|
struct sockaddr *dst, *dst_isa; |
603 |
|
|
u_int32_t nspis = GET_ISAKMP_DELETE_NSPIS(p->p); |
604 |
|
|
u_int8_t *spis = (u_int8_t *)p->p + ISAKMP_DELETE_SPI_OFF; |
605 |
|
|
u_int32_t i; |
606 |
|
|
char *addr; |
607 |
|
|
|
608 |
|
|
/* Only accept authenticated DELETEs. */ |
609 |
|
|
if ((msg->flags & MSG_AUTHENTICATED) == 0) { |
610 |
|
|
log_print("message_validate_delete: " |
611 |
|
|
"got unauthenticated DELETE"); |
612 |
|
|
message_free(msg); |
613 |
|
|
return -1; |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
doi = doi_lookup(GET_ISAKMP_DELETE_DOI(p->p)); |
617 |
|
|
if (!doi) { |
618 |
|
|
log_print("message_validate_delete: DOI not supported"); |
619 |
|
|
message_free(msg); |
620 |
|
|
return -1; |
621 |
|
|
} |
622 |
|
|
/* If we don't have an exchange yet, create one. */ |
623 |
|
|
if (!msg->exchange) { |
624 |
|
|
if (zero_test((u_int8_t *) msg->iov[0].iov_base |
625 |
|
|
+ ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) |
626 |
|
|
msg->exchange = exchange_setup_p1(msg, doi->id); |
627 |
|
|
else |
628 |
|
|
msg->exchange = exchange_setup_p2(msg, doi->id); |
629 |
|
|
if (!msg->exchange) { |
630 |
|
|
log_print("message_validate_delete: can not create " |
631 |
|
|
"exchange"); |
632 |
|
|
message_free(msg); |
633 |
|
|
return -1; |
634 |
|
|
} |
635 |
|
|
} |
636 |
|
|
/* Only accept DELETE as part of an INFORMATIONAL exchange. */ |
637 |
|
|
if (msg->exchange->type != ISAKMP_EXCH_INFO) { |
638 |
|
|
log_print("message_validate_delete: delete in exchange other " |
639 |
|
|
"than INFO: %s", constant_name(isakmp_exch_cst, |
640 |
|
|
msg->exchange->type)); |
641 |
|
|
message_free(msg); |
642 |
|
|
return -1; |
643 |
|
|
} |
644 |
|
|
if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) { |
645 |
|
|
log_print("message_validate_delete: protocol not supported"); |
646 |
|
|
message_free(msg); |
647 |
|
|
return -1; |
648 |
|
|
} |
649 |
|
|
/* Validate the SPIs. */ |
650 |
|
|
for (i = 0; i < nspis; i++) { |
651 |
|
|
/* Get ISAKMP SA protecting this message. */ |
652 |
|
|
isakmp_sa = msg->isakmp_sa; |
653 |
|
|
if (!isakmp_sa) { |
654 |
|
|
/* XXX should not happen? */ |
655 |
|
|
log_print("message_validate_delete: invalid spi (no " |
656 |
|
|
"valid ISAKMP SA found)"); |
657 |
|
|
message_free(msg); |
658 |
|
|
return -1; |
659 |
|
|
} |
660 |
|
|
isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, |
661 |
|
|
&dst_isa); |
662 |
|
|
|
663 |
|
|
/* Get SA to be deleted. */ |
664 |
|
|
msg->transport->vtbl->get_dst(msg->transport, &dst); |
665 |
|
|
if (proto == ISAKMP_PROTO_ISAKMP) |
666 |
|
|
sa = sa_lookup_isakmp_sa(dst, spis + i |
667 |
|
|
* ISAKMP_HDR_COOKIES_LEN); |
668 |
|
|
else |
669 |
|
|
sa = ipsec_sa_lookup(dst, ((u_int32_t *) spis)[i], |
670 |
|
|
proto); |
671 |
|
|
if (!sa) { |
672 |
|
|
LOG_DBG((LOG_MESSAGE, 50, "message_validate_delete: " |
673 |
|
|
"invalid spi (no valid SA found)")); |
674 |
|
|
message_free(msg); |
675 |
|
|
return -1; |
676 |
|
|
} |
677 |
|
|
sa->transport->vtbl->get_dst(sa->transport, &dst); |
678 |
|
|
|
679 |
|
|
/* Destination addresses must match. */ |
680 |
|
|
if (dst->sa_family != dst_isa->sa_family || |
681 |
|
|
memcmp(sockaddr_addrdata(dst_isa), sockaddr_addrdata(dst), |
682 |
|
|
sockaddr_addrlen(dst))) { |
683 |
|
|
sockaddr2text(dst_isa, &addr, 0); |
684 |
|
|
|
685 |
|
|
log_print("message_validate_delete: invalid spi " |
686 |
|
|
"(illegal delete request from %s)", addr); |
687 |
|
|
free(addr); |
688 |
|
|
message_free(msg); |
689 |
|
|
return -1; |
690 |
|
|
} |
691 |
|
|
} |
692 |
|
|
|
693 |
|
|
return 0; |
694 |
|
|
} |
695 |
|
|
|
696 |
|
|
/* |
697 |
|
|
* Validate the hash payload P in message MSG. |
698 |
|
|
*/ |
699 |
|
|
static int |
700 |
|
|
message_validate_hash(struct message *msg, struct payload *p) |
701 |
|
|
{ |
702 |
|
|
struct sa *isakmp_sa = msg->isakmp_sa; |
703 |
|
|
struct ipsec_sa *isa; |
704 |
|
|
struct hash *hash; |
705 |
|
|
struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); |
706 |
|
|
struct prf *prf; |
707 |
|
|
u_int8_t *rest; |
708 |
|
|
u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN]; |
709 |
|
|
size_t rest_len; |
710 |
|
|
|
711 |
|
|
/* active exchanges other than INFORMATIONAL validates hash payload. */ |
712 |
|
|
if (msg->exchange && (msg->exchange->type != ISAKMP_EXCH_INFO)) |
713 |
|
|
return 0; |
714 |
|
|
|
715 |
|
|
if (isakmp_sa == NULL) |
716 |
|
|
goto invalid; |
717 |
|
|
|
718 |
|
|
isa = isakmp_sa->data; |
719 |
|
|
hash = hash_get(isa->hash); |
720 |
|
|
if (hash == NULL) |
721 |
|
|
goto invalid; |
722 |
|
|
|
723 |
|
|
/* If no SKEYID_a, we can not do anything (should not happen). */ |
724 |
|
|
if (!isa->skeyid_a) |
725 |
|
|
goto invalid; |
726 |
|
|
|
727 |
|
|
/* Allocate the prf and start calculating our HASH(1). */ |
728 |
|
|
LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: SKEYID_a", |
729 |
|
|
isa->skeyid_a, isa->skeyid_len)); |
730 |
|
|
prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, |
731 |
|
|
isa->skeyid_len); |
732 |
|
|
if (!prf) { |
733 |
|
|
message_free(msg); |
734 |
|
|
return -1; |
735 |
|
|
} |
736 |
|
|
/* This is not an active exchange. */ |
737 |
|
|
GET_ISAKMP_HDR_MESSAGE_ID(msg->iov[0].iov_base, message_id); |
738 |
|
|
|
739 |
|
|
prf->Init(prf->prfctx); |
740 |
|
|
LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: message_id", |
741 |
|
|
message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); |
742 |
|
|
prf->Update(prf->prfctx, message_id, ISAKMP_HDR_MESSAGE_ID_LEN); |
743 |
|
|
rest = hashp->p + GET_ISAKMP_GEN_LENGTH(hashp->p); |
744 |
|
|
rest_len = (GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) - (rest - |
745 |
|
|
(u_int8_t *)msg->iov[0].iov_base)); |
746 |
|
|
LOG_DBG_BUF((LOG_MISC, 90, |
747 |
|
|
"message_validate_hash: payloads after HASH(1)", rest, rest_len)); |
748 |
|
|
prf->Update(prf->prfctx, rest, rest_len); |
749 |
|
|
prf->Final(hash->digest, prf->prfctx); |
750 |
|
|
prf_free(prf); |
751 |
|
|
|
752 |
|
|
if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, hash->digest, |
753 |
|
|
hash->hashsize)) |
754 |
|
|
goto invalid; |
755 |
|
|
|
756 |
|
|
/* Mark the HASH as handled. */ |
757 |
|
|
hashp->flags |= PL_MARK; |
758 |
|
|
|
759 |
|
|
/* Mark message as authenticated. */ |
760 |
|
|
msg->flags |= MSG_AUTHENTICATED; |
761 |
|
|
|
762 |
|
|
return 0; |
763 |
|
|
|
764 |
|
|
invalid: |
765 |
|
|
log_print("message_validate_hash: invalid hash information"); |
766 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 1); |
767 |
|
|
return -1; |
768 |
|
|
} |
769 |
|
|
|
770 |
|
|
/* Validate the identification payload P in message MSG. */ |
771 |
|
|
static int |
772 |
|
|
message_validate_id(struct message *msg, struct payload *p) |
773 |
|
|
{ |
774 |
|
|
struct exchange *exchange = msg->exchange; |
775 |
|
|
size_t len = GET_ISAKMP_GEN_LENGTH(p->p); |
776 |
|
|
|
777 |
|
|
if (!exchange) { |
778 |
|
|
/* We should have an exchange at this point. */ |
779 |
|
|
log_print("message_validate_id: payload out of sequence"); |
780 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
781 |
|
|
return -1; |
782 |
|
|
} |
783 |
|
|
if (exchange->doi && |
784 |
|
|
exchange->doi->validate_id_information(GET_ISAKMP_ID_TYPE(p->p), |
785 |
|
|
p->p + ISAKMP_ID_DOI_DATA_OFF, p->p + ISAKMP_ID_DATA_OFF, |
786 |
|
|
len - ISAKMP_ID_DATA_OFF, exchange)) { |
787 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, |
788 |
|
|
1); |
789 |
|
|
return -1; |
790 |
|
|
} |
791 |
|
|
return 0; |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
/* Validate the key exchange payload P in message MSG. */ |
795 |
|
|
static int |
796 |
|
|
message_validate_key_exch(struct message *msg, struct payload *p) |
797 |
|
|
{ |
798 |
|
|
struct exchange *exchange = msg->exchange; |
799 |
|
|
size_t len = GET_ISAKMP_GEN_LENGTH(p->p); |
800 |
|
|
|
801 |
|
|
if (!exchange) { |
802 |
|
|
/* We should have an exchange at this point. */ |
803 |
|
|
log_print("message_validate_key_exch: " |
804 |
|
|
"payload out of sequence"); |
805 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
806 |
|
|
return -1; |
807 |
|
|
} |
808 |
|
|
if (exchange->doi && exchange->doi->validate_key_information(p->p + |
809 |
|
|
ISAKMP_KE_DATA_OFF, len - ISAKMP_KE_DATA_OFF)) { |
810 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_KEY_INFORMATION, |
811 |
|
|
0, 1, 1); |
812 |
|
|
return -1; |
813 |
|
|
} |
814 |
|
|
return 0; |
815 |
|
|
} |
816 |
|
|
|
817 |
|
|
/* Validate the NAT-D payload P in message MSG. */ |
818 |
|
|
static int |
819 |
|
|
message_validate_nat_d(struct message *msg, struct payload *p) |
820 |
|
|
{ |
821 |
|
|
struct exchange *exchange = msg->exchange; |
822 |
|
|
|
823 |
|
|
if (!exchange) { |
824 |
|
|
/* We should have an exchange at this point. */ |
825 |
|
|
log_print("message_validate_nat_d: payload out of sequence"); |
826 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
827 |
|
|
return -1; |
828 |
|
|
} |
829 |
|
|
|
830 |
|
|
if (exchange->phase != 1) { |
831 |
|
|
log_print("message_validate_nat_d: " |
832 |
|
|
"NAT-D payload must be in phase 1"); |
833 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
834 |
|
|
return -1; |
835 |
|
|
} |
836 |
|
|
|
837 |
|
|
/* Mark as handled. */ |
838 |
|
|
p->flags |= PL_MARK; |
839 |
|
|
|
840 |
|
|
return 0; |
841 |
|
|
} |
842 |
|
|
|
843 |
|
|
/* Validate the NAT-OA payload P in message MSG. */ |
844 |
|
|
static int |
845 |
|
|
message_validate_nat_oa(struct message *msg, struct payload *p) |
846 |
|
|
{ |
847 |
|
|
struct exchange *exchange = msg->exchange; |
848 |
|
|
|
849 |
|
|
if (!exchange) { |
850 |
|
|
/* We should have an exchange at this point. */ |
851 |
|
|
log_print("message_validate_nat_d: payload out of sequence"); |
852 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
853 |
|
|
return -1; |
854 |
|
|
} |
855 |
|
|
|
856 |
|
|
#ifdef notyet /* XXX Probably never, due to patent issues. */ |
857 |
|
|
/* Mark as handled. */ |
858 |
|
|
p->flags |= PL_MARK; |
859 |
|
|
#endif |
860 |
|
|
|
861 |
|
|
return 0; |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
/* Validate the nonce payload P in message MSG. */ |
865 |
|
|
static int |
866 |
|
|
message_validate_nonce(struct message *msg, struct payload *p) |
867 |
|
|
{ |
868 |
|
|
if (!msg->exchange) { |
869 |
|
|
/* We should have an exchange at this point. */ |
870 |
|
|
log_print("message_validate_nonce: payload out of sequence"); |
871 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
872 |
|
|
return -1; |
873 |
|
|
} |
874 |
|
|
/* Nonces require no specific validation. */ |
875 |
|
|
return 0; |
876 |
|
|
} |
877 |
|
|
|
878 |
|
|
/* |
879 |
|
|
* Validate the notify payload P in message MSG. As a side-effect, create |
880 |
|
|
* an exchange if we do not have one already. |
881 |
|
|
*/ |
882 |
|
|
static int |
883 |
|
|
message_validate_notify(struct message *msg, struct payload *p) |
884 |
|
|
{ |
885 |
|
|
u_int8_t proto = GET_ISAKMP_NOTIFY_PROTO(p->p); |
886 |
|
|
u_int16_t type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); |
887 |
|
|
struct doi *doi; |
888 |
|
|
|
889 |
|
|
doi = doi_lookup(GET_ISAKMP_NOTIFY_DOI(p->p)); |
890 |
|
|
if (!doi) { |
891 |
|
|
log_print("message_validate_notify: DOI not supported"); |
892 |
|
|
message_free(msg); |
893 |
|
|
return -1; |
894 |
|
|
} |
895 |
|
|
/* If we don't have an exchange yet, create one. */ |
896 |
|
|
if (!msg->exchange) { |
897 |
|
|
if (zero_test((u_int8_t *) msg->iov[0].iov_base + |
898 |
|
|
ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) |
899 |
|
|
msg->exchange = exchange_setup_p1(msg, doi->id); |
900 |
|
|
else |
901 |
|
|
msg->exchange = exchange_setup_p2(msg, doi->id); |
902 |
|
|
if (!msg->exchange) { |
903 |
|
|
log_print("message_validate_notify: can not create " |
904 |
|
|
"exchange"); |
905 |
|
|
message_free(msg); |
906 |
|
|
return -1; |
907 |
|
|
} |
908 |
|
|
} |
909 |
|
|
if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) { |
910 |
|
|
log_print("message_validate_notify: protocol not supported"); |
911 |
|
|
message_free(msg); |
912 |
|
|
return -1; |
913 |
|
|
} |
914 |
|
|
|
915 |
|
|
/* Validate the SPI. XXX Just ISAKMP for now. */ |
916 |
|
|
if (proto == ISAKMP_PROTO_ISAKMP && |
917 |
|
|
GET_ISAKMP_NOTIFY_SPI_SZ(p->p) == ISAKMP_HDR_COOKIES_LEN && |
918 |
|
|
msg->isakmp_sa && |
919 |
|
|
memcmp(p->p + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, |
920 |
|
|
ISAKMP_HDR_COOKIES_LEN) != 0) { |
921 |
|
|
log_print("message_validate_notify: bad cookies"); |
922 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_SPI, 0, 1, 1); |
923 |
|
|
return -1; |
924 |
|
|
} |
925 |
|
|
|
926 |
|
|
if (type < ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE || |
927 |
|
|
(type >= ISAKMP_NOTIFY_RESERVED_MIN && |
928 |
|
|
type < ISAKMP_NOTIFY_PRIVATE_MIN) || |
929 |
|
|
(type >= ISAKMP_NOTIFY_STATUS_RESERVED1_MIN && |
930 |
|
|
type <= ISAKMP_NOTIFY_STATUS_RESERVED1_MAX) || |
931 |
|
|
(type >= ISAKMP_NOTIFY_STATUS_DOI_MIN && |
932 |
|
|
type <= ISAKMP_NOTIFY_STATUS_DOI_MAX && |
933 |
|
|
doi->validate_notification(type)) || |
934 |
|
|
type >= ISAKMP_NOTIFY_STATUS_RESERVED2_MIN) { |
935 |
|
|
log_print("message_validate_notify: " |
936 |
|
|
"message type not supported"); |
937 |
|
|
message_free(msg); |
938 |
|
|
return -1; |
939 |
|
|
} |
940 |
|
|
|
941 |
|
|
return 0; |
942 |
|
|
} |
943 |
|
|
|
944 |
|
|
/* Validate the proposal payload P in message MSG. */ |
945 |
|
|
static int |
946 |
|
|
message_validate_proposal(struct message *msg, struct payload *p) |
947 |
|
|
{ |
948 |
|
|
u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->p); |
949 |
|
|
u_int8_t *sa = p->context->p; |
950 |
|
|
|
951 |
|
|
if (!msg->exchange) { |
952 |
|
|
/* We should have an exchange at this point. */ |
953 |
|
|
log_print("message_validate_proposal: " |
954 |
|
|
"payload out of sequence"); |
955 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
956 |
|
|
return -1; |
957 |
|
|
} |
958 |
|
|
if (proto != ISAKMP_PROTO_ISAKMP && |
959 |
|
|
msg->exchange->doi->validate_proto(proto)) { |
960 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_PROTOCOL_ID, 0, 1, 1); |
961 |
|
|
return -1; |
962 |
|
|
} |
963 |
|
|
/* Check that we get monotonically increasing proposal IDs per SA. */ |
964 |
|
|
if (sa != last_sa) |
965 |
|
|
last_sa = sa; |
966 |
|
|
else if (GET_ISAKMP_PROP_NO(p->p) < last_prop_no) { |
967 |
|
|
message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1); |
968 |
|
|
return -1; |
969 |
|
|
} |
970 |
|
|
last_prop_no = GET_ISAKMP_PROP_NO(p->p); |
971 |
|
|
|
972 |
|
|
/* XXX Validate the SPI, and other syntactic things. */ |
973 |
|
|
|
974 |
|
|
return 0; |
975 |
|
|
} |
976 |
|
|
|
977 |
|
|
/* |
978 |
|
|
* Validate the SA payload P in message MSG. |
979 |
|
|
* Aside from normal validation, note what DOI is in use for other |
980 |
|
|
* validation routines to look at. Also index the proposal payloads |
981 |
|
|
* on the fly. |
982 |
|
|
* XXX This assumes PAYLOAD_SA is always the first payload |
983 |
|
|
* to be validated, which is true for IKE, except for quick mode where |
984 |
|
|
* a PAYLOAD_HASH comes first, but in that specific case it does not matter. |
985 |
|
|
* XXX Make sure the above comment is relevant, isn't SA always checked |
986 |
|
|
* first due to the IANA assigned payload number? |
987 |
|
|
*/ |
988 |
|
|
static int |
989 |
|
|
message_validate_sa(struct message *msg, struct payload *p) |
990 |
|
|
{ |
991 |
|
|
set payload_set; |
992 |
|
|
size_t len; |
993 |
|
|
u_int32_t doi_id; |
994 |
|
|
struct exchange *exchange = msg->exchange; |
995 |
|
|
u_int8_t *pkt = msg->iov[0].iov_base; |
996 |
|
|
|
997 |
|
|
doi_id = GET_ISAKMP_SA_DOI(p->p); |
998 |
|
|
if (!doi_lookup(doi_id)) { |
999 |
|
|
log_print("message_validate_sa: DOI not supported"); |
1000 |
|
|
message_drop(msg, ISAKMP_NOTIFY_DOI_NOT_SUPPORTED, 0, 1, 1); |
1001 |
|
|
return -1; |
1002 |
|
|
} |
1003 |
|
|
/* |
1004 |
|
|
* It's time to figure out what SA this message is about. If it is |
1005 |
|
|
* already set, then we are creating a new phase 1 SA. Otherwise, |
1006 |
|
|
* lookup the SA using the cookies and the message ID. If we cannot |
1007 |
|
|
* find it, and the phase 1 SA is ready, setup a phase 2 SA. |
1008 |
|
|
*/ |
1009 |
|
|
if (!exchange) { |
1010 |
|
|
if (zero_test(pkt + ISAKMP_HDR_RCOOKIE_OFF, |
1011 |
|
|
ISAKMP_HDR_RCOOKIE_LEN)) |
1012 |
|
|
exchange = exchange_setup_p1(msg, doi_id); |
1013 |
|
|
else if (msg->isakmp_sa->flags & SA_FLAG_READY) |
1014 |
|
|
exchange = exchange_setup_p2(msg, doi_id); |
1015 |
|
|
else { |
1016 |
|
|
/* XXX What to do here? */ |
1017 |
|
|
message_free(msg); |
1018 |
|
|
return -1; |
1019 |
|
|
} |
1020 |
|
|
if (!exchange) { |
1021 |
|
|
/* XXX Log? */ |
1022 |
|
|
message_free(msg); |
1023 |
|
|
return -1; |
1024 |
|
|
} |
1025 |
|
|
} |
1026 |
|
|
msg->exchange = exchange; |
1027 |
|
|
|
1028 |
|
|
/* |
1029 |
|
|
* Create a struct sa for each SA payload handed to us unless we are |
1030 |
|
|
* the initiator where we only will count them. |
1031 |
|
|
*/ |
1032 |
|
|
if (exchange->initiator) { |
1033 |
|
|
/* XXX Count SA payloads. */ |
1034 |
|
|
} else if (sa_create(exchange, msg->transport)) { |
1035 |
|
|
/* XXX Remove exchange if we just created it? */ |
1036 |
|
|
message_free(msg); |
1037 |
|
|
return -1; |
1038 |
|
|
} |
1039 |
|
|
if (exchange->phase == 1) { |
1040 |
|
|
msg->isakmp_sa = TAILQ_FIRST(&exchange->sa_list); |
1041 |
|
|
if (msg->isakmp_sa) |
1042 |
|
|
sa_reference(msg->isakmp_sa); |
1043 |
|
|
} |
1044 |
|
|
/* |
1045 |
|
|
* Let the DOI validate the situation, at the same time it tells us |
1046 |
|
|
* what the length of the situation field is. |
1047 |
|
|
*/ |
1048 |
|
|
if (exchange->doi->validate_situation(p->p + ISAKMP_SA_SIT_OFF, &len, |
1049 |
|
|
GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SA_SIT_OFF)) { |
1050 |
|
|
log_print("message_validate_sa: situation not supported"); |
1051 |
|
|
message_drop(msg, ISAKMP_NOTIFY_SITUATION_NOT_SUPPORTED, |
1052 |
|
|
0, 1, 1); |
1053 |
|
|
return -1; |
1054 |
|
|
} |
1055 |
|
|
/* |
1056 |
|
|
* Reset the fields we base our proposal & transform number checks |
1057 |
|
|
* on. |
1058 |
|
|
*/ |
1059 |
|
|
last_sa = last_prop = 0; |
1060 |
|
|
last_prop_no = last_xf_no = 0; |
1061 |
|
|
|
1062 |
|
|
/* Go through the PROPOSAL payloads. */ |
1063 |
|
|
ZERO(&payload_set); |
1064 |
|
|
SET(ISAKMP_PAYLOAD_PROPOSAL, &payload_set); |
1065 |
|
|
if (message_parse_payloads(msg, p, ISAKMP_PAYLOAD_PROPOSAL, |
1066 |
|
|
p->p + ISAKMP_SA_SIT_OFF + len, &payload_set, |
1067 |
|
|
message_parse_proposal) == -1) |
1068 |
|
|
return -1; |
1069 |
|
|
|
1070 |
|
|
return 0; |
1071 |
|
|
} |
1072 |
|
|
|
1073 |
|
|
/* Validate the signature payload P in message MSG. */ |
1074 |
|
|
static int |
1075 |
|
|
message_validate_sig(struct message *msg, struct payload *p) |
1076 |
|
|
{ |
1077 |
|
|
if (!msg->exchange) { |
1078 |
|
|
/* We should have an exchange at this point. */ |
1079 |
|
|
log_print("message_validate_sig: payload out of sequence"); |
1080 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
1081 |
|
|
return -1; |
1082 |
|
|
} |
1083 |
|
|
/* XXX Not implemented yet. */ |
1084 |
|
|
return 0; |
1085 |
|
|
} |
1086 |
|
|
|
1087 |
|
|
/* Validate the transform payload P in message MSG. */ |
1088 |
|
|
static int |
1089 |
|
|
message_validate_transform(struct message *msg, struct payload *p) |
1090 |
|
|
{ |
1091 |
|
|
u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->context->p); |
1092 |
|
|
u_int8_t *prop = p->context->p; |
1093 |
|
|
|
1094 |
|
|
if (!msg->exchange) { |
1095 |
|
|
/* We should have an exchange at this point. */ |
1096 |
|
|
log_print("message_validate_transform: " |
1097 |
|
|
"payload out of sequence"); |
1098 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
1099 |
|
|
return -1; |
1100 |
|
|
} |
1101 |
|
|
if (msg->exchange->doi |
1102 |
|
|
->validate_transform_id(proto, GET_ISAKMP_TRANSFORM_ID(p->p))) { |
1103 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_TRANSFORM_ID, 0, 1, 1); |
1104 |
|
|
return -1; |
1105 |
|
|
} |
1106 |
|
|
/* Check that the reserved field is zero. */ |
1107 |
|
|
if (!zero_test(p->p + ISAKMP_TRANSFORM_RESERVED_OFF, |
1108 |
|
|
ISAKMP_TRANSFORM_RESERVED_LEN)) { |
1109 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
1110 |
|
|
return -1; |
1111 |
|
|
} |
1112 |
|
|
/* |
1113 |
|
|
* Check that we get monotonically increasing transform numbers per |
1114 |
|
|
* proposal. |
1115 |
|
|
*/ |
1116 |
|
|
if (prop != last_prop) |
1117 |
|
|
last_prop = prop; |
1118 |
|
|
else if (GET_ISAKMP_TRANSFORM_NO(p->p) <= last_xf_no) { |
1119 |
|
|
message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1); |
1120 |
|
|
return -1; |
1121 |
|
|
} |
1122 |
|
|
last_xf_no = GET_ISAKMP_TRANSFORM_NO(p->p); |
1123 |
|
|
|
1124 |
|
|
/* Validate the attributes. */ |
1125 |
|
|
if (attribute_map(p->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
1126 |
|
|
GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
1127 |
|
|
msg->exchange->doi->validate_attribute, msg)) { |
1128 |
|
|
message_drop(msg, ISAKMP_NOTIFY_ATTRIBUTES_NOT_SUPPORTED, |
1129 |
|
|
0, 1, 1); |
1130 |
|
|
return -1; |
1131 |
|
|
} |
1132 |
|
|
return 0; |
1133 |
|
|
} |
1134 |
|
|
|
1135 |
|
|
/* Validate the vendor payload P in message MSG. */ |
1136 |
|
|
static int |
1137 |
|
|
message_validate_vendor(struct message *msg, struct payload *p) |
1138 |
|
|
{ |
1139 |
|
|
if (!msg->exchange) { |
1140 |
|
|
/* We should have an exchange at this point. */ |
1141 |
|
|
log_print("message_validate_vendor: payload out of sequence"); |
1142 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
1143 |
|
|
return -1; |
1144 |
|
|
} |
1145 |
|
|
/* Vendor IDs are only allowed in phase 1. */ |
1146 |
|
|
if (msg->exchange->phase != 1) { |
1147 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); |
1148 |
|
|
return -1; |
1149 |
|
|
} |
1150 |
|
|
check_vendor_openbsd(msg, p); |
1151 |
|
|
dpd_check_vendor_payload(msg, p); |
1152 |
|
|
nat_t_check_vendor_payload(msg, p); |
1153 |
|
|
if (!(p->flags & PL_MARK)) |
1154 |
|
|
LOG_DBG((LOG_MESSAGE, 40, "message_validate_vendor: " |
1155 |
|
|
"vendor ID seen")); |
1156 |
|
|
return 0; |
1157 |
|
|
} |
1158 |
|
|
|
1159 |
|
|
/* |
1160 |
|
|
* Add an index-record pointing to the payload at BUF in message MSG |
1161 |
|
|
* to the PAYLOAD bucket of payloads. This allows us to quickly reference |
1162 |
|
|
* payloads by type. Also stash the parent payload P link into the new |
1163 |
|
|
* node so we can go from transforms -> payloads -> SAs. |
1164 |
|
|
*/ |
1165 |
|
|
static int |
1166 |
|
|
message_index_payload(struct message *msg, struct payload *p, u_int8_t payload, |
1167 |
|
|
u_int8_t *buf) |
1168 |
|
|
{ |
1169 |
|
|
struct payload *payload_node; |
1170 |
|
|
|
1171 |
|
|
/* Put the payload pointer into the right bucket. */ |
1172 |
|
|
payload_node = malloc(sizeof *payload_node); |
1173 |
|
|
if (!payload_node) { |
1174 |
|
|
message_free(msg); |
1175 |
|
|
return -1; |
1176 |
|
|
} |
1177 |
|
|
payload_node->p = buf; |
1178 |
|
|
payload_node->context = p; |
1179 |
|
|
payload_node->flags = 0; |
1180 |
|
|
TAILQ_INSERT_TAIL(&msg->payload[payload], payload_node, link); |
1181 |
|
|
return 0; |
1182 |
|
|
} |
1183 |
|
|
|
1184 |
|
|
/* |
1185 |
|
|
* Group each payload found in MSG by type for easy reference later. |
1186 |
|
|
* While doing this, validate the generic parts of the message structure too. |
1187 |
|
|
* NEXT is the 1st payload's type. This routine will also register the |
1188 |
|
|
* computed message length (i.e. without padding) in msg->iov[0].iov_len. |
1189 |
|
|
*/ |
1190 |
|
|
static int |
1191 |
|
|
message_sort_payloads(struct message *msg, u_int8_t next) |
1192 |
|
|
{ |
1193 |
|
|
set payload_set; |
1194 |
|
|
int i, sz; |
1195 |
|
|
|
1196 |
|
|
ZERO(&payload_set); |
1197 |
|
|
for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_MAX; i++) |
1198 |
|
|
if (i != ISAKMP_PAYLOAD_PROPOSAL && i != |
1199 |
|
|
ISAKMP_PAYLOAD_TRANSFORM) |
1200 |
|
|
SET(i, &payload_set); |
1201 |
|
|
sz = message_parse_payloads(msg, 0, next, |
1202 |
|
|
(u_int8_t *)msg->iov[0].iov_base + ISAKMP_HDR_SZ, &payload_set, |
1203 |
|
|
message_index_payload); |
1204 |
|
|
if (sz == -1) |
1205 |
|
|
return -1; |
1206 |
|
|
msg->iov[0].iov_len = ISAKMP_HDR_SZ + sz; |
1207 |
|
|
SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz); |
1208 |
|
|
return 0; |
1209 |
|
|
} |
1210 |
|
|
|
1211 |
|
|
/* Run all the generic payload tests that the drafts specify. */ |
1212 |
|
|
static int |
1213 |
|
|
message_validate_payloads(struct message *msg) |
1214 |
|
|
{ |
1215 |
|
|
int i; |
1216 |
|
|
struct payload *p; |
1217 |
|
|
struct field *f; |
1218 |
|
|
|
1219 |
|
|
for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_MAX; i++) |
1220 |
|
|
TAILQ_FOREACH(p, &msg->payload[i], link) { |
1221 |
|
|
LOG_DBG((LOG_MESSAGE, 60, "message_validate_payloads: " |
1222 |
|
|
"payload %s at %p of message %p", |
1223 |
|
|
constant_name(isakmp_payload_cst, i), p->p, msg)); |
1224 |
|
|
if ((f = message_get_field(i)) != NULL) |
1225 |
|
|
field_dump_payload(f, p->p); |
1226 |
|
|
if (message_validate_payload(msg, p, i)) |
1227 |
|
|
return -1; |
1228 |
|
|
} |
1229 |
|
|
return 0; |
1230 |
|
|
} |
1231 |
|
|
|
1232 |
|
|
/* |
1233 |
|
|
* All incoming messages go through here. We do generic validity checks |
1234 |
|
|
* and try to find or establish SAs. Last but not least we try to find |
1235 |
|
|
* the exchange this message, MSG, is part of, and feed it there. |
1236 |
|
|
*/ |
1237 |
|
|
int |
1238 |
|
|
message_recv(struct message *msg) |
1239 |
|
|
{ |
1240 |
|
|
u_int8_t *buf = msg->iov[0].iov_base; |
1241 |
|
|
size_t sz = msg->iov[0].iov_len; |
1242 |
|
|
u_int8_t exch_type; |
1243 |
|
|
int setup_isakmp_sa, msgid_is_zero; |
1244 |
|
|
u_int8_t flags; |
1245 |
|
|
struct keystate *ks = 0; |
1246 |
|
|
struct proto tmp_proto; |
1247 |
|
|
struct sa tmp_sa; |
1248 |
|
|
struct transport *t; |
1249 |
|
|
|
1250 |
|
|
/* Messages shorter than an ISAKMP header are bad. */ |
1251 |
|
|
if (sz < ISAKMP_HDR_SZ || sz != GET_ISAKMP_HDR_LENGTH(buf)) { |
1252 |
|
|
log_print("message_recv: bad message length"); |
1253 |
|
|
message_drop(msg, 0, 0, 1, 1); |
1254 |
|
|
return -1; |
1255 |
|
|
} |
1256 |
|
|
/* Possibly dump a raw hex image of the message to the log channel. */ |
1257 |
|
|
message_dump_raw("message_recv", msg, LOG_MESSAGE); |
1258 |
|
|
|
1259 |
|
|
/* |
1260 |
|
|
* If the responder cookie is zero, this is a request to setup an |
1261 |
|
|
* ISAKMP SA. Otherwise the cookies should refer to an existing |
1262 |
|
|
* ISAKMP SA. |
1263 |
|
|
* |
1264 |
|
|
* XXX This is getting ugly, please reread later to see if it can be |
1265 |
|
|
* made nicer. |
1266 |
|
|
*/ |
1267 |
|
|
setup_isakmp_sa = zero_test(buf + ISAKMP_HDR_RCOOKIE_OFF, |
1268 |
|
|
ISAKMP_HDR_RCOOKIE_LEN); |
1269 |
|
|
if (setup_isakmp_sa) { |
1270 |
|
|
/* |
1271 |
|
|
* This might be a retransmission of a former ISAKMP SA setup |
1272 |
|
|
* message. If so, just drop it. |
1273 |
|
|
* XXX Must we really look in both the SA and exchange pools? |
1274 |
|
|
*/ |
1275 |
|
|
if (exchange_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF) || |
1276 |
|
|
sa_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF)) { |
1277 |
|
|
/* |
1278 |
|
|
* XXX Later we should differentiate between |
1279 |
|
|
* retransmissions and potential replay attacks. |
1280 |
|
|
*/ |
1281 |
|
|
LOG_DBG((LOG_MESSAGE, 90, |
1282 |
|
|
"message_recv: dropping setup for existing SA")); |
1283 |
|
|
message_free(msg); |
1284 |
|
|
return -1; |
1285 |
|
|
} |
1286 |
|
|
} else { |
1287 |
|
|
msg->isakmp_sa = sa_lookup_by_header(buf, 0); |
1288 |
|
|
if (msg->isakmp_sa) |
1289 |
|
|
sa_reference(msg->isakmp_sa); |
1290 |
|
|
|
1291 |
|
|
/* |
1292 |
|
|
* If we cannot find an ISAKMP SA out of the cookies, this is |
1293 |
|
|
* either a responder's first reply, and we need to upgrade |
1294 |
|
|
* our exchange, or it's just plain invalid cookies. |
1295 |
|
|
*/ |
1296 |
|
|
if (!msg->isakmp_sa) { |
1297 |
|
|
msg->exchange = exchange_lookup_from_icookie(buf + |
1298 |
|
|
ISAKMP_HDR_ICOOKIE_OFF); |
1299 |
|
|
if (msg->exchange && msg->exchange->phase == 1 && |
1300 |
|
|
zero_test(msg->exchange->cookies + |
1301 |
|
|
ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN)) |
1302 |
|
|
exchange_upgrade_p1(msg); |
1303 |
|
|
else { |
1304 |
|
|
log_print("message_recv: invalid cookie(s) " |
1305 |
|
|
"%08x%08x %08x%08x", |
1306 |
|
|
decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF), |
1307 |
|
|
decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF + 4), |
1308 |
|
|
decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF), |
1309 |
|
|
decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF + 4)); |
1310 |
|
|
tmp_proto.sa = &tmp_sa; |
1311 |
|
|
tmp_sa.doi = doi_lookup(ISAKMP_DOI_ISAKMP); |
1312 |
|
|
tmp_proto.proto = ISAKMP_PROTO_ISAKMP; |
1313 |
|
|
tmp_proto.spi_sz[1] = ISAKMP_HDR_COOKIES_LEN; |
1314 |
|
|
tmp_proto.spi[1] = |
1315 |
|
|
buf + ISAKMP_HDR_COOKIES_OFF; |
1316 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_COOKIE, |
1317 |
|
|
&tmp_proto, 1, 1); |
1318 |
|
|
return -1; |
1319 |
|
|
} |
1320 |
|
|
#if 0 |
1321 |
|
|
msg->isakmp_sa = sa_lookup_from_icookie(buf + |
1322 |
|
|
ISAKMP_HDR_ICOOKIE_OFF); |
1323 |
|
|
if (msg->isakmp_sa) |
1324 |
|
|
sa_isakmp_upgrade(msg); |
1325 |
|
|
#endif |
1326 |
|
|
} |
1327 |
|
|
msg->exchange = exchange_lookup(buf, 1); |
1328 |
|
|
} |
1329 |
|
|
|
1330 |
|
|
if (message_check_duplicate(msg)) |
1331 |
|
|
return -1; |
1332 |
|
|
|
1333 |
|
|
if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) >= ISAKMP_PAYLOAD_RESERVED_MIN) { |
1334 |
|
|
log_print("message_recv: invalid payload type %d in ISAKMP " |
1335 |
|
|
"header (check passphrases, if applicable and in Phase 1)", |
1336 |
|
|
GET_ISAKMP_HDR_NEXT_PAYLOAD(buf)); |
1337 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); |
1338 |
|
|
return -1; |
1339 |
|
|
} |
1340 |
|
|
/* Validate that the message is of version 1.0. */ |
1341 |
|
|
if (ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf)) != 1) { |
1342 |
|
|
log_print("message_recv: invalid version major %d", |
1343 |
|
|
ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf))); |
1344 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_MAJOR_VERSION, 0, 1, |
1345 |
|
|
1); |
1346 |
|
|
return -1; |
1347 |
|
|
} |
1348 |
|
|
if (ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf)) != 0) { |
1349 |
|
|
log_print("message_recv: invalid version minor %d", |
1350 |
|
|
ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf))); |
1351 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_MINOR_VERSION, 0, 1, |
1352 |
|
|
1); |
1353 |
|
|
return -1; |
1354 |
|
|
} |
1355 |
|
|
/* |
1356 |
|
|
* Validate the exchange type. If it's a DOI-specified exchange wait |
1357 |
|
|
* until after all payloads have been seen for the validation as the |
1358 |
|
|
* SA payload might not yet have been parsed, thus the DOI might be |
1359 |
|
|
* unknown. |
1360 |
|
|
*/ |
1361 |
|
|
exch_type = GET_ISAKMP_HDR_EXCH_TYPE(buf); |
1362 |
|
|
if (exch_type == ISAKMP_EXCH_NONE || |
1363 |
|
|
(exch_type >= ISAKMP_EXCH_FUTURE_MIN && |
1364 |
|
|
exch_type <= ISAKMP_EXCH_FUTURE_MAX) || |
1365 |
|
|
(setup_isakmp_sa && exch_type >= ISAKMP_EXCH_DOI_MIN)) { |
1366 |
|
|
log_print("message_recv: invalid exchange type %s", |
1367 |
|
|
constant_name(isakmp_exch_cst, exch_type)); |
1368 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1, |
1369 |
|
|
1); |
1370 |
|
|
return -1; |
1371 |
|
|
} |
1372 |
|
|
/* |
1373 |
|
|
* Check for unrecognized flags, or the encryption flag when we don't |
1374 |
|
|
* have an ISAKMP SA to decrypt with. |
1375 |
|
|
*/ |
1376 |
|
|
flags = GET_ISAKMP_HDR_FLAGS(buf); |
1377 |
|
|
if (flags & ~(ISAKMP_FLAGS_ENC | ISAKMP_FLAGS_COMMIT | |
1378 |
|
|
ISAKMP_FLAGS_AUTH_ONLY)) { |
1379 |
|
|
log_print("message_recv: invalid flags 0x%x", |
1380 |
|
|
GET_ISAKMP_HDR_FLAGS(buf)); |
1381 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1); |
1382 |
|
|
return -1; |
1383 |
|
|
} |
1384 |
|
|
/* |
1385 |
|
|
* If we are about to setup an ISAKMP SA, the message ID must be |
1386 |
|
|
* zero. |
1387 |
|
|
*/ |
1388 |
|
|
msgid_is_zero = zero_test(buf + ISAKMP_HDR_MESSAGE_ID_OFF, |
1389 |
|
|
ISAKMP_HDR_MESSAGE_ID_LEN); |
1390 |
|
|
if (setup_isakmp_sa && !msgid_is_zero) { |
1391 |
|
|
log_print("message_recv: invalid message id"); |
1392 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_MESSAGE_ID, 0, 1, 1); |
1393 |
|
|
return -1; |
1394 |
|
|
} |
1395 |
|
|
if (!setup_isakmp_sa && msgid_is_zero) { |
1396 |
|
|
/* |
1397 |
|
|
* XXX Very likely redundant, look at the else clause of the |
1398 |
|
|
* if (setup_isakmp_sa) statement above. |
1399 |
|
|
*/ |
1400 |
|
|
msg->exchange = exchange_lookup(buf, 0); |
1401 |
|
|
if (!msg->exchange) { |
1402 |
|
|
log_print("message_recv: phase 1 message after " |
1403 |
|
|
"ISAKMP SA is ready"); |
1404 |
|
|
message_free(msg); |
1405 |
|
|
return -1; |
1406 |
|
|
} else if (msg->exchange->last_sent) { |
1407 |
|
|
LOG_DBG((LOG_MESSAGE, 80, "message_recv: resending " |
1408 |
|
|
"last message from phase 1")); |
1409 |
|
|
message_send(msg->exchange->last_sent); |
1410 |
|
|
} |
1411 |
|
|
} |
1412 |
|
|
if (flags & ISAKMP_FLAGS_ENC) { |
1413 |
|
|
if (!msg->isakmp_sa) { |
1414 |
|
|
LOG_DBG((LOG_MISC, 10, "message_recv: no isakmp_sa " |
1415 |
|
|
"for encrypted message")); |
1416 |
|
|
message_free(msg); |
1417 |
|
|
return -1; |
1418 |
|
|
} |
1419 |
|
|
/* Decrypt rest of message using a DOI-specified IV. */ |
1420 |
|
|
ks = msg->isakmp_sa->doi->get_keystate(msg); |
1421 |
|
|
if (!ks) { |
1422 |
|
|
message_free(msg); |
1423 |
|
|
return -1; |
1424 |
|
|
} |
1425 |
|
|
msg->orig = malloc(sz); |
1426 |
|
|
if (!msg->orig) { |
1427 |
|
|
message_free(msg); |
1428 |
|
|
free(ks); |
1429 |
|
|
return -1; |
1430 |
|
|
} |
1431 |
|
|
memcpy(msg->orig, buf, sz); |
1432 |
|
|
crypto_decrypt(ks, buf + ISAKMP_HDR_SZ, sz - ISAKMP_HDR_SZ); |
1433 |
|
|
} else |
1434 |
|
|
msg->orig = buf; |
1435 |
|
|
msg->orig_sz = sz; |
1436 |
|
|
|
1437 |
|
|
/* IKE packet capture */ |
1438 |
|
|
message_packet_log(msg); |
1439 |
|
|
|
1440 |
|
|
/* |
1441 |
|
|
* Check the overall payload structure at the same time as indexing |
1442 |
|
|
* them by type. |
1443 |
|
|
*/ |
1444 |
|
|
if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) != ISAKMP_PAYLOAD_NONE && |
1445 |
|
|
message_sort_payloads(msg, GET_ISAKMP_HDR_NEXT_PAYLOAD(buf))) { |
1446 |
|
|
free(ks); |
1447 |
|
|
return -1; |
1448 |
|
|
} |
1449 |
|
|
/* |
1450 |
|
|
* Run generic payload tests now. If anything fails these checks, the |
1451 |
|
|
* message needs either to be retained for later duplicate checks or |
1452 |
|
|
* freed entirely. |
1453 |
|
|
* XXX Should SAs and even transports be cleaned up then too? |
1454 |
|
|
*/ |
1455 |
|
|
if (message_validate_payloads(msg)) { |
1456 |
|
|
free(ks); |
1457 |
|
|
return -1; |
1458 |
|
|
} |
1459 |
|
|
/* |
1460 |
|
|
* If we have not found an exchange by now something is definitely |
1461 |
|
|
* wrong. |
1462 |
|
|
*/ |
1463 |
|
|
if (!msg->exchange) { |
1464 |
|
|
log_print("message_recv: no exchange"); |
1465 |
|
|
message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); |
1466 |
|
|
free(ks); |
1467 |
|
|
return -1; |
1468 |
|
|
} |
1469 |
|
|
/* |
1470 |
|
|
* NAT-T may have switched ports for us. We need to replace the |
1471 |
|
|
* old ISAKMP SA transport here with one that contains the proper |
1472 |
|
|
* (i.e translated) ports. |
1473 |
|
|
*/ |
1474 |
|
|
if (msg->isakmp_sa && msg->exchange->phase == 1) { |
1475 |
|
|
t = msg->isakmp_sa->transport; |
1476 |
|
|
msg->isakmp_sa->transport = msg->transport; |
1477 |
|
|
transport_reference(msg->transport); |
1478 |
|
|
transport_release(t); |
1479 |
|
|
} |
1480 |
|
|
|
1481 |
|
|
/* |
1482 |
|
|
* Now we can validate DOI-specific exchange types. If we have no SA |
1483 |
|
|
* DOI-specific exchange types are definitely wrong. |
1484 |
|
|
*/ |
1485 |
|
|
if (exch_type >= ISAKMP_EXCH_DOI_MIN && |
1486 |
|
|
msg->exchange->doi->validate_exchange(exch_type)) { |
1487 |
|
|
log_print("message_recv: invalid DOI exchange type %d", |
1488 |
|
|
exch_type); |
1489 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1, |
1490 |
|
|
1); |
1491 |
|
|
free(ks); |
1492 |
|
|
return -1; |
1493 |
|
|
} |
1494 |
|
|
/* Make sure the IV we used gets saved in the proper SA. */ |
1495 |
|
|
if (ks) { |
1496 |
|
|
if (!msg->exchange->keystate) { |
1497 |
|
|
msg->exchange->keystate = ks; |
1498 |
|
|
msg->exchange->crypto = ks->xf; |
1499 |
|
|
} else |
1500 |
|
|
free(ks); |
1501 |
|
|
} |
1502 |
|
|
/* Handle the flags. */ |
1503 |
|
|
if (flags & ISAKMP_FLAGS_ENC) |
1504 |
|
|
msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; |
1505 |
|
|
if ((msg->exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0 && |
1506 |
|
|
(flags & ISAKMP_FLAGS_COMMIT)) |
1507 |
|
|
msg->exchange->flags |= EXCHANGE_FLAG_HE_COMMITTED; |
1508 |
|
|
|
1509 |
|
|
/* |
1510 |
|
|
* Except for the 3rd Aggressive Mode message, require encryption |
1511 |
|
|
* as soon as we have the keystate for it. |
1512 |
|
|
*/ |
1513 |
|
|
if ((flags & ISAKMP_FLAGS_ENC) == 0 && |
1514 |
|
|
(msg->exchange->phase == 2 || |
1515 |
|
|
(msg->exchange->keystate && |
1516 |
|
|
msg->exchange->type != ISAKMP_EXCH_AGGRESSIVE))) { |
1517 |
|
|
log_print("message_recv: cleartext phase %d message", |
1518 |
|
|
msg->exchange->phase); |
1519 |
|
|
message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1); |
1520 |
|
|
return -1; |
1521 |
|
|
} |
1522 |
|
|
|
1523 |
|
|
/* OK let the exchange logic do the rest. */ |
1524 |
|
|
exchange_run(msg); |
1525 |
|
|
|
1526 |
|
|
return 0; |
1527 |
|
|
} |
1528 |
|
|
|
1529 |
|
|
void |
1530 |
|
|
message_send_expire(struct message *msg) |
1531 |
|
|
{ |
1532 |
|
|
msg->retrans = 0; |
1533 |
|
|
|
1534 |
|
|
message_send(msg); |
1535 |
|
|
} |
1536 |
|
|
|
1537 |
|
|
/* Queue up message MSG for transmittal. */ |
1538 |
|
|
void |
1539 |
|
|
message_send(struct message *msg) |
1540 |
|
|
{ |
1541 |
|
|
struct exchange *exchange = msg->exchange; |
1542 |
|
|
struct message *m; |
1543 |
|
|
struct msg_head *q; |
1544 |
|
|
|
1545 |
|
|
/* Remove retransmissions on this message */ |
1546 |
|
|
if (msg->retrans) { |
1547 |
|
|
timer_remove_event(msg->retrans); |
1548 |
|
|
msg->retrans = 0; |
1549 |
|
|
} |
1550 |
|
|
/* IKE packet capture */ |
1551 |
|
|
message_packet_log(msg); |
1552 |
|
|
|
1553 |
|
|
/* |
1554 |
|
|
* If the ISAKMP SA has set up encryption, encrypt the message. |
1555 |
|
|
* However, in a retransmit, it is already encrypted. |
1556 |
|
|
*/ |
1557 |
|
|
if ((msg->flags & MSG_ENCRYPTED) == 0 && |
1558 |
|
|
exchange->flags & EXCHANGE_FLAG_ENCRYPT) { |
1559 |
|
|
if (!exchange->keystate) { |
1560 |
|
|
exchange->keystate = exchange->doi->get_keystate(msg); |
1561 |
|
|
if (!exchange->keystate) |
1562 |
|
|
return; |
1563 |
|
|
exchange->crypto = exchange->keystate->xf; |
1564 |
|
|
exchange->flags |= EXCHANGE_FLAG_ENCRYPT; |
1565 |
|
|
} |
1566 |
|
|
if (message_encrypt(msg)) { |
1567 |
|
|
/* XXX Log. */ |
1568 |
|
|
return; |
1569 |
|
|
} |
1570 |
|
|
} |
1571 |
|
|
/* Keep the COMMIT bit on. */ |
1572 |
|
|
if (exchange->flags & EXCHANGE_FLAG_COMMITTED) |
1573 |
|
|
SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base, |
1574 |
|
|
GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base) |
1575 |
|
|
| ISAKMP_FLAGS_COMMIT); |
1576 |
|
|
|
1577 |
|
|
message_dump_raw("message_send", msg, LOG_MESSAGE); |
1578 |
|
|
msg->flags |= MSG_IN_TRANSIT; |
1579 |
|
|
exchange->in_transit = msg; |
1580 |
|
|
|
1581 |
|
|
/* |
1582 |
|
|
* If we get a retransmission of a message before our response |
1583 |
|
|
* has left the queue, don't queue it again, as it will result |
1584 |
|
|
* in a circular list. |
1585 |
|
|
*/ |
1586 |
|
|
q = msg->transport->vtbl->get_queue(msg); |
1587 |
|
|
for (m = TAILQ_FIRST(q); m; m = TAILQ_NEXT(m, link)) |
1588 |
|
|
if (m == msg) { |
1589 |
|
|
LOG_DBG((LOG_MESSAGE, 60, |
1590 |
|
|
"message_send: msg %p already on sendq %p", m, q)); |
1591 |
|
|
return; |
1592 |
|
|
} |
1593 |
|
|
TAILQ_INSERT_TAIL(q, msg, link); |
1594 |
|
|
} |
1595 |
|
|
|
1596 |
|
|
/* |
1597 |
|
|
* Setup the ISAKMP message header for message MSG. EXCHANGE is the exchange |
1598 |
|
|
* type, FLAGS are the ISAKMP header flags and MSG_ID is message ID |
1599 |
|
|
* identifying the exchange. |
1600 |
|
|
*/ |
1601 |
|
|
void |
1602 |
|
|
message_setup_header(struct message *msg, u_int8_t exchange, u_int8_t flags, |
1603 |
|
|
u_int8_t *msg_id) |
1604 |
|
|
{ |
1605 |
|
|
u_int8_t *buf = msg->iov[0].iov_base; |
1606 |
|
|
|
1607 |
|
|
SET_ISAKMP_HDR_ICOOKIE(buf, msg->exchange->cookies); |
1608 |
|
|
SET_ISAKMP_HDR_RCOOKIE(buf, msg->exchange->cookies + |
1609 |
|
|
ISAKMP_HDR_ICOOKIE_LEN); |
1610 |
|
|
SET_ISAKMP_HDR_NEXT_PAYLOAD(buf, ISAKMP_PAYLOAD_NONE); |
1611 |
|
|
SET_ISAKMP_HDR_VERSION(buf, ISAKMP_VERSION_MAKE(1, 0)); |
1612 |
|
|
SET_ISAKMP_HDR_EXCH_TYPE(buf, exchange); |
1613 |
|
|
SET_ISAKMP_HDR_FLAGS(buf, flags); |
1614 |
|
|
SET_ISAKMP_HDR_MESSAGE_ID(buf, msg_id); |
1615 |
|
|
SET_ISAKMP_HDR_LENGTH(buf, msg->iov[0].iov_len); |
1616 |
|
|
} |
1617 |
|
|
|
1618 |
|
|
/* |
1619 |
|
|
* Add the payload of type PAYLOAD in BUF sized SZ to the MSG message. |
1620 |
|
|
* The caller thereby is released from the responsibility of freeing BUF, |
1621 |
|
|
* unless we return a failure of course. If LINK is set the former |
1622 |
|
|
* payload's "next payload" field to PAYLOAD. |
1623 |
|
|
* |
1624 |
|
|
* XXX We might want to resize the iov array several slots at a time. |
1625 |
|
|
*/ |
1626 |
|
|
int |
1627 |
|
|
message_add_payload(struct message *msg, u_int8_t payload, u_int8_t *buf, |
1628 |
|
|
size_t sz, int link) |
1629 |
|
|
{ |
1630 |
|
|
struct iovec *new_iov; |
1631 |
|
|
struct payload *payload_node; |
1632 |
|
|
|
1633 |
|
|
payload_node = calloc(1, sizeof *payload_node); |
1634 |
|
|
if (!payload_node) { |
1635 |
|
|
log_error("message_add_payload: calloc (1, %lu) failed", |
1636 |
|
|
(unsigned long)sizeof *payload_node); |
1637 |
|
|
return -1; |
1638 |
|
|
} |
1639 |
|
|
new_iov = reallocarray(msg->iov, msg->iovlen + 1, |
1640 |
|
|
sizeof *msg->iov); |
1641 |
|
|
if (!new_iov) { |
1642 |
|
|
log_error("message_add_payload: realloc (%p, %lu) failed", |
1643 |
|
|
msg->iov, (msg->iovlen + 1) * |
1644 |
|
|
(unsigned long)sizeof *msg->iov); |
1645 |
|
|
free(payload_node); |
1646 |
|
|
return -1; |
1647 |
|
|
} |
1648 |
|
|
msg->iov = new_iov; |
1649 |
|
|
new_iov[msg->iovlen].iov_base = buf; |
1650 |
|
|
new_iov[msg->iovlen].iov_len = sz; |
1651 |
|
|
msg->iovlen++; |
1652 |
|
|
if (link) |
1653 |
|
|
*msg->nextp = payload; |
1654 |
|
|
msg->nextp = buf + ISAKMP_GEN_NEXT_PAYLOAD_OFF; |
1655 |
|
|
*msg->nextp = ISAKMP_PAYLOAD_NONE; |
1656 |
|
|
SET_ISAKMP_GEN_RESERVED(buf, 0); |
1657 |
|
|
SET_ISAKMP_GEN_LENGTH(buf, sz); |
1658 |
|
|
SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, |
1659 |
|
|
GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) + sz); |
1660 |
|
|
|
1661 |
|
|
/* |
1662 |
|
|
* For the sake of exchange_validate we index the payloads even in |
1663 |
|
|
* outgoing messages, however context and flags are uninteresting in |
1664 |
|
|
* this situation. |
1665 |
|
|
*/ |
1666 |
|
|
payload_node->p = buf; |
1667 |
|
|
TAILQ_INSERT_TAIL(&msg->payload[payload], payload_node, link); |
1668 |
|
|
return 0; |
1669 |
|
|
} |
1670 |
|
|
|
1671 |
|
|
/* XXX Move up when ready. */ |
1672 |
|
|
struct info_args { |
1673 |
|
|
char discr; |
1674 |
|
|
u_int32_t doi; |
1675 |
|
|
u_int8_t proto; |
1676 |
|
|
u_int16_t spi_sz; |
1677 |
|
|
union { |
1678 |
|
|
struct { |
1679 |
|
|
u_int16_t msg_type; |
1680 |
|
|
u_int8_t *spi; |
1681 |
|
|
} n; |
1682 |
|
|
struct { |
1683 |
|
|
u_int16_t nspis; |
1684 |
|
|
u_int8_t *spis; |
1685 |
|
|
} d; |
1686 |
|
|
struct { |
1687 |
|
|
u_int16_t msg_type; |
1688 |
|
|
u_int8_t *spi; |
1689 |
|
|
u_int32_t seq; |
1690 |
|
|
} dpd; |
1691 |
|
|
} u; |
1692 |
|
|
}; |
1693 |
|
|
|
1694 |
|
|
/* |
1695 |
|
|
* As a reaction to the incoming message MSG create an informational exchange |
1696 |
|
|
* protected by ISAKMP_SA and send a notify payload of type NOTIFY, with |
1697 |
|
|
* fields initialized from SA. INCOMING is true if the SPI field should be |
1698 |
|
|
* filled with the incoming SPI and false if it is to be filled with the |
1699 |
|
|
* outgoing one. |
1700 |
|
|
* |
1701 |
|
|
* XXX Should we handle sending multiple notify payloads? The draft allows |
1702 |
|
|
* it, but do we need it? Furthermore, should we not return a success |
1703 |
|
|
* status value? |
1704 |
|
|
*/ |
1705 |
|
|
void |
1706 |
|
|
message_send_notification(struct message *msg, struct sa *isakmp_sa, |
1707 |
|
|
u_int16_t notify, struct proto *proto, int incoming) |
1708 |
|
|
{ |
1709 |
|
|
struct info_args args; |
1710 |
|
|
struct sa *doi_sa = proto ? proto->sa : isakmp_sa; |
1711 |
|
|
|
1712 |
|
|
args.discr = 'N'; |
1713 |
|
|
args.doi = doi_sa ? doi_sa->doi->id : ISAKMP_DOI_ISAKMP; |
1714 |
|
|
args.proto = proto ? proto->proto : ISAKMP_PROTO_ISAKMP; |
1715 |
|
|
args.spi_sz = proto ? proto->spi_sz[incoming] : 0; |
1716 |
|
|
args.u.n.msg_type = notify; |
1717 |
|
|
args.u.n.spi = proto ? proto->spi[incoming] : 0; |
1718 |
|
|
if (isakmp_sa && (isakmp_sa->flags & SA_FLAG_READY)) |
1719 |
|
|
exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, |
1720 |
|
|
0, 0); |
1721 |
|
|
else |
1722 |
|
|
exchange_establish_p1(msg->transport, ISAKMP_EXCH_INFO, |
1723 |
|
|
msg->exchange ? msg->exchange->doi->id : ISAKMP_DOI_ISAKMP, |
1724 |
|
|
0, &args, 0, 0, 0); |
1725 |
|
|
} |
1726 |
|
|
|
1727 |
|
|
/* Send a DELETE inside an informational exchange for each protocol in SA. */ |
1728 |
|
|
void |
1729 |
|
|
message_send_delete(struct sa *sa) |
1730 |
|
|
{ |
1731 |
|
|
struct info_args args; |
1732 |
|
|
struct proto *proto; |
1733 |
|
|
struct sa *isakmp_sa; |
1734 |
|
|
struct sockaddr *dst; |
1735 |
|
|
|
1736 |
|
|
if (!sa->transport) |
1737 |
|
|
return; |
1738 |
|
|
|
1739 |
|
|
sa->transport->vtbl->get_dst(sa->transport, &dst); |
1740 |
|
|
isakmp_sa = sa_isakmp_lookup_by_peer(dst, SA_LEN(dst)); |
1741 |
|
|
if (!isakmp_sa) { |
1742 |
|
|
/* |
1743 |
|
|
* XXX We ought to setup an ISAKMP SA with our peer here and |
1744 |
|
|
* send the DELETE over that one. |
1745 |
|
|
*/ |
1746 |
|
|
return; |
1747 |
|
|
} |
1748 |
|
|
args.discr = 'D'; |
1749 |
|
|
args.doi = sa->doi->id; |
1750 |
|
|
args.u.d.nspis = 1; |
1751 |
|
|
for (proto = TAILQ_FIRST(&sa->protos); proto; |
1752 |
|
|
proto = TAILQ_NEXT(proto, link)) { |
1753 |
|
|
switch (proto->proto) { |
1754 |
|
|
case ISAKMP_PROTO_ISAKMP: |
1755 |
|
|
args.spi_sz = ISAKMP_HDR_COOKIES_LEN; |
1756 |
|
|
args.u.d.spis = sa->cookies; |
1757 |
|
|
break; |
1758 |
|
|
|
1759 |
|
|
case IPSEC_PROTO_IPSEC_AH: |
1760 |
|
|
case IPSEC_PROTO_IPSEC_ESP: |
1761 |
|
|
case IPSEC_PROTO_IPCOMP: |
1762 |
|
|
args.spi_sz = proto->spi_sz[1]; |
1763 |
|
|
args.u.d.spis = proto->spi[1]; |
1764 |
|
|
break; |
1765 |
|
|
default: |
1766 |
|
|
log_print("message_send_delete: cannot delete unknown " |
1767 |
|
|
"protocol %d", proto->proto); |
1768 |
|
|
continue; |
1769 |
|
|
} |
1770 |
|
|
|
1771 |
|
|
args.proto = proto->proto; |
1772 |
|
|
exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, |
1773 |
|
|
0, 0); |
1774 |
|
|
} |
1775 |
|
|
} |
1776 |
|
|
|
1777 |
|
|
void |
1778 |
|
|
message_send_dpd_notify(struct sa* isakmp_sa, u_int16_t notify, u_int32_t seq) |
1779 |
|
|
{ |
1780 |
|
|
struct info_args args; |
1781 |
|
|
|
1782 |
|
|
args.discr = 'P'; |
1783 |
|
|
args.doi = IPSEC_DOI_IPSEC; |
1784 |
|
|
args.proto = ISAKMP_PROTO_ISAKMP; |
1785 |
|
|
args.spi_sz = ISAKMP_HDR_COOKIES_LEN; |
1786 |
|
|
args.u.dpd.msg_type = notify; |
1787 |
|
|
args.u.dpd.spi = isakmp_sa->cookies; |
1788 |
|
|
args.u.dpd.seq = htonl(seq); |
1789 |
|
|
|
1790 |
|
|
exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0); |
1791 |
|
|
} |
1792 |
|
|
|
1793 |
|
|
/* Build the informational message into MSG. */ |
1794 |
|
|
int |
1795 |
|
|
message_send_info(struct message *msg) |
1796 |
|
|
{ |
1797 |
|
|
u_int8_t *buf; |
1798 |
|
|
size_t sz = 0; |
1799 |
|
|
struct info_args *args = msg->extra; |
1800 |
|
|
u_int8_t payload; |
1801 |
|
|
|
1802 |
|
|
/* Let the DOI get the first hand on the message. */ |
1803 |
|
|
if (msg->exchange->doi->informational_pre_hook) |
1804 |
|
|
if (msg->exchange->doi->informational_pre_hook(msg)) |
1805 |
|
|
return -1; |
1806 |
|
|
|
1807 |
|
|
switch (args->discr) { |
1808 |
|
|
case 'P': |
1809 |
|
|
sz = sizeof args->u.dpd.seq; |
1810 |
|
|
/* FALLTHROUGH */ |
1811 |
|
|
case 'N': |
1812 |
|
|
sz += ISAKMP_NOTIFY_SPI_OFF + args->spi_sz; |
1813 |
|
|
break; |
1814 |
|
|
case 'D': |
1815 |
|
|
default: /* Silence gcc */ |
1816 |
|
|
sz = ISAKMP_DELETE_SPI_OFF + args->u.d.nspis * args->spi_sz; |
1817 |
|
|
break; |
1818 |
|
|
} |
1819 |
|
|
|
1820 |
|
|
buf = calloc(1, sz); |
1821 |
|
|
if (!buf) { |
1822 |
|
|
log_error("message_send_info: calloc (1, %lu) failed", |
1823 |
|
|
(unsigned long)sz); |
1824 |
|
|
message_free(msg); |
1825 |
|
|
return -1; |
1826 |
|
|
} |
1827 |
|
|
switch (args->discr) { |
1828 |
|
|
case 'P': |
1829 |
|
|
memcpy(buf + ISAKMP_NOTIFY_SPI_OFF + args->spi_sz, |
1830 |
|
|
&args->u.dpd.seq, sizeof args->u.dpd.seq); |
1831 |
|
|
/* FALLTHROUGH */ |
1832 |
|
|
case 'N': |
1833 |
|
|
/* Build the NOTIFY payload. */ |
1834 |
|
|
payload = ISAKMP_PAYLOAD_NOTIFY; |
1835 |
|
|
SET_ISAKMP_NOTIFY_DOI(buf, args->doi); |
1836 |
|
|
SET_ISAKMP_NOTIFY_PROTO(buf, args->proto); |
1837 |
|
|
SET_ISAKMP_NOTIFY_SPI_SZ(buf, args->spi_sz); |
1838 |
|
|
SET_ISAKMP_NOTIFY_MSG_TYPE(buf, args->u.n.msg_type); |
1839 |
|
|
memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, args->u.n.spi, |
1840 |
|
|
args->spi_sz); |
1841 |
|
|
break; |
1842 |
|
|
|
1843 |
|
|
case 'D': |
1844 |
|
|
default: /* Silence GCC. */ |
1845 |
|
|
/* Build the DELETE payload. */ |
1846 |
|
|
payload = ISAKMP_PAYLOAD_DELETE; |
1847 |
|
|
SET_ISAKMP_DELETE_DOI(buf, args->doi); |
1848 |
|
|
SET_ISAKMP_DELETE_PROTO(buf, args->proto); |
1849 |
|
|
SET_ISAKMP_DELETE_SPI_SZ(buf, args->spi_sz); |
1850 |
|
|
SET_ISAKMP_DELETE_NSPIS(buf, args->u.d.nspis); |
1851 |
|
|
memcpy(buf + ISAKMP_DELETE_SPI_OFF, args->u.d.spis, |
1852 |
|
|
args->u.d.nspis * args->spi_sz); |
1853 |
|
|
msg->flags |= MSG_PRIORITIZED; |
1854 |
|
|
break; |
1855 |
|
|
} |
1856 |
|
|
|
1857 |
|
|
if (message_add_payload(msg, payload, buf, sz, 1)) { |
1858 |
|
|
free(buf); |
1859 |
|
|
message_free(msg); |
1860 |
|
|
return -1; |
1861 |
|
|
} |
1862 |
|
|
/* Let the DOI get the last hand on the message. */ |
1863 |
|
|
if (msg->exchange->doi->informational_post_hook) |
1864 |
|
|
if (msg->exchange->doi->informational_post_hook(msg)) { |
1865 |
|
|
message_free(msg); |
1866 |
|
|
return -1; |
1867 |
|
|
} |
1868 |
|
|
return 0; |
1869 |
|
|
} |
1870 |
|
|
|
1871 |
|
|
/* |
1872 |
|
|
* Drop the MSG message due to reason given in NOTIFY. If NOTIFY is set |
1873 |
|
|
* send out a notification to the originator. Fill this notification with |
1874 |
|
|
* values from PROTO. INCOMING decides which SPI to include. If CLEAN is |
1875 |
|
|
* set, free the message when ready with it. |
1876 |
|
|
*/ |
1877 |
|
|
void |
1878 |
|
|
message_drop(struct message *msg, int notify, struct proto *proto, |
1879 |
|
|
int incoming, int clean) |
1880 |
|
|
{ |
1881 |
|
|
struct transport *t = msg->transport; |
1882 |
|
|
struct sockaddr *dst; |
1883 |
|
|
char *address; |
1884 |
|
|
short port = 0; |
1885 |
|
|
|
1886 |
|
|
t->vtbl->get_dst(t, &dst); |
1887 |
|
|
if (sockaddr2text(dst, &address, 0)) { |
1888 |
|
|
log_error("message_drop: sockaddr2text () failed"); |
1889 |
|
|
address = 0; |
1890 |
|
|
} |
1891 |
|
|
switch (dst->sa_family) { |
1892 |
|
|
case AF_INET: |
1893 |
|
|
port = ((struct sockaddr_in *)dst)->sin_port; |
1894 |
|
|
break; |
1895 |
|
|
case AF_INET6: |
1896 |
|
|
port = ((struct sockaddr_in6 *)dst)->sin6_port; |
1897 |
|
|
break; |
1898 |
|
|
default: |
1899 |
|
|
log_print("message_drop: unknown protocol family %d", |
1900 |
|
|
dst->sa_family); |
1901 |
|
|
} |
1902 |
|
|
|
1903 |
|
|
log_print("dropped message from %s port %d due to notification type " |
1904 |
|
|
"%s", address ? address : "<unknown>", htons(port), |
1905 |
|
|
constant_name(isakmp_notify_cst, notify)); |
1906 |
|
|
|
1907 |
|
|
free(address); |
1908 |
|
|
|
1909 |
|
|
/* If specified, return a notification. */ |
1910 |
|
|
if (notify) |
1911 |
|
|
message_send_notification(msg, msg->isakmp_sa, notify, proto, |
1912 |
|
|
incoming); |
1913 |
|
|
if (clean) |
1914 |
|
|
message_free(msg); |
1915 |
|
|
} |
1916 |
|
|
|
1917 |
|
|
/* |
1918 |
|
|
* If the user demands debug printouts, printout MSG with as much detail |
1919 |
|
|
* as we can without resorting to per-payload handling. |
1920 |
|
|
*/ |
1921 |
|
|
void |
1922 |
|
|
message_dump_raw(char *header, struct message *msg, int class) |
1923 |
|
|
{ |
1924 |
|
|
u_int32_t i, j, k = 0; |
1925 |
|
|
char buf[80], *p = buf; |
1926 |
|
|
|
1927 |
|
|
LOG_DBG((class, 70, "%s: message %p", header, msg)); |
1928 |
|
|
field_dump_payload(isakmp_hdr_fld, msg->iov[0].iov_base); |
1929 |
|
|
for (i = 0; i < msg->iovlen; i++) |
1930 |
|
|
for (j = 0; j < msg->iov[i].iov_len; j++) { |
1931 |
|
|
snprintf(p, sizeof buf - (int) (p - buf), "%02x", |
1932 |
|
|
((u_int8_t *) msg->iov[i].iov_base)[j]); |
1933 |
|
|
p += strlen(p); |
1934 |
|
|
if (++k % 32 == 0) { |
1935 |
|
|
*p = '\0'; |
1936 |
|
|
LOG_DBG((class, 70, "%s: %s", header, buf)); |
1937 |
|
|
p = buf; |
1938 |
|
|
} else if (k % 4 == 0) |
1939 |
|
|
*p++ = ' '; |
1940 |
|
|
} |
1941 |
|
|
*p = '\0'; |
1942 |
|
|
if (p != buf) |
1943 |
|
|
LOG_DBG((class, 70, "%s: %s", header, buf)); |
1944 |
|
|
} |
1945 |
|
|
|
1946 |
|
|
static void |
1947 |
|
|
message_packet_log(struct message *msg) |
1948 |
|
|
{ |
1949 |
|
|
struct sockaddr *src, *dst; |
1950 |
|
|
struct transport *t = msg->transport; |
1951 |
|
|
|
1952 |
|
|
/* Don't log retransmissions. Redundant for incoming packets... */ |
1953 |
|
|
if (msg->xmits > 0) |
1954 |
|
|
return; |
1955 |
|
|
|
1956 |
|
|
if (msg->exchange && msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) |
1957 |
|
|
t = ((struct virtual_transport *)msg->transport)->encap; |
1958 |
|
|
|
1959 |
|
|
/* Figure out direction. */ |
1960 |
|
|
if (msg->exchange && |
1961 |
|
|
msg->exchange->initiator ^ (msg->exchange->step % 2)) { |
1962 |
|
|
t->vtbl->get_src(t, &src); |
1963 |
|
|
t->vtbl->get_dst(t, &dst); |
1964 |
|
|
} else { |
1965 |
|
|
t->vtbl->get_src(t, &dst); |
1966 |
|
|
t->vtbl->get_dst(t, &src); |
1967 |
|
|
} |
1968 |
|
|
|
1969 |
|
|
log_packet_iov(src, dst, msg->iov, msg->iovlen); |
1970 |
|
|
} |
1971 |
|
|
|
1972 |
|
|
/* |
1973 |
|
|
* Encrypt an outgoing message MSG. As outgoing messages are represented |
1974 |
|
|
* with an iovec with one segment per payload, we need to coalesce them |
1975 |
|
|
* into just une buffer containing all payloads and some padding before |
1976 |
|
|
* we encrypt. |
1977 |
|
|
*/ |
1978 |
|
|
static int |
1979 |
|
|
message_encrypt(struct message *msg) |
1980 |
|
|
{ |
1981 |
|
|
struct exchange *exchange = msg->exchange; |
1982 |
|
|
size_t i, sz = 0; |
1983 |
|
|
u_int8_t *buf; |
1984 |
|
|
|
1985 |
|
|
/* If no payloads, nothing to do. */ |
1986 |
|
|
if (msg->iovlen == 1) |
1987 |
|
|
return 0; |
1988 |
|
|
|
1989 |
|
|
/* |
1990 |
|
|
* For encryption we need to put all payloads together in a single |
1991 |
|
|
* buffer. This buffer should be padded to the current crypto |
1992 |
|
|
* transform's blocksize. |
1993 |
|
|
*/ |
1994 |
|
|
for (i = 1; i < msg->iovlen; i++) |
1995 |
|
|
sz += msg->iov[i].iov_len; |
1996 |
|
|
sz = ((sz + exchange->crypto->blocksize - 1) / |
1997 |
|
|
exchange->crypto->blocksize) * exchange->crypto->blocksize; |
1998 |
|
|
buf = realloc(msg->iov[1].iov_base, sz); |
1999 |
|
|
if (!buf) { |
2000 |
|
|
log_error("message_encrypt: realloc (%p, %lu) failed", |
2001 |
|
|
msg->iov[1].iov_base, (unsigned long) sz); |
2002 |
|
|
return -1; |
2003 |
|
|
} |
2004 |
|
|
msg->iov[1].iov_base = buf; |
2005 |
|
|
for (i = 2; i < msg->iovlen; i++) { |
2006 |
|
|
memcpy(buf + msg->iov[1].iov_len, msg->iov[i].iov_base, |
2007 |
|
|
msg->iov[i].iov_len); |
2008 |
|
|
msg->iov[1].iov_len += msg->iov[i].iov_len; |
2009 |
|
|
free(msg->iov[i].iov_base); |
2010 |
|
|
} |
2011 |
|
|
|
2012 |
|
|
/* Pad with zeroes. */ |
2013 |
|
|
memset(buf + msg->iov[1].iov_len, '\0', sz - msg->iov[1].iov_len); |
2014 |
|
|
msg->iov[1].iov_len = sz; |
2015 |
|
|
msg->iovlen = 2; |
2016 |
|
|
|
2017 |
|
|
SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base, |
2018 |
|
|
GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base) | ISAKMP_FLAGS_ENC); |
2019 |
|
|
SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz); |
2020 |
|
|
crypto_encrypt(exchange->keystate, buf, msg->iov[1].iov_len); |
2021 |
|
|
msg->flags |= MSG_ENCRYPTED; |
2022 |
|
|
|
2023 |
|
|
/* Update the IV so we can decrypt the next incoming message. */ |
2024 |
|
|
crypto_update_iv(exchange->keystate); |
2025 |
|
|
|
2026 |
|
|
return 0; |
2027 |
|
|
} |
2028 |
|
|
|
2029 |
|
|
/* |
2030 |
|
|
* Check whether the message MSG is a duplicate of the last one negotiating |
2031 |
|
|
* this specific SA. |
2032 |
|
|
*/ |
2033 |
|
|
static int |
2034 |
|
|
message_check_duplicate(struct message *msg) |
2035 |
|
|
{ |
2036 |
|
|
struct exchange *exchange = msg->exchange; |
2037 |
|
|
size_t sz = msg->iov[0].iov_len; |
2038 |
|
|
u_int8_t *pkt = msg->iov[0].iov_base; |
2039 |
|
|
|
2040 |
|
|
/* If no SA has been found, we cannot test, thus it's good. */ |
2041 |
|
|
if (!exchange) |
2042 |
|
|
return 0; |
2043 |
|
|
|
2044 |
|
|
LOG_DBG((LOG_MESSAGE, 90, "message_check_duplicate: last_received %p", |
2045 |
|
|
exchange->last_received)); |
2046 |
|
|
if (exchange->last_received) { |
2047 |
|
|
LOG_DBG_BUF((LOG_MESSAGE, 95, |
2048 |
|
|
"message_check_duplicate: last_received", |
2049 |
|
|
exchange->last_received->orig, |
2050 |
|
|
exchange->last_received->orig_sz)); |
2051 |
|
|
/* Is it a duplicate, lose the new one. */ |
2052 |
|
|
if (sz == exchange->last_received->orig_sz && |
2053 |
|
|
memcmp(pkt, exchange->last_received->orig, sz) == 0) { |
2054 |
|
|
LOG_DBG((LOG_MESSAGE, 80, |
2055 |
|
|
"message_check_duplicate: dropping dup")); |
2056 |
|
|
|
2057 |
|
|
/* |
2058 |
|
|
* Retransmit if the previous sent message was the last |
2059 |
|
|
* of an exchange, otherwise just wait for the |
2060 |
|
|
* ordinary retransmission. |
2061 |
|
|
*/ |
2062 |
|
|
if (exchange->last_sent && (exchange->last_sent->flags |
2063 |
|
|
& MSG_LAST)) |
2064 |
|
|
message_send(exchange->last_sent); |
2065 |
|
|
message_free(msg); |
2066 |
|
|
return -1; |
2067 |
|
|
} |
2068 |
|
|
} |
2069 |
|
|
/* |
2070 |
|
|
* As this new message is an indication that state is moving forward |
2071 |
|
|
* at the peer, remove the retransmit timer on our last message. |
2072 |
|
|
*/ |
2073 |
|
|
if (exchange->last_sent) { |
2074 |
|
|
if (exchange->last_sent == exchange->in_transit) { |
2075 |
|
|
struct message *m = exchange->in_transit; |
2076 |
|
|
TAILQ_REMOVE(m->transport->vtbl->get_queue(m), m, |
2077 |
|
|
link); |
2078 |
|
|
exchange->in_transit = 0; |
2079 |
|
|
} |
2080 |
|
|
message_free(exchange->last_sent); |
2081 |
|
|
exchange->last_sent = 0; |
2082 |
|
|
} |
2083 |
|
|
return 0; |
2084 |
|
|
} |
2085 |
|
|
|
2086 |
|
|
/* Helper to message_negotiate_sa. */ |
2087 |
|
|
static __inline struct payload * |
2088 |
|
|
step_transform(struct payload *tp, struct payload **propp, |
2089 |
|
|
struct payload **sap) |
2090 |
|
|
{ |
2091 |
|
|
tp = TAILQ_NEXT(tp, link); |
2092 |
|
|
if (tp) { |
2093 |
|
|
*propp = tp->context; |
2094 |
|
|
*sap = (*propp)->context; |
2095 |
|
|
} |
2096 |
|
|
return tp; |
2097 |
|
|
} |
2098 |
|
|
|
2099 |
|
|
/* |
2100 |
|
|
* Pick out the first transforms out of MSG (which should contain at least one |
2101 |
|
|
* SA payload) we accept as a full protection suite. |
2102 |
|
|
*/ |
2103 |
|
|
int |
2104 |
|
|
message_negotiate_sa(struct message *msg, int (*validate)(struct exchange *, |
2105 |
|
|
struct sa *, struct sa *)) |
2106 |
|
|
{ |
2107 |
|
|
struct payload *tp, *propp, *sap, *next_tp = 0, *next_propp, *next_sap; |
2108 |
|
|
struct payload *saved_tp = 0, *saved_propp = 0, *saved_sap = 0; |
2109 |
|
|
struct sa *sa; |
2110 |
|
|
struct proto *proto; |
2111 |
|
|
int suite_ok_so_far = 0; |
2112 |
|
|
struct exchange *exchange = msg->exchange; |
2113 |
|
|
|
2114 |
|
|
/* |
2115 |
|
|
* This algorithm is a weird bottom-up thing... mostly due to the |
2116 |
|
|
* payload links pointing upwards. |
2117 |
|
|
* |
2118 |
|
|
* The algorithm goes something like this: |
2119 |
|
|
* Foreach transform |
2120 |
|
|
* If transform is compatible |
2121 |
|
|
* Remember that this protocol can work |
2122 |
|
|
* Skip to last transform of this protocol |
2123 |
|
|
* If next transform belongs to a new protocol inside the same suite |
2124 |
|
|
* If no transform was found for the current protocol |
2125 |
|
|
* Forget all earlier transforms for protocols in this suite |
2126 |
|
|
* Skip to last transform of this suite |
2127 |
|
|
* If next transform belongs to a new suite |
2128 |
|
|
* If the current protocol had an OK transform |
2129 |
|
|
* Skip to the last transform of this SA |
2130 |
|
|
* If the next transform belongs to a new SA |
2131 |
|
|
* If no transforms have been chosen |
2132 |
|
|
* Issue a NO_PROPOSAL_CHOSEN notification |
2133 |
|
|
*/ |
2134 |
|
|
|
2135 |
|
|
sa = TAILQ_FIRST(&exchange->sa_list); |
2136 |
|
|
for (tp = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); tp; |
2137 |
|
|
tp = next_tp) { |
2138 |
|
|
propp = tp->context; |
2139 |
|
|
sap = propp->context; |
2140 |
|
|
sap->flags |= PL_MARK; |
2141 |
|
|
next_tp = step_transform(tp, &next_propp, &next_sap); |
2142 |
|
|
|
2143 |
|
|
/* For each transform, see if it is compatible. */ |
2144 |
|
|
if (!attribute_map(tp->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
2145 |
|
|
GET_ISAKMP_GEN_LENGTH(tp->p) - |
2146 |
|
|
ISAKMP_TRANSFORM_SA_ATTRS_OFF, |
2147 |
|
|
exchange->doi->is_attribute_incompatible, msg)) { |
2148 |
|
|
LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: " |
2149 |
|
|
"transform %d proto %d proposal %d ok", |
2150 |
|
|
GET_ISAKMP_TRANSFORM_NO(tp->p), |
2151 |
|
|
GET_ISAKMP_PROP_PROTO(propp->p), |
2152 |
|
|
GET_ISAKMP_PROP_NO(propp->p))); |
2153 |
|
|
if (sa_add_transform(sa, tp, exchange->initiator, |
2154 |
|
|
&proto)) |
2155 |
|
|
goto cleanup; |
2156 |
|
|
suite_ok_so_far = 1; |
2157 |
|
|
|
2158 |
|
|
saved_tp = next_tp; |
2159 |
|
|
saved_propp = next_propp; |
2160 |
|
|
saved_sap = next_sap; |
2161 |
|
|
/* Skip to last transform of this protocol proposal. */ |
2162 |
|
|
while ((next_tp = step_transform(tp, &next_propp, |
2163 |
|
|
&next_sap)) && next_propp == propp) |
2164 |
|
|
tp = next_tp; |
2165 |
|
|
} |
2166 |
|
|
retry_transform: |
2167 |
|
|
/* |
2168 |
|
|
* Figure out if we will be looking at a new protocol proposal |
2169 |
|
|
* inside the current protection suite. |
2170 |
|
|
*/ |
2171 |
|
|
if (next_tp && propp != next_propp && sap == next_sap && |
2172 |
|
|
(GET_ISAKMP_PROP_NO(propp->p) == |
2173 |
|
|
GET_ISAKMP_PROP_NO(next_propp->p))) { |
2174 |
|
|
if (!suite_ok_so_far) { |
2175 |
|
|
LOG_DBG((LOG_NEGOTIATION, 30, |
2176 |
|
|
"message_negotiate_sa: proto %d proposal " |
2177 |
|
|
"%d failed", |
2178 |
|
|
GET_ISAKMP_PROP_PROTO(propp->p), |
2179 |
|
|
GET_ISAKMP_PROP_NO(propp->p))); |
2180 |
|
|
/* |
2181 |
|
|
* Remove potentially succeeded choices from |
2182 |
|
|
* the SA. |
2183 |
|
|
*/ |
2184 |
|
|
while ((proto = TAILQ_FIRST(&sa->protos))) |
2185 |
|
|
proto_free(proto); |
2186 |
|
|
|
2187 |
|
|
/* |
2188 |
|
|
* Skip to the last transform of this |
2189 |
|
|
* protection suite. |
2190 |
|
|
*/ |
2191 |
|
|
while ((next_tp = step_transform(tp, |
2192 |
|
|
&next_propp, &next_sap)) && |
2193 |
|
|
(GET_ISAKMP_PROP_NO(next_propp->p) == |
2194 |
|
|
GET_ISAKMP_PROP_NO(propp->p)) && |
2195 |
|
|
next_sap == sap) |
2196 |
|
|
tp = next_tp; |
2197 |
|
|
} |
2198 |
|
|
suite_ok_so_far = 0; |
2199 |
|
|
} |
2200 |
|
|
/* |
2201 |
|
|
* Figure out if we will be looking at a new protection |
2202 |
|
|
* suite. |
2203 |
|
|
*/ |
2204 |
|
|
if (!next_tp || |
2205 |
|
|
(propp != next_propp && (GET_ISAKMP_PROP_NO(propp->p) != |
2206 |
|
|
GET_ISAKMP_PROP_NO(next_propp->p))) || |
2207 |
|
|
sap != next_sap) { |
2208 |
|
|
/* |
2209 |
|
|
* Check if the suite we just considered was OK, if so |
2210 |
|
|
* we check it against the accepted ones. |
2211 |
|
|
*/ |
2212 |
|
|
if (suite_ok_so_far) { |
2213 |
|
|
if (!validate || validate(exchange, sa, |
2214 |
|
|
msg->isakmp_sa)) { |
2215 |
|
|
LOG_DBG((LOG_NEGOTIATION, 30, |
2216 |
|
|
"message_negotiate_sa: proposal " |
2217 |
|
|
"%d succeeded", |
2218 |
|
|
GET_ISAKMP_PROP_NO(propp->p))); |
2219 |
|
|
|
2220 |
|
|
/* |
2221 |
|
|
* Skip to the last transform of this |
2222 |
|
|
* SA. |
2223 |
|
|
*/ |
2224 |
|
|
while ((next_tp = step_transform(tp, |
2225 |
|
|
&next_propp, &next_sap)) && |
2226 |
|
|
next_sap == sap) |
2227 |
|
|
tp = next_tp; |
2228 |
|
|
} else { |
2229 |
|
|
/* Backtrack. */ |
2230 |
|
|
LOG_DBG((LOG_NEGOTIATION, 30, |
2231 |
|
|
"message_negotiate_sa: proposal " |
2232 |
|
|
"%d failed", |
2233 |
|
|
GET_ISAKMP_PROP_NO(propp->p))); |
2234 |
|
|
next_tp = saved_tp; |
2235 |
|
|
next_propp = saved_propp; |
2236 |
|
|
next_sap = saved_sap; |
2237 |
|
|
suite_ok_so_far = 0; |
2238 |
|
|
|
2239 |
|
|
/* |
2240 |
|
|
* Remove potentially succeeded |
2241 |
|
|
* choices from the SA. |
2242 |
|
|
*/ |
2243 |
|
|
while ((proto = |
2244 |
|
|
TAILQ_FIRST(&sa->protos))) |
2245 |
|
|
proto_free(proto); |
2246 |
|
|
goto retry_transform; |
2247 |
|
|
} |
2248 |
|
|
} |
2249 |
|
|
} |
2250 |
|
|
/* Have we walked all the proposals of an SA? */ |
2251 |
|
|
if (!next_tp || sap != next_sap) { |
2252 |
|
|
if (!suite_ok_so_far) { |
2253 |
|
|
/* |
2254 |
|
|
* XXX We cannot possibly call this a drop... |
2255 |
|
|
* seeing we just turn down one of the offers, |
2256 |
|
|
* can we? I suggest renaming message_drop to |
2257 |
|
|
* something else. |
2258 |
|
|
*/ |
2259 |
|
|
log_print("message_negotiate_sa: no " |
2260 |
|
|
"compatible proposal found"); |
2261 |
|
|
message_drop(msg, |
2262 |
|
|
ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); |
2263 |
|
|
} |
2264 |
|
|
sa = TAILQ_NEXT(sa, next); |
2265 |
|
|
} |
2266 |
|
|
} |
2267 |
|
|
return 0; |
2268 |
|
|
|
2269 |
|
|
cleanup: |
2270 |
|
|
/* |
2271 |
|
|
* Remove potentially succeeded choices from the SA. |
2272 |
|
|
*/ |
2273 |
|
|
while ((proto = TAILQ_FIRST(&sa->protos))) |
2274 |
|
|
proto_free(proto); |
2275 |
|
|
return -1; |
2276 |
|
|
} |
2277 |
|
|
|
2278 |
|
|
/* |
2279 |
|
|
* Add SA, proposal and transform payload(s) to MSG out of information |
2280 |
|
|
* found in the exchange MSG is part of.. |
2281 |
|
|
*/ |
2282 |
|
|
int |
2283 |
|
|
message_add_sa_payload(struct message *msg) |
2284 |
|
|
{ |
2285 |
|
|
struct exchange *exchange = msg->exchange; |
2286 |
|
|
u_int8_t *sa_buf, *saved_nextp_sa, *saved_nextp_prop; |
2287 |
|
|
size_t sa_len, extra_sa_len; |
2288 |
|
|
int i, nprotos = 0; |
2289 |
|
|
struct proto *proto; |
2290 |
|
|
u_int8_t **transforms = 0, **proposals = 0; |
2291 |
|
|
size_t *transform_lens = 0, *proposal_lens = 0; |
2292 |
|
|
struct sa *sa; |
2293 |
|
|
struct doi *doi = exchange->doi; |
2294 |
|
|
u_int8_t *spi = 0; |
2295 |
|
|
size_t spi_sz; |
2296 |
|
|
|
2297 |
|
|
/* |
2298 |
|
|
* Generate SA payloads. |
2299 |
|
|
*/ |
2300 |
|
|
for (sa = TAILQ_FIRST(&exchange->sa_list); sa; |
2301 |
|
|
sa = TAILQ_NEXT(sa, next)) { |
2302 |
|
|
/* Setup a SA payload. */ |
2303 |
|
|
sa_len = ISAKMP_SA_SIT_OFF + doi->situation_size(); |
2304 |
|
|
extra_sa_len = 0; |
2305 |
|
|
sa_buf = malloc(sa_len); |
2306 |
|
|
if (!sa_buf) { |
2307 |
|
|
log_error("message_add_sa_payload: " |
2308 |
|
|
"malloc (%lu) failed", (unsigned long)sa_len); |
2309 |
|
|
goto cleanup; |
2310 |
|
|
} |
2311 |
|
|
SET_ISAKMP_SA_DOI(sa_buf, doi->id); |
2312 |
|
|
doi->setup_situation(sa_buf); |
2313 |
|
|
|
2314 |
|
|
/* Count transforms. */ |
2315 |
|
|
nprotos = 0; |
2316 |
|
|
for (proto = TAILQ_FIRST(&sa->protos); proto; |
2317 |
|
|
proto = TAILQ_NEXT(proto, link)) |
2318 |
|
|
nprotos++; |
2319 |
|
|
|
2320 |
|
|
/* |
2321 |
|
|
* Allocate transient transform and proposal payload/size |
2322 |
|
|
* vectors. |
2323 |
|
|
*/ |
2324 |
|
|
transforms = calloc(nprotos, sizeof *transforms); |
2325 |
|
|
if (!transforms) { |
2326 |
|
|
log_error("message_add_sa_payload: calloc (%d, %lu) " |
2327 |
|
|
"failed", nprotos, |
2328 |
|
|
(unsigned long)sizeof *transforms); |
2329 |
|
|
goto cleanup; |
2330 |
|
|
} |
2331 |
|
|
transform_lens = calloc(nprotos, sizeof *transform_lens); |
2332 |
|
|
if (!transform_lens) { |
2333 |
|
|
log_error("message_add_sa_payload: calloc (%d, %lu) " |
2334 |
|
|
"failed", nprotos, |
2335 |
|
|
(unsigned long) sizeof *transform_lens); |
2336 |
|
|
goto cleanup; |
2337 |
|
|
} |
2338 |
|
|
proposals = calloc(nprotos, sizeof *proposals); |
2339 |
|
|
if (!proposals) { |
2340 |
|
|
log_error("message_add_sa_payload: calloc (%d, %lu) " |
2341 |
|
|
"failed", nprotos, |
2342 |
|
|
(unsigned long)sizeof *proposals); |
2343 |
|
|
goto cleanup; |
2344 |
|
|
} |
2345 |
|
|
proposal_lens = calloc(nprotos, sizeof *proposal_lens); |
2346 |
|
|
if (!proposal_lens) { |
2347 |
|
|
log_error("message_add_sa_payload: calloc (%d, %lu) " |
2348 |
|
|
"failed", nprotos, |
2349 |
|
|
(unsigned long)sizeof *proposal_lens); |
2350 |
|
|
goto cleanup; |
2351 |
|
|
} |
2352 |
|
|
/* Pick out the chosen transforms. */ |
2353 |
|
|
for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto; |
2354 |
|
|
proto = TAILQ_NEXT(proto, link), i++) { |
2355 |
|
|
transform_lens[i] = |
2356 |
|
|
GET_ISAKMP_GEN_LENGTH(proto->chosen->p); |
2357 |
|
|
transforms[i] = malloc(transform_lens[i]); |
2358 |
|
|
if (!transforms[i]) { |
2359 |
|
|
log_error("message_add_sa_payload: malloc " |
2360 |
|
|
"(%lu) failed", |
2361 |
|
|
(unsigned long)transform_lens[i]); |
2362 |
|
|
goto cleanup; |
2363 |
|
|
} |
2364 |
|
|
/* Get incoming SPI from application. */ |
2365 |
|
|
if (doi->get_spi) { |
2366 |
|
|
spi = doi->get_spi(&spi_sz, |
2367 |
|
|
GET_ISAKMP_PROP_PROTO(proto->chosen->context->p), |
2368 |
|
|
msg); |
2369 |
|
|
if (spi_sz && !spi) |
2370 |
|
|
goto cleanup; |
2371 |
|
|
proto->spi[1] = spi; |
2372 |
|
|
proto->spi_sz[1] = spi_sz; |
2373 |
|
|
} else |
2374 |
|
|
spi_sz = 0; |
2375 |
|
|
|
2376 |
|
|
proposal_lens[i] = ISAKMP_PROP_SPI_OFF + spi_sz; |
2377 |
|
|
proposals[i] = malloc(proposal_lens[i]); |
2378 |
|
|
if (!proposals[i]) { |
2379 |
|
|
log_error("message_add_sa_payload: malloc " |
2380 |
|
|
"(%lu) failed", |
2381 |
|
|
(unsigned long)proposal_lens[i]); |
2382 |
|
|
goto cleanup; |
2383 |
|
|
} |
2384 |
|
|
memcpy(transforms[i], proto->chosen->p, |
2385 |
|
|
transform_lens[i]); |
2386 |
|
|
memcpy(proposals[i], proto->chosen->context->p, |
2387 |
|
|
ISAKMP_PROP_SPI_OFF); |
2388 |
|
|
SET_ISAKMP_PROP_NTRANSFORMS(proposals[i], 1); |
2389 |
|
|
SET_ISAKMP_PROP_SPI_SZ(proposals[i], spi_sz); |
2390 |
|
|
if (spi_sz) |
2391 |
|
|
memcpy(proposals[i] + ISAKMP_PROP_SPI_OFF, spi, |
2392 |
|
|
spi_sz); |
2393 |
|
|
extra_sa_len += proposal_lens[i] + transform_lens[i]; |
2394 |
|
|
} |
2395 |
|
|
|
2396 |
|
|
/* |
2397 |
|
|
* Add the payloads. As this is a SA, we need to recompute the |
2398 |
|
|
* lengths of the payloads containing others. We also need to |
2399 |
|
|
* reset these payload's "next payload type" field. |
2400 |
|
|
*/ |
2401 |
|
|
if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, |
2402 |
|
|
sa_len, 1)) |
2403 |
|
|
goto cleanup; |
2404 |
|
|
SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + extra_sa_len); |
2405 |
|
|
sa_buf = 0; |
2406 |
|
|
|
2407 |
|
|
saved_nextp_sa = msg->nextp; |
2408 |
|
|
for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto; |
2409 |
|
|
proto = TAILQ_NEXT(proto, link), i++) { |
2410 |
|
|
if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, |
2411 |
|
|
proposals[i], proposal_lens[i], i > 0)) |
2412 |
|
|
goto cleanup; |
2413 |
|
|
SET_ISAKMP_GEN_LENGTH(proposals[i], proposal_lens[i] + |
2414 |
|
|
transform_lens[i]); |
2415 |
|
|
proposals[i] = 0; |
2416 |
|
|
|
2417 |
|
|
saved_nextp_prop = msg->nextp; |
2418 |
|
|
if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM, |
2419 |
|
|
transforms[i], transform_lens[i], 0)) |
2420 |
|
|
goto cleanup; |
2421 |
|
|
msg->nextp = saved_nextp_prop; |
2422 |
|
|
transforms[i] = 0; |
2423 |
|
|
} |
2424 |
|
|
msg->nextp = saved_nextp_sa; |
2425 |
|
|
|
2426 |
|
|
/* Free the temporary allocations made above. */ |
2427 |
|
|
free(transforms); |
2428 |
|
|
free(transform_lens); |
2429 |
|
|
free(proposals); |
2430 |
|
|
free(proposal_lens); |
2431 |
|
|
} |
2432 |
|
|
return 0; |
2433 |
|
|
|
2434 |
|
|
cleanup: |
2435 |
|
|
free(sa_buf); |
2436 |
|
|
for (i = 0; i < nprotos; i++) { |
2437 |
|
|
free(transforms[i]); |
2438 |
|
|
free(proposals[i]); |
2439 |
|
|
} |
2440 |
|
|
free(transforms); |
2441 |
|
|
free(transform_lens); |
2442 |
|
|
free(proposals); |
2443 |
|
|
free(proposal_lens); |
2444 |
|
|
return -1; |
2445 |
|
|
} |
2446 |
|
|
|
2447 |
|
|
/* |
2448 |
|
|
* Return a copy of MSG's constants starting from OFFSET and stash the size |
2449 |
|
|
* in SZP. It is the callers responsibility to free this up. |
2450 |
|
|
*/ |
2451 |
|
|
u_int8_t * |
2452 |
|
|
message_copy(struct message *msg, size_t offset, size_t *szp) |
2453 |
|
|
{ |
2454 |
|
|
int skip = 0; |
2455 |
|
|
size_t i, sz = 0; |
2456 |
|
|
ssize_t start = -1; |
2457 |
|
|
u_int8_t *buf, *p; |
2458 |
|
|
|
2459 |
|
|
/* Calculate size of message and where we want to start to copy. */ |
2460 |
|
|
for (i = 1; i < msg->iovlen; i++) { |
2461 |
|
|
sz += msg->iov[i].iov_len; |
2462 |
|
|
if (sz <= offset) |
2463 |
|
|
skip = i; |
2464 |
|
|
else if (start < 0) |
2465 |
|
|
start = offset - (sz - msg->iov[i].iov_len); |
2466 |
|
|
} |
2467 |
|
|
|
2468 |
|
|
/* Allocate and copy. */ |
2469 |
|
|
*szp = sz - offset; |
2470 |
|
|
buf = malloc(*szp); |
2471 |
|
|
if (!buf) |
2472 |
|
|
return 0; |
2473 |
|
|
p = buf; |
2474 |
|
|
for (i = skip + 1; i < msg->iovlen; i++) { |
2475 |
|
|
memcpy(p, (u_int8_t *) msg->iov[i].iov_base + start, |
2476 |
|
|
msg->iov[i].iov_len - start); |
2477 |
|
|
p += msg->iov[i].iov_len - start; |
2478 |
|
|
start = 0; |
2479 |
|
|
} |
2480 |
|
|
return buf; |
2481 |
|
|
} |
2482 |
|
|
|
2483 |
|
|
/* Register a post-send function POST_SEND with message MSG. */ |
2484 |
|
|
int |
2485 |
|
|
message_register_post_send(struct message *msg, |
2486 |
|
|
void (*post_send)(struct message *)) |
2487 |
|
|
{ |
2488 |
|
|
struct post_send *node; |
2489 |
|
|
|
2490 |
|
|
node = malloc(sizeof *node); |
2491 |
|
|
if (!node) |
2492 |
|
|
return -1; |
2493 |
|
|
node->func = post_send; |
2494 |
|
|
TAILQ_INSERT_TAIL(&msg->post_send, node, link); |
2495 |
|
|
return 0; |
2496 |
|
|
} |
2497 |
|
|
|
2498 |
|
|
/* Run the post-send functions of message MSG. */ |
2499 |
|
|
void |
2500 |
|
|
message_post_send(struct message *msg) |
2501 |
|
|
{ |
2502 |
|
|
struct post_send *node; |
2503 |
|
|
|
2504 |
|
|
while ((node = TAILQ_FIRST(&msg->post_send)) != 0) { |
2505 |
|
|
TAILQ_REMOVE(&msg->post_send, node, link); |
2506 |
|
|
node->func(msg); |
2507 |
|
|
free(node); |
2508 |
|
|
} |
2509 |
|
|
} |
2510 |
|
|
|
2511 |
|
|
struct payload * |
2512 |
|
|
payload_first(struct message *msg, u_int8_t payload) |
2513 |
|
|
{ |
2514 |
|
|
return TAILQ_FIRST(&msg->payload[payload]); |
2515 |
|
|
} |