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