1 |
|
|
/* $OpenBSD: ikev2_pld.c,v 1.55 2015/10/15 18:40:38 mmcc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* Copyright (c) 2014 Hans-Joerg Hoexer |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/queue.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <sys/wait.h> |
23 |
|
|
#include <sys/uio.h> |
24 |
|
|
|
25 |
|
|
#include <netinet/in.h> |
26 |
|
|
#include <arpa/inet.h> |
27 |
|
|
|
28 |
|
|
#include <stdlib.h> |
29 |
|
|
#include <stdio.h> |
30 |
|
|
#include <unistd.h> |
31 |
|
|
#include <string.h> |
32 |
|
|
#include <signal.h> |
33 |
|
|
#include <errno.h> |
34 |
|
|
#include <err.h> |
35 |
|
|
#include <pwd.h> |
36 |
|
|
#include <event.h> |
37 |
|
|
|
38 |
|
|
#include <openssl/sha.h> |
39 |
|
|
#include <openssl/evp.h> |
40 |
|
|
|
41 |
|
|
#include "iked.h" |
42 |
|
|
#include "ikev2.h" |
43 |
|
|
#include "eap.h" |
44 |
|
|
#include "dh.h" |
45 |
|
|
|
46 |
|
|
int ikev2_validate_pld(struct iked_message *, size_t, size_t, |
47 |
|
|
struct ikev2_payload *); |
48 |
|
|
int ikev2_pld_payloads(struct iked *, struct iked_message *, |
49 |
|
|
size_t, size_t, unsigned int); |
50 |
|
|
int ikev2_validate_sa(struct iked_message *, size_t, size_t, |
51 |
|
|
struct ikev2_payload *, struct ikev2_sa_proposal *); |
52 |
|
|
int ikev2_pld_sa(struct iked *, struct ikev2_payload *, |
53 |
|
|
struct iked_message *, size_t, size_t); |
54 |
|
|
int ikev2_validate_xform(struct iked_message *, size_t, size_t, |
55 |
|
|
struct ikev2_transform *); |
56 |
|
|
int ikev2_pld_xform(struct iked *, struct ikev2_sa_proposal *, |
57 |
|
|
struct iked_message *, size_t, size_t); |
58 |
|
|
int ikev2_validate_attr(struct iked_message *, size_t, size_t, |
59 |
|
|
struct ikev2_attribute *); |
60 |
|
|
int ikev2_pld_attr(struct iked *, struct ikev2_transform *, |
61 |
|
|
struct iked_message *, size_t, size_t); |
62 |
|
|
int ikev2_validate_ke(struct iked_message *, size_t, size_t, |
63 |
|
|
struct ikev2_payload *, struct ikev2_keyexchange *); |
64 |
|
|
int ikev2_pld_ke(struct iked *, struct ikev2_payload *, |
65 |
|
|
struct iked_message *, size_t, size_t); |
66 |
|
|
int ikev2_validate_id(struct iked_message *, size_t, size_t, |
67 |
|
|
struct ikev2_payload *, struct ikev2_id *); |
68 |
|
|
int ikev2_pld_id(struct iked *, struct ikev2_payload *, |
69 |
|
|
struct iked_message *, size_t, size_t, unsigned int); |
70 |
|
|
int ikev2_validate_cert(struct iked_message *, size_t, size_t, |
71 |
|
|
struct ikev2_payload *, struct ikev2_cert *); |
72 |
|
|
int ikev2_pld_cert(struct iked *, struct ikev2_payload *, |
73 |
|
|
struct iked_message *, size_t, size_t); |
74 |
|
|
int ikev2_validate_certreq(struct iked_message *, size_t, size_t, |
75 |
|
|
struct ikev2_payload *, struct ikev2_cert *); |
76 |
|
|
int ikev2_pld_certreq(struct iked *, struct ikev2_payload *, |
77 |
|
|
struct iked_message *, size_t, size_t); |
78 |
|
|
int ikev2_validate_nonce(struct iked_message *, size_t, size_t, |
79 |
|
|
struct ikev2_payload *); |
80 |
|
|
int ikev2_pld_nonce(struct iked *, struct ikev2_payload *, |
81 |
|
|
struct iked_message *, size_t, size_t); |
82 |
|
|
int ikev2_validate_notify(struct iked_message *, size_t, size_t, |
83 |
|
|
struct ikev2_payload *, struct ikev2_notify *); |
84 |
|
|
int ikev2_pld_notify(struct iked *, struct ikev2_payload *, |
85 |
|
|
struct iked_message *, size_t, size_t); |
86 |
|
|
int ikev2_validate_delete(struct iked_message *, size_t, size_t, |
87 |
|
|
struct ikev2_payload *, struct ikev2_delete *); |
88 |
|
|
int ikev2_pld_delete(struct iked *, struct ikev2_payload *, |
89 |
|
|
struct iked_message *, size_t, size_t); |
90 |
|
|
int ikev2_validate_ts(struct iked_message *, size_t, size_t, |
91 |
|
|
struct ikev2_payload *, struct ikev2_tsp *); |
92 |
|
|
int ikev2_pld_ts(struct iked *, struct ikev2_payload *, |
93 |
|
|
struct iked_message *, size_t, size_t, unsigned int); |
94 |
|
|
int ikev2_validate_auth(struct iked_message *, size_t, size_t, |
95 |
|
|
struct ikev2_payload *, struct ikev2_auth *); |
96 |
|
|
int ikev2_pld_auth(struct iked *, struct ikev2_payload *, |
97 |
|
|
struct iked_message *, size_t, size_t); |
98 |
|
|
int ikev2_pld_e(struct iked *, struct ikev2_payload *, |
99 |
|
|
struct iked_message *, size_t); |
100 |
|
|
int ikev2_validate_cp(struct iked_message *, size_t, size_t, |
101 |
|
|
struct ikev2_payload *, struct ikev2_cp *); |
102 |
|
|
int ikev2_pld_cp(struct iked *, struct ikev2_payload *, |
103 |
|
|
struct iked_message *, size_t, size_t); |
104 |
|
|
int ikev2_validate_eap(struct iked_message *, size_t, size_t, |
105 |
|
|
struct ikev2_payload *, struct eap_header *); |
106 |
|
|
int ikev2_pld_eap(struct iked *, struct ikev2_payload *, |
107 |
|
|
struct iked_message *, size_t, size_t); |
108 |
|
|
|
109 |
|
|
int |
110 |
|
|
ikev2_pld_parse(struct iked *env, struct ike_header *hdr, |
111 |
|
|
struct iked_message *msg, size_t offset) |
112 |
|
|
{ |
113 |
|
|
log_debug("%s: header ispi %s rspi %s" |
114 |
|
|
" nextpayload %s version 0x%02x exchange %s flags 0x%02x" |
115 |
|
|
" msgid %d length %d response %d", __func__, |
116 |
|
|
print_spi(betoh64(hdr->ike_ispi), 8), |
117 |
|
|
print_spi(betoh64(hdr->ike_rspi), 8), |
118 |
|
|
print_map(hdr->ike_nextpayload, ikev2_payload_map), |
119 |
|
|
hdr->ike_version, |
120 |
|
|
print_map(hdr->ike_exchange, ikev2_exchange_map), |
121 |
|
|
hdr->ike_flags, |
122 |
|
|
betoh32(hdr->ike_msgid), |
123 |
|
|
betoh32(hdr->ike_length), |
124 |
|
|
msg->msg_response); |
125 |
|
|
|
126 |
|
|
if (ibuf_size(msg->msg_data) < betoh32(hdr->ike_length)) { |
127 |
|
|
log_debug("%s: short message", __func__); |
128 |
|
|
return (-1); |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
offset += sizeof(*hdr); |
132 |
|
|
|
133 |
|
|
return (ikev2_pld_payloads(env, msg, offset, |
134 |
|
|
betoh32(hdr->ike_length), hdr->ike_nextpayload)); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
int |
138 |
|
|
ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, |
139 |
|
|
struct ikev2_payload *pld) |
140 |
|
|
{ |
141 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
142 |
|
|
size_t pld_length; |
143 |
|
|
|
144 |
|
|
/* We need at least the generic header. */ |
145 |
|
|
if (left < sizeof(*pld)) { |
146 |
|
|
log_debug("%s: malformed payload: too short for generic " |
147 |
|
|
"header (%zu < %zu)", __func__, left, sizeof(*pld)); |
148 |
|
|
return (-1); |
149 |
|
|
} |
150 |
|
|
memcpy(pld, msgbuf + offset, sizeof(*pld)); |
151 |
|
|
|
152 |
|
|
/* |
153 |
|
|
* We need at least the specified number of bytes. |
154 |
|
|
* pld_length is the full size of the payload including |
155 |
|
|
* the generic payload header. |
156 |
|
|
*/ |
157 |
|
|
pld_length = betoh16(pld->pld_length); |
158 |
|
|
if (left < pld_length) { |
159 |
|
|
log_debug("%s: malformed payload: shorter than specified " |
160 |
|
|
"(%zu < %zu)", __func__, left, pld_length); |
161 |
|
|
return (-1); |
162 |
|
|
} |
163 |
|
|
/* |
164 |
|
|
* Sanity check the specified payload size, it must |
165 |
|
|
* be at last the size of the generic payload header. |
166 |
|
|
*/ |
167 |
|
|
if (pld_length < sizeof(*pld)) { |
168 |
|
|
log_debug("%s: malformed payload: shorter than minimum " |
169 |
|
|
"header size (%zu < %zu)", __func__, pld_length, |
170 |
|
|
sizeof(*pld)); |
171 |
|
|
return (-1); |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
return (0); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
int |
178 |
|
|
ikev2_pld_payloads(struct iked *env, struct iked_message *msg, |
179 |
|
|
size_t offset, size_t length, unsigned int payload) |
180 |
|
|
{ |
181 |
|
|
struct ikev2_payload pld; |
182 |
|
|
unsigned int e; |
183 |
|
|
int ret; |
184 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
185 |
|
|
size_t left; |
186 |
|
|
|
187 |
|
|
/* Check if message was decrypted in an E payload */ |
188 |
|
|
e = msg->msg_e ? IKED_E : 0; |
189 |
|
|
|
190 |
|
|
while (payload != 0 && offset < length) { |
191 |
|
|
/* Bytes left in datagram. */ |
192 |
|
|
left = length - offset; |
193 |
|
|
|
194 |
|
|
if (ikev2_validate_pld(msg, offset, left, &pld)) |
195 |
|
|
return (-1); |
196 |
|
|
|
197 |
|
|
log_debug("%s: %spayload %s" |
198 |
|
|
" nextpayload %s critical 0x%02x length %d", |
199 |
|
|
__func__, e ? "decrypted " : "", |
200 |
|
|
print_map(payload, ikev2_payload_map), |
201 |
|
|
print_map(pld.pld_nextpayload, ikev2_payload_map), |
202 |
|
|
pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, |
203 |
|
|
betoh16(pld.pld_length)); |
204 |
|
|
|
205 |
|
|
/* Skip over generic payload header. */ |
206 |
|
|
offset += sizeof(pld); |
207 |
|
|
left -= sizeof(pld); |
208 |
|
|
ret = 0; |
209 |
|
|
|
210 |
|
|
switch (payload | e) { |
211 |
|
|
case IKEV2_PAYLOAD_SA: |
212 |
|
|
case IKEV2_PAYLOAD_SA | IKED_E: |
213 |
|
|
ret = ikev2_pld_sa(env, &pld, msg, offset, left); |
214 |
|
|
break; |
215 |
|
|
case IKEV2_PAYLOAD_KE: |
216 |
|
|
case IKEV2_PAYLOAD_KE | IKED_E: |
217 |
|
|
ret = ikev2_pld_ke(env, &pld, msg, offset, left); |
218 |
|
|
break; |
219 |
|
|
case IKEV2_PAYLOAD_IDi | IKED_E: |
220 |
|
|
case IKEV2_PAYLOAD_IDr | IKED_E: |
221 |
|
|
ret = ikev2_pld_id(env, &pld, msg, offset, left, |
222 |
|
|
payload); |
223 |
|
|
break; |
224 |
|
|
case IKEV2_PAYLOAD_CERT | IKED_E: |
225 |
|
|
ret = ikev2_pld_cert(env, &pld, msg, offset, left); |
226 |
|
|
break; |
227 |
|
|
case IKEV2_PAYLOAD_CERTREQ: |
228 |
|
|
case IKEV2_PAYLOAD_CERTREQ | IKED_E: |
229 |
|
|
ret = ikev2_pld_certreq(env, &pld, msg, offset, left); |
230 |
|
|
break; |
231 |
|
|
case IKEV2_PAYLOAD_AUTH | IKED_E: |
232 |
|
|
ret = ikev2_pld_auth(env, &pld, msg, offset, left); |
233 |
|
|
break; |
234 |
|
|
case IKEV2_PAYLOAD_NONCE: |
235 |
|
|
case IKEV2_PAYLOAD_NONCE | IKED_E: |
236 |
|
|
ret = ikev2_pld_nonce(env, &pld, msg, offset, left); |
237 |
|
|
break; |
238 |
|
|
case IKEV2_PAYLOAD_NOTIFY: |
239 |
|
|
case IKEV2_PAYLOAD_NOTIFY | IKED_E: |
240 |
|
|
ret = ikev2_pld_notify(env, &pld, msg, offset, left); |
241 |
|
|
break; |
242 |
|
|
case IKEV2_PAYLOAD_DELETE | IKED_E: |
243 |
|
|
ret = ikev2_pld_delete(env, &pld, msg, offset, left); |
244 |
|
|
break; |
245 |
|
|
case IKEV2_PAYLOAD_TSi | IKED_E: |
246 |
|
|
case IKEV2_PAYLOAD_TSr | IKED_E: |
247 |
|
|
ret = ikev2_pld_ts(env, &pld, msg, offset, left, |
248 |
|
|
payload); |
249 |
|
|
break; |
250 |
|
|
case IKEV2_PAYLOAD_SK: |
251 |
|
|
ret = ikev2_pld_e(env, &pld, msg, offset); |
252 |
|
|
break; |
253 |
|
|
case IKEV2_PAYLOAD_CP | IKED_E: |
254 |
|
|
ret = ikev2_pld_cp(env, &pld, msg, offset, left); |
255 |
|
|
break; |
256 |
|
|
case IKEV2_PAYLOAD_EAP | IKED_E: |
257 |
|
|
ret = ikev2_pld_eap(env, &pld, msg, offset, left); |
258 |
|
|
break; |
259 |
|
|
default: |
260 |
|
|
print_hex(msgbuf, offset, |
261 |
|
|
betoh16(pld.pld_length) - sizeof(pld)); |
262 |
|
|
break; |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
if (ret != 0 && ikev2_msg_frompeer(msg)) { |
266 |
|
|
(void)ikev2_send_informational(env, msg); |
267 |
|
|
return (-1); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
/* Encrypted payload must appear last */ |
271 |
|
|
if (payload == IKEV2_PAYLOAD_SK) |
272 |
|
|
return (0); |
273 |
|
|
|
274 |
|
|
payload = pld.pld_nextpayload; |
275 |
|
|
offset += betoh16(pld.pld_length) - sizeof(pld); |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
return (0); |
279 |
|
|
} |
280 |
|
|
|
281 |
|
|
int |
282 |
|
|
ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left, |
283 |
|
|
struct ikev2_payload *pld, struct ikev2_sa_proposal *sap) |
284 |
|
|
{ |
285 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
286 |
|
|
size_t pld_length, sap_length; |
287 |
|
|
|
288 |
|
|
pld_length = betoh16(pld->pld_length); |
289 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*sap)) { |
290 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
291 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
292 |
|
|
sizeof(*pld) + sizeof(*sap)); |
293 |
|
|
return (-1); |
294 |
|
|
} |
295 |
|
|
|
296 |
|
|
/* This will actually be caught by earlier checks. */ |
297 |
|
|
if (left < sizeof(*sap)) { |
298 |
|
|
log_debug("%s: malformed payload: too short for header " |
299 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*sap)); |
300 |
|
|
return (-1); |
301 |
|
|
} |
302 |
|
|
memcpy(sap, msgbuf + offset, sizeof(*sap)); |
303 |
|
|
|
304 |
|
|
sap_length = betoh16(sap->sap_length); |
305 |
|
|
if (sap_length < sizeof(*sap)) { |
306 |
|
|
log_debug("%s: malformed payload: shorter than minimum header " |
307 |
|
|
"size (%zu < %zu)", __func__, sap_length, sizeof(*sap)); |
308 |
|
|
return (-1); |
309 |
|
|
} |
310 |
|
|
if (left < sap_length) { |
311 |
|
|
log_debug("%s: malformed payload: too long for actual payload " |
312 |
|
|
"size (%zu < %zu)", __func__, left, sap_length); |
313 |
|
|
return (-1); |
314 |
|
|
} |
315 |
|
|
/* |
316 |
|
|
* NB: There might be more proposals, we parse only the first one. |
317 |
|
|
* This condition must never be true. |
318 |
|
|
*/ |
319 |
|
|
if (pld_length - sizeof(*pld) < sap_length) { |
320 |
|
|
log_debug("%s: payload malformed: SA payload length mismatches " |
321 |
|
|
"proposal substructure length (%lu < %zu)", __func__, |
322 |
|
|
pld_length - sizeof(*pld), sap_length); |
323 |
|
|
return (-1); |
324 |
|
|
} |
325 |
|
|
/* |
326 |
|
|
* If there is only one proposal, sap_length must be the |
327 |
|
|
* total payload size. |
328 |
|
|
*/ |
329 |
|
|
if (!sap->sap_more && ((pld_length - sizeof(*pld)) != sap_length)) { |
330 |
|
|
log_debug("%s: payload malformed: SA payload length mismatches " |
331 |
|
|
"single proposal substructure length (%lu != %zu)", |
332 |
|
|
__func__, pld_length - sizeof(*pld), sap_length); |
333 |
|
|
return (-1); |
334 |
|
|
} |
335 |
|
|
/* |
336 |
|
|
* If there are more than one proposal, there must be bytes |
337 |
|
|
* left in the payload. |
338 |
|
|
*/ |
339 |
|
|
if (sap->sap_more && ((pld_length - sizeof(*pld)) <= sap_length)) { |
340 |
|
|
log_debug("%s: payload malformed: SA payload too small for " |
341 |
|
|
"further proposals (%zu <= %zu)", __func__, |
342 |
|
|
pld_length - sizeof(*pld), sap_length); |
343 |
|
|
return (-1); |
344 |
|
|
} |
345 |
|
|
return (0); |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
/* |
349 |
|
|
* NB: This function parses both the SA header and the first proposal. |
350 |
|
|
* Additional proposals are ignored. |
351 |
|
|
*/ |
352 |
|
|
int |
353 |
|
|
ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, |
354 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
355 |
|
|
{ |
356 |
|
|
struct ikev2_sa_proposal sap; |
357 |
|
|
struct iked_proposal *prop = NULL; |
358 |
|
|
uint32_t spi32; |
359 |
|
|
uint64_t spi = 0, spi64; |
360 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
361 |
|
|
struct iked_proposals *props; |
362 |
|
|
size_t total; |
363 |
|
|
|
364 |
|
|
if (ikev2_validate_sa(msg, offset, left, pld, &sap)) |
365 |
|
|
return (-1); |
366 |
|
|
|
367 |
|
|
if (sap.sap_more) |
368 |
|
|
log_debug("%s: more than one proposal specified", __func__); |
369 |
|
|
|
370 |
|
|
/* Assumed size of the first proposals, including SPI if present. */ |
371 |
|
|
total = (betoh16(sap.sap_length) - sizeof(sap)); |
372 |
|
|
|
373 |
|
|
props = &msg->msg_parent->msg_proposals; |
374 |
|
|
|
375 |
|
|
offset += sizeof(sap); |
376 |
|
|
left -= sizeof(sap); |
377 |
|
|
|
378 |
|
|
if (sap.sap_spisize) { |
379 |
|
|
if (left < sap.sap_spisize) { |
380 |
|
|
log_debug("%s: malformed payload: SPI larger than " |
381 |
|
|
"actual payload (%zu < %d)", __func__, left, |
382 |
|
|
sap.sap_spisize); |
383 |
|
|
return (-1); |
384 |
|
|
} |
385 |
|
|
if (total < sap.sap_spisize) { |
386 |
|
|
log_debug("%s: malformed payload: SPI larger than " |
387 |
|
|
"proposal (%zu < %d)", __func__, total, |
388 |
|
|
sap.sap_spisize); |
389 |
|
|
return (-1); |
390 |
|
|
} |
391 |
|
|
if (total < sap.sap_spisize) { |
392 |
|
|
log_debug("%s: malformed payload: SPI too large " |
393 |
|
|
"(%zu < %d)", __func__, total, sap.sap_spisize); |
394 |
|
|
return (-1); |
395 |
|
|
} |
396 |
|
|
switch (sap.sap_spisize) { |
397 |
|
|
case 4: |
398 |
|
|
memcpy(&spi32, msgbuf + offset, 4); |
399 |
|
|
spi = betoh32(spi32); |
400 |
|
|
break; |
401 |
|
|
case 8: |
402 |
|
|
memcpy(&spi64, msgbuf + offset, 8); |
403 |
|
|
spi = betoh64(spi64); |
404 |
|
|
break; |
405 |
|
|
default: |
406 |
|
|
log_debug("%s: unsupported SPI size %d", |
407 |
|
|
__func__, sap.sap_spisize); |
408 |
|
|
return (-1); |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
offset += sap.sap_spisize; |
412 |
|
|
left -= sap.sap_spisize; |
413 |
|
|
|
414 |
|
|
/* Assumed size of the proposal, now without SPI. */ |
415 |
|
|
total -= sap.sap_spisize; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
/* |
419 |
|
|
* As we verified sanity of packet headers, this check will |
420 |
|
|
* be always false, but just to be sure we keep it. |
421 |
|
|
*/ |
422 |
|
|
if (left < total) { |
423 |
|
|
log_debug("%s: payload malformed: too long for payload " |
424 |
|
|
"(%zu < %zu)", __func__, left, total); |
425 |
|
|
return (-1); |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
log_debug("%s: more %d reserved %d length %d" |
429 |
|
|
" proposal #%d protoid %s spisize %d xforms %d spi %s", |
430 |
|
|
__func__, sap.sap_more, sap.sap_reserved, |
431 |
|
|
betoh16(sap.sap_length), sap.sap_proposalnr, |
432 |
|
|
print_map(sap.sap_protoid, ikev2_saproto_map), sap.sap_spisize, |
433 |
|
|
sap.sap_transforms, print_spi(spi, sap.sap_spisize)); |
434 |
|
|
|
435 |
|
|
if (ikev2_msg_frompeer(msg)) { |
436 |
|
|
if ((msg->msg_parent->msg_prop = config_add_proposal(props, |
437 |
|
|
sap.sap_proposalnr, sap.sap_protoid)) == NULL) { |
438 |
|
|
log_debug("%s: invalid proposal", __func__); |
439 |
|
|
return (-1); |
440 |
|
|
} |
441 |
|
|
prop = msg->msg_parent->msg_prop; |
442 |
|
|
prop->prop_peerspi.spi = spi; |
443 |
|
|
prop->prop_peerspi.spi_protoid = sap.sap_protoid; |
444 |
|
|
prop->prop_peerspi.spi_size = sap.sap_spisize; |
445 |
|
|
|
446 |
|
|
prop->prop_localspi.spi_protoid = sap.sap_protoid; |
447 |
|
|
prop->prop_localspi.spi_size = sap.sap_spisize; |
448 |
|
|
} |
449 |
|
|
|
450 |
|
|
/* |
451 |
|
|
* Parse the attached transforms |
452 |
|
|
*/ |
453 |
|
|
if (sap.sap_transforms && |
454 |
|
|
ikev2_pld_xform(env, &sap, msg, offset, total) != 0) { |
455 |
|
|
log_debug("%s: invalid proposal transforms", __func__); |
456 |
|
|
return (-1); |
457 |
|
|
} |
458 |
|
|
|
459 |
|
|
return (0); |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
int |
463 |
|
|
ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, |
464 |
|
|
struct ikev2_transform *xfrm) |
465 |
|
|
{ |
466 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
467 |
|
|
size_t xfrm_length; |
468 |
|
|
|
469 |
|
|
if (total < sizeof(*xfrm)) { |
470 |
|
|
log_debug("%s: payload malformed: too short for header " |
471 |
|
|
"(%zu < %zu)", __func__, total, sizeof(*xfrm)); |
472 |
|
|
return (-1); |
473 |
|
|
} |
474 |
|
|
memcpy(xfrm, msgbuf + offset, sizeof(*xfrm)); |
475 |
|
|
|
476 |
|
|
xfrm_length = betoh16(xfrm->xfrm_length); |
477 |
|
|
if (xfrm_length < sizeof(*xfrm)) { |
478 |
|
|
log_debug("%s: payload malformed: shorter than minimal header " |
479 |
|
|
"(%zu < %zu)", __func__, xfrm_length, sizeof(*xfrm)); |
480 |
|
|
return (-1); |
481 |
|
|
} |
482 |
|
|
if (total < xfrm_length) { |
483 |
|
|
log_debug("%s: malformed payload: too long for payload size " |
484 |
|
|
"(%zu < %zu)", __func__, total, xfrm_length); |
485 |
|
|
return (-1); |
486 |
|
|
} |
487 |
|
|
|
488 |
|
|
return (0); |
489 |
|
|
} |
490 |
|
|
|
491 |
|
|
int |
492 |
|
|
ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, |
493 |
|
|
struct iked_message *msg, size_t offset, size_t total) |
494 |
|
|
{ |
495 |
|
|
struct ikev2_transform xfrm; |
496 |
|
|
char id[BUFSIZ]; |
497 |
|
|
int ret = 0; |
498 |
|
|
size_t xfrm_length; |
499 |
|
|
|
500 |
|
|
if (ikev2_validate_xform(msg, offset, total, &xfrm)) |
501 |
|
|
return (-1); |
502 |
|
|
|
503 |
|
|
xfrm_length = betoh16(xfrm.xfrm_length); |
504 |
|
|
|
505 |
|
|
switch (xfrm.xfrm_type) { |
506 |
|
|
case IKEV2_XFORMTYPE_ENCR: |
507 |
|
|
strlcpy(id, print_map(betoh16(xfrm.xfrm_id), |
508 |
|
|
ikev2_xformencr_map), sizeof(id)); |
509 |
|
|
break; |
510 |
|
|
case IKEV2_XFORMTYPE_PRF: |
511 |
|
|
strlcpy(id, print_map(betoh16(xfrm.xfrm_id), |
512 |
|
|
ikev2_xformprf_map), sizeof(id)); |
513 |
|
|
break; |
514 |
|
|
case IKEV2_XFORMTYPE_INTEGR: |
515 |
|
|
strlcpy(id, print_map(betoh16(xfrm.xfrm_id), |
516 |
|
|
ikev2_xformauth_map), sizeof(id)); |
517 |
|
|
break; |
518 |
|
|
case IKEV2_XFORMTYPE_DH: |
519 |
|
|
strlcpy(id, print_map(betoh16(xfrm.xfrm_id), |
520 |
|
|
ikev2_xformdh_map), sizeof(id)); |
521 |
|
|
break; |
522 |
|
|
case IKEV2_XFORMTYPE_ESN: |
523 |
|
|
strlcpy(id, print_map(betoh16(xfrm.xfrm_id), |
524 |
|
|
ikev2_xformesn_map), sizeof(id)); |
525 |
|
|
break; |
526 |
|
|
default: |
527 |
|
|
snprintf(id, sizeof(id), "<%d>", betoh16(xfrm.xfrm_id)); |
528 |
|
|
break; |
529 |
|
|
} |
530 |
|
|
|
531 |
|
|
log_debug("%s: more %d reserved %d length %zu" |
532 |
|
|
" type %s id %s", |
533 |
|
|
__func__, xfrm.xfrm_more, xfrm.xfrm_reserved, xfrm_length, |
534 |
|
|
print_map(xfrm.xfrm_type, ikev2_xformtype_map), id); |
535 |
|
|
|
536 |
|
|
/* |
537 |
|
|
* Parse transform attributes, if available |
538 |
|
|
*/ |
539 |
|
|
msg->msg_attrlength = 0; |
540 |
|
|
if (xfrm_length > sizeof(xfrm)) { |
541 |
|
|
if (ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), |
542 |
|
|
xfrm_length - sizeof(xfrm)) != 0) { |
543 |
|
|
return (-1); |
544 |
|
|
} |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
if (ikev2_msg_frompeer(msg)) { |
548 |
|
|
if (config_add_transform(msg->msg_parent->msg_prop, |
549 |
|
|
xfrm.xfrm_type, betoh16(xfrm.xfrm_id), |
550 |
|
|
msg->msg_attrlength, msg->msg_attrlength) == NULL) { |
551 |
|
|
log_debug("%s: failed to add transform", __func__); |
552 |
|
|
return (-1); |
553 |
|
|
} |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
/* Next transform */ |
557 |
|
|
offset += xfrm_length; |
558 |
|
|
total -= xfrm_length; |
559 |
|
|
if (xfrm.xfrm_more == IKEV2_XFORM_MORE) |
560 |
|
|
ret = ikev2_pld_xform(env, sap, msg, offset, total); |
561 |
|
|
else if (total != 0) { |
562 |
|
|
/* No more transforms but still some data left. */ |
563 |
|
|
log_debug("%s: less data than specified, %zu bytes left", |
564 |
|
|
__func__, total); |
565 |
|
|
ret = -1; |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
return (ret); |
569 |
|
|
} |
570 |
|
|
|
571 |
|
|
int |
572 |
|
|
ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, |
573 |
|
|
struct ikev2_attribute *attr) |
574 |
|
|
{ |
575 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
576 |
|
|
|
577 |
|
|
if (total < sizeof(*attr)) { |
578 |
|
|
log_debug("%s: payload malformed: too short for header " |
579 |
|
|
"(%zu < %zu)", __func__, total, sizeof(*attr)); |
580 |
|
|
return (-1); |
581 |
|
|
} |
582 |
|
|
memcpy(attr, msgbuf + offset, sizeof(*attr)); |
583 |
|
|
|
584 |
|
|
return (0); |
585 |
|
|
} |
586 |
|
|
|
587 |
|
|
int |
588 |
|
|
ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, |
589 |
|
|
struct iked_message *msg, size_t offset, size_t total) |
590 |
|
|
{ |
591 |
|
|
struct ikev2_attribute attr; |
592 |
|
|
unsigned int type; |
593 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
594 |
|
|
int ret = 0; |
595 |
|
|
size_t attr_length; |
596 |
|
|
|
597 |
|
|
if (ikev2_validate_attr(msg, offset, total, &attr)) |
598 |
|
|
return (-1); |
599 |
|
|
|
600 |
|
|
type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; |
601 |
|
|
|
602 |
|
|
log_debug("%s: attribute type %s length %d total %zu", |
603 |
|
|
__func__, print_map(type, ikev2_attrtype_map), |
604 |
|
|
betoh16(attr.attr_length), total); |
605 |
|
|
|
606 |
|
|
if (betoh16(attr.attr_type) & IKEV2_ATTRAF_TV) { |
607 |
|
|
/* Type-Value attribute */ |
608 |
|
|
offset += sizeof(attr); |
609 |
|
|
total -= sizeof(attr); |
610 |
|
|
|
611 |
|
|
if (type == IKEV2_ATTRTYPE_KEY_LENGTH) |
612 |
|
|
msg->msg_attrlength = betoh16(attr.attr_length); |
613 |
|
|
} else { |
614 |
|
|
/* Type-Length-Value attribute */ |
615 |
|
|
attr_length = betoh16(attr.attr_length); |
616 |
|
|
if (attr_length < sizeof(attr)) { |
617 |
|
|
log_debug("%s: payload malformed: shorter than " |
618 |
|
|
"minimal header (%zu < %zu)", __func__, |
619 |
|
|
attr_length, sizeof(attr)); |
620 |
|
|
return (-1); |
621 |
|
|
} |
622 |
|
|
if (total < attr_length) { |
623 |
|
|
log_debug("%s: payload malformed: attribute larger " |
624 |
|
|
"than actual payload (%zu < %zu)", __func__, |
625 |
|
|
total, attr_length); |
626 |
|
|
return (-1); |
627 |
|
|
} |
628 |
|
|
print_hex(msgbuf, offset + sizeof(attr), |
629 |
|
|
attr_length - sizeof(attr)); |
630 |
|
|
offset += attr_length; |
631 |
|
|
total -= attr_length; |
632 |
|
|
} |
633 |
|
|
|
634 |
|
|
if (total > 0) { |
635 |
|
|
/* Next attribute */ |
636 |
|
|
ret = ikev2_pld_attr(env, xfrm, msg, offset, total); |
637 |
|
|
} |
638 |
|
|
|
639 |
|
|
return (ret); |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
int |
643 |
|
|
ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left, |
644 |
|
|
struct ikev2_payload *pld, struct ikev2_keyexchange *kex) |
645 |
|
|
{ |
646 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
647 |
|
|
size_t pld_length; |
648 |
|
|
|
649 |
|
|
pld_length = betoh16(pld->pld_length); |
650 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*kex)) { |
651 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
652 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
653 |
|
|
sizeof(*pld) + sizeof(*kex)); |
654 |
|
|
return (-1); |
655 |
|
|
} |
656 |
|
|
|
657 |
|
|
/* This will actually be caught by earlier checks. */ |
658 |
|
|
if (left < sizeof(*kex)) { |
659 |
|
|
log_debug("%s: malformed payload: too short for header " |
660 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*kex)); |
661 |
|
|
return (-1); |
662 |
|
|
} |
663 |
|
|
memcpy(kex, msgbuf + offset, sizeof(*kex)); |
664 |
|
|
|
665 |
|
|
return (0); |
666 |
|
|
} |
667 |
|
|
|
668 |
|
|
int |
669 |
|
|
ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, |
670 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
671 |
|
|
{ |
672 |
|
|
struct ikev2_keyexchange kex; |
673 |
|
|
uint8_t *buf; |
674 |
|
|
size_t len; |
675 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
676 |
|
|
|
677 |
|
|
if (ikev2_validate_ke(msg, offset, left, pld, &kex)) |
678 |
|
|
return (-1); |
679 |
|
|
|
680 |
|
|
log_debug("%s: dh group %s reserved %d", __func__, |
681 |
|
|
print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), |
682 |
|
|
betoh16(kex.kex_reserved)); |
683 |
|
|
|
684 |
|
|
buf = msgbuf + offset + sizeof(kex); |
685 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); |
686 |
|
|
|
687 |
|
|
if (len == 0) { |
688 |
|
|
log_debug("%s: malformed payload: no KE data given", __func__); |
689 |
|
|
return (-1); |
690 |
|
|
} |
691 |
|
|
/* This will actually be caught by earlier checks. */ |
692 |
|
|
if (left < len) { |
693 |
|
|
log_debug("%s: malformed payload: smaller than specified " |
694 |
|
|
"(%zu < %zu)", __func__, left, len); |
695 |
|
|
return (-1); |
696 |
|
|
} |
697 |
|
|
|
698 |
|
|
print_hex(buf, 0, len); |
699 |
|
|
|
700 |
|
|
if (ikev2_msg_frompeer(msg)) { |
701 |
|
|
ibuf_release(msg->msg_parent->msg_ke); |
702 |
|
|
if ((msg->msg_parent->msg_ke = ibuf_new(buf, len)) == NULL) { |
703 |
|
|
log_debug("%s: failed to get exchange", __func__); |
704 |
|
|
return (-1); |
705 |
|
|
} |
706 |
|
|
} |
707 |
|
|
|
708 |
|
|
return (0); |
709 |
|
|
} |
710 |
|
|
|
711 |
|
|
int |
712 |
|
|
ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, |
713 |
|
|
struct ikev2_payload *pld, struct ikev2_id *id) |
714 |
|
|
{ |
715 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
716 |
|
|
size_t pld_length; |
717 |
|
|
|
718 |
|
|
pld_length = betoh16(pld->pld_length); |
719 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*id)) { |
720 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
721 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
722 |
|
|
sizeof(*pld) + sizeof(*id)); |
723 |
|
|
return (-1); |
724 |
|
|
} |
725 |
|
|
|
726 |
|
|
/* This will actually be caught by earlier checks. */ |
727 |
|
|
if (left < sizeof(*id)) { |
728 |
|
|
log_debug("%s: malformed payload: too short for header " |
729 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*id)); |
730 |
|
|
return (-1); |
731 |
|
|
} |
732 |
|
|
memcpy(id, msgbuf + offset, sizeof(*id)); |
733 |
|
|
|
734 |
|
|
return (0); |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
int |
738 |
|
|
ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, |
739 |
|
|
struct iked_message *msg, size_t offset, size_t left, unsigned int payload) |
740 |
|
|
{ |
741 |
|
|
uint8_t *ptr; |
742 |
|
|
struct ikev2_id id; |
743 |
|
|
size_t len; |
744 |
|
|
struct iked_id *idp, idb; |
745 |
|
|
struct iked_sa *sa = msg->msg_sa; |
746 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
747 |
|
|
char idstr[IKED_ID_SIZE]; |
748 |
|
|
|
749 |
|
|
if (ikev2_validate_id(msg, offset, left, pld, &id)) |
750 |
|
|
return (-1); |
751 |
|
|
|
752 |
|
|
bzero(&idb, sizeof(idb)); |
753 |
|
|
|
754 |
|
|
/* Don't strip the Id payload header */ |
755 |
|
|
ptr = msgbuf + offset; |
756 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld); |
757 |
|
|
|
758 |
|
|
idb.id_type = id.id_type; |
759 |
|
|
idb.id_offset = sizeof(id); |
760 |
|
|
if ((idb.id_buf = ibuf_new(ptr, len)) == NULL) |
761 |
|
|
return (-1); |
762 |
|
|
|
763 |
|
|
if (ikev2_print_id(&idb, idstr, sizeof(idstr)) == -1) { |
764 |
|
|
log_debug("%s: malformed id", __func__); |
765 |
|
|
return (-1); |
766 |
|
|
} |
767 |
|
|
|
768 |
|
|
log_debug("%s: id %s length %zu", __func__, idstr, len); |
769 |
|
|
|
770 |
|
|
if (!ikev2_msg_frompeer(msg)) { |
771 |
|
|
ibuf_release(idb.id_buf); |
772 |
|
|
return (0); |
773 |
|
|
} |
774 |
|
|
|
775 |
|
|
if (!((sa->sa_hdr.sh_initiator && payload == IKEV2_PAYLOAD_IDr) || |
776 |
|
|
(!sa->sa_hdr.sh_initiator && payload == IKEV2_PAYLOAD_IDi))) { |
777 |
|
|
log_debug("%s: unexpected id payload", __func__); |
778 |
|
|
return (0); |
779 |
|
|
} |
780 |
|
|
|
781 |
|
|
idp = &msg->msg_parent->msg_id; |
782 |
|
|
if (idp->id_type) { |
783 |
|
|
log_debug("%s: duplicate id payload", __func__); |
784 |
|
|
return (-1); |
785 |
|
|
} |
786 |
|
|
|
787 |
|
|
idp->id_buf = idb.id_buf; |
788 |
|
|
idp->id_offset = idb.id_offset; |
789 |
|
|
idp->id_type = idb.id_type; |
790 |
|
|
|
791 |
|
|
return (0); |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
int |
795 |
|
|
ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left, |
796 |
|
|
struct ikev2_payload *pld, struct ikev2_cert *cert) |
797 |
|
|
{ |
798 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
799 |
|
|
size_t pld_length; |
800 |
|
|
|
801 |
|
|
pld_length = betoh16(pld->pld_length); |
802 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*cert)) { |
803 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
804 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
805 |
|
|
sizeof(*pld) + sizeof(*cert)); |
806 |
|
|
return (-1); |
807 |
|
|
} |
808 |
|
|
|
809 |
|
|
/* This will actually be caught by earlier checks. */ |
810 |
|
|
if (left < sizeof(*cert)) { |
811 |
|
|
log_debug("%s: malformed payload: too short for header " |
812 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*cert)); |
813 |
|
|
return (-1); |
814 |
|
|
} |
815 |
|
|
memcpy(cert, msgbuf + offset, sizeof(*cert)); |
816 |
|
|
|
817 |
|
|
return (0); |
818 |
|
|
} |
819 |
|
|
|
820 |
|
|
int |
821 |
|
|
ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, |
822 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
823 |
|
|
{ |
824 |
|
|
struct ikev2_cert cert; |
825 |
|
|
uint8_t *buf; |
826 |
|
|
size_t len; |
827 |
|
|
struct iked_id *certid; |
828 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
829 |
|
|
|
830 |
|
|
if (ikev2_validate_cert(msg, offset, left, pld, &cert)) |
831 |
|
|
return (-1); |
832 |
|
|
offset += sizeof(cert); |
833 |
|
|
|
834 |
|
|
buf = msgbuf + offset; |
835 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); |
836 |
|
|
|
837 |
|
|
log_debug("%s: type %s length %zu", |
838 |
|
|
__func__, print_map(cert.cert_type, ikev2_cert_map), len); |
839 |
|
|
|
840 |
|
|
print_hex(buf, 0, len); |
841 |
|
|
|
842 |
|
|
if (!ikev2_msg_frompeer(msg)) |
843 |
|
|
return (0); |
844 |
|
|
|
845 |
|
|
certid = &msg->msg_parent->msg_cert; |
846 |
|
|
if (certid->id_type) { |
847 |
|
|
log_debug("%s: duplicate cert payload", __func__); |
848 |
|
|
return (-1); |
849 |
|
|
} |
850 |
|
|
|
851 |
|
|
if ((certid->id_buf = ibuf_new(buf, len)) == NULL) { |
852 |
|
|
log_debug("%s: failed to save cert", __func__); |
853 |
|
|
return (-1); |
854 |
|
|
} |
855 |
|
|
certid->id_type = cert.cert_type; |
856 |
|
|
certid->id_offset = 0; |
857 |
|
|
|
858 |
|
|
return (0); |
859 |
|
|
} |
860 |
|
|
|
861 |
|
|
int |
862 |
|
|
ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left, |
863 |
|
|
struct ikev2_payload *pld, struct ikev2_cert *cert) |
864 |
|
|
{ |
865 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
866 |
|
|
size_t pld_length; |
867 |
|
|
|
868 |
|
|
pld_length = betoh16(pld->pld_length); |
869 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*cert)) { |
870 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
871 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
872 |
|
|
sizeof(*pld) + sizeof(*cert)); |
873 |
|
|
return (-1); |
874 |
|
|
} |
875 |
|
|
|
876 |
|
|
/* This will actually be caught by earlier checks. */ |
877 |
|
|
if (left < sizeof(*cert)) { |
878 |
|
|
log_debug("%s: malformed payload: too short for header " |
879 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*cert)); |
880 |
|
|
return (-1); |
881 |
|
|
} |
882 |
|
|
memcpy(cert, msgbuf + offset, sizeof(*cert)); |
883 |
|
|
|
884 |
|
|
return (0); |
885 |
|
|
} |
886 |
|
|
|
887 |
|
|
int |
888 |
|
|
ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, |
889 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
890 |
|
|
{ |
891 |
|
|
struct iked_sa *sa = msg->msg_sa; |
892 |
|
|
struct ikev2_cert cert; |
893 |
|
|
uint8_t *buf; |
894 |
|
|
ssize_t len; |
895 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
896 |
|
|
|
897 |
|
|
if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) |
898 |
|
|
return (-1); |
899 |
|
|
offset += sizeof(cert); |
900 |
|
|
|
901 |
|
|
buf = msgbuf + offset; |
902 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); |
903 |
|
|
|
904 |
|
|
log_debug("%s: type %s length %zd", |
905 |
|
|
__func__, print_map(cert.cert_type, ikev2_cert_map), len); |
906 |
|
|
|
907 |
|
|
/* This will actually be caught by earlier checks. */ |
908 |
|
|
if (len < 0) { |
909 |
|
|
log_debug("%s: invalid certificate request length", __func__); |
910 |
|
|
return (-1); |
911 |
|
|
} |
912 |
|
|
|
913 |
|
|
print_hex(buf, 0, len); |
914 |
|
|
|
915 |
|
|
if (!ikev2_msg_frompeer(msg)) |
916 |
|
|
return (0); |
917 |
|
|
|
918 |
|
|
if (cert.cert_type == IKEV2_CERT_X509_CERT) { |
919 |
|
|
if (!len) |
920 |
|
|
return (0); |
921 |
|
|
if ((len % SHA_DIGEST_LENGTH) != 0) { |
922 |
|
|
log_debug("%s: invalid certificate request", __func__); |
923 |
|
|
return (-1); |
924 |
|
|
} |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
if (msg->msg_sa == NULL) |
928 |
|
|
return (-1); |
929 |
|
|
|
930 |
|
|
/* Optional certreq for PSK */ |
931 |
|
|
if (sa->sa_hdr.sh_initiator) |
932 |
|
|
sa->sa_stateinit |= IKED_REQ_CERT; |
933 |
|
|
else |
934 |
|
|
sa->sa_statevalid |= IKED_REQ_CERT; |
935 |
|
|
|
936 |
|
|
ca_setreq(env, sa, &sa->sa_policy->pol_localid, |
937 |
|
|
cert.cert_type, buf, len, PROC_CERT); |
938 |
|
|
|
939 |
|
|
return (0); |
940 |
|
|
} |
941 |
|
|
|
942 |
|
|
int |
943 |
|
|
ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left, |
944 |
|
|
struct ikev2_payload *pld, struct ikev2_auth *auth) |
945 |
|
|
{ |
946 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
947 |
|
|
size_t pld_length; |
948 |
|
|
|
949 |
|
|
pld_length = betoh16(pld->pld_length); |
950 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*auth)) { |
951 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
952 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
953 |
|
|
sizeof(*pld) + sizeof(*auth)); |
954 |
|
|
return (-1); |
955 |
|
|
} |
956 |
|
|
|
957 |
|
|
/* This will actually be caught by earlier checks. */ |
958 |
|
|
if (left < sizeof(*auth)) { |
959 |
|
|
log_debug("%s: malformed payload: too short for header " |
960 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*auth)); |
961 |
|
|
return (-1); |
962 |
|
|
} |
963 |
|
|
memcpy(auth, msgbuf + offset, sizeof(*auth)); |
964 |
|
|
|
965 |
|
|
return (0); |
966 |
|
|
} |
967 |
|
|
|
968 |
|
|
int |
969 |
|
|
ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, |
970 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
971 |
|
|
{ |
972 |
|
|
struct ikev2_auth auth; |
973 |
|
|
struct iked_id *idp; |
974 |
|
|
uint8_t *buf; |
975 |
|
|
size_t len; |
976 |
|
|
struct iked_sa *sa = msg->msg_sa; |
977 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
978 |
|
|
|
979 |
|
|
if (ikev2_validate_auth(msg, offset, left, pld, &auth)) |
980 |
|
|
return (-1); |
981 |
|
|
offset += sizeof(auth); |
982 |
|
|
|
983 |
|
|
buf = msgbuf + offset; |
984 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth); |
985 |
|
|
|
986 |
|
|
log_debug("%s: method %s length %zu", |
987 |
|
|
__func__, print_map(auth.auth_method, ikev2_auth_map), len); |
988 |
|
|
|
989 |
|
|
print_hex(buf, 0, len); |
990 |
|
|
|
991 |
|
|
if (!ikev2_msg_frompeer(msg)) |
992 |
|
|
return (0); |
993 |
|
|
|
994 |
|
|
/* The AUTH payload indicates if the responder wants EAP or not */ |
995 |
|
|
if (!sa_stateok(sa, IKEV2_STATE_EAP)) |
996 |
|
|
sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); |
997 |
|
|
|
998 |
|
|
idp = &msg->msg_parent->msg_auth; |
999 |
|
|
if (idp->id_type) { |
1000 |
|
|
log_debug("%s: duplicate auth payload", __func__); |
1001 |
|
|
return (-1); |
1002 |
|
|
} |
1003 |
|
|
|
1004 |
|
|
ibuf_release(idp->id_buf); |
1005 |
|
|
idp->id_type = auth.auth_method; |
1006 |
|
|
idp->id_offset = 0; |
1007 |
|
|
if ((idp->id_buf = ibuf_new(buf, len)) == NULL) |
1008 |
|
|
return (-1); |
1009 |
|
|
|
1010 |
|
|
return (0); |
1011 |
|
|
} |
1012 |
|
|
|
1013 |
|
|
int |
1014 |
|
|
ikev2_validate_nonce(struct iked_message *msg, size_t offset, size_t left, |
1015 |
|
|
struct ikev2_payload *pld) |
1016 |
|
|
{ |
1017 |
|
|
size_t pld_length; |
1018 |
|
|
|
1019 |
|
|
/* This will actually be caught by earlier checks. */ |
1020 |
|
|
pld_length = betoh16(pld->pld_length); |
1021 |
|
|
if (pld_length < sizeof(*pld)) { |
1022 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1023 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1024 |
|
|
sizeof(*pld)); |
1025 |
|
|
return (-1); |
1026 |
|
|
} |
1027 |
|
|
|
1028 |
|
|
return (0); |
1029 |
|
|
} |
1030 |
|
|
|
1031 |
|
|
int |
1032 |
|
|
ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, |
1033 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
1034 |
|
|
{ |
1035 |
|
|
size_t len; |
1036 |
|
|
uint8_t *buf; |
1037 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1038 |
|
|
|
1039 |
|
|
if (ikev2_validate_nonce(msg, offset, left, pld)) |
1040 |
|
|
return (-1); |
1041 |
|
|
|
1042 |
|
|
buf = msgbuf + offset; |
1043 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld); |
1044 |
|
|
|
1045 |
|
|
if (len == 0) { |
1046 |
|
|
log_debug("%s: malformed payload: no NONCE given", __func__); |
1047 |
|
|
return (-1); |
1048 |
|
|
} |
1049 |
|
|
/* This will actually be caught by earlier checks. */ |
1050 |
|
|
if (left < len) { |
1051 |
|
|
log_debug("%s: malformed payload: smaller than specified " |
1052 |
|
|
"(%zu < %zu)", __func__, left, len); |
1053 |
|
|
return (-1); |
1054 |
|
|
} |
1055 |
|
|
|
1056 |
|
|
print_hex(buf, 0, len); |
1057 |
|
|
|
1058 |
|
|
if (ikev2_msg_frompeer(msg)) { |
1059 |
|
|
ibuf_release(msg->msg_nonce); |
1060 |
|
|
if ((msg->msg_nonce = ibuf_new(buf, len)) == NULL) { |
1061 |
|
|
log_debug("%s: failed to get peer nonce", __func__); |
1062 |
|
|
return (-1); |
1063 |
|
|
} |
1064 |
|
|
msg->msg_parent->msg_nonce = msg->msg_nonce; |
1065 |
|
|
} |
1066 |
|
|
|
1067 |
|
|
return (0); |
1068 |
|
|
} |
1069 |
|
|
|
1070 |
|
|
int |
1071 |
|
|
ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left, |
1072 |
|
|
struct ikev2_payload *pld, struct ikev2_notify *n) |
1073 |
|
|
{ |
1074 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1075 |
|
|
size_t pld_length; |
1076 |
|
|
|
1077 |
|
|
pld_length = betoh16(pld->pld_length); |
1078 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*n)) { |
1079 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1080 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1081 |
|
|
sizeof(*pld) + sizeof(*n)); |
1082 |
|
|
return (-1); |
1083 |
|
|
} |
1084 |
|
|
|
1085 |
|
|
/* This will actually be caught by earlier checks. */ |
1086 |
|
|
if (left < sizeof(*n)) { |
1087 |
|
|
log_debug("%s: malformed payload: too short for header " |
1088 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*n)); |
1089 |
|
|
return (-1); |
1090 |
|
|
} |
1091 |
|
|
memcpy(n, msgbuf + offset, sizeof(*n)); |
1092 |
|
|
|
1093 |
|
|
return (0); |
1094 |
|
|
} |
1095 |
|
|
|
1096 |
|
|
int |
1097 |
|
|
ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, |
1098 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
1099 |
|
|
{ |
1100 |
|
|
struct ikev2_notify n; |
1101 |
|
|
uint8_t *buf, md[SHA_DIGEST_LENGTH]; |
1102 |
|
|
size_t len; |
1103 |
|
|
uint32_t spi32; |
1104 |
|
|
uint64_t spi64; |
1105 |
|
|
struct iked_spi *rekey; |
1106 |
|
|
uint16_t type; |
1107 |
|
|
uint16_t group; |
1108 |
|
|
uint16_t cpi; |
1109 |
|
|
uint16_t signature_hash; |
1110 |
|
|
uint8_t transform; |
1111 |
|
|
|
1112 |
|
|
if (ikev2_validate_notify(msg, offset, left, pld, &n)) |
1113 |
|
|
return (-1); |
1114 |
|
|
type = betoh16(n.n_type); |
1115 |
|
|
|
1116 |
|
|
log_debug("%s: protoid %s spisize %d type %s", |
1117 |
|
|
__func__, |
1118 |
|
|
print_map(n.n_protoid, ikev2_saproto_map), n.n_spisize, |
1119 |
|
|
print_map(type, ikev2_n_map)); |
1120 |
|
|
|
1121 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(n); |
1122 |
|
|
if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(n), len)) == NULL) |
1123 |
|
|
return (-1); |
1124 |
|
|
|
1125 |
|
|
print_hex(buf, 0, len); |
1126 |
|
|
|
1127 |
|
|
if (!ikev2_msg_frompeer(msg)) |
1128 |
|
|
return (0); |
1129 |
|
|
|
1130 |
|
|
switch (type) { |
1131 |
|
|
case IKEV2_N_NAT_DETECTION_SOURCE_IP: |
1132 |
|
|
case IKEV2_N_NAT_DETECTION_DESTINATION_IP: |
1133 |
|
|
if (len != sizeof(md)) { |
1134 |
|
|
log_debug("%s: malformed payload: hash size mismatch" |
1135 |
|
|
" (%zu != %zu)", __func__, len, sizeof(md)); |
1136 |
|
|
return (-1); |
1137 |
|
|
} |
1138 |
|
|
if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) |
1139 |
|
|
return (-1); |
1140 |
|
|
if (memcmp(buf, md, len) != 0) { |
1141 |
|
|
log_debug("%s: %s detected NAT, enabling " |
1142 |
|
|
"UDP encapsulation", __func__, |
1143 |
|
|
print_map(type, ikev2_n_map)); |
1144 |
|
|
|
1145 |
|
|
/* |
1146 |
|
|
* Enable UDP encapsulation of ESP packages if |
1147 |
|
|
* the check detected NAT. |
1148 |
|
|
*/ |
1149 |
|
|
if (msg->msg_sa != NULL) |
1150 |
|
|
msg->msg_sa->sa_udpencap = 1; |
1151 |
|
|
} |
1152 |
|
|
print_hex(md, 0, sizeof(md)); |
1153 |
|
|
break; |
1154 |
|
|
case IKEV2_N_INVALID_KE_PAYLOAD: |
1155 |
|
|
if (sa_stateok(msg->msg_sa, IKEV2_STATE_VALID) && |
1156 |
|
|
!msg->msg_e) { |
1157 |
|
|
log_debug("%s: INVALID_KE_PAYLOAD not encrypted", |
1158 |
|
|
__func__); |
1159 |
|
|
return (-1); |
1160 |
|
|
} |
1161 |
|
|
if (len != sizeof(group)) { |
1162 |
|
|
log_debug("%s: malformed payload: group size mismatch" |
1163 |
|
|
" (%zu != %zu)", __func__, len, sizeof(group)); |
1164 |
|
|
return (-1); |
1165 |
|
|
} |
1166 |
|
|
/* XXX chould also happen for PFS */ |
1167 |
|
|
if (!msg->msg_sa->sa_hdr.sh_initiator) { |
1168 |
|
|
log_debug("%s: not an initiator", __func__); |
1169 |
|
|
sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); |
1170 |
|
|
msg->msg_sa = NULL; |
1171 |
|
|
return (-1); |
1172 |
|
|
} |
1173 |
|
|
memcpy(&group, buf, len); |
1174 |
|
|
group = betoh16(group); |
1175 |
|
|
if ((msg->msg_policy->pol_peerdh = group_get(group)) |
1176 |
|
|
== NULL) { |
1177 |
|
|
log_debug("%s: unable to select DH group %d", __func__, |
1178 |
|
|
group); |
1179 |
|
|
return (-1); |
1180 |
|
|
} |
1181 |
|
|
log_debug("%s: responder selected DH group %d", __func__, |
1182 |
|
|
group); |
1183 |
|
|
sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); |
1184 |
|
|
msg->msg_sa = NULL; |
1185 |
|
|
|
1186 |
|
|
/* |
1187 |
|
|
* XXX should also happen for PFS so we have to check state. |
1188 |
|
|
*/ |
1189 |
|
|
timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); |
1190 |
|
|
timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); |
1191 |
|
|
break; |
1192 |
|
|
case IKEV2_N_NO_ADDITIONAL_SAS: |
1193 |
|
|
if (!msg->msg_e) { |
1194 |
|
|
log_debug("%s: NO_ADDITIONAL_SAS not encrypted", |
1195 |
|
|
__func__); |
1196 |
|
|
return (-1); |
1197 |
|
|
} |
1198 |
|
|
/* This makes sense for Child SAs only atm */ |
1199 |
|
|
if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) { |
1200 |
|
|
ikev2_disable_rekeying(env, msg->msg_sa); |
1201 |
|
|
msg->msg_sa->sa_stateflags &= ~IKED_REQ_CHILDSA; |
1202 |
|
|
} |
1203 |
|
|
break; |
1204 |
|
|
case IKEV2_N_REKEY_SA: |
1205 |
|
|
if (!msg->msg_e) { |
1206 |
|
|
log_debug("%s: N_REKEY_SA not encrypted", __func__); |
1207 |
|
|
return (-1); |
1208 |
|
|
} |
1209 |
|
|
if (len != n.n_spisize) { |
1210 |
|
|
log_debug("%s: malformed notification", __func__); |
1211 |
|
|
return (-1); |
1212 |
|
|
} |
1213 |
|
|
rekey = &msg->msg_parent->msg_rekey; |
1214 |
|
|
if (rekey->spi != 0) { |
1215 |
|
|
log_debug("%s: rekeying of multiple SAs not supported", |
1216 |
|
|
__func__); |
1217 |
|
|
return (-1); |
1218 |
|
|
} |
1219 |
|
|
switch (n.n_spisize) { |
1220 |
|
|
case 4: |
1221 |
|
|
memcpy(&spi32, buf, len); |
1222 |
|
|
rekey->spi = betoh32(spi32); |
1223 |
|
|
break; |
1224 |
|
|
case 8: |
1225 |
|
|
memcpy(&spi64, buf, len); |
1226 |
|
|
rekey->spi = betoh64(spi64); |
1227 |
|
|
break; |
1228 |
|
|
default: |
1229 |
|
|
log_debug("%s: invalid spi size %d", __func__, |
1230 |
|
|
n.n_spisize); |
1231 |
|
|
return (-1); |
1232 |
|
|
} |
1233 |
|
|
rekey->spi_size = n.n_spisize; |
1234 |
|
|
rekey->spi_protoid = n.n_protoid; |
1235 |
|
|
|
1236 |
|
|
log_debug("%s: rekey %s spi %s", __func__, |
1237 |
|
|
print_map(n.n_protoid, ikev2_saproto_map), |
1238 |
|
|
print_spi(rekey->spi, n.n_spisize)); |
1239 |
|
|
break; |
1240 |
|
|
case IKEV2_N_IPCOMP_SUPPORTED: |
1241 |
|
|
if (!msg->msg_e) { |
1242 |
|
|
log_debug("%s: N_IPCOMP_SUPPORTED not encrypted", |
1243 |
|
|
__func__); |
1244 |
|
|
return (-1); |
1245 |
|
|
} |
1246 |
|
|
if (len < sizeof(cpi) + sizeof(transform)) { |
1247 |
|
|
log_debug("%s: ignoring malformed ipcomp notification", |
1248 |
|
|
__func__); |
1249 |
|
|
return (0); |
1250 |
|
|
} |
1251 |
|
|
memcpy(&cpi, buf, sizeof(cpi)); |
1252 |
|
|
memcpy(&transform, buf + sizeof(cpi), sizeof(transform)); |
1253 |
|
|
log_debug("%s: cpi 0x%x, transform %s, len %zu", __func__, |
1254 |
|
|
betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len); |
1255 |
|
|
/* we only support deflate */ |
1256 |
|
|
if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) && |
1257 |
|
|
(transform == IKEV2_IPCOMP_DEFLATE)) { |
1258 |
|
|
msg->msg_sa->sa_ipcomp = transform; |
1259 |
|
|
msg->msg_sa->sa_cpi_out = betoh16(cpi); |
1260 |
|
|
} |
1261 |
|
|
break; |
1262 |
|
|
case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: |
1263 |
|
|
if (msg->msg_e) { |
1264 |
|
|
log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", |
1265 |
|
|
__func__); |
1266 |
|
|
return (-1); |
1267 |
|
|
} |
1268 |
|
|
if (msg->msg_sa == NULL || |
1269 |
|
|
msg->msg_sa->sa_sigsha2) { |
1270 |
|
|
log_debug("%s: SIGNATURE_HASH_ALGORITHMS: no SA or " |
1271 |
|
|
"duplicate notify", __func__); |
1272 |
|
|
return (-1); |
1273 |
|
|
} |
1274 |
|
|
if (len < sizeof(signature_hash) || |
1275 |
|
|
len % sizeof(signature_hash)) { |
1276 |
|
|
log_debug("%s: malformed signature hash notification" |
1277 |
|
|
"(%zu bytes)", __func__, len); |
1278 |
|
|
return (0); |
1279 |
|
|
} |
1280 |
|
|
while (len >= sizeof(signature_hash)) { |
1281 |
|
|
memcpy(&signature_hash, buf, sizeof(signature_hash)); |
1282 |
|
|
signature_hash = betoh16(signature_hash); |
1283 |
|
|
log_debug("%s: signature hash %s (%x)", __func__, |
1284 |
|
|
print_map(signature_hash, ikev2_sighash_map), |
1285 |
|
|
signature_hash); |
1286 |
|
|
len -= sizeof(signature_hash); |
1287 |
|
|
buf += sizeof(signature_hash); |
1288 |
|
|
if (signature_hash == IKEV2_SIGHASH_SHA2_256) |
1289 |
|
|
msg->msg_sa->sa_sigsha2 = 1; |
1290 |
|
|
} |
1291 |
|
|
break; |
1292 |
|
|
} |
1293 |
|
|
|
1294 |
|
|
return (0); |
1295 |
|
|
} |
1296 |
|
|
|
1297 |
|
|
int |
1298 |
|
|
ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left, |
1299 |
|
|
struct ikev2_payload *pld, struct ikev2_delete *del) |
1300 |
|
|
{ |
1301 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1302 |
|
|
size_t pld_length; |
1303 |
|
|
|
1304 |
|
|
pld_length = betoh16(pld->pld_length); |
1305 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*del)) { |
1306 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1307 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1308 |
|
|
sizeof(*pld) + sizeof(*del)); |
1309 |
|
|
return (-1); |
1310 |
|
|
} |
1311 |
|
|
|
1312 |
|
|
/* This will actually be caught by earlier checks. */ |
1313 |
|
|
if (left < sizeof(*del)) { |
1314 |
|
|
log_debug("%s: malformed payload: too short for header " |
1315 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*del)); |
1316 |
|
|
return (-1); |
1317 |
|
|
} |
1318 |
|
|
memcpy(del, msgbuf + offset, sizeof(*del)); |
1319 |
|
|
|
1320 |
|
|
return (0); |
1321 |
|
|
} |
1322 |
|
|
|
1323 |
|
|
int |
1324 |
|
|
ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, |
1325 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
1326 |
|
|
{ |
1327 |
|
|
struct iked_childsa **peersas = NULL; |
1328 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1329 |
|
|
struct ikev2_delete del, *localdel; |
1330 |
|
|
struct ibuf *resp = NULL; |
1331 |
|
|
uint64_t *localspi = NULL; |
1332 |
|
|
uint64_t spi64, spi = 0; |
1333 |
|
|
uint32_t spi32; |
1334 |
|
|
uint8_t *buf, *msgbuf = ibuf_data(msg->msg_data); |
1335 |
|
|
size_t found = 0, failed = 0; |
1336 |
|
|
int cnt, i, len, sz, ret = -1; |
1337 |
|
|
|
1338 |
|
|
/* Skip if it's a response, then we don't have to deal with it */ |
1339 |
|
|
if (ikev2_msg_frompeer(msg) && |
1340 |
|
|
msg->msg_parent->msg_response) |
1341 |
|
|
return (0); |
1342 |
|
|
|
1343 |
|
|
if (ikev2_validate_delete(msg, offset, left, pld, &del)) |
1344 |
|
|
return (-1); |
1345 |
|
|
cnt = betoh16(del.del_nspi); |
1346 |
|
|
sz = del.del_spisize; |
1347 |
|
|
|
1348 |
|
|
log_debug("%s: proto %s spisize %d nspi %d", |
1349 |
|
|
__func__, print_map(del.del_protoid, ikev2_saproto_map), |
1350 |
|
|
sz, cnt); |
1351 |
|
|
|
1352 |
|
|
buf = msgbuf + offset + sizeof(del); |
1353 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(del); |
1354 |
|
|
|
1355 |
|
|
print_hex(buf, 0, len); |
1356 |
|
|
|
1357 |
|
|
switch (sz) { |
1358 |
|
|
case 4: |
1359 |
|
|
case 8: |
1360 |
|
|
break; |
1361 |
|
|
default: |
1362 |
|
|
if (del.del_protoid != IKEV2_SAPROTO_IKE) { |
1363 |
|
|
log_debug("%s: invalid SPI size", __func__); |
1364 |
|
|
return (-1); |
1365 |
|
|
} |
1366 |
|
|
if (ikev2_msg_frompeer(msg)) { |
1367 |
|
|
/* Send an empty informational response */ |
1368 |
|
|
if ((resp = ibuf_static()) == NULL) |
1369 |
|
|
goto done; |
1370 |
|
|
ret = ikev2_send_ike_e(env, sa, resp, |
1371 |
|
|
IKEV2_PAYLOAD_NONE, |
1372 |
|
|
IKEV2_EXCHANGE_INFORMATIONAL, 1); |
1373 |
|
|
msg->msg_parent->msg_responded = 1; |
1374 |
|
|
ibuf_release(resp); |
1375 |
|
|
sa_state(env, sa, IKEV2_STATE_CLOSED); |
1376 |
|
|
} else { |
1377 |
|
|
/* |
1378 |
|
|
* We're sending a delete message. Upper layer |
1379 |
|
|
* must deal with deletion of the IKE SA. |
1380 |
|
|
*/ |
1381 |
|
|
ret = 0; |
1382 |
|
|
} |
1383 |
|
|
return (ret); |
1384 |
|
|
} |
1385 |
|
|
|
1386 |
|
|
if ((len / sz) != cnt) { |
1387 |
|
|
log_debug("%s: invalid payload length %d/%d != %d", |
1388 |
|
|
__func__, len, sz, cnt); |
1389 |
|
|
return (-1); |
1390 |
|
|
} |
1391 |
|
|
|
1392 |
|
|
if (ikev2_msg_frompeer(msg) && |
1393 |
|
|
((peersas = calloc(cnt, sizeof(struct iked_childsa *))) == NULL || |
1394 |
|
|
(localspi = calloc(cnt, sizeof(uint64_t))) == NULL)) { |
1395 |
|
|
log_warn("%s", __func__); |
1396 |
|
|
goto done; |
1397 |
|
|
} |
1398 |
|
|
|
1399 |
|
|
for (i = 0; i < cnt; i++) { |
1400 |
|
|
switch (sz) { |
1401 |
|
|
case 4: |
1402 |
|
|
memcpy(&spi32, buf + (i * sz), sizeof(spi32)); |
1403 |
|
|
spi = betoh32(spi32); |
1404 |
|
|
break; |
1405 |
|
|
case 8: |
1406 |
|
|
memcpy(&spi64, buf + (i * sz), sizeof(spi64)); |
1407 |
|
|
spi = betoh64(spi64); |
1408 |
|
|
break; |
1409 |
|
|
} |
1410 |
|
|
|
1411 |
|
|
log_debug("%s: spi %s", __func__, print_spi(spi, sz)); |
1412 |
|
|
|
1413 |
|
|
if (peersas == NULL || sa == NULL) |
1414 |
|
|
continue; |
1415 |
|
|
|
1416 |
|
|
if ((peersas[i] = childsa_lookup(sa, spi, |
1417 |
|
|
del.del_protoid)) == NULL) { |
1418 |
|
|
log_warnx("%s: CHILD SA doesn't exist for spi %s", |
1419 |
|
|
__func__, print_spi(spi, del.del_spisize)); |
1420 |
|
|
continue; |
1421 |
|
|
} |
1422 |
|
|
|
1423 |
|
|
if (ikev2_childsa_delete(env, sa, del.del_protoid, spi, |
1424 |
|
|
&localspi[i], 0) == -1) |
1425 |
|
|
failed++; |
1426 |
|
|
else |
1427 |
|
|
found++; |
1428 |
|
|
|
1429 |
|
|
/* |
1430 |
|
|
* Flows are left in the require mode so that it would be |
1431 |
|
|
* possible to quickly negotiate a new Child SA |
1432 |
|
|
*/ |
1433 |
|
|
} |
1434 |
|
|
|
1435 |
|
|
/* Parsed outgoing message? */ |
1436 |
|
|
if (!ikev2_msg_frompeer(msg)) |
1437 |
|
|
goto done; |
1438 |
|
|
|
1439 |
|
|
if (msg->msg_parent->msg_response) { |
1440 |
|
|
ret = 0; |
1441 |
|
|
goto done; |
1442 |
|
|
} |
1443 |
|
|
|
1444 |
|
|
/* Response to the INFORMATIONAL with Delete payload */ |
1445 |
|
|
|
1446 |
|
|
if ((resp = ibuf_static()) == NULL) |
1447 |
|
|
goto done; |
1448 |
|
|
|
1449 |
|
|
if (found) { |
1450 |
|
|
if ((localdel = ibuf_advance(resp, sizeof(*localdel))) == NULL) |
1451 |
|
|
goto done; |
1452 |
|
|
|
1453 |
|
|
localdel->del_protoid = del.del_protoid; |
1454 |
|
|
localdel->del_spisize = del.del_spisize; |
1455 |
|
|
localdel->del_nspi = htobe16(found); |
1456 |
|
|
|
1457 |
|
|
for (i = 0; i < cnt; i++) { |
1458 |
|
|
switch (sz) { |
1459 |
|
|
case 4: |
1460 |
|
|
spi32 = htobe32(localspi[i]); |
1461 |
|
|
if (ibuf_add(resp, &spi32, sizeof(spi32)) != 0) |
1462 |
|
|
goto done; |
1463 |
|
|
break; |
1464 |
|
|
case 8: |
1465 |
|
|
spi64 = htobe64(localspi[i]); |
1466 |
|
|
if (ibuf_add(resp, &spi64, sizeof(spi64)) != 0) |
1467 |
|
|
goto done; |
1468 |
|
|
break; |
1469 |
|
|
} |
1470 |
|
|
} |
1471 |
|
|
|
1472 |
|
|
log_warnx("%s: deleted %zu spis", __func__, found); |
1473 |
|
|
} |
1474 |
|
|
|
1475 |
|
|
if (found) { |
1476 |
|
|
ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_DELETE, |
1477 |
|
|
IKEV2_EXCHANGE_INFORMATIONAL, 1); |
1478 |
|
|
msg->msg_parent->msg_responded = 1; |
1479 |
|
|
} else { |
1480 |
|
|
/* XXX should we send an INVALID_SPI notification? */ |
1481 |
|
|
ret = 0; |
1482 |
|
|
} |
1483 |
|
|
|
1484 |
|
|
done: |
1485 |
|
|
free(localspi); |
1486 |
|
|
free(peersas); |
1487 |
|
|
ibuf_release(resp); |
1488 |
|
|
return (ret); |
1489 |
|
|
} |
1490 |
|
|
|
1491 |
|
|
int |
1492 |
|
|
ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, |
1493 |
|
|
struct ikev2_payload *pld, struct ikev2_tsp *tsp) |
1494 |
|
|
{ |
1495 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1496 |
|
|
size_t pld_length; |
1497 |
|
|
|
1498 |
|
|
pld_length = betoh16(pld->pld_length); |
1499 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*tsp)) { |
1500 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1501 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1502 |
|
|
sizeof(*pld) + sizeof(*tsp)); |
1503 |
|
|
return (-1); |
1504 |
|
|
} |
1505 |
|
|
|
1506 |
|
|
/* This will actually be caught by earlier checks. */ |
1507 |
|
|
if (left < sizeof(*tsp)) { |
1508 |
|
|
log_debug("%s: malformed payload: too short for header " |
1509 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*tsp)); |
1510 |
|
|
return (-1); |
1511 |
|
|
} |
1512 |
|
|
memcpy(tsp, msgbuf + offset, sizeof(*tsp)); |
1513 |
|
|
|
1514 |
|
|
return (0); |
1515 |
|
|
} |
1516 |
|
|
|
1517 |
|
|
int |
1518 |
|
|
ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, |
1519 |
|
|
struct iked_message *msg, size_t offset, size_t left, unsigned int payload) |
1520 |
|
|
{ |
1521 |
|
|
struct ikev2_tsp tsp; |
1522 |
|
|
struct ikev2_ts ts; |
1523 |
|
|
size_t len, i; |
1524 |
|
|
struct sockaddr_in s4; |
1525 |
|
|
struct sockaddr_in6 s6; |
1526 |
|
|
uint8_t buf[2][128]; |
1527 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1528 |
|
|
|
1529 |
|
|
if (ikev2_validate_ts(msg, offset, left, pld, &tsp)) |
1530 |
|
|
return (-1); |
1531 |
|
|
offset += sizeof(tsp); |
1532 |
|
|
|
1533 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(tsp); |
1534 |
|
|
|
1535 |
|
|
log_debug("%s: count %d length %zu", __func__, |
1536 |
|
|
tsp.tsp_count, len); |
1537 |
|
|
|
1538 |
|
|
for (i = 0; i < tsp.tsp_count; i++) { |
1539 |
|
|
memcpy(&ts, msgbuf + offset, sizeof(ts)); |
1540 |
|
|
|
1541 |
|
|
log_debug("%s: type %s protoid %u length %d " |
1542 |
|
|
"startport %u endport %u", __func__, |
1543 |
|
|
print_map(ts.ts_type, ikev2_ts_map), |
1544 |
|
|
ts.ts_protoid, betoh16(ts.ts_length), |
1545 |
|
|
betoh16(ts.ts_startport), |
1546 |
|
|
betoh16(ts.ts_endport)); |
1547 |
|
|
|
1548 |
|
|
switch (ts.ts_type) { |
1549 |
|
|
case IKEV2_TS_IPV4_ADDR_RANGE: |
1550 |
|
|
bzero(&s4, sizeof(s4)); |
1551 |
|
|
s4.sin_family = AF_INET; |
1552 |
|
|
s4.sin_len = sizeof(s4); |
1553 |
|
|
memcpy(&s4.sin_addr.s_addr, |
1554 |
|
|
msgbuf + offset + sizeof(ts), 4); |
1555 |
|
|
print_host((struct sockaddr *)&s4, |
1556 |
|
|
(char *)buf[0], sizeof(buf[0])); |
1557 |
|
|
memcpy(&s4.sin_addr.s_addr, |
1558 |
|
|
msgbuf + offset + sizeof(ts) + 4, 4); |
1559 |
|
|
print_host((struct sockaddr *)&s4, |
1560 |
|
|
(char *)buf[1], sizeof(buf[1])); |
1561 |
|
|
log_debug("%s: start %s end %s", __func__, |
1562 |
|
|
buf[0], buf[1]); |
1563 |
|
|
break; |
1564 |
|
|
case IKEV2_TS_IPV6_ADDR_RANGE: |
1565 |
|
|
bzero(&s6, sizeof(s6)); |
1566 |
|
|
s6.sin6_family = AF_INET6; |
1567 |
|
|
s6.sin6_len = sizeof(s6); |
1568 |
|
|
memcpy(&s6.sin6_addr, |
1569 |
|
|
msgbuf + offset + sizeof(ts), 16); |
1570 |
|
|
print_host((struct sockaddr *)&s6, |
1571 |
|
|
(char *)buf[0], sizeof(buf[0])); |
1572 |
|
|
memcpy(&s6.sin6_addr, |
1573 |
|
|
msgbuf + offset + sizeof(ts) + 16, 16); |
1574 |
|
|
print_host((struct sockaddr *)&s6, |
1575 |
|
|
(char *)buf[1], sizeof(buf[1])); |
1576 |
|
|
log_debug("%s: start %s end %s", __func__, |
1577 |
|
|
buf[0], buf[1]); |
1578 |
|
|
break; |
1579 |
|
|
default: |
1580 |
|
|
break; |
1581 |
|
|
} |
1582 |
|
|
|
1583 |
|
|
offset += betoh16(ts.ts_length); |
1584 |
|
|
} |
1585 |
|
|
|
1586 |
|
|
return (0); |
1587 |
|
|
} |
1588 |
|
|
|
1589 |
|
|
int |
1590 |
|
|
ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, |
1591 |
|
|
struct iked_message *msg, size_t offset) |
1592 |
|
|
{ |
1593 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1594 |
|
|
struct ibuf *e = NULL; |
1595 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1596 |
|
|
struct iked_message emsg; |
1597 |
|
|
uint8_t *buf; |
1598 |
|
|
size_t len; |
1599 |
|
|
int ret = -1; |
1600 |
|
|
|
1601 |
|
|
buf = msgbuf + offset; |
1602 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld); |
1603 |
|
|
|
1604 |
|
|
if ((e = ibuf_new(buf, len)) == NULL) |
1605 |
|
|
goto done; |
1606 |
|
|
|
1607 |
|
|
if (ikev2_msg_frompeer(msg)) { |
1608 |
|
|
e = ikev2_msg_decrypt(env, msg->msg_sa, msg->msg_data, e); |
1609 |
|
|
} else { |
1610 |
|
|
sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; |
1611 |
|
|
e = ikev2_msg_decrypt(env, msg->msg_sa, msg->msg_data, e); |
1612 |
|
|
sa->sa_hdr.sh_initiator = sa->sa_hdr.sh_initiator ? 0 : 1; |
1613 |
|
|
} |
1614 |
|
|
|
1615 |
|
|
if (e == NULL) |
1616 |
|
|
goto done; |
1617 |
|
|
|
1618 |
|
|
/* |
1619 |
|
|
* Parse decrypted payload |
1620 |
|
|
*/ |
1621 |
|
|
bzero(&emsg, sizeof(emsg)); |
1622 |
|
|
memcpy(&emsg, msg, sizeof(*msg)); |
1623 |
|
|
emsg.msg_data = e; |
1624 |
|
|
emsg.msg_e = 1; |
1625 |
|
|
emsg.msg_parent = msg; |
1626 |
|
|
TAILQ_INIT(&emsg.msg_proposals); |
1627 |
|
|
|
1628 |
|
|
ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e), |
1629 |
|
|
pld->pld_nextpayload); |
1630 |
|
|
|
1631 |
|
|
done: |
1632 |
|
|
ibuf_release(e); |
1633 |
|
|
|
1634 |
|
|
return (ret); |
1635 |
|
|
} |
1636 |
|
|
|
1637 |
|
|
int |
1638 |
|
|
ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left, |
1639 |
|
|
struct ikev2_payload *pld, struct ikev2_cp *cp) |
1640 |
|
|
{ |
1641 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1642 |
|
|
size_t pld_length; |
1643 |
|
|
|
1644 |
|
|
pld_length = betoh16(pld->pld_length); |
1645 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*cp)) { |
1646 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1647 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1648 |
|
|
sizeof(*pld) + sizeof(*cp)); |
1649 |
|
|
return (-1); |
1650 |
|
|
} |
1651 |
|
|
|
1652 |
|
|
/* This will actually be caught by earlier checks. */ |
1653 |
|
|
if (left < sizeof(*cp)) { |
1654 |
|
|
log_debug("%s: malformed payload: too short for header " |
1655 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*cp)); |
1656 |
|
|
return (-1); |
1657 |
|
|
} |
1658 |
|
|
memcpy(cp, msgbuf + offset, sizeof(*cp)); |
1659 |
|
|
|
1660 |
|
|
return (0); |
1661 |
|
|
} |
1662 |
|
|
|
1663 |
|
|
int |
1664 |
|
|
ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, |
1665 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
1666 |
|
|
{ |
1667 |
|
|
struct ikev2_cp cp; |
1668 |
|
|
struct ikev2_cfg *cfg; |
1669 |
|
|
uint8_t *buf; |
1670 |
|
|
size_t len, i; |
1671 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1672 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1673 |
|
|
|
1674 |
|
|
if (ikev2_validate_cp(msg, offset, left, pld, &cp)) |
1675 |
|
|
return (-1); |
1676 |
|
|
offset += sizeof(cp); |
1677 |
|
|
|
1678 |
|
|
buf = msgbuf + offset; |
1679 |
|
|
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp); |
1680 |
|
|
|
1681 |
|
|
log_debug("%s: type %s length %zu", |
1682 |
|
|
__func__, print_map(cp.cp_type, ikev2_cp_map), len); |
1683 |
|
|
print_hex(buf, 0, len); |
1684 |
|
|
|
1685 |
|
|
for (i = 0; i < len;) { |
1686 |
|
|
cfg = (struct ikev2_cfg *)(buf + i); |
1687 |
|
|
|
1688 |
|
|
log_debug("%s: %s 0x%04x length %d", __func__, |
1689 |
|
|
print_map(betoh16(cfg->cfg_type), ikev2_cfg_map), |
1690 |
|
|
betoh16(cfg->cfg_type), |
1691 |
|
|
betoh16(cfg->cfg_length)); |
1692 |
|
|
|
1693 |
|
|
i += betoh16(cfg->cfg_length) + sizeof(*cfg); |
1694 |
|
|
} |
1695 |
|
|
|
1696 |
|
|
if (!ikev2_msg_frompeer(msg)) |
1697 |
|
|
return (0); |
1698 |
|
|
|
1699 |
|
|
if (sa) |
1700 |
|
|
sa->sa_cp = cp.cp_type; |
1701 |
|
|
|
1702 |
|
|
return (0); |
1703 |
|
|
} |
1704 |
|
|
|
1705 |
|
|
int |
1706 |
|
|
ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left, |
1707 |
|
|
struct ikev2_payload *pld, struct eap_header *hdr) |
1708 |
|
|
{ |
1709 |
|
|
uint8_t *msgbuf = ibuf_data(msg->msg_data); |
1710 |
|
|
size_t pld_length; |
1711 |
|
|
|
1712 |
|
|
pld_length = betoh16(pld->pld_length); |
1713 |
|
|
if (pld_length < sizeof(*pld) + sizeof(*hdr)) { |
1714 |
|
|
log_debug("%s: malformed payload: specified length smaller " |
1715 |
|
|
"than minimum size (%zu < %zu)", __func__, pld_length, |
1716 |
|
|
sizeof(*pld) + sizeof(*hdr)); |
1717 |
|
|
return (-1); |
1718 |
|
|
} |
1719 |
|
|
|
1720 |
|
|
/* This will actually be caught by earlier checks. */ |
1721 |
|
|
if (left < sizeof(*hdr)) { |
1722 |
|
|
log_debug("%s: malformed payload: too short for header " |
1723 |
|
|
"(%zu < %zu)", __func__, left, sizeof(*hdr)); |
1724 |
|
|
return (-1); |
1725 |
|
|
} |
1726 |
|
|
memcpy(hdr, msgbuf + offset, sizeof(*hdr)); |
1727 |
|
|
|
1728 |
|
|
return (0); |
1729 |
|
|
} |
1730 |
|
|
|
1731 |
|
|
int |
1732 |
|
|
ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, |
1733 |
|
|
struct iked_message *msg, size_t offset, size_t left) |
1734 |
|
|
{ |
1735 |
|
|
struct eap_header hdr; |
1736 |
|
|
struct eap_message *eap = NULL; |
1737 |
|
|
struct iked_sa *sa = msg->msg_sa; |
1738 |
|
|
size_t len; |
1739 |
|
|
|
1740 |
|
|
if (ikev2_validate_eap(msg, offset, left, pld, &hdr)) |
1741 |
|
|
return (-1); |
1742 |
|
|
len = betoh16(hdr.eap_length); |
1743 |
|
|
|
1744 |
|
|
if (len < sizeof(*eap)) { |
1745 |
|
|
log_info("%s: %s id %d length %d", __func__, |
1746 |
|
|
print_map(hdr.eap_code, eap_code_map), |
1747 |
|
|
hdr.eap_id, betoh16(hdr.eap_length)); |
1748 |
|
|
} else { |
1749 |
|
|
/* Now try to get the indicated length */ |
1750 |
|
|
if ((eap = ibuf_seek(msg->msg_data, offset, len)) == NULL) { |
1751 |
|
|
log_debug("%s: invalid EAP length", __func__); |
1752 |
|
|
return (-1); |
1753 |
|
|
} |
1754 |
|
|
|
1755 |
|
|
log_info("%s: %s id %d length %d EAP-%s", __func__, |
1756 |
|
|
print_map(eap->eap_code, eap_code_map), |
1757 |
|
|
eap->eap_id, betoh16(eap->eap_length), |
1758 |
|
|
print_map(eap->eap_type, eap_type_map)); |
1759 |
|
|
|
1760 |
|
|
if (eap_parse(env, sa, eap, msg->msg_response) == -1) |
1761 |
|
|
return (-1); |
1762 |
|
|
} |
1763 |
|
|
|
1764 |
|
|
return (0); |
1765 |
|
|
} |