pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40413?usp=email )
Change subject: WIP: Implement AKA authentication
......................................................................
WIP: Implement AKA authentication
Some of the functionalities from deps/nas.git
c4d162995a625c072f28554e3157e97962f84988 are imported into our own
files:
* ttcn: Otherwise ttcn/Lib_NG_NAS/LIB_NG_NAS_Functions.ttcn brings in
tons of dependencies about Emulation stuff which is not interesting
for us.
* .cc: We want to implement our own low level functions using our
eclipse Titan API, as well as our own C lib dependencies (because some
code for those dependencies is not really available in the repo).
Change-Id: I11527f47e4310863124f3f02148e3f71da7d911e
---
M 5gc/C5G_Tests.ttcn
A 5gc/NG_CryptoFunctionDefs.cc
A 5gc/NG_CryptoFunctions.ttcn
M 5gc/gen_links.sh
M 5gc/regen_makefile.sh
M library/General_Types.ttcn
6 files changed, 735 insertions(+), 6 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/13/40413/1
diff --git a/5gc/C5G_Tests.ttcn b/5gc/C5G_Tests.ttcn
index 9b45298..fa8c336 100644
--- a/5gc/C5G_Tests.ttcn
+++ b/5gc/C5G_Tests.ttcn
@@ -31,14 +31,14 @@
import from NGAP_Emulation all;
import from NAS_CommonTypeDefs all;
-
+import from NAS_CommonTemplates all;
import from NG_NAS_Common all;
import from NG_NAS_MsgContainers all;
-import from NAS_CommonTemplates all;
import from NG_NAS_Templates all;
import from NG_NAS_Osmo_Templates all;
import from NG_NAS_Functions all;
+import from NG_CryptoFunctions all;
/* (maximum) number of emulated eNBs */
const integer NUM_NGRAN := 1;
@@ -211,12 +211,18 @@
iE_Extensions := omit
}
-private function f_SUCI_IMSI() runs on ConnHdlr return octetstring {
+private function f_imsi_plmn_id() runs on ConnHdlr return PLMNIdentity {
var hexstring imsi := g_pars.ue_pars.imsi;
var GsmMcc mcc := substr(imsi, 0, 3);
var GsmMnc mnc := substr(imsi, 3, 2);
- var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi)-10, 10));
- return f_enc_mcc_mnc(mcc, mnc) & '21430001'O & imsi_suffix;
+ return f_enc_mcc_mnc(mcc, mnc);
+}
+
+private function f_SUCI_IMSI() runs on ConnHdlr return octetstring {
+ var hexstring imsi := g_pars.ue_pars.imsi;
+ var PLMNIdentity plmn_id := f_imsi_plmn_id();
+ var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi) - 10, 10));
+ return plmn_id & '21430001'O & imsi_suffix;
}
friend function f_ngap_setup(integer idx := 0, template (omit) NGAP_IEs.Cause cause :=
omit) runs on MTC_CT {
@@ -270,17 +276,27 @@
}
}
+/* 3GPP TS 24.501 5.4.1.3.2, 3GPP TS 33.501 6.1.3.2 */
private altstep as_ngap_handle_auth() runs on ConnHdlr {
var NG_NAS_DL_Message_Type rx_nas;
var template (present) NAS_KeySetIdentifier kset_id := f_tr_ConnHdlr_kset_id();
[] NGAP.receive(cr_NG_AUTHENTICATION_REQUEST) -> value rx_nas {
+ var NG_NAS_SecurityParams_Type vc_ng_nas_security_params_type := {};
log("Rx NAS message: ", rx_nas);
g_pars.kset_id := rx_nas.authentication_Request.ngNasKeySetId;
+ f_5g_aka_compute_res_xres(rx_nas.authentication_Request.rand.randValue,
+ rx_nas.authentication_Request.autn.aUTN,
+ rx_nas.authentication_Request.abba,
+ f_imsi_plmn_id(),
+ oct2hex(f_SUCI_IMSI()),
+ oct2bit('00000000000000000000000000000000'O), /* TODO: pass secret key!!!
*/
+ vc_ng_nas_security_params_type);
+
/* TODO: generate proper RES, 3GPP TS 33.501 A.4 */
const OCT8 res := '6a91970e838fd079'O;
- NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(oct2bit(res))));
+ NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(vc_ng_nas_security_params_type.AuthParams.XRES)));
}
}
diff --git a/5gc/NG_CryptoFunctionDefs.cc b/5gc/NG_CryptoFunctionDefs.cc
new file mode 100644
index 0000000..5fdb120
--- /dev/null
+++ b/5gc/NG_CryptoFunctionDefs.cc
@@ -0,0 +1,334 @@
+/* AKA USIM Utility functions */
+/**
+ * @author ETSI / TTF041
+ * @version $URL$
+ * $Id$
+ * @desc This module provides test functions for NG_NAS tests.
+ * @copyright ETSI Copyright Notification
+ * No part may be reproduced except as authorized by written permission.
+ * The copyright and the foregoing restriction extend to reproduction in
all media.
+ * All rights reserved.
+ * @see ETSI TS
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <gnutls/crypto.h>
+
+#include <Addfunc.hh>
+#include <Encdec.hh>
+#include <Boolean.hh>
+#include <Integer.hh>
+#include <Octetstring.hh>
+#include <Bitstring.hh>
+
+#include "rijndael.hh"
+#include "opc.hh"
+
+//#define DEBUG
+
+#ifdef DEBUG
+static __thread char hexd_buff[4096];
+static const char hex_chars[] = "0123456789abcdef";
+
+static const char *_osmo_hexdump_buf(char *out_buf, size_t out_buf_size, const unsigned
char *buf, int len, const char *delim,
+ bool delim_after_last)
+{
+ int i;
+ char *cur = out_buf;
+ size_t delim_len;
+
+ if (!out_buf || !out_buf_size)
+ return "";
+
+ delim = delim ? : "";
+ delim_len = strlen(delim);
+
+ for (i = 0; i < len; i++) {
+ const char *delimp = delim;
+ int len_remain = out_buf_size - (cur - out_buf) - 1;
+ if (len_remain < (2 + delim_len)
+ && !(!delim_after_last && i == (len - 1) && len_remain
>= 2))
+ break;
+
+ *cur++ = hex_chars[buf[i] >> 4];
+ *cur++ = hex_chars[buf[i] & 0xf];
+
+ if (i == (len - 1) && !delim_after_last)
+ break;
+
+ while (len_remain > 1 && *delimp) {
+ *cur++ = *delimp++;
+ len_remain--;
+ }
+ }
+ *cur = '\0';
+ return out_buf;
+}
+
+static char *_osmo_hexdump(const unsigned char *buf, int len)
+{
+ _osmo_hexdump_buf(hexd_buff, sizeof(hexd_buff), buf, len, "", true);
+ return hexd_buff;
+}
+#endif
+
+namespace NG__CryptoFunctions {
+
+ static uint8_t OP[16] = {0}; // FIXME FSCOM To be refined. This is a Q&D
implementation
+
+ BITSTRING fx__KeyDerivationFunction(const INTEGER& p__KDF, const BITSTRING&
p__Key, const OCTETSTRING& p__String){
+
+ if (p__KDF != 1) {
+ TTCN_error("pespin: fx__KeyDerivationFunction(p__KDF!=1) NOT IMPLEMENTED!");
+ return int2bit(0, 0);
+ }
+ //TODO: is this correct?
+ TTCN_Buffer ttcn_buf_key(bit2oct(p__Key));
+ TTCN_Buffer ttcn_buf_str(p__String);
+ uint8_t out[256];
+
+ gnutls_hmac_fast(GNUTLS_MAC_SHA256, ttcn_buf_key.get_data(), ttcn_buf_key.get_len(),
+ ttcn_buf_str.get_data(), ttcn_buf_str.get_len(), out);
+ OCTETSTRING res(sizeof(out), out);
+ return oct2bit(res);
+ }
+
+ void fx__set__op(const OCTETSTRING& p_op) {
+ std::memcpy(OP, static_cast<const unsigned char*>(p_op), 16);
+ }
+
+ INTEGER fx__f1(const BITSTRING& p_authK, const BITSTRING& p_rand, const
BITSTRING& p_sqn, const BITSTRING& p_amf, BITSTRING& p_mac_a) {
+
+ rijndael r;
+ OCTETSTRING authK = bit2oct(p_authK);
+ r.rijndael_key_schedule(authK);
+ opc op(r, OP);
+ uint8_t op_c[16] = { 0x00 };
+ op.compute_opc(op_c);
+
+ OCTETSTRING rand = bit2oct(p_rand);
+ uint8_t rijndael_input[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] = rand[i].get_octet() ^ op_c[i];
+ } // End of 'for' statement
+ uint8_t temp[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, temp);
+
+ OCTETSTRING sqn = bit2oct(p_sqn);
+ uint8_t in1[16] = { 0x00 };
+ for (int i = 0; i < 6; i++) {
+ in1[i] = sqn[i].get_octet();
+ in1[i + 8] = sqn[i].get_octet();
+ } // End of 'for' statement
+ OCTETSTRING amf = bit2oct(p_amf);
+ for (int i = 0; i < 2; i++) {
+ in1[i + 6] = amf[i].get_octet();
+ in1[i + 14] = amf[i].get_octet();
+ } // End of 'for' statement
+
+ // XOR op_c and in1, rotate by r1=64, and XOR on the constant c1 (which is all
zeroes)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[(i + 8) % 16] = in1[i] ^ op_c[i];
+ }
+
+ // XOR on the value temp computed before
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] ^= temp[i];
+ } // End of 'for' statement
+
+ uint8_t out1[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, out1);
+ for (int i = 0; i < 16; i++) {
+ out1[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t mac_a[8] = { 0x00 };
+ for (int i = 0; i < 8; i++) {
+ mac_a[i] = out1[i];
+ } // End of 'for' statement
+ OCTETSTRING os(8, static_cast<const unsigned char*>(&mac_a[0]));
+ p_mac_a = oct2bit(os);
+
+ return 0;
+ }
+
+ INTEGER fx__f1star(const BITSTRING& p_authK, const BITSTRING& p_rand, const
BITSTRING& p_sqn, const BITSTRING& p_amf, BITSTRING& p_mac_s) {
+
+ rijndael r;
+ OCTETSTRING authK = bit2oct(p_authK);
+ r.rijndael_key_schedule(authK);
+ opc op(r, OP);
+ uint8_t op_c[16] = { 0x00 };
+ op.compute_opc(op_c);
+
+ OCTETSTRING rand = bit2oct(p_rand);
+ uint8_t rijndael_input[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] = rand[i].get_octet() ^ op_c[i];
+ } // End of 'for' statement
+ uint8_t temp[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, temp);
+
+ OCTETSTRING sqn = bit2oct(p_sqn);
+ uint8_t in1[16] = { 0x00 };
+ for (int i = 0; i < 6; i++) {
+ in1[i] = sqn[i].get_octet();
+ in1[i + 8] = sqn[i].get_octet();
+ } // End of 'for' statement
+ OCTETSTRING amf = bit2oct(p_amf);
+ for (int i = 0; i < 2; i++) {
+ in1[i + 6] = amf[i].get_octet();
+ in1[i + 14] = amf[i].get_octet();
+ } // End of 'for' statement
+
+ // XOR op_c and in1, rotate by r1=64, and XOR on the constant c1 (which is all
zeroes)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[(i + 8) % 16] = in1[i] ^ op_c[i];
+ }
+
+ // XOR on the value temp computed before
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] ^= temp[i];
+ } // End of 'for' statement
+
+ uint8_t out1[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, out1);
+ for (int i = 0; i < 16; i++) {
+ out1[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t mac_s[8] = { 0x00 };
+ for (int i = 0; i < 8; i++) {
+ mac_s[i] = out1[i + 8];
+ } // End of 'for' statement
+ OCTETSTRING os(8, static_cast<const unsigned char*>(&mac_s[0]));
+ p_mac_s = oct2bit(os);
+
+ return 0;
+ }
+
+ INTEGER fx__f2345(const BITSTRING& p_authK, const BITSTRING& p_rand,
BITSTRING& p_res, BITSTRING& p_ck, BITSTRING& p_ik, BITSTRING& p_ak) {
+ rijndael r;
+ OCTETSTRING authK = bit2oct(p_authK);
+ r.rijndael_key_schedule(authK);
+ opc op(r, OP);
+ uint8_t op_c[16] = { 0x00 };
+ op.compute_opc(op_c);
+
+ OCTETSTRING rand = bit2oct(p_rand);
+ uint8_t rijndael_input[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] = rand[i].get_octet() ^ op_c[i];
+ } // End of 'for' statement
+ uint8_t temp[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, temp);
+
+ // To obtain output block OUT2: XOR OPc and TEMP, rotate by r2=0, and XOR on the
constant c2 (which is all zeroes except that the last bit is 1)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] = temp[i] ^ op_c[i];
+ } // End of 'for' statement
+ rijndael_input[15] ^= 1;
+
+ uint8_t out[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, out);
+ for (int i = 0; i < 16; i++) {
+ out[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t res[8] = { 0x00 };
+ for (int i = 0; i < 8; i++) {
+ res[i] = out[i + 8];
+ } // End of 'for' statement
+
+ uint8_t ak[6] = { 0x00 };
+ for (int i = 0; i < 6; i++) {
+ ak[i] = out[i];
+ } // End of 'for' statement
+
+ // To obtain output block OUT3: XOR OPc and TEMP, rotate by r3=32, and XOR on the
constant c3 (which is all zeroes except that the next to last bit is 1)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[(i + 12) % 16] = temp[i] ^ op_c[i];
+ } // End of 'for' statement
+ rijndael_input[15] ^= 2;
+
+ r.rijndael_encrypt(rijndael_input, out);
+ for (int i = 0; i < 16; i++) {
+ out[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t ck[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ ck[i] = out[i];
+ } // End of 'for' statement
+
+ // To obtain output block OUT4: XOR OPc and TEMP, rotate by r4=64, and XOR on the
constant c4 (which is all zeroes except that the 2nd from last bit is 1)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[(i+8) % 16] = temp[i] ^ op_c[i];
+ } // End of 'for' statement
+ rijndael_input[15] ^= 4;
+
+ r.rijndael_encrypt(rijndael_input, out);
+ for (int i = 0; i < 16; i++) {
+ out[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t ik[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ ik[i] = out[i];
+ } // End of 'for' statement
+
+ OCTETSTRING os(8, static_cast<const unsigned char*>(&res[0]));
+ p_res = oct2bit(os);
+ os = OCTETSTRING(16, static_cast<const unsigned char*>(&ik[0]));
+ p_ik = oct2bit(os);
+ os = OCTETSTRING(16, static_cast<const unsigned char*>(&ck[0]));
+ p_ck = oct2bit(os);
+ os = OCTETSTRING(6, static_cast<const unsigned char*>(&ak[0]));
+ p_ak = oct2bit(os);
+
+ return 0;
+ }
+
+ INTEGER fx__f5star(const BITSTRING& p_authK, const BITSTRING& p_rand,
BITSTRING& p_ak) {
+
+ rijndael r;
+ OCTETSTRING authK = bit2oct(p_authK);
+ r.rijndael_key_schedule(authK);
+ opc op(r, OP);
+ uint8_t op_c[16] = { 0x00 };
+ op.compute_opc(op_c);
+
+ OCTETSTRING rand = bit2oct(p_rand);
+ uint8_t rijndael_input[16] = { 0x00 };
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[i] = rand[i].get_octet() ^ op_c[i];
+ } // End of 'for' statement
+ uint8_t temp[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, temp);
+
+ // To obtain output block OUT5: XOR OPc and TEMP, rotate by r5=96, and XOR on the
constant c5 (which is all zeroes except that the 3rd from last bit is 1)
+ for (int i = 0; i < 16; i++) {
+ rijndael_input[(i + 4) % 16] = temp[i] ^ op_c[i];
+ } // End of 'for' statement
+ rijndael_input[15] ^= 8;
+
+ uint8_t out[16] = { 0x00 };
+ r.rijndael_encrypt(rijndael_input, out);
+ for (int i = 0; i < 16; i++) {
+ out[i] ^= op_c[i];
+ } // End of 'for' statement
+
+ uint8_t ak[6] = { 0x00 };
+ for (int i = 0; i < 6; i++) {
+ ak[i] = out[i];
+ }
+ OCTETSTRING os(6, static_cast<const unsigned char*>(&ak[0]));
+ p_ak = oct2bit(os);
+
+ return 0;
+ }
+
+} // namespace
diff --git a/5gc/NG_CryptoFunctions.ttcn b/5gc/NG_CryptoFunctions.ttcn
new file mode 100644
index 0000000..e4f266b
--- /dev/null
+++ b/5gc/NG_CryptoFunctions.ttcn
@@ -0,0 +1,369 @@
+/* Utility functions from ogslib imported to TTCN-3
+ *
+ * (C) 2019 Harald Welte <laforge(a)gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+module NG_CryptoFunctions {
+
+import from General_Types all;
+import from Misc_Helpers all;
+
+import from NAS_CommonTypeDefs all;
+import from NG_NAS_TypeDefs all;
+
+/*********************************************************************************
+ * low-level API (external C/C++ code)
+ *********************************************************************************/
+
+/* 3GPP TS 33.102 Figure 9, 3GPP TS 35.206 Annex 3 */
+external function fx_f1(in BIT128 p_authK, in BIT128 p_rand, in BIT48 v_sqn, in BIT16
v_amf, out BIT64 v_mac_a) return integer;
+external function fx_f1star(in BIT128 p_authK, in BIT128 p_rand, in BIT48 v_sqn, in BIT16
v_amf, out BIT64 v_mac_s) return integer;
+external function fx_f2345(in BIT128 p_authK, in BIT128 p_rand, out BIT64 v_res, out
BIT128 v_ck, out BIT128 v_ik, out BIT48 v_ak) return integer;
+external function fx_f5star(in BIT128 p_authK, in BIT128 p_rand, out BIT48 p_ak) return
integer;
+
+external function fx_KeyDerivationFunction(KDF_Type p_KDF,
+ bitstring p_Key,
+ octetstring p_String) return BIT256;
+
+/*********************************************************************************
+ * mid-level API
+ *********************************************************************************/
+type bitstring BIT32_128 length(32..128)
+const integer tsc_KDF_HMAC_SHA_256 := 1; /* @status APPROVED (IMS, IMS_IRAT, LTE,
LTE_IRAT, POS, SSNITZ, UTRAN) */
+const integer tsc_KDF_Spare3 := 4;
+type integer KDF_Type ( tsc_KDF_HMAC_SHA_256 .. tsc_KDF_Spare3 );
+
+type record NG_NAS_SecurityInfo_Type { /* ciphering/integrity
algorithm and key */
+ BIT4 Algorithm, /* acc. to 24.501 cl. 9.10.3.32 NAS security
algorithms */
+ BIT128 K_NAS /* key acc. 33.501 Figure 6.2-2 (K_NASint,
K_NASenc) */
+};
+
+const BIT32 tsc_AuthUndefinedB32 := oct2bit ('FFFFFFFF'O); /* @status
APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12,
LTE_IRAT, MCX, NBIOT, NR5GC, NR5GC_IRAT, POS, SSNITZ, UTRAN) */
+const BIT128 tsc_AuthUndefinedB128 := tsc_AuthUndefinedB32 & tsc_AuthUndefinedB32
& tsc_AuthUndefinedB32 & tsc_AuthUndefinedB32; /* @status APPROVED (ENDC,
IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, MCX, NBIOT,
NR5GC, NR5GC_IRAT, POS, SSNITZ, UTRAN) */
+const BIT256 tsc_AuthUndefinedB256 := tsc_AuthUndefinedB128 & tsc_AuthUndefinedB128;
/* @status APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO,
LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, NBIOT, NR5GC, NR5GC_IRAT, POS) */
+
+type record Common_AuthenticationParams_Type { /* parameters related/used to/by
EUTRA/UTRAN/GERAN authentication
+ @status APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO,
LTE_A_R10_R11, LTE_A_R12, LTE_IRAT, MCX, NBIOT, NR5GC, NR5GC_IRAT, POS, SSNITZ, UTRAN) */
+ BIT128 RandValue,
+ BIT128 AUTN,
+ BIT32_128 XRES,
+ BIT64 KcGSM,
+ BIT128 Kc128, // @sic R5s150121 sic@
+ BIT3 KeySeq,
+ BIT128 CK,
+ BIT128 IK,
+ integer XRESLength optional // @sic R5s120907 sic@
+};
+
+type record NG_NAS_SecurityParams_Type {
+ // Keys shared with NR
+ KDF_Type KDF,
+ BIT3 KSIamf, // 3 bit KSIasme used when Authentication is performed by MME.
+ BIT256 Ks, // = Ck || IK
+ BIT256 KAMF,
+ // NAS keys
+ bitstring MK, // Master key MK in RFC 5448 to be used to derive other keys acc. TS
33.501 cl. 6.2.1
+ BIT256 KAUSF,
+ BIT256 KSEAF,
+ octetstring ABBA,
+ // NAS Security structures
+ NG_NAS_SecurityInfo_Type NAS_Integrity,
+ NG_NAS_SecurityInfo_Type NAS_Ciphering,
+ Common_AuthenticationParams_Type AuthParams
+};
+
+const BIT4 tsc_NG_Integrity_Snow3G := '0001'B; /* @status APPROVED (NR5GC)
*/
+const BIT4 tsc_NG_Integrity_AES := '0010'B; /* @status APPROVED (NR5GC)
*/
+const BIT4 tsc_NG_Integrity_ZUC := '0011'B; /* @status APPROVED (NR5GC)
*/
+const BIT4 tsc_NG_Encryption_Snow3G := '0001'B; /* @status APPROVED (NR5GC)
*/
+const BIT4 tsc_NG_Encryption_AES := '0010'B; /* @status APPROVED (NR5GC)
*/
+const BIT4 tsc_NG_Encryption_ZUC := '0011'B; /* @status APPROVED (NR5GC)
*/
+
+template (value) NG_NAS_SecurityInfo_Type cs_NG_NAS_SecurityInfo(BIT4 p_Algo,
+ BIT128 p_Key) :=
+{
+ Algorithm := p_Algo,
+ K_NAS := p_Key
+};
+
+template (value) Common_AuthenticationParams_Type cs_CommonAuthParams_Init (template
(value) BIT128 p_Rand) :=
+{ /* @status APPROVED (ENDC, IMS, IMS_IRAT, LTE, LTE_A_IRAT, LTE_A_PRO, LTE_A_R10_R11,
LTE_A_R12, LTE_IRAT, MCX, NBIOT, NR5GC, NR5GC_IRAT, POS, SSNITZ, UTRAN) */
+ RandValue := p_Rand,
+ AUTN := tsc_AuthUndefinedB128,
+ XRES := tsc_AuthUndefinedB128,
+ KcGSM := tsc_AuthUndefinedB32 & tsc_AuthUndefinedB32,
+ Kc128 := tsc_AuthUndefinedB128, // @sic R5s150121 sic@
+ KeySeq := '111'B,
+ CK := tsc_AuthUndefinedB128,
+ IK := tsc_AuthUndefinedB128,
+ XRESLength := omit // @sic R5s120907 sic@
+};
+
+template (value) NG_NAS_SecurityParams_Type cs_NG_NAS_SecurityParamsInit :=
+{
+ KDF := tsc_KDF_HMAC_SHA_256,
+ KSIamf := '111'B, //un initialised
+ Ks := tsc_AuthUndefinedB256,
+ KAMF := tsc_AuthUndefinedB256,
+ MK := tsc_AuthUndefinedB256,
+ KAUSF := tsc_AuthUndefinedB256,
+ KSEAF := tsc_AuthUndefinedB256,
+ ABBA := '0000'O,
+ NAS_Integrity := cs_NG_NAS_SecurityInfo ('0010'B, tsc_AuthUndefinedB128),
+ NAS_Ciphering := cs_NG_NAS_SecurityInfo ('0010'B, tsc_AuthUndefinedB128),
+ AuthParams := cs_CommonAuthParams_Init
(oct2bit('A3DE0C6D363E30C364A4078F1BF8D577'O))
+};
+
+//----------------------------------------------------------------------------
+/*
+* @desc Used when building the network name from the PLMN
+* @param p_NAS_PlmnId
+* @return charstring
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function fl_Nas2SNN_MNC(NAS_PlmnId p_NAS_PlmnId) return charstring
+{
+ var charstring v_MNC := "";
+ var hexstring v_PLMN_hexstring := oct2hex(p_NAS_PlmnId);
+
+ if (v_PLMN_hexstring[2] == 'F'H) {
+ v_MNC := "0";
+ }
+ v_MNC := v_MNC & hex2str(v_PLMN_hexstring[5]) & hex2str(v_PLMN_hexstring[4]);
+ if (v_PLMN_hexstring[2] != 'F'H) { // add last digit if not F
+ v_MNC := v_MNC & hex2str(v_PLMN_hexstring[2]);
+ }
+ return v_MNC;
+}
+
+/*
+* @desc Used when building the network name from the PLMN
+* @param p_NAS_PlmnId
+* @return charstring
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function fl_Nas2SNN_MCC(NAS_PlmnId p_NAS_PlmnId) return charstring
+{
+ var charstring v_MCC;
+ var hexstring v_PLMN_hexstring := oct2hex(p_NAS_PlmnId);
+
+ v_MCC := hex2str(v_PLMN_hexstring[1]) & hex2str(v_PLMN_hexstring[0]) &
hex2str(v_PLMN_hexstring[3]);
+
+ return v_MCC;
+}
+
+/*
+* @desc To build the Serving Network Name
+* @param p_PLMN
+* @param p_NID (default value: omit)
+* @return octetstring
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function fl_GetServingNetworkName (NAS_PlmnId p_PLMN,
+ template (omit) hexstring p_NID := omit) return octetstring
+{
+ var charstring v_P0 := "5G:mnc" & fl_Nas2SNN_MNC(p_PLMN) &
".mcc" & fl_Nas2SNN_MCC(p_PLMN) & ".3gppnetwork.org";
+ if (isvalue(p_NID)) { // @sic R5s220753 sic@
+ v_P0 := v_P0 & ":" & hex2str (valueof(p_NID));
+ }
+ return char2oct (v_P0);
+}
+
+//============================================================================
+// Group of S functions defined in Annex A of 33.501
+//----------------------------------------------------------------------------
+/*
+* @desc KAUSF derivation function; As per annex A.2 of 33.501
+* @param p_AuthParams
+* @param p_KDF
+* @param p_Ks
+* @param p_PLMN
+* @param p_NID (default value: omit)
+* @return BIT256
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function f_NG_Authentication_A2(Common_AuthenticationParams_Type p_AuthParams,
+ KDF_Type p_KDF,
+ BIT256 p_Ks,
+ NAS_PlmnId p_PLMN,
+ template (omit) hexstring p_NID := omit) return BIT256
+{
+ const octetstring const_S6A_FC := '6A'O;
+ var octetstring v_S;
+ var octetstring v_P0;
+
+ // Generation of String
+ v_S := const_S6A_FC;
+ //FC = 0x6A
+ v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@
+ v_S := (v_S & v_P0);
+ //P0 = serving network ID
+ v_S := (v_S & int2oct(lengthof(v_P0), 2)) ;
+ //L0 = length of serving network ID (i.e. 0x00 0x03)
+ v_S := ( v_S & ( substr (( bit2oct ( p_AuthParams.AUTN )) , 0,6 )));
+ //P1 = SQN XOR AK
+ // to have MSB 6 bytes which is SQN xor AK and truncated as SQN xor AK is first 6 bytes
of AUTN
+ v_S := ( v_S & '0006'O );
+ //L1 = length of SQN XOR AK (i.e. 0x00 0x06)
+ return fx_KeyDerivationFunction( p_KDF, p_Ks, v_S );
+}
+
+//--------------------------------------------------------------------------
+/*
+* @desc RES* and XRES* derivation functions
+* As per annex A.4 of 33.501
+* @param p_PLMN
+* @param p_AuthParams
+* @param p_KDF
+* @param p_Key
+* @param p_NID (default value: omit)
+* @return BIT128
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function f_NG_Authentication_A4(NAS_PlmnId p_PLMN,
+ Common_AuthenticationParams_Type p_AuthParams,
+ KDF_Type p_KDF,
+ BIT256 p_Key,
+ template (omit) hexstring p_NID := omit) return BIT128
+{
+ const octetstring const_S6B_FC :='6B'O;
+ var octetstring v_S;
+ var octetstring v_P0;
+ const integer px_NAS_5GC_XRES_Length := 16;
+
+ // Generation of String
+ v_S := const_S6B_FC;
+ //FC = 0x6B
+ v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@
+ v_S := (v_S & v_P0);
+ //P0 = serving network ID
+ v_S := (v_S & int2oct(lengthof(v_P0), 2)) ;
+ //L0 = length of serving network ID
+ v_S := ( v_S & bit2oct ( p_AuthParams.RandValue ) );
+ //P1 = RAND
+ v_S := ( v_S & '0010'O );
+ //L1 = length of RAND (i.e. 0x00 0x10)
+ v_S := ( v_S & bit2oct (substr(p_AuthParams.XRES, 0, px_NAS_5GC_XRES_Length*8)));
// @sic R5s190394 sic@
+ //P2 = RES or XRES
+ v_S := ( v_S & int2oct(px_NAS_5GC_XRES_Length, 2) ); // @sic R5w190117 sic@
+ //L2 = length of RES/XRES (e.g. 0x00 0x10)
+
+ return substr(fx_KeyDerivationFunction(p_KDF, p_Key, v_S), 128, 128);
+// returns LSB 128 bits[truncated] of the key generated
+}
+
+//--------------------------------------------------------------------------
+/*
+* @desc KSEAF derivation function
+* As per annex A.6 of 33.501
+* @param p_PLMN
+* @param p_KAUSF
+* @param p_KDF_Type
+* @param p_NID (default value: omit)
+* @return BIT256
+* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS)
+*/
+function f_NG_Authentication_A6(NAS_PlmnId p_PLMN,
+ BIT256 p_KAUSF,
+ KDF_Type p_KDF_Type,
+ template (omit) hexstring p_NID := omit) return BIT256
+{
+ const octetstring const_S6C_FC :='6C'O;
+ var octetstring v_S;
+ var octetstring v_P0;
+
+ // Generation of String
+ v_S := const_S6C_FC;
+ //FC = 0x6C
+ v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@
+ v_S := (v_S & v_P0);
+ //P0 = serving network ID
+ v_S := (v_S & int2oct(lengthof(v_P0), 2)) ;
+ //L0 = length of serving network ID
+
+ return fx_KeyDerivationFunction(p_KDF_Type, p_KAUSF, v_S);
+};
+
+/* Compute RES and XRES values based on rAND & AUTN received in the
NG_AUTHENTICATION_REQUEST.
+ * 3GPP TS 33.102 Figure 9, 3GPP TS 35.206 Annex 3 */
+function f_5g_aka_compute_res_xres(BIT128 p_rand,
+ BIT128 p_autn,
+ ABBA p_abba,
+ NAS_PlmnId p_PLMN,
+ hexstring p_NID,
+ BIT128 usim_secret_key,
+ inout NG_NAS_SecurityParams_Type pars)
+return boolean {
+
+ pars := valueof(cs_NG_NAS_SecurityParamsInit);
+ log("f_5g_aka_compute_res_xres: KDF=", pars.KDF);
+ pars.ABBA := p_abba.abbaValue;
+ pars.AuthParams.RandValue := p_rand;
+ pars.AuthParams.AUTN := p_autn;
+
+ // Extract SQN from v_sqn_ak and XOR it with calculated MAC
+ var BIT48 v_sqn_ak := substr(p_autn, 0, 48);
+ var BIT16 v_amf := substr(p_autn, 48, 16);
+ var BIT64 v_mac := substr(p_autn, 64, 64);
+
+ // Calculate RES, CK, IK and AK in one step
+ var BIT128 v_ck;
+ var BIT128 v_ik;
+ var BIT48 v_ak;
+ var BIT64 v_res;
+ if (fx_f2345(usim_secret_key, p_rand, v_res, v_ck, v_ik, v_ak) == -1) {
+ return false;
+ }
+ pars.AuthParams.CK := v_ck;
+ pars.AuthParams.IK := v_ik;
+ pars.Ks := pars.AuthParams.CK & pars.AuthParams.IK;
+ var BIT48 v_sqn := v_sqn_ak xor4b v_ak;
+
+ // Verify that MAC was accepted
+ var BIT64 v_mac_p;
+ if (fx_f1(usim_secret_key, p_rand, v_sqn, v_amf, v_mac_p) == -1) {
+ return false;
+ }
+ if (v_mac != v_mac_p) {
+ return false;
+ }
+
+ // Compute XRES
+ pars.AuthParams.XRES := f_NG_Authentication_A4(p_PLMN,
+ pars.AuthParams,
+ pars.KDF,
+ pars.Ks,
+ p_NID);
+
+ // Generate KAUSF
+ pars.KAUSF := f_NG_Authentication_A2(pars.AuthParams,
+ pars.KDF,
+ pars.Ks,
+ p_PLMN,
+ p_NID);
+
+ // Generate KSEAF
+ pars.KSEAF := f_NG_Authentication_A6(p_PLMN,
+ pars.KAUSF,
+ pars.KDF,
+ p_NID
+ );
+
+ // TODO Generate KMAF
+ // pars.KAMF := f_NG_Authentication_A7(p_Identity,
+ // pars.KSEAF,
+ // pars.ABBA,
+ // pars.KDF
+ // );
+
+ return true;
+}
+
+
+} // namespace
diff --git a/5gc/gen_links.sh b/5gc/gen_links.sh
index 295ca24..8b70010 100755
--- a/5gc/gen_links.sh
+++ b/5gc/gen_links.sh
@@ -25,6 +25,10 @@
FILES="common_ext.cc "
gen_links $DIR $FILES
+DIR=$BASEDIR/nas/ccsrc/Protocols/FiveG_AKA
+FILES="opc.cc opc.hh rijndael.cc rijndael.hh "
+gen_links $DIR $FILES
+
DIR=$BASEDIR/nas/ttcn/Lib3GPP/Common
FILES="CommonDefs.ttcn "
gen_links $DIR $FILES
diff --git a/5gc/regen_makefile.sh b/5gc/regen_makefile.sh
index 44f7a56..c76046b 100755
--- a/5gc/regen_makefile.sh
+++ b/5gc/regen_makefile.sh
@@ -9,8 +9,10 @@
IPL4asp_discovery.cc
Native_FunctionDefs.cc
common_ext.cc
+ opc.cc rijndael.cc
NGAP_CodecPort_CtrlFunctDef.cc
NGAP_EncDec.cc
+ NG_CryptoFunctionDefs.cc
TCCConversion.cc
TCCEncoding.cc
TCCInterface.cc
diff --git a/library/General_Types.ttcn b/library/General_Types.ttcn
index 2daa593..163ec47 100644
--- a/library/General_Types.ttcn
+++ b/library/General_Types.ttcn
@@ -84,7 +84,11 @@
type bitstring BIT30 length(30) with { variant "FIELDLENGTH(30)" };
type bitstring BIT31 length(31) with { variant "FIELDLENGTH(31)" };
type bitstring BIT32 length(32) with { variant "FIELDLENGTH(32)" };
+ type bitstring BIT48 length(48) with { variant "FIELDLENGTH(48)" };
type bitstring BIT56 length(56) with { variant "FIELDLENGTH(56)" };
+ type bitstring BIT64 length(64) with { variant "FIELDLENGTH(64)" };
+ type bitstring BIT128 length(128) with { variant "FIELDLENGTH(128)" };
+ type bitstring BIT256 length(256) with { variant "FIELDLENGTH(256)" };
//****************************************************
// Octetstrings
--
To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40413?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I11527f47e4310863124f3f02148e3f71da7d911e
Gerrit-Change-Number: 40413
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>