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