]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * IKEv2 responder (RFC 4306) for EAP-IKEV2 | |
3 | * Copyright (c) 2007, Jouni Malinen <j@w1.fi> | |
4 | * | |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
6fc6879b JM |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
03da66bd | 12 | #include "crypto/dh_groups.h" |
3642c431 | 13 | #include "crypto/random.h" |
6fc6879b JM |
14 | #include "ikev2.h" |
15 | ||
16 | ||
17 | void ikev2_responder_deinit(struct ikev2_responder_data *data) | |
18 | { | |
19 | ikev2_free_keys(&data->keys); | |
20 | wpabuf_free(data->i_dh_public); | |
21 | wpabuf_free(data->r_dh_private); | |
22 | os_free(data->IDi); | |
23 | os_free(data->IDr); | |
24 | os_free(data->shared_secret); | |
25 | wpabuf_free(data->i_sign_msg); | |
26 | wpabuf_free(data->r_sign_msg); | |
27 | os_free(data->key_pad); | |
28 | } | |
29 | ||
30 | ||
31 | static int ikev2_derive_keys(struct ikev2_responder_data *data) | |
32 | { | |
33 | u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; | |
34 | size_t buf_len, pad_len; | |
35 | struct wpabuf *shared; | |
36 | const struct ikev2_integ_alg *integ; | |
37 | const struct ikev2_prf_alg *prf; | |
38 | const struct ikev2_encr_alg *encr; | |
39 | int ret; | |
40 | const u8 *addr[2]; | |
41 | size_t len[2]; | |
42 | ||
43 | /* RFC 4306, Sect. 2.14 */ | |
44 | ||
45 | integ = ikev2_get_integ(data->proposal.integ); | |
46 | prf = ikev2_get_prf(data->proposal.prf); | |
47 | encr = ikev2_get_encr(data->proposal.encr); | |
48 | if (integ == NULL || prf == NULL || encr == NULL) { | |
49 | wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); | |
50 | return -1; | |
51 | } | |
52 | ||
53 | shared = dh_derive_shared(data->i_dh_public, data->r_dh_private, | |
54 | data->dh); | |
55 | if (shared == NULL) | |
56 | return -1; | |
57 | ||
58 | /* Construct Ni | Nr | SPIi | SPIr */ | |
59 | ||
60 | buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; | |
61 | buf = os_malloc(buf_len); | |
62 | if (buf == NULL) { | |
63 | wpabuf_free(shared); | |
64 | return -1; | |
65 | } | |
66 | ||
67 | pos = buf; | |
68 | os_memcpy(pos, data->i_nonce, data->i_nonce_len); | |
69 | pos += data->i_nonce_len; | |
70 | os_memcpy(pos, data->r_nonce, data->r_nonce_len); | |
71 | pos += data->r_nonce_len; | |
72 | os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); | |
73 | pos += IKEV2_SPI_LEN; | |
74 | os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); | |
6fc6879b JM |
75 | |
76 | /* SKEYSEED = prf(Ni | Nr, g^ir) */ | |
77 | /* Use zero-padding per RFC 4306, Sect. 2.14 */ | |
78 | pad_len = data->dh->prime_len - wpabuf_len(shared); | |
6fc6879b JM |
79 | pad = os_zalloc(pad_len ? pad_len : 1); |
80 | if (pad == NULL) { | |
81 | wpabuf_free(shared); | |
82 | os_free(buf); | |
83 | return -1; | |
84 | } | |
85 | ||
86 | addr[0] = pad; | |
87 | len[0] = pad_len; | |
88 | addr[1] = wpabuf_head(shared); | |
89 | len[1] = wpabuf_len(shared); | |
90 | if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, | |
91 | 2, addr, len, skeyseed) < 0) { | |
92 | wpabuf_free(shared); | |
93 | os_free(buf); | |
94 | os_free(pad); | |
95 | return -1; | |
96 | } | |
97 | os_free(pad); | |
98 | wpabuf_free(shared); | |
99 | ||
100 | /* DH parameters are not needed anymore, so free them */ | |
101 | wpabuf_free(data->i_dh_public); | |
102 | data->i_dh_public = NULL; | |
103 | wpabuf_free(data->r_dh_private); | |
104 | data->r_dh_private = NULL; | |
105 | ||
106 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", | |
107 | skeyseed, prf->hash_len); | |
108 | ||
109 | ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, | |
110 | &data->keys); | |
111 | os_free(buf); | |
112 | return ret; | |
113 | } | |
114 | ||
115 | ||
116 | static int ikev2_parse_transform(struct ikev2_proposal_data *prop, | |
117 | const u8 *pos, const u8 *end) | |
118 | { | |
119 | int transform_len; | |
120 | const struct ikev2_transform *t; | |
121 | u16 transform_id; | |
122 | const u8 *tend; | |
123 | ||
124 | if (end - pos < (int) sizeof(*t)) { | |
125 | wpa_printf(MSG_INFO, "IKEV2: Too short transform"); | |
126 | return -1; | |
127 | } | |
128 | ||
129 | t = (const struct ikev2_transform *) pos; | |
130 | transform_len = WPA_GET_BE16(t->transform_length); | |
3991cb7b | 131 | if (transform_len < (int) sizeof(*t) || transform_len > end - pos) { |
6fc6879b JM |
132 | wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", |
133 | transform_len); | |
134 | return -1; | |
135 | } | |
136 | tend = pos + transform_len; | |
137 | ||
138 | transform_id = WPA_GET_BE16(t->transform_id); | |
139 | ||
140 | wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); | |
141 | wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " | |
142 | "Transform Type: %d Transform ID: %d", | |
143 | t->type, transform_len, t->transform_type, transform_id); | |
144 | ||
145 | if (t->type != 0 && t->type != 3) { | |
146 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); | |
147 | return -1; | |
148 | } | |
149 | ||
150 | pos = (const u8 *) (t + 1); | |
151 | if (pos < tend) { | |
152 | wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", | |
153 | pos, tend - pos); | |
154 | } | |
155 | ||
156 | switch (t->transform_type) { | |
157 | case IKEV2_TRANSFORM_ENCR: | |
158 | if (ikev2_get_encr(transform_id)) { | |
159 | if (transform_id == ENCR_AES_CBC) { | |
160 | if (tend - pos != 4) { | |
161 | wpa_printf(MSG_DEBUG, "IKEV2: No " | |
162 | "Transform Attr for AES"); | |
163 | break; | |
164 | } | |
6fc6879b JM |
165 | if (WPA_GET_BE16(pos) != 0x800e) { |
166 | wpa_printf(MSG_DEBUG, "IKEV2: Not a " | |
167 | "Key Size attribute for " | |
168 | "AES"); | |
169 | break; | |
170 | } | |
6fc6879b JM |
171 | if (WPA_GET_BE16(pos + 2) != 128) { |
172 | wpa_printf(MSG_DEBUG, "IKEV2: " | |
173 | "Unsupported AES key size " | |
174 | "%d bits", | |
175 | WPA_GET_BE16(pos + 2)); | |
176 | break; | |
177 | } | |
178 | } | |
179 | prop->encr = transform_id; | |
180 | } | |
181 | break; | |
182 | case IKEV2_TRANSFORM_PRF: | |
183 | if (ikev2_get_prf(transform_id)) | |
184 | prop->prf = transform_id; | |
185 | break; | |
186 | case IKEV2_TRANSFORM_INTEG: | |
187 | if (ikev2_get_integ(transform_id)) | |
188 | prop->integ = transform_id; | |
189 | break; | |
190 | case IKEV2_TRANSFORM_DH: | |
191 | if (dh_groups_get(transform_id)) | |
192 | prop->dh = transform_id; | |
193 | break; | |
194 | } | |
195 | ||
196 | return transform_len; | |
197 | } | |
198 | ||
199 | ||
200 | static int ikev2_parse_proposal(struct ikev2_proposal_data *prop, | |
201 | const u8 *pos, const u8 *end) | |
202 | { | |
203 | const u8 *pend, *ppos; | |
204 | int proposal_len, i; | |
205 | const struct ikev2_proposal *p; | |
206 | ||
207 | if (end - pos < (int) sizeof(*p)) { | |
208 | wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); | |
209 | return -1; | |
210 | } | |
211 | ||
212 | /* FIX: AND processing if multiple proposals use the same # */ | |
213 | ||
214 | p = (const struct ikev2_proposal *) pos; | |
215 | proposal_len = WPA_GET_BE16(p->proposal_length); | |
d36f4169 | 216 | if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) { |
6fc6879b JM |
217 | wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", |
218 | proposal_len); | |
219 | return -1; | |
220 | } | |
221 | wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", | |
222 | p->proposal_num); | |
223 | wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " | |
224 | " Protocol ID: %d", | |
225 | p->type, proposal_len, p->protocol_id); | |
226 | wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", | |
227 | p->spi_size, p->num_transforms); | |
228 | ||
229 | if (p->type != 0 && p->type != 2) { | |
230 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | if (p->protocol_id != IKEV2_PROTOCOL_IKE) { | |
235 | wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " | |
236 | "(only IKE allowed for EAP-IKEv2)"); | |
237 | return -1; | |
238 | } | |
239 | ||
240 | if (p->proposal_num != prop->proposal_num) { | |
241 | if (p->proposal_num == prop->proposal_num + 1) | |
242 | prop->proposal_num = p->proposal_num; | |
243 | else { | |
244 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); | |
245 | return -1; | |
246 | } | |
247 | } | |
248 | ||
249 | ppos = (const u8 *) (p + 1); | |
250 | pend = pos + proposal_len; | |
3991cb7b | 251 | if (p->spi_size > pend - ppos) { |
6fc6879b JM |
252 | wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " |
253 | "in proposal"); | |
254 | return -1; | |
255 | } | |
256 | if (p->spi_size) { | |
257 | wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", | |
258 | ppos, p->spi_size); | |
259 | ppos += p->spi_size; | |
260 | } | |
261 | ||
262 | /* | |
263 | * For initial IKE_SA negotiation, SPI Size MUST be zero; for | |
264 | * subsequent negotiations, it must be 8 for IKE. We only support | |
265 | * initial case for now. | |
266 | */ | |
267 | if (p->spi_size != 0) { | |
268 | wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); | |
269 | return -1; | |
270 | } | |
271 | ||
272 | if (p->num_transforms == 0) { | |
273 | wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); | |
274 | return -1; | |
275 | } | |
276 | ||
277 | for (i = 0; i < (int) p->num_transforms; i++) { | |
278 | int tlen = ikev2_parse_transform(prop, ppos, pend); | |
279 | if (tlen < 0) | |
280 | return -1; | |
281 | ppos += tlen; | |
282 | } | |
283 | ||
284 | if (ppos != pend) { | |
285 | wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " | |
286 | "transforms"); | |
287 | return -1; | |
288 | } | |
289 | ||
290 | return proposal_len; | |
291 | } | |
292 | ||
293 | ||
294 | static int ikev2_process_sai1(struct ikev2_responder_data *data, | |
295 | const u8 *sai1, size_t sai1_len) | |
296 | { | |
297 | struct ikev2_proposal_data prop; | |
298 | const u8 *pos, *end; | |
299 | int found = 0; | |
300 | ||
301 | /* Security Association Payloads: <Proposals> */ | |
302 | ||
303 | if (sai1 == NULL) { | |
304 | wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); | |
305 | return -1; | |
306 | } | |
307 | ||
308 | os_memset(&prop, 0, sizeof(prop)); | |
309 | prop.proposal_num = 1; | |
310 | ||
311 | pos = sai1; | |
312 | end = sai1 + sai1_len; | |
313 | ||
314 | while (pos < end) { | |
315 | int plen; | |
316 | ||
317 | prop.integ = -1; | |
318 | prop.prf = -1; | |
319 | prop.encr = -1; | |
320 | prop.dh = -1; | |
321 | plen = ikev2_parse_proposal(&prop, pos, end); | |
322 | if (plen < 0) | |
323 | return -1; | |
324 | ||
325 | if (!found && prop.integ != -1 && prop.prf != -1 && | |
326 | prop.encr != -1 && prop.dh != -1) { | |
327 | os_memcpy(&data->proposal, &prop, sizeof(prop)); | |
328 | data->dh = dh_groups_get(prop.dh); | |
329 | found = 1; | |
330 | } | |
331 | ||
332 | pos += plen; | |
333 | } | |
334 | ||
335 | if (pos != end) { | |
336 | wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); | |
337 | return -1; | |
338 | } | |
339 | ||
340 | if (!found) { | |
341 | wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); | |
342 | return -1; | |
343 | } | |
344 | ||
345 | wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " | |
346 | "INTEG:%d D-H:%d", data->proposal.proposal_num, | |
347 | data->proposal.encr, data->proposal.prf, | |
348 | data->proposal.integ, data->proposal.dh); | |
349 | ||
350 | return 0; | |
351 | } | |
352 | ||
353 | ||
354 | static int ikev2_process_kei(struct ikev2_responder_data *data, | |
355 | const u8 *kei, size_t kei_len) | |
356 | { | |
357 | u16 group; | |
358 | ||
359 | /* | |
360 | * Key Exchange Payload: | |
361 | * DH Group # (16 bits) | |
362 | * RESERVED (16 bits) | |
363 | * Key Exchange Data (Diffie-Hellman public value) | |
364 | */ | |
365 | ||
366 | if (kei == NULL) { | |
367 | wpa_printf(MSG_INFO, "IKEV2: KEi not received"); | |
368 | return -1; | |
369 | } | |
370 | ||
371 | if (kei_len < 4 + 96) { | |
8779ac8a | 372 | wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload"); |
6fc6879b JM |
373 | return -1; |
374 | } | |
375 | ||
376 | group = WPA_GET_BE16(kei); | |
377 | wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); | |
378 | ||
379 | if (group != data->proposal.dh) { | |
380 | wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " | |
381 | "with the selected proposal (%u)", | |
382 | group, data->proposal.dh); | |
383 | /* Reject message with Notify payload of type | |
384 | * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ | |
385 | data->error_type = INVALID_KE_PAYLOAD; | |
386 | data->state = NOTIFY; | |
387 | return -1; | |
388 | } | |
389 | ||
390 | if (data->dh == NULL) { | |
391 | wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); | |
392 | return -1; | |
393 | } | |
394 | ||
395 | /* RFC 4306, Section 3.4: | |
ffbf1eaa | 396 | * The length of DH public value MUST be equal to the length of the |
6fc6879b JM |
397 | * prime modulus. |
398 | */ | |
399 | if (kei_len - 4 != data->dh->prime_len) { | |
400 | wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " | |
401 | "%ld (expected %ld)", | |
402 | (long) (kei_len - 4), (long) data->dh->prime_len); | |
403 | return -1; | |
404 | } | |
405 | ||
406 | wpabuf_free(data->i_dh_public); | |
407 | data->i_dh_public = wpabuf_alloc(kei_len - 4); | |
408 | if (data->i_dh_public == NULL) | |
409 | return -1; | |
410 | wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); | |
411 | ||
412 | wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", | |
413 | data->i_dh_public); | |
414 | ||
415 | return 0; | |
416 | } | |
417 | ||
418 | ||
419 | static int ikev2_process_ni(struct ikev2_responder_data *data, | |
420 | const u8 *ni, size_t ni_len) | |
421 | { | |
422 | if (ni == NULL) { | |
423 | wpa_printf(MSG_INFO, "IKEV2: Ni not received"); | |
424 | return -1; | |
425 | } | |
426 | ||
427 | if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) { | |
428 | wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld", | |
429 | (long) ni_len); | |
430 | return -1; | |
431 | } | |
432 | ||
6fc6879b JM |
433 | data->i_nonce_len = ni_len; |
434 | os_memcpy(data->i_nonce, ni, ni_len); | |
435 | wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", | |
436 | data->i_nonce, data->i_nonce_len); | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
441 | ||
442 | static int ikev2_process_sa_init(struct ikev2_responder_data *data, | |
443 | const struct ikev2_hdr *hdr, | |
444 | struct ikev2_payloads *pl) | |
445 | { | |
446 | if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 || | |
447 | ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 || | |
448 | ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0) | |
449 | return -1; | |
450 | ||
451 | os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN); | |
452 | ||
453 | return 0; | |
454 | } | |
455 | ||
456 | ||
457 | static int ikev2_process_idi(struct ikev2_responder_data *data, | |
458 | const u8 *idi, size_t idi_len) | |
459 | { | |
460 | u8 id_type; | |
461 | ||
462 | if (idi == NULL) { | |
463 | wpa_printf(MSG_INFO, "IKEV2: No IDi received"); | |
464 | return -1; | |
465 | } | |
466 | ||
467 | if (idi_len < 4) { | |
468 | wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload"); | |
469 | return -1; | |
470 | } | |
471 | ||
472 | id_type = idi[0]; | |
473 | idi += 4; | |
474 | idi_len -= 4; | |
475 | ||
476 | wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type); | |
477 | wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len); | |
478 | os_free(data->IDi); | |
a1f11e34 | 479 | data->IDi = os_memdup(idi, idi_len); |
6fc6879b JM |
480 | if (data->IDi == NULL) |
481 | return -1; | |
6fc6879b JM |
482 | data->IDi_len = idi_len; |
483 | data->IDi_type = id_type; | |
484 | ||
485 | return 0; | |
486 | } | |
487 | ||
488 | ||
489 | static int ikev2_process_cert(struct ikev2_responder_data *data, | |
490 | const u8 *cert, size_t cert_len) | |
491 | { | |
492 | u8 cert_encoding; | |
493 | ||
494 | if (cert == NULL) { | |
495 | if (data->peer_auth == PEER_AUTH_CERT) { | |
496 | wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); | |
497 | return -1; | |
498 | } | |
499 | return 0; | |
500 | } | |
501 | ||
502 | if (cert_len < 1) { | |
503 | wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); | |
504 | return -1; | |
505 | } | |
506 | ||
507 | cert_encoding = cert[0]; | |
508 | cert++; | |
509 | cert_len--; | |
510 | ||
511 | wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); | |
512 | wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); | |
513 | ||
514 | /* TODO: validate certificate */ | |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
519 | ||
520 | static int ikev2_process_auth_cert(struct ikev2_responder_data *data, | |
521 | u8 method, const u8 *auth, size_t auth_len) | |
522 | { | |
523 | if (method != AUTH_RSA_SIGN) { | |
524 | wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " | |
525 | "method %d", method); | |
526 | return -1; | |
527 | } | |
528 | ||
529 | /* TODO: validate AUTH */ | |
530 | return 0; | |
531 | } | |
532 | ||
533 | ||
534 | static int ikev2_process_auth_secret(struct ikev2_responder_data *data, | |
535 | u8 method, const u8 *auth, | |
536 | size_t auth_len) | |
537 | { | |
538 | u8 auth_data[IKEV2_MAX_HASH_LEN]; | |
539 | const struct ikev2_prf_alg *prf; | |
540 | ||
541 | if (method != AUTH_SHARED_KEY_MIC) { | |
542 | wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " | |
543 | "method %d", method); | |
544 | return -1; | |
545 | } | |
546 | ||
547 | /* msg | Nr | prf(SK_pi,IDi') */ | |
548 | if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, | |
549 | data->IDi, data->IDi_len, data->IDi_type, | |
550 | &data->keys, 1, data->shared_secret, | |
551 | data->shared_secret_len, | |
552 | data->r_nonce, data->r_nonce_len, | |
553 | data->key_pad, data->key_pad_len, | |
554 | auth_data) < 0) { | |
555 | wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); | |
556 | return -1; | |
557 | } | |
558 | ||
559 | wpabuf_free(data->i_sign_msg); | |
560 | data->i_sign_msg = NULL; | |
561 | ||
562 | prf = ikev2_get_prf(data->proposal.prf); | |
563 | if (prf == NULL) | |
564 | return -1; | |
565 | ||
566 | if (auth_len != prf->hash_len || | |
675ddad1 | 567 | os_memcmp_const(auth, auth_data, auth_len) != 0) { |
6fc6879b JM |
568 | wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); |
569 | wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", | |
570 | auth, auth_len); | |
571 | wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", | |
572 | auth_data, prf->hash_len); | |
573 | data->error_type = AUTHENTICATION_FAILED; | |
574 | data->state = NOTIFY; | |
575 | return -1; | |
576 | } | |
577 | ||
578 | wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully " | |
579 | "using shared keys"); | |
580 | ||
581 | return 0; | |
582 | } | |
583 | ||
584 | ||
585 | static int ikev2_process_auth(struct ikev2_responder_data *data, | |
586 | const u8 *auth, size_t auth_len) | |
587 | { | |
588 | u8 auth_method; | |
589 | ||
590 | if (auth == NULL) { | |
591 | wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); | |
592 | return -1; | |
593 | } | |
594 | ||
595 | if (auth_len < 4) { | |
596 | wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " | |
597 | "Payload"); | |
598 | return -1; | |
599 | } | |
600 | ||
601 | auth_method = auth[0]; | |
602 | auth += 4; | |
603 | auth_len -= 4; | |
604 | ||
605 | wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); | |
606 | wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); | |
607 | ||
608 | switch (data->peer_auth) { | |
609 | case PEER_AUTH_CERT: | |
610 | return ikev2_process_auth_cert(data, auth_method, auth, | |
611 | auth_len); | |
612 | case PEER_AUTH_SECRET: | |
613 | return ikev2_process_auth_secret(data, auth_method, auth, | |
614 | auth_len); | |
615 | } | |
616 | ||
617 | return -1; | |
618 | } | |
619 | ||
620 | ||
621 | static int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data, | |
622 | u8 next_payload, | |
623 | u8 *payload, size_t payload_len) | |
624 | { | |
625 | struct ikev2_payloads pl; | |
626 | ||
627 | wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); | |
628 | ||
629 | if (ikev2_parse_payloads(&pl, next_payload, payload, payload + | |
630 | payload_len) < 0) { | |
631 | wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " | |
632 | "payloads"); | |
633 | return -1; | |
634 | } | |
635 | ||
636 | if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 || | |
637 | ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || | |
638 | ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) | |
639 | return -1; | |
640 | ||
641 | return 0; | |
642 | } | |
643 | ||
644 | ||
645 | static int ikev2_process_sa_auth(struct ikev2_responder_data *data, | |
646 | const struct ikev2_hdr *hdr, | |
647 | struct ikev2_payloads *pl) | |
648 | { | |
649 | u8 *decrypted; | |
650 | size_t decrypted_len; | |
651 | int ret; | |
652 | ||
653 | decrypted = ikev2_decrypt_payload(data->proposal.encr, | |
654 | data->proposal.integ, | |
655 | &data->keys, 1, hdr, pl->encrypted, | |
656 | pl->encrypted_len, &decrypted_len); | |
657 | if (decrypted == NULL) | |
658 | return -1; | |
659 | ||
660 | ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, | |
661 | decrypted, decrypted_len); | |
662 | os_free(decrypted); | |
663 | ||
664 | return ret; | |
665 | } | |
666 | ||
667 | ||
668 | static int ikev2_validate_rx_state(struct ikev2_responder_data *data, | |
669 | u8 exchange_type, u32 message_id) | |
670 | { | |
671 | switch (data->state) { | |
672 | case SA_INIT: | |
673 | /* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */ | |
674 | if (exchange_type != IKE_SA_INIT) { | |
675 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " | |
676 | "%u in SA_INIT state", exchange_type); | |
677 | return -1; | |
678 | } | |
679 | if (message_id != 0) { | |
680 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " | |
681 | "in SA_INIT state", message_id); | |
682 | return -1; | |
683 | } | |
684 | break; | |
685 | case SA_AUTH: | |
686 | /* Expect to receive IKE_SA_AUTH: | |
687 | * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,] | |
688 | * AUTH, SAi2, TSi, TSr} | |
689 | */ | |
690 | if (exchange_type != IKE_SA_AUTH) { | |
691 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " | |
692 | "%u in SA_AUTH state", exchange_type); | |
693 | return -1; | |
694 | } | |
695 | if (message_id != 1) { | |
696 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " | |
697 | "in SA_AUTH state", message_id); | |
698 | return -1; | |
699 | } | |
700 | break; | |
701 | case CHILD_SA: | |
702 | if (exchange_type != CREATE_CHILD_SA) { | |
703 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " | |
704 | "%u in CHILD_SA state", exchange_type); | |
705 | return -1; | |
706 | } | |
707 | if (message_id != 2) { | |
708 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " | |
709 | "in CHILD_SA state", message_id); | |
710 | return -1; | |
711 | } | |
712 | break; | |
713 | case NOTIFY: | |
714 | case IKEV2_DONE: | |
715 | case IKEV2_FAILED: | |
716 | return -1; | |
717 | } | |
718 | ||
719 | return 0; | |
720 | } | |
721 | ||
722 | ||
723 | int ikev2_responder_process(struct ikev2_responder_data *data, | |
724 | const struct wpabuf *buf) | |
725 | { | |
726 | const struct ikev2_hdr *hdr; | |
727 | u32 length, message_id; | |
728 | const u8 *pos, *end; | |
729 | struct ikev2_payloads pl; | |
730 | ||
731 | wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", | |
732 | (unsigned long) wpabuf_len(buf)); | |
733 | ||
734 | if (wpabuf_len(buf) < sizeof(*hdr)) { | |
735 | wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); | |
736 | return -1; | |
737 | } | |
738 | ||
739 | data->error_type = 0; | |
740 | hdr = (const struct ikev2_hdr *) wpabuf_head(buf); | |
741 | end = wpabuf_head_u8(buf) + wpabuf_len(buf); | |
742 | message_id = WPA_GET_BE32(hdr->message_id); | |
743 | length = WPA_GET_BE32(hdr->length); | |
744 | ||
745 | wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", | |
746 | hdr->i_spi, IKEV2_SPI_LEN); | |
747 | wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", | |
748 | hdr->r_spi, IKEV2_SPI_LEN); | |
749 | wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " | |
750 | "Exchange Type: %u", | |
751 | hdr->next_payload, hdr->version, hdr->exchange_type); | |
752 | wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", | |
753 | message_id, length); | |
754 | ||
755 | if (hdr->version != IKEV2_VERSION) { | |
756 | wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " | |
757 | "(expected 0x%x)", hdr->version, IKEV2_VERSION); | |
758 | return -1; | |
759 | } | |
760 | ||
761 | if (length != wpabuf_len(buf)) { | |
762 | wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " | |
763 | "RX: %lu)", (unsigned long) length, | |
764 | (unsigned long) wpabuf_len(buf)); | |
765 | return -1; | |
766 | } | |
767 | ||
768 | if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) | |
769 | return -1; | |
770 | ||
771 | if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != | |
772 | IKEV2_HDR_INITIATOR) { | |
773 | wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", | |
774 | hdr->flags); | |
775 | return -1; | |
776 | } | |
777 | ||
778 | if (data->state != SA_INIT) { | |
779 | if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { | |
780 | wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " | |
781 | "Initiator's SPI"); | |
782 | return -1; | |
783 | } | |
784 | if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { | |
785 | wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " | |
786 | "Responder's SPI"); | |
787 | return -1; | |
788 | } | |
789 | } | |
790 | ||
791 | pos = (const u8 *) (hdr + 1); | |
792 | if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) | |
793 | return -1; | |
794 | ||
795 | if (data->state == SA_INIT) { | |
796 | data->last_msg = LAST_MSG_SA_INIT; | |
797 | if (ikev2_process_sa_init(data, hdr, &pl) < 0) { | |
798 | if (data->state == NOTIFY) | |
799 | return 0; | |
800 | return -1; | |
801 | } | |
802 | wpabuf_free(data->i_sign_msg); | |
803 | data->i_sign_msg = wpabuf_dup(buf); | |
804 | } | |
805 | ||
806 | if (data->state == SA_AUTH) { | |
807 | data->last_msg = LAST_MSG_SA_AUTH; | |
808 | if (ikev2_process_sa_auth(data, hdr, &pl) < 0) { | |
809 | if (data->state == NOTIFY) | |
810 | return 0; | |
811 | return -1; | |
812 | } | |
813 | } | |
814 | ||
815 | return 0; | |
816 | } | |
817 | ||
818 | ||
819 | static void ikev2_build_hdr(struct ikev2_responder_data *data, | |
820 | struct wpabuf *msg, u8 exchange_type, | |
821 | u8 next_payload, u32 message_id) | |
822 | { | |
823 | struct ikev2_hdr *hdr; | |
824 | ||
825 | wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); | |
826 | ||
827 | /* HDR - RFC 4306, Sect. 3.1 */ | |
828 | hdr = wpabuf_put(msg, sizeof(*hdr)); | |
829 | os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); | |
830 | os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); | |
831 | hdr->next_payload = next_payload; | |
832 | hdr->version = IKEV2_VERSION; | |
833 | hdr->exchange_type = exchange_type; | |
834 | hdr->flags = IKEV2_HDR_RESPONSE; | |
835 | WPA_PUT_BE32(hdr->message_id, message_id); | |
836 | } | |
837 | ||
838 | ||
839 | static int ikev2_build_sar1(struct ikev2_responder_data *data, | |
840 | struct wpabuf *msg, u8 next_payload) | |
841 | { | |
842 | struct ikev2_payload_hdr *phdr; | |
843 | size_t plen; | |
844 | struct ikev2_proposal *p; | |
845 | struct ikev2_transform *t; | |
846 | ||
847 | wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload"); | |
848 | ||
849 | /* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */ | |
850 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
851 | phdr->next_payload = next_payload; | |
852 | phdr->flags = 0; | |
853 | ||
854 | p = wpabuf_put(msg, sizeof(*p)); | |
6fc6879b | 855 | p->proposal_num = data->proposal.proposal_num; |
6fc6879b JM |
856 | p->protocol_id = IKEV2_PROTOCOL_IKE; |
857 | p->num_transforms = 4; | |
858 | ||
859 | t = wpabuf_put(msg, sizeof(*t)); | |
860 | t->type = 3; | |
861 | t->transform_type = IKEV2_TRANSFORM_ENCR; | |
862 | WPA_PUT_BE16(t->transform_id, data->proposal.encr); | |
863 | if (data->proposal.encr == ENCR_AES_CBC) { | |
864 | /* Transform Attribute: Key Len = 128 bits */ | |
6fc6879b | 865 | wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ |
6fc6879b JM |
866 | wpabuf_put_be16(msg, 128); /* 128-bit key */ |
867 | } | |
868 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; | |
869 | WPA_PUT_BE16(t->transform_length, plen); | |
870 | ||
871 | t = wpabuf_put(msg, sizeof(*t)); | |
872 | t->type = 3; | |
873 | WPA_PUT_BE16(t->transform_length, sizeof(*t)); | |
874 | t->transform_type = IKEV2_TRANSFORM_PRF; | |
875 | WPA_PUT_BE16(t->transform_id, data->proposal.prf); | |
876 | ||
877 | t = wpabuf_put(msg, sizeof(*t)); | |
878 | t->type = 3; | |
879 | WPA_PUT_BE16(t->transform_length, sizeof(*t)); | |
880 | t->transform_type = IKEV2_TRANSFORM_INTEG; | |
881 | WPA_PUT_BE16(t->transform_id, data->proposal.integ); | |
882 | ||
883 | t = wpabuf_put(msg, sizeof(*t)); | |
884 | WPA_PUT_BE16(t->transform_length, sizeof(*t)); | |
885 | t->transform_type = IKEV2_TRANSFORM_DH; | |
886 | WPA_PUT_BE16(t->transform_id, data->proposal.dh); | |
887 | ||
888 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; | |
889 | WPA_PUT_BE16(p->proposal_length, plen); | |
890 | ||
891 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
892 | WPA_PUT_BE16(phdr->payload_length, plen); | |
893 | ||
894 | return 0; | |
895 | } | |
896 | ||
897 | ||
898 | static int ikev2_build_ker(struct ikev2_responder_data *data, | |
899 | struct wpabuf *msg, u8 next_payload) | |
900 | { | |
901 | struct ikev2_payload_hdr *phdr; | |
902 | size_t plen; | |
903 | struct wpabuf *pv; | |
904 | ||
905 | wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload"); | |
906 | ||
907 | pv = dh_init(data->dh, &data->r_dh_private); | |
908 | if (pv == NULL) { | |
909 | wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); | |
910 | return -1; | |
911 | } | |
912 | ||
913 | /* KEr - RFC 4306, Sect. 3.4 */ | |
914 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
915 | phdr->next_payload = next_payload; | |
916 | phdr->flags = 0; | |
917 | ||
918 | wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ | |
919 | wpabuf_put(msg, 2); /* RESERVED */ | |
920 | /* | |
921 | * RFC 4306, Sect. 3.4: possible zero padding for public value to | |
922 | * match the length of the prime. | |
923 | */ | |
924 | wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); | |
925 | wpabuf_put_buf(msg, pv); | |
926 | wpabuf_free(pv); | |
927 | ||
928 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
929 | WPA_PUT_BE16(phdr->payload_length, plen); | |
930 | return 0; | |
931 | } | |
932 | ||
933 | ||
934 | static int ikev2_build_nr(struct ikev2_responder_data *data, | |
935 | struct wpabuf *msg, u8 next_payload) | |
936 | { | |
937 | struct ikev2_payload_hdr *phdr; | |
938 | size_t plen; | |
939 | ||
940 | wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); | |
941 | ||
942 | /* Nr - RFC 4306, Sect. 3.9 */ | |
943 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
944 | phdr->next_payload = next_payload; | |
945 | phdr->flags = 0; | |
946 | wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); | |
947 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
948 | WPA_PUT_BE16(phdr->payload_length, plen); | |
949 | return 0; | |
950 | } | |
951 | ||
952 | ||
953 | static int ikev2_build_idr(struct ikev2_responder_data *data, | |
954 | struct wpabuf *msg, u8 next_payload) | |
955 | { | |
956 | struct ikev2_payload_hdr *phdr; | |
957 | size_t plen; | |
958 | ||
959 | wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); | |
960 | ||
961 | if (data->IDr == NULL) { | |
962 | wpa_printf(MSG_INFO, "IKEV2: No IDr available"); | |
963 | return -1; | |
964 | } | |
965 | ||
966 | /* IDr - RFC 4306, Sect. 3.5 */ | |
967 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
968 | phdr->next_payload = next_payload; | |
969 | phdr->flags = 0; | |
970 | wpabuf_put_u8(msg, ID_KEY_ID); | |
971 | wpabuf_put(msg, 3); /* RESERVED */ | |
972 | wpabuf_put_data(msg, data->IDr, data->IDr_len); | |
973 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
974 | WPA_PUT_BE16(phdr->payload_length, plen); | |
975 | return 0; | |
976 | } | |
977 | ||
978 | ||
979 | static int ikev2_build_auth(struct ikev2_responder_data *data, | |
980 | struct wpabuf *msg, u8 next_payload) | |
981 | { | |
982 | struct ikev2_payload_hdr *phdr; | |
983 | size_t plen; | |
984 | const struct ikev2_prf_alg *prf; | |
985 | ||
986 | wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); | |
987 | ||
988 | prf = ikev2_get_prf(data->proposal.prf); | |
989 | if (prf == NULL) | |
990 | return -1; | |
991 | ||
992 | /* Authentication - RFC 4306, Sect. 3.8 */ | |
993 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
994 | phdr->next_payload = next_payload; | |
995 | phdr->flags = 0; | |
996 | wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); | |
997 | wpabuf_put(msg, 3); /* RESERVED */ | |
998 | ||
999 | /* msg | Ni | prf(SK_pr,IDr') */ | |
1000 | if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, | |
1001 | data->IDr, data->IDr_len, ID_KEY_ID, | |
1002 | &data->keys, 0, data->shared_secret, | |
1003 | data->shared_secret_len, | |
1004 | data->i_nonce, data->i_nonce_len, | |
1005 | data->key_pad, data->key_pad_len, | |
1006 | wpabuf_put(msg, prf->hash_len)) < 0) { | |
1007 | wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); | |
1008 | return -1; | |
1009 | } | |
1010 | wpabuf_free(data->r_sign_msg); | |
1011 | data->r_sign_msg = NULL; | |
1012 | ||
1013 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
1014 | WPA_PUT_BE16(phdr->payload_length, plen); | |
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | ||
1019 | static int ikev2_build_notification(struct ikev2_responder_data *data, | |
1020 | struct wpabuf *msg, u8 next_payload) | |
1021 | { | |
1022 | struct ikev2_payload_hdr *phdr; | |
1023 | size_t plen; | |
1024 | ||
1025 | wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); | |
1026 | ||
1027 | if (data->error_type == 0) { | |
1028 | wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " | |
1029 | "available"); | |
1030 | return -1; | |
1031 | } | |
1032 | ||
1033 | /* Notify - RFC 4306, Sect. 3.10 */ | |
1034 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
1035 | phdr->next_payload = next_payload; | |
1036 | phdr->flags = 0; | |
6fc6879b | 1037 | wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ |
6fc6879b JM |
1038 | wpabuf_put_u8(msg, 0); /* SPI Size */ |
1039 | wpabuf_put_be16(msg, data->error_type); | |
1040 | ||
1041 | switch (data->error_type) { | |
1042 | case INVALID_KE_PAYLOAD: | |
1043 | if (data->proposal.dh == -1) { | |
1044 | wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " | |
1045 | "INVALID_KE_PAYLOAD notifications"); | |
1046 | return -1; | |
1047 | } | |
1048 | wpabuf_put_be16(msg, data->proposal.dh); | |
1049 | wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " | |
1050 | "DH Group #%d", data->proposal.dh); | |
1051 | break; | |
1052 | case AUTHENTICATION_FAILED: | |
1053 | /* no associated data */ | |
1054 | break; | |
1055 | default: | |
1056 | wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " | |
1057 | "%d", data->error_type); | |
1058 | return -1; | |
1059 | } | |
1060 | ||
1061 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
1062 | WPA_PUT_BE16(phdr->payload_length, plen); | |
1063 | return 0; | |
1064 | } | |
1065 | ||
1066 | ||
1067 | static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) | |
1068 | { | |
1069 | struct wpabuf *msg; | |
1070 | ||
1071 | /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ | |
1072 | ||
1073 | if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) | |
1074 | return NULL; | |
1075 | wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", | |
1076 | data->r_spi, IKEV2_SPI_LEN); | |
1077 | ||
1078 | data->r_nonce_len = IKEV2_NONCE_MIN_LEN; | |
3642c431 | 1079 | if (random_get_bytes(data->r_nonce, data->r_nonce_len)) |
6fc6879b | 1080 | return NULL; |
6fc6879b JM |
1081 | wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); |
1082 | ||
1083 | msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); | |
1084 | if (msg == NULL) | |
1085 | return NULL; | |
1086 | ||
1087 | ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); | |
1088 | if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || | |
1089 | ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || | |
1090 | ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? | |
1091 | IKEV2_PAYLOAD_ENCRYPTED : | |
1092 | IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { | |
1093 | wpabuf_free(msg); | |
1094 | return NULL; | |
1095 | } | |
1096 | ||
1097 | if (ikev2_derive_keys(data)) { | |
1098 | wpabuf_free(msg); | |
1099 | return NULL; | |
1100 | } | |
1101 | ||
1102 | if (data->peer_auth == PEER_AUTH_CERT) { | |
1103 | /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info | |
1104 | * for trust agents */ | |
1105 | } | |
1106 | ||
1107 | if (data->peer_auth == PEER_AUTH_SECRET) { | |
1108 | struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); | |
1109 | if (plain == NULL) { | |
1110 | wpabuf_free(msg); | |
1111 | return NULL; | |
1112 | } | |
1113 | if (ikev2_build_idr(data, plain, | |
1114 | IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || | |
1115 | ikev2_build_encrypted(data->proposal.encr, | |
1116 | data->proposal.integ, | |
1117 | &data->keys, 0, msg, plain, | |
1118 | IKEV2_PAYLOAD_IDr)) { | |
1119 | wpabuf_free(plain); | |
1120 | wpabuf_free(msg); | |
1121 | return NULL; | |
1122 | } | |
1123 | wpabuf_free(plain); | |
1124 | } | |
1125 | ||
1126 | ikev2_update_hdr(msg); | |
1127 | ||
1128 | wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); | |
1129 | ||
1130 | data->state = SA_AUTH; | |
1131 | ||
1132 | wpabuf_free(data->r_sign_msg); | |
1133 | data->r_sign_msg = wpabuf_dup(msg); | |
1134 | ||
1135 | return msg; | |
1136 | } | |
1137 | ||
1138 | ||
1139 | static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) | |
1140 | { | |
1141 | struct wpabuf *msg, *plain; | |
1142 | ||
1143 | /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ | |
1144 | ||
1145 | msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); | |
1146 | if (msg == NULL) | |
1147 | return NULL; | |
1148 | ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); | |
1149 | ||
1150 | plain = wpabuf_alloc(data->IDr_len + 1000); | |
1151 | if (plain == NULL) { | |
1152 | wpabuf_free(msg); | |
1153 | return NULL; | |
1154 | } | |
1155 | ||
1156 | if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || | |
1157 | ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || | |
1158 | ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, | |
1159 | &data->keys, 0, msg, plain, | |
1160 | IKEV2_PAYLOAD_IDr)) { | |
1161 | wpabuf_free(plain); | |
1162 | wpabuf_free(msg); | |
1163 | return NULL; | |
1164 | } | |
1165 | wpabuf_free(plain); | |
1166 | ||
1167 | wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); | |
1168 | ||
1169 | data->state = IKEV2_DONE; | |
1170 | ||
1171 | return msg; | |
1172 | } | |
1173 | ||
1174 | ||
1175 | static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) | |
1176 | { | |
1177 | struct wpabuf *msg; | |
1178 | ||
1179 | msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); | |
1180 | if (msg == NULL) | |
1181 | return NULL; | |
1182 | if (data->last_msg == LAST_MSG_SA_AUTH) { | |
1183 | /* HDR, SK{N} */ | |
1184 | struct wpabuf *plain = wpabuf_alloc(100); | |
1185 | if (plain == NULL) { | |
1186 | wpabuf_free(msg); | |
1187 | return NULL; | |
1188 | } | |
1189 | ikev2_build_hdr(data, msg, IKE_SA_AUTH, | |
1190 | IKEV2_PAYLOAD_ENCRYPTED, 1); | |
1191 | if (ikev2_build_notification(data, plain, | |
1192 | IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || | |
1193 | ikev2_build_encrypted(data->proposal.encr, | |
1194 | data->proposal.integ, | |
1195 | &data->keys, 0, msg, plain, | |
1196 | IKEV2_PAYLOAD_NOTIFICATION)) { | |
1197 | wpabuf_free(plain); | |
1198 | wpabuf_free(msg); | |
1199 | return NULL; | |
1200 | } | |
188ebcd0 | 1201 | wpabuf_free(plain); |
6fc6879b JM |
1202 | data->state = IKEV2_FAILED; |
1203 | } else { | |
1204 | /* HDR, N */ | |
1205 | ikev2_build_hdr(data, msg, IKE_SA_INIT, | |
1206 | IKEV2_PAYLOAD_NOTIFICATION, 0); | |
1207 | if (ikev2_build_notification(data, msg, | |
1208 | IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { | |
1209 | wpabuf_free(msg); | |
1210 | return NULL; | |
1211 | } | |
1212 | data->state = SA_INIT; | |
1213 | } | |
1214 | ||
1215 | ikev2_update_hdr(msg); | |
1216 | ||
1217 | wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", | |
1218 | msg); | |
1219 | ||
1220 | return msg; | |
1221 | } | |
1222 | ||
1223 | ||
1224 | struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data) | |
1225 | { | |
1226 | switch (data->state) { | |
1227 | case SA_INIT: | |
1228 | return ikev2_build_sa_init(data); | |
1229 | case SA_AUTH: | |
1230 | return ikev2_build_sa_auth(data); | |
1231 | case CHILD_SA: | |
1232 | return NULL; | |
1233 | case NOTIFY: | |
1234 | return ikev2_build_notify(data); | |
1235 | case IKEV2_DONE: | |
1236 | case IKEV2_FAILED: | |
1237 | return NULL; | |
1238 | } | |
1239 | return NULL; | |
1240 | } |