The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
crypto.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * @file src/lib/eap_aka_sim/crypto.c
19 * @brief Calculate keys from GSM vectors.
20 *
21 * The development of the original EAP/SIM support was funded by Internet Foundation
22 * Austria (http://www.nic.at/ipa). The original EAP-SIM PRF functions were written
23 * by Michael Richardson <mcr@sandelman.ottawa.on.ca>, but these have since been
24 * replaced.
25 *
26 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
27 *
28 * @copyright 2003-2018 The FreeRADIUS server project
29 * @copyright 2016-2018 Network RADIUS (legal@networkradius.com)
30 */
31RCSID("$Id: 989c90614b8d8f5359a4447bf32deab27a33e8a9 $")
32
33#include <stdio.h>
34#include <stdlib.h>
35
36#include <freeradius-devel/protocol/eap/aka-sim/dictionary.h>
37
38#include <freeradius-devel/eap/types.h>
39#include <freeradius-devel/sim/common.h>
40#include <freeradius-devel/sim/milenage.h>
41#include <freeradius-devel/tls/base.h>
42#include <freeradius-devel/tls/strerror.h>
43#include <freeradius-devel/util/atexit.h>
44#include <freeradius-devel/util/rand.h>
45#include <freeradius-devel/util/sha1.h>
46#include <openssl/evp.h>
47
48#include "base.h"
49#include "attrs.h"
50#include "crypto_priv.h"
51
52/** Used for every non-persistent EVP_CIPHER operation in this library
53 *
54 * Avoids memory churn allocating and freeing the ctx for each operation.
55 */
56static _Thread_local EVP_CIPHER_CTX *evp_chipher_ctx;
57
58static int _evp_cipher_ctx_free_on_exit(void *arg)
59{
60 EVP_CIPHER_CTX_free(arg);
61 return 0;
62}
63
64/** Allocate and reset a resumable EVP_CIPHER_CTX for each thread
65 *
66 * No two crypto operations ever occur simultaneously in the same thread,
67 * so it's fine to use a single context that persists for all operations.
68 */
69EVP_CIPHER_CTX *aka_sim_crypto_cipher_ctx(void)
70{
72 EVP_CIPHER_CTX *ctx;
73
74 MEM(ctx = EVP_CIPHER_CTX_new());
76 } else {
77 EVP_CIPHER_CTX_reset(evp_chipher_ctx);
78 }
79
80 return evp_chipher_ctx;
81}
82
83/** Explicitly free all thread load cipher ctxs
84 *
85 */
91
92/** Free OpenSSL memory associated with our checkcode ctx
93 *
94 * @param[in] checkcode to free.
95 * @return 0
96 */
98{
99 if (checkcode->md_ctx) EVP_MD_CTX_destroy(checkcode->md_ctx);
100 return 0;
101}
102
103/** Initialise checkcode message digest
104 *
105 * @param[in] ctx to allocate checkcode structure in.
106 * @param[out] checkcode a new checkcode structure.
107 * @param[in] md to use when calculating the checkcode,
108 * either EVP_sha1(), or EVP_sha256().
109 * @return
110 * - 0 on success.
111 * - -1 on failure.
112 */
113int fr_aka_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_aka_sim_checkcode_t **checkcode, EVP_MD const *md)
114{
115 *checkcode = talloc_zero(ctx, fr_aka_sim_checkcode_t);
116 if (!*checkcode) {
117 fr_strerror_const("Out of memory");
118 return -1;
119 }
120
121 (*checkcode)->md_ctx = EVP_MD_CTX_create();
122 if (!(*checkcode)->md_ctx) {
123 fr_tls_strerror_printf("Failed creating MD ctx");
124 error:
125 TALLOC_FREE(*checkcode);
126 return -1;
127 }
128 if (EVP_DigestInit_ex((*checkcode)->md_ctx, md, NULL) != 1) {
129 fr_tls_strerror_printf("Failed initialising MD ctx");
130 goto error;
131 }
132
133 talloc_set_destructor(*checkcode, _fr_aka_sim_crypto_free_checkcode);
134
135 return 0;
136}
137
138/** Digest a packet, updating the checkcode
139 *
140 * Call #fr_aka_sim_crypto_finalise_checkcode to obtain the final checkcode value.
141 *
142 * @param[in,out] checkcode if *checkcode is NULL, a new checkcode structure
143 * will be allocated and the message digest context
144 * will be initialised before the provided
145 * eap_packet is fed into the digest.
146 * @param[in] eap_packet to digest.
147 * @return
148 * - 0 on success.
149 * - -1 on failure.
150 */
152{
153 uint16_t packet_len;
154 eap_packet_hdr_t eap_hdr;
155
156 eap_hdr.code = eap_packet->code;
157 eap_hdr.id = eap_packet->id;
158 packet_len = htons((sizeof(eap_hdr) + eap_packet->type.length) & UINT16_MAX); /* EAP Header + Method + SIM data */
159 memcpy(&eap_hdr.length, &packet_len, sizeof(packet_len));
160 eap_hdr.data[0] = eap_packet->type.num;
161
162 FR_PROTO_HEX_DUMP((void *)&eap_hdr, sizeof(eap_hdr), "Ingesting checkcode EAP header");
163
164 /*
165 * Digest the header
166 */
167 if (EVP_DigestUpdate(checkcode->md_ctx, &eap_hdr, sizeof(eap_hdr)) != 1) {
168 fr_tls_strerror_printf("Failed digesting EAP header");
169 return -1;
170 }
171
172 FR_PROTO_HEX_DUMP((void *)eap_packet->type.data, eap_packet->type.length, "Ingesting checkcode EAP data");
173
174 /*
175 * Digest the packet
176 */
177 if (EVP_DigestUpdate(checkcode->md_ctx, eap_packet->type.data, eap_packet->type.length) != 1) {
178 fr_tls_strerror_printf("Failed digesting packet data");
179 return -1;
180 }
181
182 return 0;
183}
184
185/** Write out the final checkcode value
186 *
187 * @param[in] ctx ctx to allocate buffer containing the checkcode.
188 * @param[out] out talloced buffer containing the checkcode.
189 * bytes if MD was SHA1, or 32 bytes if MD was SHA256.
190 * @param[in,out] checkcode structure to get final digest from and to tree.
191 * @return
192 * - <= 0 on failure.
193 * - > 0 the number of bytes written to out.
194 */
196{
197 size_t len;
198 uint8_t *buff;
199
200 len = (size_t)EVP_MD_CTX_size((*checkcode).md_ctx);
201 MEM(buff = talloc_array(ctx, uint8_t, len));
202 if (EVP_DigestFinal_ex((*checkcode).md_ctx, buff, NULL) != 1) {
203 fr_tls_strerror_printf("Failed finalising checkcode digest");
204 return -1;
205 }
206 *out = buff;
207
208 return (size_t)len;
209}
210
211/** Locate the start of the AT_MAC value in the buffer
212 *
213 * @param[out] out The start of the digest portion of the AT_MAC attribute.
214 * @param[in] data to search for the AT_MAC in.
215 * @param[in] data_len size of the data.
216 * @return
217 * - 1 if we couldn't find a MAC.
218 * - 0 if we found and zeroed out the mac field.
219 * - -1 if the field was malformed.
220 */
221static int fr_aka_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
222{
223 uint8_t *p = data, *end = p + data_len;
224 size_t len;
225
226 *out = NULL;
227
228 p += 3; /* Skip header */
229 while ((p + 2) < end) {
230 if (!p[1]) {
231 fr_strerror_const("Malformed field - length zero is invalid");
232 return -1;
233 }
234
235 if (p[0] == FR_MAC) {
236 len = p[1] << 2;
237 if ((p + len) > end) {
238 fr_strerror_printf("Malformed AT_MAC: Length (%zu) exceeds buffer (%zu)", len, (size_t) (end - p));
239 return -1;
240 }
241
242 if (len != AKA_SIM_MAC_SIZE) {
243 fr_strerror_printf("Malformed AT_MAC: Length (%zu) incorrect (%u)",
244 len, AKA_SIM_MAC_SIZE);
245 return -1;
246 }
247 *out = p + 4;
248
249 return 0;
250 }
251
252 p += p[1] << 2; /* Advance */
253 }
254
255 fr_strerror_const("No MAC attribute found");
256
257 return 1;
258}
259
260/** Calculate the digest value for a packet
261 *
262 * Run a digest over a fake EAP header, the entire SIM packet and any extra HMAC data,
263 * writing a truncated (16 byte) digest value to out.
264 *
265 * @note The 16 byte digest field in the packet must have either been zeroed out before
266 * this function is called (as it is when encoding data), or zero_mac must be set
267 * to true.
268 *
269 * @note This function uses the EVP_* signing functions. Do not be tempted to swap them
270 * for the HMAC functions, as the EVP interface may be hardware accelerated but
271 * the HMAC interface is purely a software implementation.
272 *
273 * @param[out] out Where to write the digest.
274 * @param[in] eap_packet to extract header values from.
275 * @param[in] zero_mac Assume the mac field is not zeroed (i.e. received packet)
276 * and skip it during mac calculation feeding in 16 zeroed
277 * bytes in its place.
278 * @param[in] md to use to create the HMAC.
279 * @param[in] key to use to sign the packet.
280 * @param[in] key_len Length of the key.
281 * @param[in] hmac_extra data to concatenate with the packet when calculating the HMAC
282 * (may be NULL).
283 * @param[in] hmac_extra_len Length of hmac_extra (may be zero).
284 * @return
285 * - < 0 on failure.
286 * - 0 if there's no MAC attribute to verify.
287 * - > 0 the number of bytes written to out.
288 */
290 eap_packet_t *eap_packet, bool zero_mac,
291 EVP_MD const *md, uint8_t const *key, size_t const key_len,
292 uint8_t const *hmac_extra, size_t const hmac_extra_len)
293{
294 EVP_MD_CTX *md_ctx = NULL;
295 EVP_PKEY *pkey;
296
297 uint8_t digest[SHA256_DIGEST_LENGTH];
298 size_t digest_len = sizeof(digest);
299 uint8_t const *mac;
300 uint8_t *p = eap_packet->type.data, *end = p + eap_packet->type.length;
301
302 eap_packet_hdr_t eap_hdr;
303 uint16_t packet_len;
304
305 if (unlikely(!eap_packet)) {
306 fr_strerror_const("Invalid argument: eap_packet is NULL");
307 return -1;
308 }
309
310 if (unlikely(!md)) {
311 fr_strerror_const("Invalid argument: md is NULL");
312 return -1;
313 }
314
315 if (unlikely(!key) || (key_len == 0)) {
316 fr_strerror_const("Invalid argument: key is NULL");
317 return -1;
318 }
319
320 FR_PROTO_HEX_DUMP(key, key_len, "MAC key");
321 pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
322 if (!pkey) {
323 fr_tls_strerror_printf("Failed creating HMAC signing key");
324 error:
325 if (pkey) EVP_PKEY_free(pkey);
326 if (md_ctx) EVP_MD_CTX_destroy(md_ctx);
327 return -1;
328 }
329
330 md_ctx = EVP_MD_CTX_create();
331 if (!md_ctx) {
332 fr_tls_strerror_printf("Failed creating HMAC ctx");
333 goto error;
334 }
335
336 if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, pkey) != 1) {
337 fr_tls_strerror_printf("Failed initialising digest");
338 goto error;
339 }
340
341 /*
342 * The HMAC has to be over the entire packet, which
343 * we don't get access too. So we create a fake EAP
344 * header now, and feed that into the HMAC function.
345 */
346 eap_hdr.code = eap_packet->code;
347 eap_hdr.id = eap_packet->id;
348 packet_len = htons((sizeof(eap_hdr) + eap_packet->type.length) & UINT16_MAX); /* EAP Header + Method + SIM data */
349 memcpy(&eap_hdr.length, &packet_len, sizeof(packet_len));
350 eap_hdr.data[0] = eap_packet->type.num;
351
352 FR_PROTO_HEX_DUMP((uint8_t *)&eap_hdr, sizeof(eap_hdr), "MAC digest input (eap header)");
353 if (EVP_DigestSignUpdate(md_ctx, &eap_hdr, sizeof(eap_hdr)) != 1) {
354 fr_tls_strerror_printf("Failed digesting EAP data");
355 goto error;
356 }
357
358 /*
359 * Digest the packet up to the AT_MAC, value, then
360 * digest 16 bytes of zero.
361 */
362 if (zero_mac) {
363 switch (fr_aka_sim_find_mac(&mac, p, end - p)) {
364 case 0:
365 {
366 uint8_t zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
368
369 FR_PROTO_HEX_DUMP(p, mac - p, "MAC digest input");
370
371 /*
372 * Digest everything up to the hash
373 * part of the AT_MAC, including
374 * AT_MAC header and reserved bytes.
375 */
376 if (EVP_DigestSignUpdate(md_ctx, p, mac - p) != 1) {
377 fr_tls_strerror_printf("Failed digesting packet data (before MAC)");
378 goto error;
379 }
380 p += mac - p;
381
382
383 FR_PROTO_HEX_DUMP(zero, sizeof(zero), "MAC digest input");
384 /*
385 * Feed in 16 bytes of zeroes to
386 * simulated the zeroed out Mac.
387 */
388 if (EVP_DigestSignUpdate(md_ctx, zero, sizeof(zero)) != 1) {
389 fr_tls_strerror_printf("Failed digesting zeroed MAC");
390 goto error;
391 }
392 p += sizeof(zero);
393 }
394 break;
395
396 case 1:
397 return 0;
398
399 case -1:
400 fr_assert(0); /* Should have been checked by encoder or decoder */
401 goto error;
402 }
403 }
404
405 if (p < end) {
406 FR_PROTO_HEX_DUMP(p, (end - p), "MAC digest input");
407
408 /*
409 * Digest the rest of the packet.
410 */
411 if (EVP_DigestSignUpdate(md_ctx, p, end - p) != 1) {
412 fr_tls_strerror_printf("Failed digesting packet data");
413 goto error;
414 }
415 }
416
417 /*
418 * Digest any HMAC concatenated data
419 *
420 * Some subtypes require the HMAC to be calculated over
421 * a concatenation of packet data, and something extra...
422 */
423 if (hmac_extra) {
424 FR_PROTO_HEX_DUMP(hmac_extra, hmac_extra_len, "MAC digest input (extra)");
425 if (EVP_DigestSignUpdate(md_ctx, hmac_extra, hmac_extra_len) != 1) {
426 fr_tls_strerror_printf("Failed digesting HMAC extra data");
427 goto error;
428 }
429 }
430
431 if (EVP_DigestSignFinal(md_ctx, digest, &digest_len) != 1) {
432 fr_tls_strerror_printf("Failed finalising digest");
433 goto error;
434 }
435
436 FR_PROTO_HEX_DUMP(digest, digest_len, "MAC");
437
438 /*
439 * Truncate by four bytes.
440 */
441 memcpy(out, digest, 16);
442
443 EVP_PKEY_free(pkey);
444 EVP_MD_CTX_destroy(md_ctx);
445
446 return 16; /* AT_MAC (1), LEN (1), RESERVED (2) */
447}
448
449/** Key Derivation Function as described in RFC4186 (EAP-SIM) section 7
450 *
451 @verbatim
452 MK = SHA1(Identity|n*Kc| NONCE_MT| Version List| Selected Version)
453 FK = PRF(MK)
454 K_encr = FK[0..127]
455 K_aut = FK[128..255]
456 MSK = FK[256..767]
457 EMSK = FK[768..1279]
458 @endverbatim
459 * @note expects keys to contain a AKA_SIM_VECTOR_GSM.
460 *
461 * @param[in,out] keys Contains the authentication vectors and the buffers
462 * to store the result of the derivation.
463 * @return
464 * - 0 on success.
465 * - -1 on failure.
466 */
468{
470 uint8_t fk[160];
471
472 uint8_t buf[AKA_SIM_MAX_STRING_LENGTH + sizeof(keys->gsm.nonce_mt) + 2 + sizeof(keys->gsm.version_select)];
473 uint8_t *p;
474
475 if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_GSM)) return -1;
476
477 /*
478 * Our stack buffer should be large enough in
479 * all cases.
480 */
481 if (!fr_cond_assert((keys->identity_len +
483 sizeof(keys->gsm.nonce_mt) +
484 keys->gsm.version_list_len +
485 sizeof(keys->gsm.version_select)) <= sizeof(buf))) return -1;
486
487 p = buf;
488 memcpy(p, keys->identity, keys->identity_len);
489 p += keys->identity_len;
490
491 memcpy(p, keys->gsm.vector[0].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
493
494 memcpy(p, keys->gsm.vector[1].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
496
497 memcpy(p, keys->gsm.vector[2].kc, AKA_SIM_VECTOR_GSM_KC_SIZE);
499
500 memcpy(p, keys->gsm.nonce_mt, sizeof(keys->gsm.nonce_mt));
501 p += sizeof(keys->gsm.nonce_mt);
502
503 memcpy(p, keys->gsm.version_list, keys->gsm.version_list_len);
504 p += keys->gsm.version_list_len;
505
506 memcpy(p, keys->gsm.version_select, sizeof(keys->gsm.version_select));
507 p += sizeof(keys->gsm.version_select);
508
509 FR_PROTO_HEX_DUMP(buf, p - buf, "Identity || n*Kc || NONCE_MT || Version List || Selected Version");
510
511 /*
512 * Do the master key first
513 */
515 fr_sha1_update(&context, buf, p - buf);
516 fr_sha1_final(keys->mk, &context);
517 keys->mk_len = AKA_SIM_MK_SIZE;
518
519 FR_PROTO_HEX_DUMP(keys->mk, keys->mk_len, "Master key");
520
521 /*
522 * Now use the PRF to expand it, generated
523 * k_aut, k_encr, MSK and EMSK.
524 */
525 fr_aka_sim_fips186_2prf(fk, keys->mk);
526
527 /*
528 * Split up the result
529 */
530 p = fk;
531 memcpy(keys->k_encr, p, 16); /* 128 bits for encryption */
532 p += 16;
533 FR_PROTO_HEX_DUMP(keys->k_encr, sizeof(keys->k_encr), "K_encr");
534
535 memcpy(keys->k_aut, p, EAP_AKA_SIM_AUTH_SIZE); /* 128 bits for auth */
538 FR_PROTO_HEX_DUMP(keys->k_aut, keys->k_aut_len, "K_aut");
539
540 memcpy(keys->msk, p, 64); /* 64 bytes for Master Session Key */
541 p += 64;
542 FR_PROTO_HEX_DUMP(keys->msk, sizeof(keys->msk), "K_msk");
543
544 memcpy(keys->emsk, p, 64); /* 64 bytes for Extended Master Session Key */
545 FR_PROTO_HEX_DUMP(keys->emsk, sizeof(keys->emsk), "K_emsk");
546
547 return 0;
548}
549
550/** Key Derivation Function as described in RFC4187 (EAP-AKA) section 7
551 *
552 * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
553 *
554 @verbatim
555 MK = SHA1(Identity|IK|CK)
556 FK = PRF(MK)
557 K_encr = FK[0..127]
558 K_aut = FK[128..255]
559 MSK = FK[256..767]
560 EMSK = FK[768..1279]
561 @endverbatim
562 *
563 * @param[in,out] keys Contains the authentication vectors and the buffers
564 * to store the result of the derivation.
565 * @return
566 * - 0 on success.
567 * - -1 on failure.
568 */
570{
572 uint8_t fk[160];
573 uint8_t buf[AKA_SIM_MAX_STRING_LENGTH + sizeof(keys->umts.vector.ik) + sizeof(keys->umts.vector.ck)];
574 uint8_t *p;
575 size_t blen;
576
577 if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return - 1;
578
579 /*
580 * Our stack buffer should be large enough in
581 * all cases.
582 */
583 if (!fr_cond_assert((keys->identity_len +
584 sizeof(keys->umts.vector.ik) +
585 sizeof(keys->umts.vector.ck)) <= sizeof(buf))) return -1;
586
587 p = buf;
588 memcpy(p, keys->identity, keys->identity_len);
589 p += keys->identity_len;
590
591 memcpy(p, keys->umts.vector.ik, sizeof(keys->umts.vector.ik));
592 p += sizeof(keys->umts.vector.ik);
593
594 memcpy(p, keys->umts.vector.ck, sizeof(keys->umts.vector.ck));
595 p += sizeof(keys->umts.vector.ck);
596
597 blen = p - buf;
598
599 /* do the master key first */
601 fr_sha1_update(&context, buf, blen);
602 fr_sha1_final(keys->mk, &context);
603 keys->mk_len = AKA_SIM_MK_SIZE;
604
605 /*
606 * now use the PRF to expand it, generated k_aut, k_encr,
607 * MSK and EMSK.
608 */
609 fr_aka_sim_fips186_2prf(fk, keys->mk);
610
611 /* split up the result */
612 p = fk;
613
614 memcpy(keys->k_encr, p, 16); /* 128 bits for encryption */
615 p += 16;
616
617 memcpy(keys->k_aut, p, EAP_AKA_AUTH_SIZE); /* 128 bits for auth */
620
621 memcpy(keys->msk, p, 64); /* 64 bytes for Master Session Key */
622 p += 64;
623
624 memcpy(keys->emsk, p, 64); /* 64 bytes for Extended Master Session Key */
625
626 return 0;
627}
628
629/** Key Derivation Function (CK', IK') as specified in 3GPP.33.402
630 *
631 @verbatim
632 CK' || IK' = HMAC-SHA-256(Key, S)
633 S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
634 Key = CK || IK
635 FC = 0x20
636 P0 = access network identity (3GPP TS 24.302)
637 L0 = length of access network identity (2 octets, big endian)
638 P1 = SQN xor AK (if AK is not used, AK is treated as 000..0
639 L1 = 0x00 0x06
640 @endverbatim
641 *
642 * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
643 *
644 * @param[in,out] keys Contains the authentication vectors and the buffers
645 * to store the result of the derivation.
646 * @return
647 * - 0 on success.
648 * - -1 on failure.
649 */
651{
652 uint8_t digest[sizeof(keys->ik_prime) + sizeof(keys->ck_prime)];
653 size_t digest_len = sizeof(digest);
654
655 uint8_t sqn_ak_buff[MILENAGE_SQN_SIZE];
656 uint16_t l0, l1;
657
658 uint8_t k[sizeof(keys->umts.vector.ik) + sizeof(keys->umts.vector.ck)];
659 uint8_t s[sizeof(uint8_t) + AKA_SIM_MAX_STRING_LENGTH + sizeof(l0) + AKA_SIM_SQN_AK_SIZE + sizeof(l1)];
660
661 uint8_t *p = s;
662
663 size_t s_len;
664 EVP_PKEY *pkey;
665 EVP_MD_CTX *md_ctx = NULL;
666
667 if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return -1;
668
669 uint48_to_buff(sqn_ak_buff, keys->sqn ^ uint48_from_buff(keys->umts.vector.ak));
670
671 /*
672 * Our stack buffer should be large enough in
673 * all cases.
674 */
675 if (!fr_cond_assert((sizeof(uint8_t) +
676 keys->network_len +
677 sizeof(l0) +
679 sizeof(l1)) <= sizeof(s))) return -1;
680
681 FR_PROTO_HEX_DUMP(keys->network, keys->network_len, "Network");
682 FR_PROTO_HEX_DUMP(keys->umts.vector.ck, sizeof(keys->umts.vector.ck), "CK");
683 FR_PROTO_HEX_DUMP(keys->umts.vector.ik, sizeof(keys->umts.vector.ik), "IK");
684 FR_PROTO_HEX_DUMP(sqn_ak_buff, AKA_SIM_SQN_AK_SIZE, "SQN ⊕ AK");
685
686 /*
687 * FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
688 */
689 *p++ = 0x20;
690 memcpy(p, keys->network, keys->network_len);
691 p += keys->network_len;
692
693 l0 = htons((uint16_t)keys->network_len);
694 memcpy(p, &l0, sizeof(l0));
695 p += sizeof(l0);
696
697 memcpy(p, sqn_ak_buff, AKA_SIM_SQN_AK_SIZE);
699
700 l1 = htons(AKA_SIM_SQN_AK_SIZE);
701 memcpy(p, &l1, sizeof(l1));
702 p += sizeof(l1);
703
704 s_len = p - s;
705
706 FR_PROTO_HEX_DUMP(s, s_len, "FC || P0 || L0 || P1 || L1 || ... || Pn || Ln");
707
708 /*
709 * CK || IK
710 */
711 p = k;
712 memcpy(p, keys->umts.vector.ck, sizeof(keys->umts.vector.ck));
713 p += sizeof(keys->umts.vector.ck);
714 memcpy(p, keys->umts.vector.ik, sizeof(keys->umts.vector.ik));
715
716 FR_PROTO_HEX_DUMP(k, sizeof(k), "CK || IK");
717
718 pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, k, sizeof(k));
719 if (!pkey) {
720 fr_tls_strerror_printf("Failed creating HMAC signing key");
721 error:
722 if (pkey) EVP_PKEY_free(pkey);
723 if (md_ctx) EVP_MD_CTX_destroy(md_ctx);
724 return -1;
725 }
726
727 md_ctx = EVP_MD_CTX_create();
728 if (!md_ctx) {
729 fr_tls_strerror_printf("Failed creating HMAC ctx");
730 goto error;
731 }
732
733 if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
734 fr_tls_strerror_printf("Failed initialising digest");
735 goto error;
736 }
737
738 if (EVP_DigestSignUpdate(md_ctx, s, s_len) != 1) goto error;
739 if (EVP_DigestSignFinal(md_ctx, digest, &digest_len) != 1) goto error;
740
741 memcpy(keys->ik_prime, digest, sizeof(keys->ik_prime));
742 memcpy(keys->ck_prime, digest + sizeof(keys->ik_prime), sizeof(keys->ck_prime));
743
744 FR_PROTO_HEX_DUMP(keys->ck_prime, sizeof(keys->ck_prime), "CK'");
745 FR_PROTO_HEX_DUMP(keys->ik_prime, sizeof(keys->ik_prime), "IK'");
746
747 EVP_MD_CTX_destroy(md_ctx);
748 EVP_PKEY_free(pkey);
749
750 return 0;
751}
752
753/** PRF as described in RFC 5448 (EAP-AKA') section 3.4.1
754 *
755 @verbatim
756 PRF'(K,S) = T1 | T2 | T3 | T4 | ...
757
758 where:
759 T1 = HMAC-SHA-256 (K, S | 0x01)
760 T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
761 T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
762 T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
763 ...
764 @endverbatim
765 *
766 * PRF' produces as many bits of output as is needed.
767 *
768 * @param[out] out Where to write the output of the PRF.
769 * @param[in] outlen how many bytes need to be generated.
770 * @param[in] key for the PRF (K).
771 * @param[in] key_len Length of key data.
772 * @param[in] in Data to feed into the PRF (S).
773 * @param[in] in_len Length of input data.
774 * @return
775 * - 0 on success.
776 * - -1 on failure.
777 */
778static int aka_prime_prf(uint8_t *out, size_t outlen,
779 uint8_t const *key, size_t key_len, uint8_t const *in, size_t in_len)
780{
781 uint8_t *p = out, *end = p + outlen;
782 uint8_t c = 0;
783 uint8_t digest[SHA256_DIGEST_LENGTH];
784 EVP_PKEY *pkey;
785 EVP_MD_CTX *md_ctx = NULL;
786
787 pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
788 if (!pkey) {
789 fr_tls_strerror_printf("Failed creating HMAC signing key");
790 error:
791 if (pkey) EVP_PKEY_free(pkey);
792 if (md_ctx) EVP_MD_CTX_destroy(md_ctx);
793 return -1;
794 }
795
796 md_ctx = EVP_MD_CTX_create();
797 if (!md_ctx) {
798 fr_tls_strerror_printf("Failed creating HMAC ctx");
799 goto error;
800 }
801
802 if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
803 fr_tls_strerror_printf("Failed initialising digest");
804 goto error;
805 }
806
807 while (p < end) {
808 size_t digest_len = sizeof(digest);
809 size_t copy;
810
811 c++;
812
813 if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) goto error;
814 if ((p != out) && EVP_DigestSignUpdate(md_ctx, digest, sizeof(digest)) != 1) goto error;/* Ingest last round */
815 if (EVP_DigestSignUpdate(md_ctx, in, in_len) != 1) goto error; /* Ingest s */
816 if (EVP_DigestSignUpdate(md_ctx, &c, sizeof(c)) != 1) goto error; /* Ingest round number */
817 if (EVP_DigestSignFinal(md_ctx, digest, &digest_len) != 1) goto error; /* Output T(i) */
818
819 copy = end - p;
820 if (copy > digest_len) copy = digest_len;
821
822 memcpy(p, digest, copy);
823 p += copy;
824 }
825
826 EVP_MD_CTX_destroy(md_ctx);
827 EVP_PKEY_free(pkey);
828
829 return 0;
830}
831
832/** Key Derivation Function as described in RFC 5448 (EAP-AKA') section 3.3
833 *
834 @verbatim
835 MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
836 K_encr = MK[0..127]
837 K_aut = MK[128..383]
838 K_re = MK[384..639]
839 MSK = MK[640..1151]
840 EMSK = MK[1152..1663]
841 @endverbatim
842 *
843 * @note expects keys to contain a AKA_SIM_VECTOR_UMTS.
844 *
845 * @param[in,out] keys Contains the authentication vectors and the buffers
846 * to store the result of the derivation.
847 * @return
848 * - 0 on success.
849 * - -1 on failure.
850 */
852{
853 uint8_t k[sizeof(keys->ck_prime) + sizeof(keys->ik_prime)];
854#define KDF_1_S_STATIC "EAP-AKA'"
856 uint8_t *p = s;
857 size_t s_len;
858
859 if (ck_ik_prime_derive(keys) < 0) return -1;
860
861 if (!fr_cond_assert(keys->vector_type == AKA_SIM_VECTOR_UMTS)) return -1;
862
863 /*
864 * build s, a concatenation of EAP-AKA' and Identity
865 */
866 if (!fr_cond_assert((sizeof(KDF_1_S_STATIC) - 1) + keys->identity_len <= sizeof(s))) return -1;
867
868 memcpy(p, KDF_1_S_STATIC, sizeof(KDF_1_S_STATIC) - 1);
869 p += sizeof(KDF_1_S_STATIC) - 1;
870
871 memcpy(p, keys->identity, keys->identity_len);
872 p += keys->identity_len;
873
874 s_len = p - s;
875
876 /*
877 * build k, a concatenation of IK' and CK'
878 */
879 p = k;
880 memcpy(p, keys->ck_prime, sizeof(keys->ck_prime));
881 p += sizeof(keys->ck_prime);
882
883 memcpy(p, keys->ik_prime, sizeof(keys->ik_prime));
884
885 /*
886 * Feed into PRF
887 */
889 if (aka_prime_prf(keys->mk, keys->mk_len, k, sizeof(k), s, s_len) < 0) return -1;
890
891 /*
892 * Split the PRF output into separate keys
893 */
894 p = keys->mk;
895 memcpy(keys->k_encr, p, 16); /* 128 bits for encryption */
896 p += 16;
897
898 memcpy(keys->k_aut, p, EAP_AKA_PRIME_AUTH_SIZE); /* 256 bits for aut */
901
902 memcpy(keys->k_re, p, AKA_SIM_K_RE_SIZE); /* 256 bits for reauthentication key */
904
905 memcpy(keys->msk, p, sizeof(keys->msk)); /* 64 bytes for Master Session Key */
906 p += sizeof(keys->msk);
907
908 memcpy(keys->emsk, p, sizeof(keys->emsk)); /* 64 bytes for Extended Master Session Key */
909
910 return 0;
911}
912
913
914/** Initialise fr_aka_sim_keys_t with EAP-SIM reauthentication data
915 *
916 * Generates a new nonce_s and copies the mk and counter values into the fr_aka_sim_keys_t.
917 *
918 * @param[out] keys structure to populate.
919 * @param[in] mk from original authentication.
920 * @param[in] counter re-authentication counter.
921 */
923 uint8_t const mk[static AKA_SIM_MK_SIZE], uint16_t counter)
924{
925 uint32_t nonce_s[4];
926
927 static_assert(sizeof(keys->mk) >= AKA_SIM_MK_SIZE, "mk buffer is too small");
928
929 /*
930 * Copy in master key
931 */
932 keys->mk_len = AKA_SIM_MK_SIZE;
933 memcpy(keys->mk, mk, keys->mk_len);
934
935 keys->reauth.counter = counter;
936
937 nonce_s[0] = fr_rand();
938 nonce_s[1] = fr_rand();
939 nonce_s[2] = fr_rand();
940 nonce_s[3] = fr_rand();
941 memcpy(keys->reauth.nonce_s, (uint8_t *)&nonce_s, sizeof(keys->reauth.nonce_s));
942}
943
944/** Initialise fr_aka_sim_keys_t with EAP-AKA['] reauthentication data
945 *
946 * Generates a new nonce_s and copies the mk and counter values into the fr_aka_sim_keys_t.
947 *
948 * @param[out] keys structure to populate.
949 * @param[in] mk from original authentication.
950 * @param[in] counter re-authentication counter.
951 */
953 uint8_t const mk[static AKA_PRIME_MK_REAUTH_SIZE], uint16_t counter)
954{
955 uint32_t nonce_s[4];
956
957 static_assert(sizeof(keys->mk) >= AKA_PRIME_MK_REAUTH_SIZE, "mk buffer is too small");
958
959 /*
960 * Copy in master key
961 */
963 memcpy(keys->mk, mk, keys->mk_len);
964
965 keys->reauth.counter = counter;
966
967 nonce_s[0] = fr_rand();
968 nonce_s[1] = fr_rand();
969 nonce_s[2] = fr_rand();
970 nonce_s[3] = fr_rand();
971 memcpy(keys->reauth.nonce_s, (uint8_t *)&nonce_s, sizeof(keys->reauth.nonce_s));
972}
973
974/** Key Derivation Function (Fast-Reauthentication) as described in RFC4186/7 (EAP-SIM/AKA) section 7
975 *
976 @verbatim
977 XKEY' = SHA1(Identity|counter|NONCE_S|MK)
978 FK = PRF(XKEY')
979 MSK = FK[0..511]
980 EMSK = FK[512..1023]
981 @endverbatim
982 *
983 * Derives new MSK, EMSK, k_aut, k_encr
984 *
985 * Use #fr_aka_sim_crypto_keys_init_kdf_0_reauth to populate the #fr_aka_sim_keys_t structure.
986 *
987 * @note expects keys to contain a populated mk, none_s and counter values.
988 *
989 * @param[in,out] keys Contains the authentication vectors and the buffers
990 * to store the result of the derivation.
991 * @return
992 * - 0 on success.
993 * - -1 on failure.
994 */
996{
997 EVP_MD_CTX *md_ctx;
998 uint8_t fk[160];
999
1000 uint8_t buf[384];
1001 uint8_t *p;
1002
1003 size_t need;
1004 unsigned int len = 0;
1005
1006 /*
1007 * RFC 4187 Section 5.1
1008 * ...
1009 * "On full authentication, both the server and
1010 * the peer initialize the counter to one."
1011 */
1012 if (keys->reauth.counter == 0) {
1013 fr_strerror_const("Re-authentication counter not initialised, must be >= 1");
1014 return -1;
1015 }
1016
1017 if (keys->mk_len != AKA_SIM_MK_SIZE) {
1018 fr_strerror_printf("Master key is incorrect length, expected %u, got %zu", AKA_SIM_MK_SIZE,
1019 keys->mk_len);
1020 return -1;
1021 }
1022
1023 need = keys->identity_len + sizeof(uint16_t) + AKA_SIM_NONCE_S_SIZE + keys->mk_len;
1024 if (need > sizeof(buf)) {
1025 fr_strerror_printf("Identity too long. PRF input is %zu bytes, input buffer is %zu bytes",
1026 need, sizeof(buf));
1027 return -1;
1028 }
1029
1030 /*
1031 * Re-derive k_aut and k_encr from the original Master Key
1032 * These keys stay the same over multiple re-auth attempts.
1033 */
1034 fr_aka_sim_fips186_2prf(fk, keys->mk);
1035
1036 p = fk;
1037 memcpy(keys->k_encr, p, 16); /* 128 bits for encryption */
1038 p += 16;
1039 FR_PROTO_HEX_DUMP(keys->k_encr, sizeof(keys->k_encr), "K_encr");
1040
1041 memcpy(keys->k_aut, p, EAP_AKA_SIM_AUTH_SIZE); /* 128 bits for auth */
1042
1044 FR_PROTO_HEX_DUMP(keys->k_aut, keys->k_aut_len, "K_aut");
1045
1046 /*
1047 * Derive a new MSK and EMSK
1048 *
1049 * New PRF input is:
1050 * XKEY' = SHA1(Identity|counter|NONCE_S| MK)
1051 */
1052
1053 /*
1054 * Identity
1055 */
1056 p = buf;
1057 memcpy(p, keys->identity, keys->identity_len);
1058 p += keys->identity_len;
1059 FR_PROTO_HEX_DUMP(keys->identity, keys->identity_len, "identity");
1060
1061 /*
1062 * Counter
1063 */
1064 *p++ = ((keys->reauth.counter & 0xff00) >> 8);
1065 *p++ = (keys->reauth.counter & 0x00ff);
1066
1067 /*
1068 * nonce_s
1069 */
1070 memcpy(p, keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s));
1071 p += sizeof(keys->reauth.nonce_s);
1072
1073 /*
1074 * Master key
1075 */
1076 memcpy(p, keys->mk, keys->mk_len);
1077 p += keys->mk_len;
1078
1079 FR_PROTO_HEX_DUMP(buf, p - buf, "Identity || counter || NONCE_S || MK");
1080
1081 /*
1082 * Digest re-auth key with SHA1
1083 */
1084 md_ctx = EVP_MD_CTX_create();
1085 if (!md_ctx) {
1086 fr_tls_strerror_printf("Failed creating MD ctx");
1087 error:
1088 EVP_MD_CTX_destroy(md_ctx);
1089 return -1;
1090 }
1091
1092 if (EVP_DigestInit_ex(md_ctx, EVP_sha1(), NULL) != 1) {
1093 fr_tls_strerror_printf("Failed initialising digest");
1094 goto error;
1095 }
1096
1097 if (EVP_DigestUpdate(md_ctx, buf, p - buf) != 1) {
1098 fr_tls_strerror_printf("Failed digesting crypto data");
1099 goto error;
1100 }
1101
1102 if (EVP_DigestFinal_ex(md_ctx, keys->reauth.xkey_prime, &len) != 1) {
1103 fr_tls_strerror_printf("Failed finalising digest");
1104 goto error;
1105 }
1106
1107 EVP_MD_CTX_destroy(md_ctx);
1108
1109 FR_PROTO_HEX_DUMP(keys->reauth.xkey_prime, sizeof(keys->reauth.xkey_prime), "xkey'");
1110
1111 /*
1112 * Expand XKEY' with PRF
1113 */
1114 fr_aka_sim_fips186_2prf(fk, keys->reauth.xkey_prime);
1115
1116 /*
1117 * Split up the result
1118 */
1119 p = fk;
1120 memcpy(keys->msk, p, 64); /* 64 bytes for Master Session Key */
1121 p += 64;
1122 FR_PROTO_HEX_DUMP(keys->msk, sizeof(keys->msk), "K_msk");
1123
1124 memcpy(keys->emsk, p, 64); /* 64 bytes for Extended Master Session Key */
1125 FR_PROTO_HEX_DUMP(keys->emsk, sizeof(keys->emsk), "K_emsk");
1126
1127 return 0;
1128}
1129
1130/** Key Derivation Function (Fast-Reauthentication) as described in RFC 5448 (EAP-AKA') section 3.3
1131 *
1132 @verbatim
1133 MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
1134 MSK = MK[0..511]
1135 EMSK = MK[512..1023]
1136 @endverbatim
1137 *
1138 * @param[in,out] keys Contains the authentication vectors and the buffers
1139 * to store the result of the derivation.
1140 * @return
1141 * - 0 on success.
1142 * - -1 on failure.
1143 */
1145{
1146#define KDF_1_S_REAUTH_STATIC "EAP-AKA' re-auth"
1149 fr_dbuff_t dbuff;
1150
1151 if (!fr_cond_assert(((sizeof(KDF_1_S_REAUTH_STATIC) - 1) +
1152 keys->identity_len +
1153 sizeof(uint16_t) +
1154 AKA_SIM_NONCE_S_SIZE) <= sizeof(s))) return -1;
1155
1156 fr_dbuff_init(&dbuff, keys->mk, keys->mk_len);
1157
1158 /*
1159 * k_encr - Taken from original MK
1160 */
1161 fr_dbuff_out_memcpy(keys->k_encr, &dbuff, sizeof(keys->k_encr));
1162 FR_PROTO_HEX_DUMP(keys->k_encr, sizeof(keys->k_encr), "K_encr");
1163
1164 /*
1165 * k_aut - Taken from original MK
1166 */
1169 FR_PROTO_HEX_DUMP(keys->k_aut, keys->k_aut_len, "K_aut");
1170
1171 /*
1172 * k_re - Taken from original MK
1173 */
1176
1177 fr_dbuff_init(&dbuff, s, sizeof(s)); /* dbuff now points to s */
1178
1179 /*
1180 * "EAP-AKA' re-auth"
1181 */
1183
1184 /*
1185 * Identity
1186 */
1187 fr_dbuff_in_memcpy(&dbuff, keys->identity, keys->identity_len);
1188 FR_PROTO_HEX_DUMP(keys->identity, keys->identity_len, "identity");
1189
1190 /*
1191 * Counter
1192 */
1193 fr_dbuff_in_bytes(&dbuff, ((keys->reauth.counter & 0xff00) >> 8), (keys->reauth.counter & 0x00ff));
1194
1195 /*
1196 * nonce_s
1197 */
1198 fr_dbuff_in_memcpy(&dbuff, keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s));
1199
1201 "\"EAP-AKA' re-auth\" || Identity || counter || NONCE_S");
1202
1203 /*
1204 * Feed into PRF
1205 *
1206 * Note, we don't update the mk in the keys structure
1207 * as the original MK needs to be written into session
1208 * store, it doesn't change between re-authentication
1209 * rounds.
1210 */
1211 if (aka_prime_prf(mk, sizeof(mk), keys->k_re, sizeof(keys->k_re),
1212 fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff)) < 0) return -1;
1213 FR_PROTO_HEX_DUMP(mk, sizeof(mk), "mk");
1214
1215 fr_dbuff_init(&dbuff, mk, sizeof(mk)); /* dbuff now points to mk */
1216
1217 fr_dbuff_out_memcpy(keys->msk, &dbuff, sizeof(keys->msk)); /* 64 bytes for msk */
1218 FR_PROTO_HEX_DUMP(keys->msk, sizeof(keys->msk), "K_msk");
1219
1220 fr_dbuff_out_memcpy(keys->emsk, &dbuff, sizeof(keys->emsk)); /* 64 bytes for Extended Master Session Key */
1221 FR_PROTO_HEX_DUMP(keys->emsk, sizeof(keys->emsk), "K_emsk");
1222
1223 return 0;
1224}
1225
1226/** Dump the current state of all keys associated with the EAP SIM session
1227 *
1228 * @param[in] request The current request.
1229 * @param[in] keys SIM keys associated with the session.
1230 */
1232{
1233 RDEBUG3("KDF inputs");
1234
1235 RINDENT();
1237 "Identity :");
1238 switch (keys->vector_type) {
1239 case AKA_SIM_VECTOR_GSM:
1240 {
1241 unsigned int i;
1242
1243 RHEXDUMP_INLINE3(keys->gsm.nonce_mt, sizeof(keys->gsm.nonce_mt),
1244 "nonce_mt :");
1245
1246 RHEXDUMP_INLINE3(keys->gsm.version_list, keys->gsm.version_list_len,
1247 "version_list :");
1248
1249 for (i = 0; i < keys->gsm.num_vectors; i++) {
1250 RHEXDUMP_INLINE3(keys->gsm.vector[i].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE,
1251 "[%u] RAND :", i);
1252 RHEXDUMP_INLINE3(keys->gsm.vector[i].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE,
1253 "[%u] SRES :", i);
1254 RHEXDUMP_INLINE3(keys->gsm.vector[i].kc, AKA_SIM_VECTOR_GSM_KC_SIZE,
1255 "[%u] KC :", i);
1256 }
1257 }
1258 break;
1259
1261 RHEXDUMP_INLINE3(keys->umts.vector.autn, AKA_SIM_VECTOR_UMTS_AUTN_SIZE,
1262 "AUTN :");
1263
1264 RHEXDUMP_INLINE3(keys->umts.vector.ck, AKA_SIM_VECTOR_UMTS_CK_SIZE,
1265 "CK :");
1266
1267 RHEXDUMP_INLINE3(keys->umts.vector.ik, AKA_SIM_VECTOR_UMTS_IK_SIZE,
1268 "IK :");
1269
1270 RHEXDUMP_INLINE3(keys->umts.vector.rand, AKA_SIM_VECTOR_UMTS_RAND_SIZE,
1271 "RAND :");
1272
1273 RHEXDUMP_INLINE3(keys->umts.vector.xres, keys->umts.vector.xres_len,
1274 "XRES :");
1275
1277 "CK' :");
1278
1280 "IK' :");
1281 break;
1282
1284 RHEXDUMP_INLINE3(keys->mk, keys->mk_len,
1285 "MK :");
1286 RDEBUG3(
1287 "counter : %u", keys->reauth.counter);
1288 RHEXDUMP_INLINE3(keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s),
1289 "nonce_s :");
1290 break;
1291
1293 RHEXDUMP_INLINE3(keys->mk, keys->mk_len,
1294 "MK :");
1295 RDEBUG3(
1296 "counter : %u", keys->reauth.counter);
1297 RHEXDUMP_INLINE3(keys->reauth.nonce_s, sizeof(keys->reauth.nonce_s),
1298 "nonce_s :");
1299 break;
1300
1302 break;
1303 }
1304 REXDENT();
1305
1306 RDEBUG3("Intermediary keys");
1307 RINDENT();
1308 switch (keys->vector_type) {
1310 RHEXDUMP_INLINE3(keys->reauth.xkey_prime, sizeof(keys->reauth.xkey_prime),
1311 "XKEY' :");
1312 break;
1313
1314 default:
1315 break;
1316 }
1317 REXDENT();
1318
1319 RDEBUG3("PRF output");
1320 RINDENT();
1321 RHEXDUMP_INLINE3(keys->mk, keys->mk_len,
1322 "MK :");
1323 RHEXDUMP_INLINE3(keys->k_re, sizeof(keys->k_re),
1324 "k_re :");
1325 RHEXDUMP_INLINE3(keys->k_aut, keys->k_aut_len,
1326 "k_aut :");
1327 RHEXDUMP_INLINE3(keys->k_encr, sizeof(keys->k_encr),
1328 "k_encr :");
1329 RHEXDUMP_INLINE3(keys->msk, sizeof(keys->msk),
1330 "MSK :");
1331 RHEXDUMP_INLINE3(keys->emsk, sizeof(keys->emsk),
1332 "EMSK :");
1333 REXDENT();
1334}
1335
1336
1337#ifdef TESTING_SIM_CRYPTO
1338/*
1339 * cc crypto.c fips186prf.c -g3 -Wall -DHAVE_DLFCN_H -DTESTING_SIM_CRYPTO -DWITH_TLS -I../../../../ -I../../../ -I ../base/ -I /usr/local/opt/openssl/include/ -include ../include/build.h -L /usr/local/opt/openssl/lib/ -l ssl -l crypto -l talloc -L ../../../../../build/lib/local/.libs/ -lfreeradius-server -lfreeradius-tls -lfreeradius-util -o test_sim_crypto && ./test_sim_crypto
1340 */
1341#include <freeradius-devel/util/test/acutest.h>
1342
1343/*
1344 * EAP-SIM (RFC4186) GSM authentication vectors
1345 */
1346static fr_aka_sim_keys_t const rfc4186_vector0_in = {
1347 .identity = (uint8_t const *)"1244070100000001@eapsim.foo",
1348 .identity_len = sizeof("1244070100000001@eapsim.foo") - 1,
1349
1350 .gsm = {
1351 .vector = {
1352 {
1353 .rand = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1354 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
1355 .sres = { 0xd1, 0xd2, 0xd3, 0xd4 },
1356 .kc = { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7 }
1357 },
1358 {
1359 .rand = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1360 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f },
1361 .sres = { 0xe1, 0xe2, 0xe3, 0xe4 },
1362 .kc = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7 }
1363 },
1364 {
1365 .rand = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1366 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f },
1367 .sres = { 0xf1, 0xf2, 0xf3, 0xf4 },
1368 .kc = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 }
1369 }
1370 },
1371 .nonce_mt = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
1372 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
1373 .version_list = { 0x00, 0x01 },
1374 .version_list_len = 2,
1375 .version_select = { 0x00, 0x01 },
1376 .num_vectors = 3
1377 },
1378 .vector_type = AKA_SIM_VECTOR_GSM
1379};
1380
1381static fr_aka_sim_keys_t const rfc4186_vector0_out = {
1382 .k_encr = { 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a,
1383 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 },
1384 .k_aut = { 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc,
1385 0x72, 0xb3, 0x94, 0x34, 0x21, 0xf2, 0xa9, 0x74 },
1386 .k_aut_len = 16,
1387 .msk = { 0x39, 0xd4, 0x5a, 0xea, 0xf4, 0xe3, 0x06, 0x01,
1388 0x98, 0x3e, 0x97, 0x2b, 0x6c, 0xfd, 0x46, 0xd1,
1389 0xc3, 0x63, 0x77, 0x33, 0x65, 0x69, 0x0d, 0x09,
1390 0xcd, 0x44, 0x97, 0x6b, 0x52, 0x5f, 0x47, 0xd3,
1391 0xa6, 0x0a, 0x98, 0x5e, 0x95, 0x5c, 0x53, 0xb0,
1392 0x90, 0xb2, 0xe4, 0xb7, 0x37, 0x19, 0x19, 0x6a,
1393 0x40, 0x25, 0x42, 0x96, 0x8f, 0xd1, 0x4a, 0x88,
1394 0x8f, 0x46, 0xb9, 0xa7, 0x88, 0x6e, 0x44, 0x88 },
1395 .emsk = { 0x59, 0x49, 0xea, 0xb0, 0xff, 0xf6, 0x9d, 0x52,
1396 0x31, 0x5c, 0x6c, 0x63, 0x4f, 0xd1, 0x4a, 0x7f,
1397 0x0d, 0x52, 0x02, 0x3d, 0x56, 0xf7, 0x96, 0x98,
1398 0xfa, 0x65, 0x96, 0xab, 0xee, 0xd4, 0xf9, 0x3f,
1399 0xbb, 0x48, 0xeb, 0x53, 0x4d, 0x98, 0x54, 0x14,
1400 0xce, 0xed, 0x0d, 0x9a, 0x8e, 0xd3, 0x3c, 0x38,
1401 0x7c, 0x9d, 0xfd, 0xab, 0x92, 0xff, 0xbd, 0xf2,
1402 0x40, 0xfc, 0xec, 0xf6, 0x5a, 0x2c, 0x93, 0xb9 }
1403};
1404
1405static void test_eap_sim_kdf_0_gsm(void)
1406{
1407 fr_aka_sim_keys_t keys;
1408 int ret;
1409
1410/*
1411 fr_debug_lvl = 4;
1412 printf("\n");
1413*/
1414
1415 memcpy(&keys, &rfc4186_vector0_in, sizeof(keys));
1416
1417 ret = fr_aka_sim_crypto_gsm_kdf_0(&keys);
1418 TEST_CHECK(ret == 0);
1419
1420 TEST_CHECK(memcmp(&rfc4186_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
1421 TEST_CHECK(rfc4186_vector0_out.k_aut_len == keys.k_aut_len);
1422 TEST_CHECK(memcmp(&rfc4186_vector0_out.k_aut, keys.k_aut, keys.k_aut_len) == 0);
1423 TEST_CHECK(memcmp(&rfc4186_vector0_out.msk, keys.msk, sizeof(keys.msk)) == 0);
1424 TEST_CHECK(memcmp(&rfc4186_vector0_out.emsk, keys.emsk, sizeof(keys.emsk)) == 0);
1425}
1426
1427/*
1428 * UMTS authentication vectors
1429 *
1430 * Test vector from 18 from 3GPP TS 35.208 V9 (the same used by EAP-AKA')
1431 */
1432static fr_aka_sim_keys_t const rfc4187_vector0_in = {
1433 .identity = (uint8_t const *)"0555444333222111",
1434 .identity_len = sizeof("0555444333222111") - 1,
1435
1436 .sqn = 205964772668538,
1437
1438 .umts = {
1439 .vector = {
1440 .rand = { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
1441 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
1442 .autn = { 0xbb, 0x52, 0xe9, 0x1c, 0x74, 0x7a, 0xc3, 0xab,
1443 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 },
1444 .ik = { 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb,
1445 0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a },
1446 .ck = { 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94,
1447 0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f },
1448 .xres = { 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 },
1449 .xres_len = 8
1450 }
1451 },
1452 .vector_type = AKA_SIM_VECTOR_UMTS
1453};
1454
1455static fr_aka_sim_keys_t const rfc4187_vector0_out = {
1456 .k_encr = { 0x18, 0xe8, 0xb2, 0x0b, 0xcd, 0xa7, 0x04, 0x86,
1457 0xfd, 0x59, 0x59, 0x58, 0x6a, 0x9e, 0x7c, 0x3d },
1458 .k_aut = { 0x18, 0xc0, 0x44, 0x07, 0x0e, 0x5e, 0x64, 0x2a,
1459 0x26, 0x43, 0x87, 0x6f, 0xf7, 0xa8, 0x38, 0x12 },
1460 .k_aut_len = 16,
1461 .msk = { 0x35, 0x2f, 0xfa, 0xef, 0x2d, 0xf1, 0x20, 0xcb,
1462 0x22, 0x41, 0x0b, 0x9c, 0x0b, 0x70, 0x62, 0x3c,
1463 0xb5, 0xa3, 0x5b, 0xc9, 0xfc, 0xd6, 0xbc, 0xa0,
1464 0xfc, 0x33, 0x7b, 0x48, 0xb1, 0x76, 0x30, 0x89,
1465 0x0a, 0x03, 0x37, 0x5c, 0xfd, 0x1e, 0x64, 0xcb,
1466 0xd6, 0xbf, 0x83, 0x04, 0x37, 0x4d, 0xd2, 0xe1,
1467 0x39, 0xd6, 0x4e, 0xd1, 0xa6, 0xd6, 0x18, 0xff,
1468 0xef, 0xb0, 0x8c, 0x26, 0xa6, 0xbb, 0x35, 0x85 },
1469 .emsk = { 0x9e, 0x06, 0x59, 0xae, 0x03, 0x97, 0x7d, 0xcb,
1470 0xb1, 0xd6, 0x4d, 0x24, 0x05, 0xe1, 0x10, 0x82,
1471 0xa9, 0x1a, 0xdb, 0x9a, 0xc7, 0xf7, 0xbd, 0x0b,
1472 0x74, 0xa6, 0x1e, 0xc0, 0xe9, 0x80, 0xb3, 0x6f,
1473 0xa0, 0xc3, 0x98, 0x8b, 0x6e, 0x11, 0xef, 0x12,
1474 0x52, 0x8e, 0x38, 0x04, 0xb3, 0x2d, 0xf1, 0xbc,
1475 0x52, 0xf6, 0x24, 0x9f, 0xa9, 0x6d, 0xc9, 0x4c,
1476 0x94, 0xa3, 0xd9, 0xb1, 0x48, 0xf4, 0xf9, 0x96 }
1477};
1478
1479static void test_eap_aka_kdf_0_umts(void)
1480{
1481 fr_aka_sim_keys_t keys;
1482 int ret;
1483
1484/*
1485 fr_debug_lvl = 4;
1486 printf("\n");
1487*/
1488
1489 memcpy(&keys, &rfc4187_vector0_in, sizeof(keys));
1490
1491 ret = fr_aka_sim_crypto_umts_kdf_0(&keys);
1492 TEST_CHECK(ret == 0);
1493
1494 TEST_CHECK(memcmp(&rfc4187_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
1495 TEST_CHECK(rfc4187_vector0_out.k_aut_len == keys.k_aut_len);
1496
1497 TEST_CHECK(memcmp(&rfc4187_vector0_out.k_aut, keys.k_aut, keys.k_aut_len) == 0);
1498 TEST_CHECK(memcmp(&rfc4187_vector0_out.msk, keys.msk, sizeof(keys.msk)) == 0);
1499 TEST_CHECK(memcmp(&rfc4187_vector0_out.emsk, keys.emsk, sizeof(keys.emsk)) == 0);
1500}
1501
1502/*
1503 * EAP-SIM (RFC4186) GSM re-authentication vectors
1504 */
1505static fr_aka_sim_keys_t const rfc4186_vector0_reauth_in = {
1506 .identity = (uint8_t const *)"Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo",
1507 .identity_len = sizeof("Y24fNSrz8BP274jOJaF17WfxI8YO7QX00pMXk9XMMVOw7broaNhTczuFq53aEpOkk3L0dm@eapsim.foo") - 1,
1508
1509 .reauth = {
1510 .counter = 1,
1511 .nonce_s = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
1512 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }
1513 },
1514 .mk = { 0xe5, 0x76, 0xd5, 0xca, 0x33, 0x2e, 0x99, 0x30,
1515 0x01, 0x8b, 0xf1, 0xba, 0xee, 0x27, 0x63, 0xc7,
1516 0x95, 0xb3, 0xc7, 0x12 },
1517};
1518
1519static fr_aka_sim_keys_t const rfc4186_vector0_reauth_out = {
1520 .k_encr = { 0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a,
1521 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 },
1522 .k_aut = { 0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc,
1523 0x72, 0xb3, 0x94, 0x34, 0x21, 0xf2, 0xa9, 0x74 },
1524 .k_aut_len = 16,
1525 .msk = { 0x62, 0x63, 0xf6, 0x14, 0x97, 0x38, 0x95, 0xe1,
1526 0x33, 0x5f, 0x7e, 0x30, 0xcf, 0xf0, 0x28, 0xee,
1527 0x21, 0x76, 0xf5, 0x19, 0x00, 0x2c, 0x9a, 0xbe,
1528 0x73, 0x2f, 0xe0, 0xef, 0x00, 0xcf, 0x16, 0x7c,
1529 0x75, 0x6d, 0x9e, 0x4c, 0xed, 0x6d, 0x5e, 0xd6,
1530 0x40, 0xeb, 0x3f, 0xe3, 0x85, 0x65, 0xca, 0x07,
1531 0x6e, 0x7f, 0xb8, 0xa8, 0x17, 0xcf, 0xe8, 0xd9,
1532 0xad, 0xbc, 0xe4, 0x41, 0xd4, 0x7c, 0x4f, 0x5e },
1533 .emsk = { 0x3d, 0x8f, 0xf7, 0x86, 0x3a, 0x63, 0x0b, 0x2b,
1534 0x06, 0xe2, 0xcf, 0x20, 0x96, 0x84, 0xc1, 0x3f,
1535 0x6b, 0x82, 0xf9, 0x92, 0xf2, 0xb0, 0x6f, 0x1b,
1536 0x54, 0xbf, 0x51, 0xef, 0x23, 0x7f, 0x2a, 0x40,
1537 0x1e, 0xf5, 0xe0, 0xd7, 0xe0, 0x98, 0xa3, 0x4c,
1538 0x53, 0x3e, 0xae, 0xbf, 0x34, 0x57, 0x88, 0x54,
1539 0xb7, 0x72, 0x15, 0x26, 0x20, 0xa7, 0x77, 0xf0,
1540 0xe0, 0x34, 0x08, 0x84, 0xa2, 0x94, 0xfb, 0x73 }
1541};
1542
1543static void test_eap_sim_kdf_0_reauth(void)
1544{
1545 fr_aka_sim_keys_t keys;
1546 int ret;
1547
1548/*
1549 fr_debug_lvl = 4;
1550 printf("\n");
1551*/
1552
1553 memcpy(&keys, &rfc4186_vector0_reauth_in, sizeof(keys));
1554
1555 ret = fr_aka_sim_crypto_kdf_0_reauth(&keys);
1556 TEST_CHECK(ret == 0);
1557
1558 TEST_CHECK(memcmp(&rfc4186_vector0_reauth_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
1559 TEST_CHECK(rfc4186_vector0_reauth_out.k_aut_len == keys.k_aut_len);
1560 TEST_CHECK(memcmp(&rfc4186_vector0_reauth_out.k_aut, keys.k_aut, keys.k_aut_len) == 0);
1561 TEST_CHECK(memcmp(&rfc4186_vector0_reauth_out.msk, keys.msk, sizeof(keys.msk)) == 0);
1562 TEST_CHECK(memcmp(&rfc4186_vector0_reauth_out.emsk, keys.emsk, sizeof(keys.emsk)) == 0);
1563}
1564
1565
1566/*
1567 * EAP-AKA' (RFC5448) UMTS authentication vectors
1568 */
1569static fr_aka_sim_keys_t const rfc5448_vector0_in = {
1570 .identity = (uint8_t const *)"0555444333222111",
1571 .identity_len = sizeof("0555444333222111") - 1,
1572
1573 .network = (uint8_t const *)"WLAN",
1574 .network_len = sizeof("WLAN") - 1,
1575
1576 .sqn = 205964772668538,
1577
1578 .umts = {
1579 .vector = {
1580 .rand = { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
1581 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
1582 .autn = { 0xbb, 0x52, 0xe9, 0x1c, 0x74, 0x7a, 0xc3, 0xab,
1583 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 },
1584 .ik = { 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb,
1585 0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a },
1586 .ck = { 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94,
1587 0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f },
1588 .xres = { 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 },
1589 .xres_len = 8
1590 }
1591 },
1592 .vector_type = AKA_SIM_VECTOR_UMTS
1593};
1594
1595static fr_aka_sim_keys_t const rfc5448_vector0_out = {
1596 .ik_prime = { 0x00, 0x93, 0x96, 0x2d, 0x0d, 0xd8, 0x4a, 0xa5,
1597 0x68, 0x4b, 0x04, 0x5c, 0x9e, 0xdf, 0xfa, 0x04 },
1598 .ck_prime = { 0xcc, 0xfc, 0x23, 0x0c, 0xa7, 0x4f, 0xcc, 0x96,
1599 0xc0, 0xa5, 0xd6, 0x11, 0x64, 0xf5, 0xa7, 0x6c },
1600
1601 .k_encr = { 0x76, 0x6f, 0xa0, 0xa6, 0xc3, 0x17, 0x17, 0x4b,
1602 0x81, 0x2d, 0x52, 0xfb, 0xcd, 0x11, 0xa1, 0x79 },
1603 .k_aut = { 0x08, 0x42, 0xea, 0x72, 0x2f, 0xf6, 0x83, 0x5b,
1604 0xfa, 0x20, 0x32, 0x49, 0x9f, 0xc3, 0xec, 0x23,
1605 0xc2, 0xf0, 0xe3, 0x88, 0xb4, 0xf0, 0x75, 0x43,
1606 0xff, 0xc6, 0x77, 0xf1, 0x69, 0x6d, 0x71, 0xea },
1607 .k_aut_len = 32,
1608 .k_re = { 0xcf, 0x83, 0xaa, 0x8b, 0xc7, 0xe0, 0xac, 0xed,
1609 0x89, 0x2a, 0xcc, 0x98, 0xe7, 0x6a, 0x9b, 0x20,
1610 0x95, 0xb5, 0x58, 0xc7, 0x79, 0x5c, 0x70, 0x94,
1611 0x71, 0x5c, 0xb3, 0x39, 0x3a, 0xa7, 0xd1, 0x7a },
1612 .msk = { 0x67, 0xc4, 0x2d, 0x9a, 0xa5, 0x6c, 0x1b, 0x79,
1613 0xe2, 0x95, 0xe3, 0x45, 0x9f, 0xc3, 0xd1, 0x87,
1614 0xd4, 0x2b, 0xe0, 0xbf, 0x81, 0x8d, 0x30, 0x70,
1615 0xe3, 0x62, 0xc5, 0xe9, 0x67, 0xa4, 0xd5, 0x44,
1616 0xe8, 0xec, 0xfe, 0x19, 0x35, 0x8a, 0xb3, 0x03,
1617 0x9a, 0xff, 0x03, 0xb7, 0xc9, 0x30, 0x58, 0x8c,
1618 0x05, 0x5b, 0xab, 0xee, 0x58, 0xa0, 0x26, 0x50,
1619 0xb0, 0x67, 0xec, 0x4e, 0x93, 0x47, 0xc7, 0x5a },
1620 .emsk = { 0xf8, 0x61, 0x70, 0x3c, 0xd7, 0x75, 0x59, 0x0e,
1621 0x16, 0xc7, 0x67, 0x9e, 0xa3, 0x87, 0x4a, 0xda,
1622 0x86, 0x63, 0x11, 0xde, 0x29, 0x07, 0x64, 0xd7,
1623 0x60, 0xcf, 0x76, 0xdf, 0x64, 0x7e, 0xa0, 0x1c,
1624 0x31, 0x3f, 0x69, 0x92, 0x4b, 0xdd, 0x76, 0x50,
1625 0xca, 0x9b, 0xac, 0x14, 0x1e, 0xa0, 0x75, 0xc4,
1626 0xef, 0x9e, 0x80, 0x29, 0xc0, 0xe2, 0x90, 0xcd,
1627 0xba, 0xd5, 0x63, 0x8b, 0x63, 0xbc, 0x23, 0xfb }
1628};
1629
1630static void test_eap_aka_kdf_1_umts(void)
1631{
1632 fr_aka_sim_keys_t keys;
1633 int ret;
1634
1635/*
1636 fr_debug_lvl = 4;
1637 printf("\n");
1638*/
1639
1640 memcpy(&keys, &rfc5448_vector0_in, sizeof(keys));
1641
1642 memcpy(keys.ck_prime, rfc5448_vector0_out.ck_prime, sizeof(keys.ck_prime));
1643 memcpy(keys.ik_prime, rfc5448_vector0_out.ik_prime, sizeof(keys.ik_prime));
1644
1645 ret = fr_aka_sim_crypto_umts_kdf_1(&keys);
1646 TEST_CHECK(ret == 0);
1647
1648 TEST_CHECK(memcmp(&rfc5448_vector0_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
1649 TEST_CHECK(rfc5448_vector0_out.k_aut_len == keys.k_aut_len);
1650 TEST_CHECK(memcmp(&rfc5448_vector0_out.k_aut, keys.k_aut, keys.k_aut_len) == 0);
1651 TEST_CHECK(memcmp(&rfc5448_vector0_out.k_re, keys.k_re, sizeof(keys.k_re)) == 0);
1652 TEST_CHECK(memcmp(&rfc5448_vector0_out.msk, keys.msk, sizeof(keys.msk)) == 0);
1653 TEST_CHECK(memcmp(&rfc5448_vector0_out.emsk, keys.emsk, sizeof(keys.emsk)) == 0);
1654}
1655
1656static void test_eap_aka_derive_ck_ik(void)
1657{
1658
1659 fr_aka_sim_keys_t keys;
1660 int ret;
1661
1662/*
1663 fr_debug_lvl = 4;
1664 printf("\n");
1665*/
1666
1667 memcpy(&keys, &rfc5448_vector0_in, sizeof(keys));
1668 ret = ck_ik_prime_derive(&keys);
1669 TEST_CHECK(ret == 0);
1670 TEST_CHECK(memcmp(&rfc5448_vector0_out.ck_prime, keys.ck_prime, sizeof(keys.ck_prime)) == 0);
1671 TEST_CHECK(memcmp(&rfc5448_vector0_out.ik_prime, keys.ik_prime, sizeof(keys.ik_prime)) == 0);
1672}
1673
1674/*
1675 * EAP-AKA' (RFC5448) UMTS authentication vectors
1676 */
1677static fr_aka_sim_keys_t const rfc5448_vector0_reauth_in = {
1678 .identity = (uint8_t const *)"5555444333222111",
1679 .identity_len = sizeof("5555444333222111") - 1,
1680
1681 .network = (uint8_t const *)"WLAN",
1682 .network_len = sizeof("WLAN") - 1,
1683
1684 .reauth = {
1685 .counter = 1,
1686 .nonce_s = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
1687 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }
1688 },
1689 .k_encr = { 0x76, 0x6f, 0xa0, 0xa6, 0xc3, 0x17, 0x17, 0x4b,
1690 0x81, 0x2d, 0x52, 0xfb, 0xcd, 0x11, 0xa1, 0x79 },
1691 .k_aut = { 0x08, 0x42, 0xea, 0x72, 0x2f, 0xf6, 0x83, 0x5b,
1692 0xfa, 0x20, 0x32, 0x49, 0x9f, 0xc3, 0xec, 0x23,
1693 0xc2, 0xf0, 0xe3, 0x88, 0xb4, 0xf0, 0x75, 0x43,
1694 0xff, 0xc6, 0x77, 0xf1, 0x69, 0x6d, 0x71, 0xea },
1695 .k_aut_len = 32,
1696 .k_re = { 0xcf, 0x83, 0xaa, 0x8b, 0xc7, 0xe0, 0xac, 0xed,
1697 0x89, 0x2a, 0xcc, 0x98, 0xe7, 0x6a, 0x9b, 0x20,
1698 0x95, 0xb5, 0x58, 0xc7, 0x79, 0x5c, 0x70, 0x94,
1699 0x71, 0x5c, 0xb3, 0x39, 0x3a, 0xa7, 0xd1, 0x7a }
1700};
1701
1702/*
1703 * Not tested against external source (yet)
1704 */
1705static fr_aka_sim_keys_t const rfc5448_vector0_reauth_out = {
1706 .k_encr = { 0x76, 0x6f, 0xa0, 0xa6, 0xc3, 0x17, 0x17, 0x4b,
1707 0x81, 0x2d, 0x52, 0xfb, 0xcd, 0x11, 0xa1, 0x79 },
1708 .k_aut = { 0x08, 0x42, 0xea, 0x72, 0x2f, 0xf6, 0x83, 0x5b,
1709 0xfa, 0x20, 0x32, 0x49, 0x9f, 0xc3, 0xec, 0x23,
1710 0xc2, 0xf0, 0xe3, 0x88, 0xb4, 0xf0, 0x75, 0x43,
1711 0xff, 0xc6, 0x77, 0xf1, 0x69, 0x6d, 0x71, 0xea },
1712 .k_aut_len = 32,
1713 .msk = { 0x28, 0xf2, 0xb9, 0x3a, 0x8e, 0xdc, 0x4a, 0x01,
1714 0xb6, 0x9d, 0x37, 0x8b, 0xa6, 0x8a, 0x77, 0xbb,
1715 0x01, 0x6c, 0x0f, 0xeb, 0xb7, 0x60, 0xdb, 0x98,
1716 0x57, 0x99, 0x64, 0x99, 0x00, 0x00, 0x6f, 0x97,
1717 0xa1, 0x76, 0x5c, 0x65, 0xf5, 0xd5, 0xbf, 0xde,
1718 0xe7, 0x61, 0xba, 0x42, 0x92, 0xe4, 0x51, 0xd1,
1719 0xa0, 0xc5, 0x7e, 0x76, 0xeb, 0x91, 0x3e, 0xe9,
1720 0x95, 0xf5, 0xce, 0x6e, 0xb7, 0x98, 0x91, 0x38 },
1721 .emsk = { 0xb9, 0x05, 0xa2, 0xf4, 0x67, 0xe0, 0xeb, 0x9a,
1722 0xfb, 0xa4, 0x59, 0xa7, 0xd8, 0xa7, 0xc8, 0x77,
1723 0xd5, 0xfa, 0x2e, 0x5e, 0xd3, 0x77, 0xf8, 0xc5,
1724 0x2f, 0xa4, 0x86, 0xad, 0xf5, 0x15, 0x5e, 0xb7,
1725 0x96, 0xac, 0xa9, 0x3e, 0xa3, 0xa9, 0x95, 0xe8,
1726 0xa2, 0x34, 0x36, 0x54, 0x5a, 0xf1, 0x57, 0x22,
1727 0xaa, 0x94, 0xb9, 0xfb, 0xd9, 0x06, 0x0c, 0x50,
1728 0xa3, 0x56, 0xcc, 0xb4, 0xc7, 0x10, 0x0e, 0x66 }
1729};
1730
1731static void test_eap_aka_kdf_1_reauth(void)
1732{
1733 fr_aka_sim_keys_t keys;
1734 int ret;
1735
1736/*
1737 fr_debug_lvl = 4;
1738 printf("\n");
1739*/
1740
1741 memcpy(&keys, &rfc5448_vector0_reauth_in, sizeof(keys));
1742
1744 TEST_CHECK(ret == 0);
1745
1746 TEST_CHECK(memcmp(&rfc5448_vector0_reauth_out.k_encr, keys.k_encr, sizeof(keys.k_encr)) == 0);
1747 TEST_CHECK(rfc5448_vector0_reauth_out.k_aut_len == keys.k_aut_len);
1748 TEST_CHECK(memcmp(&rfc5448_vector0_reauth_out.k_aut, keys.k_aut, keys.k_aut_len) == 0);
1749 TEST_CHECK(memcmp(&rfc5448_vector0_reauth_out.msk, keys.msk, sizeof(keys.msk)) == 0);
1750 TEST_CHECK(memcmp(&rfc5448_vector0_reauth_out.emsk, keys.emsk, sizeof(keys.emsk)) == 0);
1751}
1752
1753
1754TEST_LIST = {
1755 /*
1756 * EAP-SIM
1757 */
1758 { "test_eap_sim_kdf_0_gsm", test_eap_sim_kdf_0_gsm },
1759
1760 /*
1761 * EAP-AKA
1762 */
1763 { "test_eap_aka_kdf_0_umts", test_eap_aka_kdf_0_umts },
1764
1765 /*
1766 * EAP-SIM/EAP-AKA
1767 */
1768 { "test_eap_sim_kdf_0_reauth", test_eap_sim_kdf_0_reauth },
1769
1770 /*
1771 * EAP-AKA'
1772 */
1773 { "test_eap_aka_kdf_1_umts", test_eap_aka_kdf_1_umts },
1774 { "test_eap_aka_derive_ck_ik", test_eap_aka_derive_ck_ik },
1775 { "test_eap_aka_kdf_1_reauth", test_eap_aka_kdf_1_reauth },
1776
1777
1778 { NULL }
1779};
1780#endif
1781
#define TEST_CHECK(cond)
Definition acutest.h:87
#define TEST_LIST
Definition acutest.h:62
int fr_atexit_trigger(bool uctx_scope, fr_atexit_t func, void const *uctx)
Iterates through all thread local destructor lists, causing destructor to be triggered.
Definition atexit.c:330
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:220
static int context
Definition radmin.c:69
#define RCSID(id)
Definition build.h:506
#define unlikely(_x)
Definition build.h:402
static uint8_t * uint48_to_buff(uint8_t out[static 6], uint64_t i)
Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order.
Definition common.h:37
static uint64_t uint48_from_buff(uint8_t const in[6])
Convert a 48bit big endian value into a unsigned 64bit integer.
Definition common.h:52
eap_type_data_t type
Definition compose.h:38
eap_code_t code
Definition compose.h:35
uint8_t id
Definition compose.h:36
Structure to hold EAP data.
Definition compose.h:34
EAP-SIM/EAP-AKA Private crypto functions.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:775
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:362
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:906
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1741
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
Definition dbuff.h:1474
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1359
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:141
#define MEM(x)
Definition debug.h:46
static fr_slen_t in
Definition dict.h:882
uint8_t id
Definition types.h:133
eap_type_t num
Definition types.h:110
uint8_t code
Definition types.h:132
uint8_t length[2]
Definition types.h:134
size_t length
Definition types.h:111
uint8_t * data
Definition types.h:112
uint8_t data[1]
Definition types.h:135
When we need to create a base EAP packet.
Definition types.h:131
uint8_t * identity
Identity from AT_IDENTITY.
Definition base.h:152
#define AKA_SIM_VECTOR_UMTS_RAND_SIZE
Definition base.h:73
#define AKA_SIM_VECTOR_GSM_RAND_SIZE
Length of RAND in GSM triplet.
Definition base.h:65
uint8_t * network
Network name (EAP-AKA-Prime only).
Definition base.h:155
void fr_aka_sim_fips186_2prf(uint8_t out[static 160], uint8_t mk[static 20])
Implement the FIPS-186-2 PRF to derive keying material from the MK.
Definition fips186prf.c:91
size_t mk_len
Definition base.h:212
#define AKA_SIM_VECTOR_GSM_SRES_SIZE
Length of SRES in GSM triplet.
Definition base.h:66
uint8_t emsk[64]
Derived extended master session key.
Definition base.h:228
size_t network_len
Length of the network name (EAP-AKA-Prime only).
Definition base.h:156
#define AKA_SIM_NONCE_S_SIZE
Length of re-authentication nonce.
Definition base.h:46
uint8_t ik_prime[AKA_SIM_VECTOR_UMTS_IK_SIZE]
Derived from IK, for AKA'.
Definition base.h:219
uint64_t sqn
Sequence number.
Definition base.h:158
#define AKA_SIM_MAC_SIZE
Length of MAC used to prevent packet modification.
Definition base.h:43
#define AKA_PRIME_MK_REAUTH_SIZE
The portion of the MK used for re-auth.
Definition base.h:57
#define AKA_SIM_SQN_AK_SIZE
Definition base.h:45
#define AKA_SIM_K_RE_SIZE
Reauthentication key size.
Definition base.h:61
#define EAP_AKA_AUTH_SIZE
Definition base.h:84
#define AKA_SIM_VECTOR_UMTS_CK_SIZE
Definition base.h:70
#define AKA_SIM_MAX_STRING_LENGTH
Maximum size of a SIM/AKA['] string ((4 * 255) - 4).
Definition base.h:40
uint8_t ck_prime[AKA_SIM_VECTOR_UMTS_CK_SIZE]
Derived from CK, for AKA'.
Definition base.h:218
size_t identity_len
Length of the identity.
Definition base.h:153
#define EAP_AKA_PRIME_AUTH_SIZE
Definition base.h:85
#define AKA_PRIME_MK_SIZE
Definition base.h:55
#define AKA_SIM_MK_SIZE
Definition base.h:54
uint8_t k_aut[32]
Derived authentication key.
Definition base.h:224
#define AKA_SIM_VECTOR_GSM_KC_SIZE
Length of Kc in GSM triplet.
Definition base.h:67
size_t k_aut_len
Length of k_aut. 16 for AKA/SIM, 32 for AKA'.
Definition base.h:225
uint8_t k_re[AKA_SIM_K_RE_SIZE]
Derived reauthentication key for AKA'(kdf 1).
Definition base.h:213
#define AKA_SIM_MAC_DIGEST_SIZE
Length of MAC used to prevent packet modification.
Definition base.h:42
#define AKA_SIM_VECTOR_UMTS_IK_SIZE
Definition base.h:71
uint8_t k_encr[16]
Derived encryption key.
Definition base.h:226
#define AKA_SIM_VECTOR_UMTS_AUTN_SIZE
Definition base.h:69
EVP_MD_CTX * md_ctx
Context to hold state of digest as we consume packets.
Definition base.h:141
@ AKA_SIM_VECTOR_GSM
Vector is GSM triplets.
Definition base.h:91
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH
Definition base.h:94
@ AKA_SIM_VECTOR_UMTS
Vector is UMTS quintuplets.
Definition base.h:92
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH
Definition base.h:93
@ AKA_SIM_VECTOR_NONE
Definition base.h:90
uint8_t mk[AKA_SIM_MK_MAX_SIZE]
Master key from session attributes.
Definition base.h:211
uint8_t msk[64]
Derived master session key.
Definition base.h:227
#define EAP_AKA_SIM_AUTH_SIZE
Definition base.h:79
Stores our checkcode state.
Definition base.h:140
Master key state struct for all SIMlike EAP protocols.
Definition base.h:148
int fr_aka_sim_crypto_umts_kdf_0(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC4187 (EAP-AKA) section 7.
Definition crypto.c:569
int fr_aka_sim_crypto_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys)
Key Derivation Function (Fast-Reauthentication) as described in RFC 5448 (EAP-AKA') section 3....
Definition crypto.c:1144
ssize_t fr_aka_sim_crypto_sign_packet(uint8_t out[static AKA_SIM_MAC_DIGEST_SIZE], eap_packet_t *eap_packet, bool zero_mac, EVP_MD const *md, uint8_t const *key, size_t const key_len, uint8_t const *hmac_extra, size_t const hmac_extra_len)
Calculate the digest value for a packet.
Definition crypto.c:289
static int aka_prime_prf(uint8_t *out, size_t outlen, uint8_t const *key, size_t key_len, uint8_t const *in, size_t in_len)
PRF as described in RFC 5448 (EAP-AKA') section 3.4.1.
Definition crypto.c:778
void fr_aka_sim_crypto_keys_log(request_t *request, fr_aka_sim_keys_t *keys)
Dump the current state of all keys associated with the EAP SIM session.
Definition crypto.c:1231
void fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys, uint8_t const mk[static AKA_PRIME_MK_REAUTH_SIZE], uint16_t counter)
Initialise fr_aka_sim_keys_t with EAP-AKA['] reauthentication data.
Definition crypto.c:952
#define KDF_1_S_STATIC
int fr_aka_sim_crypto_kdf_0_reauth(fr_aka_sim_keys_t *keys)
Key Derivation Function (Fast-Reauthentication) as described in RFC4186/7 (EAP-SIM/AKA) section 7.
Definition crypto.c:995
static int _evp_cipher_ctx_free_on_exit(void *arg)
Definition crypto.c:58
void aka_sim_crypto_cipher_ctx_free(void)
Explicitly free all thread load cipher ctxs.
Definition crypto.c:86
static int fr_aka_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
Locate the start of the AT_MAC value in the buffer.
Definition crypto.c:221
ssize_t fr_aka_sim_crypto_finalise_checkcode(TALLOC_CTX *ctx, uint8_t **out, fr_aka_sim_checkcode_t *checkcode)
Write out the final checkcode value.
Definition crypto.c:195
int fr_aka_sim_crypto_gsm_kdf_0(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC4186 (EAP-SIM) section 7.
Definition crypto.c:467
#define KDF_1_S_REAUTH_STATIC
void fr_aka_sim_crypto_keys_init_kdf_0_reauth(fr_aka_sim_keys_t *keys, uint8_t const mk[static AKA_SIM_MK_SIZE], uint16_t counter)
Initialise fr_aka_sim_keys_t with EAP-SIM reauthentication data.
Definition crypto.c:922
static int _fr_aka_sim_crypto_free_checkcode(fr_aka_sim_checkcode_t *checkcode)
Free OpenSSL memory associated with our checkcode ctx.
Definition crypto.c:97
int fr_aka_sim_crypto_umts_kdf_1(fr_aka_sim_keys_t *keys)
Key Derivation Function as described in RFC 5448 (EAP-AKA') section 3.3.
Definition crypto.c:851
int fr_aka_sim_crypto_update_checkcode(fr_aka_sim_checkcode_t *checkcode, eap_packet_t *eap_packet)
Digest a packet, updating the checkcode.
Definition crypto.c:151
static int ck_ik_prime_derive(fr_aka_sim_keys_t *keys)
Key Derivation Function (CK', IK') as specified in 3GPP.33.402.
Definition crypto.c:650
static _Thread_local EVP_CIPHER_CTX * evp_chipher_ctx
Used for every non-persistent EVP_CIPHER operation in this library.
Definition crypto.c:56
int fr_aka_sim_crypto_init_checkcode(TALLOC_CTX *ctx, fr_aka_sim_checkcode_t **checkcode, EVP_MD const *md)
Initialise checkcode message digest.
Definition crypto.c:113
EVP_CIPHER_CTX * aka_sim_crypto_cipher_ctx(void)
Allocate and reset a resumable EVP_CIPHER_CTX for each thread.
Definition crypto.c:69
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RHEXDUMP_INLINE3(_data, _len, _fmt,...)
Definition log.h:698
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
static const uint8_t * zero
Definition md4.c:359
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
#define MILENAGE_SQN_SIZE
Sequence number.
Definition milenage.h:30
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:37
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
void fr_sha1_init(fr_sha1_ctx *context)
Definition sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition sha1.c:105
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
Master include file to access all functions and structures in the library.
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030