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