]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * IKEv2 common routines for initiator and responder | |
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 JM |
12 | #include "crypto/crypto.h" |
13 | #include "crypto/md5.h" | |
14 | #include "crypto/sha1.h" | |
3642c431 | 15 | #include "crypto/random.h" |
6fc6879b JM |
16 | #include "ikev2_common.h" |
17 | ||
18 | ||
8b423edb | 19 | static const struct ikev2_integ_alg ikev2_integ_algs[] = { |
6fc6879b JM |
20 | { AUTH_HMAC_SHA1_96, 20, 12 }, |
21 | { AUTH_HMAC_MD5_96, 16, 12 } | |
22 | }; | |
23 | ||
e7ecab4a | 24 | #define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs) |
6fc6879b JM |
25 | |
26 | ||
8b423edb | 27 | static const struct ikev2_prf_alg ikev2_prf_algs[] = { |
6fc6879b JM |
28 | { PRF_HMAC_SHA1, 20, 20 }, |
29 | { PRF_HMAC_MD5, 16, 16 } | |
30 | }; | |
31 | ||
e7ecab4a | 32 | #define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs) |
6fc6879b JM |
33 | |
34 | ||
8b423edb | 35 | static const struct ikev2_encr_alg ikev2_encr_algs[] = { |
6fc6879b JM |
36 | { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ |
37 | { ENCR_3DES, 24, 8 } | |
38 | }; | |
39 | ||
e7ecab4a | 40 | #define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs) |
6fc6879b JM |
41 | |
42 | ||
43 | const struct ikev2_integ_alg * ikev2_get_integ(int id) | |
44 | { | |
45 | size_t i; | |
46 | ||
47 | for (i = 0; i < NUM_INTEG_ALGS; i++) { | |
48 | if (ikev2_integ_algs[i].id == id) | |
49 | return &ikev2_integ_algs[i]; | |
50 | } | |
51 | ||
52 | return NULL; | |
53 | } | |
54 | ||
55 | ||
56 | int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, | |
57 | size_t data_len, u8 *hash) | |
58 | { | |
59 | u8 tmphash[IKEV2_MAX_HASH_LEN]; | |
60 | ||
61 | switch (alg) { | |
62 | case AUTH_HMAC_SHA1_96: | |
63 | if (key_len != 20) | |
64 | return -1; | |
5c8acf7d JM |
65 | if (hmac_sha1(key, key_len, data, data_len, tmphash) < 0) |
66 | return -1; | |
6fc6879b JM |
67 | os_memcpy(hash, tmphash, 12); |
68 | break; | |
69 | case AUTH_HMAC_MD5_96: | |
70 | if (key_len != 16) | |
71 | return -1; | |
5c8acf7d JM |
72 | if (hmac_md5(key, key_len, data, data_len, tmphash) < 0) |
73 | return -1; | |
6fc6879b JM |
74 | os_memcpy(hash, tmphash, 12); |
75 | break; | |
76 | default: | |
77 | return -1; | |
78 | } | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
83 | ||
84 | const struct ikev2_prf_alg * ikev2_get_prf(int id) | |
85 | { | |
86 | size_t i; | |
87 | ||
88 | for (i = 0; i < NUM_PRF_ALGS; i++) { | |
89 | if (ikev2_prf_algs[i].id == id) | |
90 | return &ikev2_prf_algs[i]; | |
91 | } | |
92 | ||
93 | return NULL; | |
94 | } | |
95 | ||
96 | ||
97 | int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, | |
98 | size_t num_elem, const u8 *addr[], const size_t *len, | |
99 | u8 *hash) | |
100 | { | |
101 | switch (alg) { | |
102 | case PRF_HMAC_SHA1: | |
5c8acf7d JM |
103 | return hmac_sha1_vector(key, key_len, num_elem, addr, len, |
104 | hash); | |
6fc6879b | 105 | case PRF_HMAC_MD5: |
5c8acf7d | 106 | return hmac_md5_vector(key, key_len, num_elem, addr, len, hash); |
6fc6879b JM |
107 | default: |
108 | return -1; | |
109 | } | |
6fc6879b JM |
110 | } |
111 | ||
112 | ||
113 | int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, | |
114 | const u8 *data, size_t data_len, | |
115 | u8 *out, size_t out_len) | |
116 | { | |
117 | u8 hash[IKEV2_MAX_HASH_LEN]; | |
118 | size_t hash_len; | |
119 | u8 iter, *pos, *end; | |
120 | const u8 *addr[3]; | |
121 | size_t len[3]; | |
122 | const struct ikev2_prf_alg *prf; | |
123 | int res; | |
124 | ||
125 | prf = ikev2_get_prf(alg); | |
126 | if (prf == NULL) | |
127 | return -1; | |
128 | hash_len = prf->hash_len; | |
129 | ||
130 | addr[0] = hash; | |
131 | len[0] = hash_len; | |
132 | addr[1] = data; | |
133 | len[1] = data_len; | |
134 | addr[2] = &iter; | |
135 | len[2] = 1; | |
136 | ||
137 | pos = out; | |
138 | end = out + out_len; | |
139 | iter = 1; | |
140 | while (pos < end) { | |
141 | size_t clen; | |
142 | if (iter == 1) | |
143 | res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], | |
144 | &len[1], hash); | |
145 | else | |
146 | res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, | |
147 | hash); | |
148 | if (res < 0) | |
149 | return -1; | |
150 | clen = hash_len; | |
151 | if ((int) clen > end - pos) | |
152 | clen = end - pos; | |
153 | os_memcpy(pos, hash, clen); | |
154 | pos += clen; | |
155 | iter++; | |
156 | } | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
161 | ||
162 | const struct ikev2_encr_alg * ikev2_get_encr(int id) | |
163 | { | |
164 | size_t i; | |
165 | ||
166 | for (i = 0; i < NUM_ENCR_ALGS; i++) { | |
167 | if (ikev2_encr_algs[i].id == id) | |
168 | return &ikev2_encr_algs[i]; | |
169 | } | |
170 | ||
171 | return NULL; | |
172 | } | |
173 | ||
174 | ||
6fc6879b JM |
175 | int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, |
176 | const u8 *plain, u8 *crypt, size_t len) | |
177 | { | |
178 | struct crypto_cipher *cipher; | |
179 | int encr_alg; | |
180 | ||
6fc6879b JM |
181 | switch (alg) { |
182 | case ENCR_3DES: | |
183 | encr_alg = CRYPTO_CIPHER_ALG_3DES; | |
184 | break; | |
185 | case ENCR_AES_CBC: | |
186 | encr_alg = CRYPTO_CIPHER_ALG_AES; | |
187 | break; | |
188 | default: | |
189 | wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); | |
190 | return -1; | |
191 | } | |
192 | ||
193 | cipher = crypto_cipher_init(encr_alg, iv, key, key_len); | |
194 | if (cipher == NULL) { | |
195 | wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); | |
196 | return -1; | |
197 | } | |
198 | ||
199 | if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { | |
200 | wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); | |
201 | crypto_cipher_deinit(cipher); | |
202 | return -1; | |
203 | } | |
204 | crypto_cipher_deinit(cipher); | |
6fc6879b JM |
205 | |
206 | return 0; | |
207 | } | |
208 | ||
209 | ||
210 | int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, | |
211 | const u8 *crypt, u8 *plain, size_t len) | |
212 | { | |
213 | struct crypto_cipher *cipher; | |
214 | int encr_alg; | |
215 | ||
6fc6879b JM |
216 | switch (alg) { |
217 | case ENCR_3DES: | |
218 | encr_alg = CRYPTO_CIPHER_ALG_3DES; | |
219 | break; | |
220 | case ENCR_AES_CBC: | |
221 | encr_alg = CRYPTO_CIPHER_ALG_AES; | |
222 | break; | |
223 | default: | |
224 | wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); | |
225 | return -1; | |
226 | } | |
227 | ||
228 | cipher = crypto_cipher_init(encr_alg, iv, key, key_len); | |
229 | if (cipher == NULL) { | |
230 | wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { | |
235 | wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); | |
236 | crypto_cipher_deinit(cipher); | |
237 | return -1; | |
238 | } | |
239 | crypto_cipher_deinit(cipher); | |
6fc6879b JM |
240 | |
241 | return 0; | |
242 | } | |
243 | ||
244 | ||
245 | int ikev2_parse_payloads(struct ikev2_payloads *payloads, | |
246 | u8 next_payload, const u8 *pos, const u8 *end) | |
247 | { | |
248 | const struct ikev2_payload_hdr *phdr; | |
249 | ||
250 | os_memset(payloads, 0, sizeof(*payloads)); | |
251 | ||
252 | while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { | |
f931374f | 253 | unsigned int plen, pdatalen, left; |
6fc6879b JM |
254 | const u8 *pdata; |
255 | wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", | |
256 | next_payload); | |
f931374f JM |
257 | if (end < pos) |
258 | return -1; | |
259 | left = end - pos; | |
260 | if (left < sizeof(*phdr)) { | |
6fc6879b JM |
261 | wpa_printf(MSG_INFO, "IKEV2: Too short message for " |
262 | "payload header (left=%ld)", | |
263 | (long) (end - pos)); | |
08ef4426 | 264 | return -1; |
6fc6879b JM |
265 | } |
266 | phdr = (const struct ikev2_payload_hdr *) pos; | |
267 | plen = WPA_GET_BE16(phdr->payload_length); | |
f931374f | 268 | if (plen < sizeof(*phdr) || plen > left) { |
6fc6879b JM |
269 | wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " |
270 | "length %d", plen); | |
271 | return -1; | |
272 | } | |
273 | ||
274 | wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" | |
08ef4426 | 275 | " Payload Length: %u", |
6fc6879b JM |
276 | phdr->next_payload, phdr->flags, plen); |
277 | ||
278 | pdata = (const u8 *) (phdr + 1); | |
279 | pdatalen = plen - sizeof(*phdr); | |
280 | ||
281 | switch (next_payload) { | |
282 | case IKEV2_PAYLOAD_SA: | |
283 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " | |
284 | "Association"); | |
285 | payloads->sa = pdata; | |
286 | payloads->sa_len = pdatalen; | |
287 | break; | |
288 | case IKEV2_PAYLOAD_KEY_EXCHANGE: | |
289 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " | |
290 | "Exchange"); | |
291 | payloads->ke = pdata; | |
292 | payloads->ke_len = pdatalen; | |
293 | break; | |
294 | case IKEV2_PAYLOAD_IDi: | |
295 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); | |
296 | payloads->idi = pdata; | |
297 | payloads->idi_len = pdatalen; | |
298 | break; | |
299 | case IKEV2_PAYLOAD_IDr: | |
300 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); | |
301 | payloads->idr = pdata; | |
302 | payloads->idr_len = pdatalen; | |
303 | break; | |
304 | case IKEV2_PAYLOAD_CERTIFICATE: | |
305 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); | |
306 | payloads->cert = pdata; | |
307 | payloads->cert_len = pdatalen; | |
308 | break; | |
309 | case IKEV2_PAYLOAD_AUTHENTICATION: | |
310 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: " | |
311 | "Authentication"); | |
312 | payloads->auth = pdata; | |
313 | payloads->auth_len = pdatalen; | |
314 | break; | |
315 | case IKEV2_PAYLOAD_NONCE: | |
316 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); | |
317 | payloads->nonce = pdata; | |
318 | payloads->nonce_len = pdatalen; | |
319 | break; | |
320 | case IKEV2_PAYLOAD_ENCRYPTED: | |
321 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); | |
322 | payloads->encrypted = pdata; | |
323 | payloads->encrypted_len = pdatalen; | |
324 | break; | |
325 | case IKEV2_PAYLOAD_NOTIFICATION: | |
326 | wpa_printf(MSG_DEBUG, "IKEV2: Payload: " | |
327 | "Notification"); | |
328 | payloads->notification = pdata; | |
329 | payloads->notification_len = pdatalen; | |
330 | break; | |
331 | default: | |
332 | if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) { | |
333 | wpa_printf(MSG_INFO, "IKEV2: Unsupported " | |
334 | "critical payload %u - reject the " | |
335 | "entire message", next_payload); | |
336 | return -1; | |
337 | } else { | |
338 | wpa_printf(MSG_DEBUG, "IKEV2: Skipped " | |
339 | "unsupported payload %u", | |
340 | next_payload); | |
341 | } | |
342 | } | |
343 | ||
344 | if (next_payload == IKEV2_PAYLOAD_ENCRYPTED && | |
345 | pos + plen == end) { | |
346 | /* | |
347 | * Next Payload in the case of Encrypted Payload is | |
348 | * actually the payload type for the first embedded | |
349 | * payload. | |
350 | */ | |
351 | payloads->encr_next_payload = phdr->next_payload; | |
352 | next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD; | |
353 | } else | |
354 | next_payload = phdr->next_payload; | |
355 | ||
356 | pos += plen; | |
357 | } | |
358 | ||
359 | if (pos != end) { | |
360 | wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after " | |
361 | "payloads"); | |
362 | return -1; | |
363 | } | |
364 | ||
365 | return 0; | |
366 | } | |
367 | ||
368 | ||
369 | int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, | |
370 | const u8 *ID, size_t ID_len, u8 ID_type, | |
371 | struct ikev2_keys *keys, int initiator, | |
372 | const u8 *shared_secret, size_t shared_secret_len, | |
373 | const u8 *nonce, size_t nonce_len, | |
374 | const u8 *key_pad, size_t key_pad_len, | |
375 | u8 *auth_data) | |
376 | { | |
377 | size_t sign_len, buf_len; | |
378 | u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN]; | |
379 | const struct ikev2_prf_alg *prf; | |
380 | const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr; | |
381 | ||
382 | prf = ikev2_get_prf(prf_alg); | |
383 | if (sign_msg == NULL || ID == NULL || SK_p == NULL || | |
384 | shared_secret == NULL || nonce == NULL || prf == NULL) | |
385 | return -1; | |
386 | ||
387 | /* prf(SK_pi/r,IDi/r') */ | |
388 | buf_len = 4 + ID_len; | |
389 | buf = os_zalloc(buf_len); | |
390 | if (buf == NULL) | |
391 | return -1; | |
392 | buf[0] = ID_type; | |
393 | os_memcpy(buf + 4, ID, ID_len); | |
394 | if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len, | |
395 | 1, (const u8 **) &buf, &buf_len, hash) < 0) { | |
396 | os_free(buf); | |
397 | return -1; | |
398 | } | |
399 | os_free(buf); | |
400 | ||
401 | /* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */ | |
402 | sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len; | |
403 | sign_data = os_malloc(sign_len); | |
404 | if (sign_data == NULL) | |
405 | return -1; | |
406 | pos = sign_data; | |
407 | os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg)); | |
408 | pos += wpabuf_len(sign_msg); | |
409 | os_memcpy(pos, nonce, nonce_len); | |
410 | pos += nonce_len; | |
411 | os_memcpy(pos, hash, prf->hash_len); | |
412 | ||
413 | /* AUTH = prf(prf(Shared Secret, key pad, sign_data) */ | |
414 | if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1, | |
415 | &key_pad, &key_pad_len, hash) < 0 || | |
416 | ikev2_prf_hash(prf->id, hash, prf->hash_len, 1, | |
417 | (const u8 **) &sign_data, &sign_len, auth_data) < 0) | |
418 | { | |
419 | os_free(sign_data); | |
420 | return -1; | |
421 | } | |
422 | os_free(sign_data); | |
423 | ||
424 | return 0; | |
425 | } | |
426 | ||
427 | ||
428 | u8 * ikev2_decrypt_payload(int encr_id, int integ_id, | |
429 | struct ikev2_keys *keys, int initiator, | |
430 | const struct ikev2_hdr *hdr, | |
431 | const u8 *encrypted, size_t encrypted_len, | |
432 | size_t *res_len) | |
433 | { | |
434 | size_t iv_len; | |
435 | const u8 *pos, *end, *iv, *integ; | |
436 | u8 hash[IKEV2_MAX_HASH_LEN], *decrypted; | |
437 | size_t decrypted_len, pad_len; | |
438 | const struct ikev2_integ_alg *integ_alg; | |
439 | const struct ikev2_encr_alg *encr_alg; | |
440 | const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; | |
441 | const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; | |
442 | ||
443 | if (encrypted == NULL) { | |
444 | wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH"); | |
445 | return NULL; | |
446 | } | |
447 | ||
448 | encr_alg = ikev2_get_encr(encr_id); | |
449 | if (encr_alg == NULL) { | |
450 | wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); | |
451 | return NULL; | |
452 | } | |
453 | iv_len = encr_alg->block_size; | |
454 | ||
455 | integ_alg = ikev2_get_integ(integ_id); | |
456 | if (integ_alg == NULL) { | |
457 | wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); | |
458 | return NULL; | |
459 | } | |
460 | ||
461 | if (encrypted_len < iv_len + 1 + integ_alg->hash_len) { | |
462 | wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity " | |
463 | "Checksum"); | |
464 | return NULL; | |
465 | } | |
466 | ||
467 | iv = encrypted; | |
468 | pos = iv + iv_len; | |
469 | end = encrypted + encrypted_len; | |
470 | integ = end - integ_alg->hash_len; | |
471 | ||
472 | if (SK_a == NULL) { | |
473 | wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); | |
474 | return NULL; | |
475 | } | |
476 | if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, | |
477 | (const u8 *) hdr, | |
478 | integ - (const u8 *) hdr, hash) < 0) { | |
479 | wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity " | |
480 | "hash"); | |
481 | return NULL; | |
482 | } | |
675ddad1 | 483 | if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) { |
6fc6879b JM |
484 | wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " |
485 | "Data"); | |
486 | return NULL; | |
487 | } | |
488 | ||
489 | if (SK_e == NULL) { | |
490 | wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); | |
491 | return NULL; | |
492 | } | |
493 | ||
494 | decrypted_len = integ - pos; | |
495 | decrypted = os_malloc(decrypted_len); | |
496 | if (decrypted == NULL) | |
497 | return NULL; | |
498 | ||
499 | if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos, | |
500 | decrypted, decrypted_len) < 0) { | |
501 | os_free(decrypted); | |
502 | return NULL; | |
503 | } | |
504 | ||
505 | pad_len = decrypted[decrypted_len - 1]; | |
506 | if (decrypted_len < pad_len + 1) { | |
507 | wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted " | |
508 | "payload"); | |
509 | os_free(decrypted); | |
510 | return NULL; | |
511 | } | |
512 | ||
513 | decrypted_len -= pad_len + 1; | |
514 | ||
515 | *res_len = decrypted_len; | |
516 | return decrypted; | |
517 | } | |
518 | ||
519 | ||
520 | void ikev2_update_hdr(struct wpabuf *msg) | |
521 | { | |
522 | struct ikev2_hdr *hdr; | |
523 | ||
524 | /* Update lenth field in HDR */ | |
525 | hdr = wpabuf_mhead(msg); | |
526 | WPA_PUT_BE32(hdr->length, wpabuf_len(msg)); | |
527 | } | |
528 | ||
529 | ||
530 | int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, | |
531 | int initiator, struct wpabuf *msg, | |
532 | struct wpabuf *plain, u8 next_payload) | |
533 | { | |
534 | struct ikev2_payload_hdr *phdr; | |
535 | size_t plen; | |
536 | size_t iv_len, pad_len; | |
537 | u8 *icv, *iv; | |
538 | const struct ikev2_integ_alg *integ_alg; | |
539 | const struct ikev2_encr_alg *encr_alg; | |
540 | const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; | |
541 | const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; | |
542 | ||
543 | wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); | |
544 | ||
545 | /* Encr - RFC 4306, Sect. 3.14 */ | |
546 | ||
547 | encr_alg = ikev2_get_encr(encr_id); | |
548 | if (encr_alg == NULL) { | |
549 | wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); | |
550 | return -1; | |
551 | } | |
552 | iv_len = encr_alg->block_size; | |
553 | ||
554 | integ_alg = ikev2_get_integ(integ_id); | |
555 | if (integ_alg == NULL) { | |
556 | wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); | |
557 | return -1; | |
558 | } | |
559 | ||
560 | if (SK_e == NULL) { | |
561 | wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); | |
562 | return -1; | |
563 | } | |
564 | ||
565 | if (SK_a == NULL) { | |
566 | wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); | |
567 | return -1; | |
568 | } | |
569 | ||
570 | phdr = wpabuf_put(msg, sizeof(*phdr)); | |
571 | phdr->next_payload = next_payload; | |
572 | phdr->flags = 0; | |
573 | ||
574 | iv = wpabuf_put(msg, iv_len); | |
3642c431 | 575 | if (random_get_bytes(iv, iv_len)) { |
6fc6879b JM |
576 | wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); |
577 | return -1; | |
578 | } | |
579 | ||
580 | pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; | |
581 | if (pad_len == iv_len) | |
582 | pad_len = 0; | |
583 | wpabuf_put(plain, pad_len); | |
584 | wpabuf_put_u8(plain, pad_len); | |
585 | ||
586 | if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, | |
587 | wpabuf_head(plain), wpabuf_mhead(plain), | |
588 | wpabuf_len(plain)) < 0) | |
589 | return -1; | |
590 | ||
591 | wpabuf_put_buf(msg, plain); | |
592 | ||
593 | /* Need to update all headers (Length fields) prior to hash func */ | |
594 | icv = wpabuf_put(msg, integ_alg->hash_len); | |
595 | plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; | |
596 | WPA_PUT_BE16(phdr->payload_length, plen); | |
597 | ||
598 | ikev2_update_hdr(msg); | |
599 | ||
600 | return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, | |
601 | wpabuf_head(msg), | |
602 | wpabuf_len(msg) - integ_alg->hash_len, icv); | |
603 | ||
604 | return 0; | |
605 | } | |
606 | ||
607 | ||
608 | int ikev2_keys_set(struct ikev2_keys *keys) | |
609 | { | |
610 | return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei && | |
611 | keys->SK_er && keys->SK_pi && keys->SK_pr; | |
612 | } | |
613 | ||
614 | ||
615 | void ikev2_free_keys(struct ikev2_keys *keys) | |
616 | { | |
617 | os_free(keys->SK_d); | |
618 | os_free(keys->SK_ai); | |
619 | os_free(keys->SK_ar); | |
620 | os_free(keys->SK_ei); | |
621 | os_free(keys->SK_er); | |
622 | os_free(keys->SK_pi); | |
623 | os_free(keys->SK_pr); | |
624 | keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er = | |
625 | keys->SK_pi = keys->SK_pr = NULL; | |
626 | } | |
627 | ||
628 | ||
629 | int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, | |
630 | const struct ikev2_integ_alg *integ, | |
631 | const struct ikev2_encr_alg *encr, | |
632 | const u8 *skeyseed, const u8 *data, size_t data_len, | |
633 | struct ikev2_keys *keys) | |
634 | { | |
635 | u8 *keybuf, *pos; | |
636 | size_t keybuf_len; | |
637 | ||
638 | /* | |
639 | * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = | |
640 | * prf+(SKEYSEED, Ni | Nr | SPIi | SPIr ) | |
641 | */ | |
642 | ikev2_free_keys(keys); | |
643 | keys->SK_d_len = prf->key_len; | |
644 | keys->SK_integ_len = integ->key_len; | |
645 | keys->SK_encr_len = encr->key_len; | |
646 | keys->SK_prf_len = prf->key_len; | |
6fc6879b JM |
647 | |
648 | keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + | |
649 | 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; | |
650 | keybuf = os_malloc(keybuf_len); | |
651 | if (keybuf == NULL) | |
652 | return -1; | |
653 | ||
654 | if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len, | |
655 | data, data_len, keybuf, keybuf_len)) { | |
656 | os_free(keybuf); | |
657 | return -1; | |
658 | } | |
659 | ||
660 | pos = keybuf; | |
661 | ||
662 | keys->SK_d = os_malloc(keys->SK_d_len); | |
663 | if (keys->SK_d) { | |
664 | os_memcpy(keys->SK_d, pos, keys->SK_d_len); | |
665 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d", | |
666 | keys->SK_d, keys->SK_d_len); | |
667 | } | |
668 | pos += keys->SK_d_len; | |
669 | ||
670 | keys->SK_ai = os_malloc(keys->SK_integ_len); | |
671 | if (keys->SK_ai) { | |
672 | os_memcpy(keys->SK_ai, pos, keys->SK_integ_len); | |
673 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai", | |
674 | keys->SK_ai, keys->SK_integ_len); | |
675 | } | |
676 | pos += keys->SK_integ_len; | |
677 | ||
678 | keys->SK_ar = os_malloc(keys->SK_integ_len); | |
679 | if (keys->SK_ar) { | |
680 | os_memcpy(keys->SK_ar, pos, keys->SK_integ_len); | |
681 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar", | |
682 | keys->SK_ar, keys->SK_integ_len); | |
683 | } | |
684 | pos += keys->SK_integ_len; | |
685 | ||
686 | keys->SK_ei = os_malloc(keys->SK_encr_len); | |
687 | if (keys->SK_ei) { | |
688 | os_memcpy(keys->SK_ei, pos, keys->SK_encr_len); | |
689 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei", | |
690 | keys->SK_ei, keys->SK_encr_len); | |
691 | } | |
692 | pos += keys->SK_encr_len; | |
693 | ||
694 | keys->SK_er = os_malloc(keys->SK_encr_len); | |
695 | if (keys->SK_er) { | |
696 | os_memcpy(keys->SK_er, pos, keys->SK_encr_len); | |
697 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er", | |
698 | keys->SK_er, keys->SK_encr_len); | |
699 | } | |
700 | pos += keys->SK_encr_len; | |
701 | ||
702 | keys->SK_pi = os_malloc(keys->SK_prf_len); | |
703 | if (keys->SK_pi) { | |
704 | os_memcpy(keys->SK_pi, pos, keys->SK_prf_len); | |
705 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi", | |
706 | keys->SK_pi, keys->SK_prf_len); | |
707 | } | |
708 | pos += keys->SK_prf_len; | |
709 | ||
710 | keys->SK_pr = os_malloc(keys->SK_prf_len); | |
711 | if (keys->SK_pr) { | |
712 | os_memcpy(keys->SK_pr, pos, keys->SK_prf_len); | |
713 | wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr", | |
714 | keys->SK_pr, keys->SK_prf_len); | |
715 | } | |
716 | ||
717 | os_free(keybuf); | |
718 | ||
719 | if (!ikev2_keys_set(keys)) { | |
720 | ikev2_free_keys(keys); | |
721 | return -1; | |
722 | } | |
723 | ||
724 | return 0; | |
725 | } |