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