pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40440?usp=email )


Change subject: 5gc: Implement NAS integrity check of DL messages
......................................................................

5gc: Implement NAS integrity check of DL messages

Change-Id: I118081af10f260513734550854c3a1751e32cbb4
---
M 5gc/C5G_Tests.ttcn
M 5gc/gen_links.sh
M 5gc/open5gs/open5gs-amf.yaml
M 5gc/regen_makefile.sh
M library/LTE_CryptoFunctions.ttcn
M library/NGAP_Emulation.ttcn
M library/NG_CryptoFunctionDefs.cc
M library/NG_CryptoFunctions.ttcn
M library/NG_NAS_Osmo_Templates.ttcn
M library/ng_crypto/key_derivation.c
M library/ng_crypto/key_derivation.h
11 files changed, 499 insertions(+), 29 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks 
refs/changes/40/40440/1

diff --git a/5gc/C5G_Tests.ttcn b/5gc/C5G_Tests.ttcn
index 9cf5ec3..3695f69 100644
--- a/5gc/C5G_Tests.ttcn
+++ b/5gc/C5G_Tests.ttcn
@@ -40,6 +40,7 @@

 import from NG_NAS_Osmo_Templates all;
 import from NG_NAS_Functions all;
+import from NG_NAS_Osmo_Templates all;
 import from NG_CryptoFunctions all;

 /* (maximum) number of emulated eNBs */
@@ -75,7 +76,21 @@
        hexstring imsi,
        octetstring usim_key,
        octetstring usim_opc,
-       charstring ue_ip
+       charstring ue_ip,
+       OCT32 kausf optional,
+       OCT32 kseaf optional,
+       OCT32 kamf optional
+}
+
+template (value) UeParams ts_UeParams(integer imsi_suffix) :=
+{
+       imsi := f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, 
lengthof(mp_imsi) - 6), imsi_suffix),
+       usim_key := mp_usim_key,
+       usim_opc := mp_usim_opc,
+       ue_ip := "192.168.123.50",
+       kausf := omit,
+       kseaf := omit,
+       kamf := omit
 }

 type component MTC_CT {
@@ -122,7 +137,7 @@
                remote_sctp_port := mp_5gc_ngap_port,
                local_ip := mp_local_ngap_ip,
                local_sctp_port := mp_local_ngap_port + num,
-               role := NGAP_NAS_ROLE_UE
+               role := NG_NAS_ROLE_UE
        };
        var PLMNIdentity plmn_id := f_enc_mcc_mnc(mp_mcc, mp_mnc);
        var NGRANParams ngran_pars := {
@@ -147,15 +162,12 @@
        vc_NGAP[num].start(NGAP_Emulation.main(ops, pars, id));
        NGAP_UNIT[num].receive(NGAPEM_Event:{up_down:=NGAPEM_EVENT_UP});
 }
+
 friend function f_init_one_ue(inout UeParams uep, integer imsi_suffix) {

-       uep := {
-               imsi := f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, 
lengthof(mp_imsi) - 6), imsi_suffix),
-               usim_key := mp_usim_key,
-               usim_opc := mp_usim_opc,
-               ue_ip := "192.168.123.50"
-       }
+       uep := valueof(ts_UeParams(imsi_suffix));
 }
+
 friend function f_init_ngap(integer imsi_suffix := 0) runs on MTC_CT {
        var integer i;
        for (i := 0; i < NUM_NGRAN; i := i+1) {
@@ -294,6 +306,7 @@
                var integer my_sqn := 0; /* TODO: move to a ConnHdlr state 
attribute? */
                var OCT16 rand := 
bit2oct(rx_nas.authentication_Request.rand.randValue);
                var OCT16 autn := 
bit2oct(rx_nas.authentication_Request.autn.aUTN);
+               var OCT2 abba := rx_nas.authentication_Request.abba.abbaValue;
                var OCT16 ik;
                var OCT16 ck;
                var OCT8 res;
@@ -322,8 +335,20 @@
                        return;
                }

-               /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4  */
                var octetstring ssn := 
f_NG_NAS_ServingNetworkName_OCT(f_imsi_plmn_id(), omit);
+               g_pars.ue_pars.kausf := f_kdf_kausf(ck, ik, ssn, autn);
+               g_pars.ue_pars.kseaf := f_kdf_kseaf(g_pars.ue_pars.kausf, ssn);
+               g_pars.ue_pars.kamf := f_kdf_kamf(g_pars.ue_pars.kseaf, 
char2oct(hex2str(g_pars.ue_pars.imsi)), abba);
+
+               var NGAPEM_Config cfg := {
+                       set_nas_keys := {
+                               k_nas_int := 
f_kdf_ng_nas_int(g_pars.ue_pars.kamf, NG_NAS_ALG_IP_EIA1),
+                               k_nas_enc := 
f_kdf_ng_nas_enc(g_pars.ue_pars.kamf, NG_NAS_ALG_ENC_EEA0)
+                       }
+               };
+               NGAP.send(cfg);
+
+               /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4  */
                var OCT16 res_star := f_kdf_xres_star(ssn, ck, ik, rand, res);
                log("Auth Response: RES=", res, ", SSN=", ssn, " / ", 
oct2char(ssn), ", RES*=", res_star);

@@ -334,9 +359,8 @@
 private altstep as_ngap_handle_sec_mode() runs on ConnHdlr {
        var NG_NAS_DL_Message_Type rx_nas;

-       [] NGAP.receive(cr_NG_SECURITY_PROTECTED_NAS_MESSAGE) -> value rx_nas {
-               var NG_NAS_DL_Message_Type in_nas := 
dec_NG_NAS_DL_Message_Type(rx_nas.security_Protected_Nas_Message.plainNASMessage);
-               log("PESPIN: Rx inner NAS: ", in_nas);
+       [] NGAP.receive(cr_NG_SECURITY_MODE_COMMAND) -> value rx_nas {
+               log("PESPIN: Rx inner NAS: ", rx_nas);
                /* TODO: apply below integrity and ciphering based on Security 
Mode Command */
        }
 }
diff --git a/5gc/gen_links.sh b/5gc/gen_links.sh
index 9f67736..ee09250 100755
--- a/5gc/gen_links.sh
+++ b/5gc/gen_links.sh
@@ -61,6 +61,10 @@
 FILES+="NGAP_EncDec.cc NGAP_Types.ttcn NGAP_Pixits.ttcn NGAP_Templates.ttcn "
 gen_links $DIR $FILES

+DIR=../library/snow_3g
+FILES="snow-3g.c snow-3g.h Snow3G_FunctionDefs.cc Snow3G_Functions.ttcn "
+gen_links $DIR $FILES
+
 DIR=../library/milenage
 FILES="milenage.c milenage.h Milenage_FunctionDefs.cc Milenage_Functions.ttcn "
 gen_links $DIR $FILES
diff --git a/5gc/open5gs/open5gs-amf.yaml b/5gc/open5gs/open5gs-amf.yaml
index ca52090..e8da7a5 100644
--- a/5gc/open5gs/open5gs-amf.yaml
+++ b/5gc/open5gs/open5gs-amf.yaml
@@ -43,7 +43,7 @@
       s_nssai:
         - sst: 1
   security:
-    integrity_order : [ NIA2, NIA1, NIA0 ]
+    integrity_order : [ NIA1, NIA2, NIA0 ]
     ciphering_order : [ NEA0, NEA1, NEA2 ]
   network_name:
     full: Open5GS
diff --git a/5gc/regen_makefile.sh b/5gc/regen_makefile.sh
index 0d53583..be45468 100755
--- a/5gc/regen_makefile.sh
+++ b/5gc/regen_makefile.sh
@@ -14,6 +14,7 @@
        NGAP_CodecPort_CtrlFunctDef.cc
        NGAP_EncDec.cc
        NG_CryptoFunctionDefs.cc
+       Snow3G_FunctionDefs.cc
        TCCConversion.cc
        TCCEncoding.cc
        TCCInterface.cc
diff --git a/library/LTE_CryptoFunctions.ttcn b/library/LTE_CryptoFunctions.ttcn
index 57e0c4d..882861b 100644
--- a/library/LTE_CryptoFunctions.ttcn
+++ b/library/LTE_CryptoFunctions.ttcn
@@ -49,7 +49,7 @@
                return '00000000'O;
                }
        case (NAS_ALG_IP_EIA1) {
-               return f_snow_3g_f9(k_nas_int, seq_nr, bearer, is_downlink, 
data);
+               return f_snow_3g_f9(k_nas_int, seq_nr, bit2int(int2bit(bearer, 
32) << 27), is_downlink, data);
                }
        case else {
                Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
log2str("Unsupported EIA: ", alg));
diff --git a/library/NGAP_Emulation.ttcn b/library/NGAP_Emulation.ttcn
index 12487ae..8f63e09 100644
--- a/library/NGAP_Emulation.ttcn
+++ b/library/NGAP_Emulation.ttcn
@@ -54,10 +54,8 @@
 import from NG_NAS_MsgContainers all;
 import from NG_NAS_Functions all;

-type enumerated NGAP_NAS_Role {
-       NGAP_NAS_ROLE_UE,       /* ATS implements/emulates UE */
-       NGAP_NAS_ROLE_AMF       /* ATS implements/emulates AMF */
-};
+import from NG_NAS_Osmo_Templates all;
+import from NG_CryptoFunctions all;

 type component NGAP_ConnHdlr {
        port NGAP_Conn_PT NGAP;
@@ -67,9 +65,22 @@

 /* port between individual per-connection components and this dispatcher */
 type port NGAP_Conn_PT message {
-       inout NGAP_PDU, NG_NAS_UL_Message_Type, NG_NAS_DL_Message_Type;
+       inout NGAP_PDU, NG_NAS_UL_Message_Type, NG_NAS_DL_Message_Type, 
NGAPEM_Config;
 } with { extension "internal" };

+type record NG_NAS_Keys {
+       OCT32 k_nas_int,
+       OCT32 k_nas_enc
+};
+type record NG_ResetNAScounts {
+/* empty */
+};
+type union NGAPEM_Config {
+       NG_NAS_Keys set_nas_keys,
+       NG_ResetNAScounts reset_nas_counts,
+       NG_NAS_ALG_INT set_nas_alg_int,
+       NG_NAS_ALG_ENC set_nas_alg_enc
+};

 type enumerated NGAPEM_EventUpDown {
        NGAPEM_EVENT_DOWN,
@@ -145,8 +156,8 @@
        NGAP_ConnHdlr   comp_ref,                       /* component handling 
this UE connection */
        uint32_t        ran_ue_ngap_id optional,        /* eNB side NGAP ID */
        uint40_t        amf_ue_ngap_id optional,        /* AMF side NGAP ID */
-       UserLocationInformation uli optional
-       //NAS_UE_State  nus
+       UserLocationInformation uli optional,
+       NG_NAS_UE_State nus
 };

 type component NGAP_Emulation_CT {
@@ -191,7 +202,7 @@
        IPL4asp_Types.PortNumber remote_sctp_port,
        HostName local_ip,
        IPL4asp_Types.PortNumber local_sctp_port,
-       NGAP_NAS_Role role
+       NG_NAS_Role role
 }

 function tr_NGAP_RecvFrom_R(template NGAP_PDU msg)
@@ -329,7 +340,7 @@
                NGapAssociationTable[i].amf_ue_ngap_id := omit;
                NGapAssociationTable[i].ran_ue_ngap_id := omit;
                NGapAssociationTable[i].uli := omit;
-               //NGapAssociationTable[i].nus := 
valueof(t_NAS_UE_State(g_pars.role));
+               NGapAssociationTable[i].nus := 
valueof(t_NG_NAS_UE_State(g_pars.role));
                NGapAssociationTable[i].comp_ref := null;
        }
 }
@@ -451,11 +462,38 @@
                var integer procedureCode;
                var NGAP_RecvFrom mrf;
                var NGAP_PDU msg;
+               var NGAPEM_Config ngcfg;
                var charstring vlr_name, amf_name;
                var integer ai;
                var octetstring kasme;

                alt {
+               /* Configuration primitive from client */
+               [] NGAP_CLIENT.receive(NGAPEM_Config:{set_nas_keys:=?}) -> 
value ngcfg sender vc_conn {
+                       var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+                       NGapAssociationTable[assoc_id].nus.k_nas_int := 
ngcfg.set_nas_keys.k_nas_int;
+                       NGapAssociationTable[assoc_id].nus.k_nas_enc := 
ngcfg.set_nas_keys.k_nas_enc;
+                       }
+               /* Configuration primitive from client */
+               [] NGAP_CLIENT.receive(NGAPEM_Config:{reset_nas_counts:=?}) -> 
value ngcfg sender vc_conn {
+                       var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+                       NGapAssociationTable[assoc_id].nus.rx_count := 0;
+                       NGapAssociationTable[assoc_id].nus.tx_count := 0;
+                       }
+               /* Configuration primitive from client */
+               [] NGAP_CLIENT.receive(NGAPEM_Config:{set_nas_alg_int:=?}) -> 
value ngcfg sender vc_conn {
+                       var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+                       NGapAssociationTable[assoc_id].nus.alg_int := 
ngcfg.set_nas_alg_int;
+                       /* Mark ciphering even if using EIA0: */
+                       NGapAssociationTable[assoc_id].nus.use_int := true;
+                       }
+               /* Configuration primitive from client */
+               [] NGAP_CLIENT.receive(NGAPEM_Config:{set_nas_alg_enc:=?}) -> 
value ngcfg sender vc_conn {
+                       var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+                       NGapAssociationTable[assoc_id].nus.alg_enc := 
ngcfg.set_nas_alg_enc;
+                       /* Mark ciphering even if using EEA0: */
+                       NGapAssociationTable[assoc_id].nus.use_enc := true;
+                       }
                /* NGAP from client: InitialUE */
                [] NGAP_CLIENT.receive(mw_ngap_initMsg(mw_n2_initialUeMessage)) 
-> value msg sender vc_conn {
                        /* create a table entry about this connection */
@@ -513,11 +551,11 @@
                                        vc_conn := 
NGapAssociationTable[assoc_id].comp_ref;
                                        nas_enc := f_NGAP_get_NAS_PDU(mrf.msg);
                                        if (isvalue(nas_enc)) {
-                                               if (g_pars.role == 
NGAP_NAS_ROLE_UE) {
+                                               if (g_pars.role == 
NG_NAS_ROLE_UE) {
                                                        var 
NG_NAS_DL_Message_Type dl_nas := dec_NG_NAS_DL_Message_Type(valueof(nas_enc));
-//                                                     if (match(dl_nas, 
tr_NAS_EMM_SecurityProtected)) {
-//                                                             dl_nas := 
f_nas_try_decaps(NGapAssociationTable[assoc_id].nus, dl_nas);
-//                                                     }
+                                                       if (match(dl_nas, 
cr_NG_SECURITY_PROTECTED_NAS_MESSAGE)) {
+                                                               dl_nas := 
f_NG_NAS_try_decaps_dl(NGapAssociationTable[assoc_id].nus, dl_nas);
+                                                       }
                                                        /* DL/UlNasTransport 
are not interesting, don't send them */
                                                        if (not match(mrf.msg, 
mw_ngap_initMsg(mw_n2_DownlinkNASTransport))) {
                                                                /* send raw 
NGAP */
@@ -594,7 +632,7 @@
 }

 /* client/conn_hdlr side function to use procedure port to create expect in 
emulation */
-function f_create_s1ap_expect(template (omit) AMF_UE_NGAP_ID amf_id,
+function f_create_ngap_expect(template (omit) AMF_UE_NGAP_ID amf_id,
                              template (omit) RAN_UE_NGAP_ID ran_id) runs on 
NGAP_ConnHdlr {
        NGAP_PROC.call(NGAPEM_register:{amf_id, ran_id, self}) {
                [] NGAP_PROC.getreply(NGAPEM_register:{?,?,?}) {};
diff --git a/library/NG_CryptoFunctionDefs.cc b/library/NG_CryptoFunctionDefs.cc
index e45e519..9211916 100644
--- a/library/NG_CryptoFunctionDefs.cc
+++ b/library/NG_CryptoFunctionDefs.cc
@@ -17,6 +17,22 @@

 namespace NG__CryptoFunctions {

+/* 3GPP TS 33.501 Annex A.2 */
+OCTETSTRING f__kdf__kausf(const OCTETSTRING& ck, const OCTETSTRING& ik, const 
OCTETSTRING &ssn,
+                         const OCTETSTRING& autn)
+{
+       TTCN_Buffer ttcn_buf_ck(ck);
+       TTCN_Buffer ttcn_buf_ik(ik);
+       TTCN_Buffer ttcn_buf_ssn(ssn);
+       TTCN_Buffer ttcn_buf_autn(autn);
+       uint8_t kausf[32];
+
+       kdf_kausf(ttcn_buf_ck.get_data(), ttcn_buf_ik.get_data(),
+                 ttcn_buf_ssn.get_data(), ttcn_buf_ssn.get_len(),
+                 ttcn_buf_autn.get_data(), kausf);
+       return OCTETSTRING(sizeof(kausf), kausf);
+}
+
 /* 3GPP TS 33.501 A.4 RES* and XRES* derivation function */
 OCTETSTRING f__kdf__xres__star(const OCTETSTRING &ssn, const OCTETSTRING& ck, 
const OCTETSTRING& ik,
                               const OCTETSTRING& rand, const OCTETSTRING& xres)
@@ -37,4 +53,44 @@
        return OCTETSTRING(sizeof(xres_star), xres_star);
 }

+/* 3GPP TS 33.501 Annex A.6 */
+OCTETSTRING f__kdf__kseaf(const OCTETSTRING& kausf, const OCTETSTRING &ssn)
+{
+       TTCN_Buffer ttcn_buf_kausf(kausf);
+       TTCN_Buffer ttcn_buf_ssn(ssn);
+       uint8_t kseaf[32];
+
+       kdf_kseaf(ttcn_buf_kausf.get_data(),
+                 ttcn_buf_ssn.get_data(), ttcn_buf_ssn.get_len(), kseaf);
+       return OCTETSTRING(sizeof(kseaf), kseaf);
+}
+
+/* 3GPP TS 33.501 Annex A.7 */
+OCTETSTRING f__kdf__kamf(const OCTETSTRING& kseaf, const OCTETSTRING &supi, 
const OCTETSTRING &abba)
+{
+       TTCN_Buffer ttcn_buf_kseaf(kseaf);
+       TTCN_Buffer ttcn_buf_supi(supi);
+       TTCN_Buffer ttcn_buf_abba(abba);
+       uint8_t kamf[32];
+
+       kdf_kamf(ttcn_buf_kseaf.get_data(),
+                 ttcn_buf_supi.get_data(), ttcn_buf_supi.get_len(),
+                 ttcn_buf_abba.get_data(), kamf);
+       return OCTETSTRING(sizeof(kamf), kamf);
+}
+
+/* 3GPP TS 33.501 Annex A.8 */
+OCTETSTRING f__kdf__ng__nas__algo(const OCTETSTRING& kamf, const OCTETSTRING 
&algo_type, const OCTETSTRING &algo_id)
+{
+       TTCN_Buffer ttcn_buf_kamf(kamf);
+       TTCN_Buffer ttcn_buf_algo_type(algo_type);
+       TTCN_Buffer ttcn_buf_algo_id(algo_id);
+       uint8_t out[32];
+
+       kdf_ng_nas_algo(ttcn_buf_kamf.get_data(),
+                       algo_type[0].get_octet(),
+                       algo_id[0].get_octet(), out);
+       return OCTETSTRING(sizeof(out), out);
+}
+
 }
diff --git a/library/NG_CryptoFunctions.ttcn b/library/NG_CryptoFunctions.ttcn
index fbbe57e..2ad0753 100644
--- a/library/NG_CryptoFunctions.ttcn
+++ b/library/NG_CryptoFunctions.ttcn
@@ -15,13 +15,43 @@
 import from General_Types all;
 import from Misc_Helpers all;

+import from Snow3G_Functions all;
+
 import from NAS_CommonTypeDefs all;
+import from NG_NAS_Common all;
+import from NG_NAS_TypeDefs all;
+import from NG_NAS_MsgContainers all;
+import from NG_NAS_Osmo_Templates all;
+import from NG_NAS_Functions all;

 
/*********************************************************************************
  * low-level API (external C/C++ code)
  
*********************************************************************************/

-/* 3GPP TS 33.102 Figure 9, 3GPP TS 35.206 Annex 3 */
+/* 3GPP TS 33.501 Annex A.2 */
+external function f_kdf_kausf(in OCT16 ck, in OCT16 ik, octetstring ssn,
+                             in OCT16 autn) return OCT32;
+
+/* 3GPP TS 33.501 Annex A.6 */
+external function f_kdf_kseaf(in OCT32 kausf, octetstring ssn) return OCT32;
+
+/* 3GPP TS 33.501 Annex A.7 */
+external function f_kdf_kamf(in OCT32 kseaf, octetstring p0, OCT2 abba) return 
OCT32;
+
+/* 3GPP TS 33.501 Annex A.8 */
+const OCT1 KDF_ALGO_TYPE_NAS_ENC := '01'O;
+const OCT1 KDF_ALGO_TYPE_NAS_INT := '02'O;
+external function f_kdf_ng_nas_algo(in OCT32 kamf, in OCT1 algo_type, in OCT1 
algo_id) return OCT32;
+function f_kdf_ng_nas_enc(in OCT32 kamf, in NG_NAS_ALG_ENC algo_id) return 
OCT32
+{
+       return f_kdf_ng_nas_algo(kamf, KDF_ALGO_TYPE_NAS_ENC, 
int2oct(enum2int(algo_id), 1));
+}
+function f_kdf_ng_nas_int(in OCT32 kamf, in NG_NAS_ALG_INT algo_id) return 
OCT32
+{
+       return f_kdf_ng_nas_algo(kamf, KDF_ALGO_TYPE_NAS_INT, 
int2oct(enum2int(algo_id), 1));
+}
+
+/* 3GPP TS 33.102 Figure 9, 3GPP TS 35.206 Annex 3, 3GPP TS 33.501 Annex A.4 */
 external function f_kdf_xres_star(octetstring ssn, OCT16 ck, OCT16 ik, OCT16 
rand,
                                  octetstring xres) return OCT16;

@@ -75,4 +105,165 @@
        return char2oct(f_NG_NAS_ServingNetworkName(plmn_id, NID));
 }

+function f_NG_NAS_mac_calc(NG_NAS_ALG_INT alg, OCT32 k_nas_int, integer seq_nr,
+                       integer bearer, boolean is_downlink, octetstring data) 
return OCT4 {
+       select (alg) {
+       case (NG_NAS_ALG_IP_EIA0) {
+               return '00000000'O;
+               }
+       case (NG_NAS_ALG_IP_EIA1) {
+               return f_snow_3g_f9(substr(k_nas_int, 16, 16), seq_nr, 
bit2int(int2bit(bearer, 32) << 27), is_downlink, data);
+               }
+       case else {
+               Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
log2str("Unsupported EIA: ", alg));
+               return '00000000'O; /* never reached */
+               }
+       }
+}
+
+/*********************************************************************************
+ * high-level API (full NAS encapsulation/decapsulation)
+ 
*********************************************************************************/
+
+ type enumerated NG_NAS_Role {
+       NG_NAS_ROLE_UE, /* ATS implements/emulates UE */
+       NG_NAS_ROLE_AMF /* ATS implements/emulates AMF */
+};
+
+type enumerated NG_NAS_ALG_INT {
+       NG_NAS_ALG_IP_EIA0,     /* no integrity protection */
+       NG_NAS_ALG_IP_EIA1,     /* SNOW-3G F9 based */
+       NG_NAS_ALG_IP_EIA2,     /* AES based */
+       NG_NAS_ALG_IP_EIA3      /* ZUC */
+};
+type enumerated NG_NAS_ALG_ENC {
+       NG_NAS_ALG_ENC_EEA0,    /* no encryption */
+       NG_NAS_ALG_ENC_EEA1,    /* SNOW-3G F8 based */
+       NG_NAS_ALG_ENC_EEA2,    /* AES based */
+       NG_NAS_ALG_ENC_EEA3     /* ZUC */
+};
+
+type record NG_NAS_UE_State {
+       NG_NAS_Role role, /* ATS implements UE or AMR role? */
+       NG_NAS_ALG_INT alg_int, /* NAS Integrity Protection Algorithm */
+       OCT32 k_nas_int,        /* NAS Integrity Protection Key */
+       NG_NAS_ALG_ENC alg_enc, /* NAS Encryption Algorithm */
+       OCT32 k_nas_enc,        /* NAS Encryption Key */
+       integer rx_count,       /* frame counter (ATS rx side) */
+       integer tx_count,       /* frame counter (ATS tx side) */
+       boolean new_ctx,        /* Use "New EPS Security Context" when building 
next sec_hdr_t */
+       boolean use_int,        /* Whether to use "Integrity" in sec_hdr_t */
+       boolean use_enc         /* Whether to use "Ciphering" in sec_hdr_t */
+};
+
+template (value) NG_NAS_UE_State t_NG_NAS_UE_State(NG_NAS_Role role) := {
+       role := role,
+       alg_int := NG_NAS_ALG_IP_EIA0,
+       k_nas_int := 
'0000000000000000000000000000000000000000000000000000000000000000'O,
+       alg_enc := NG_NAS_ALG_ENC_EEA0,
+       k_nas_enc := 
'0000000000000000000000000000000000000000000000000000000000000000'O,
+       rx_count := 0,
+       tx_count := 0,
+       new_ctx := false,
+       use_int := false,
+       use_enc := false
+};
+
+/* determine if a received (from the IUT) message is downlink or not */
+private function f_rx_is_downlink(in NG_NAS_UE_State nus) return boolean
+{
+       if (nus.role == NG_NAS_ROLE_UE) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+/* determine if a message transmitted to the IUT message is downlink or not */
+private function f_tx_is_downlink(in NG_NAS_UE_State nus) return boolean
+{
+       return not f_rx_is_downlink(nus);
+}
+
+private function f_NG_NAS_check_ip(inout NG_NAS_UE_State nus,
+                                  in NG_SECURITY_PROTECTED_NAS_MESSAGE 
secp_nas) return boolean
+{
+       var octetstring data_with_seq := secp_nas.sequenceNumber & 
secp_nas.plainNASMessage;
+       var OCT4 exp_mac := f_NG_NAS_mac_calc(nus.alg_int, nus.k_nas_int, 
nus.rx_count, bit2int(tsc_NG_RegResult_3GPP),
+                                          f_rx_is_downlink(nus), 
data_with_seq);
+
+       if (nus.rx_count != oct2int(secp_nas.sequenceNumber)) {
+               setverdict(fail, "Received NAS SeqNr ", secp_nas.sequenceNumber,
+                          " doesn't match expected SeqNr ", nus.rx_count, ": 
", secp_nas, " | nus: ", nus);
+               return false;
+       }
+       if (exp_mac != secp_nas.messageAuthenticationCode) {
+               setverdict(fail, "Received NAS MAC ", 
secp_nas.messageAuthenticationCode,
+                          " doesn't match expected MAC ", exp_mac, ": ", 
secp_nas, " | nus: ", nus);
+               return false;
+       }
+       return true;
+}
+
+/* try to decapsulate (MAC verify, decrypt) NAS message */
+function f_NG_NAS_try_decaps_dl(inout NG_NAS_UE_State nus, 
NG_NAS_DL_Message_Type nas) return NG_NAS_DL_Message_Type
+{
+       var NG_SECURITY_PROTECTED_NAS_MESSAGE secp_nas;
+
+       /* transparently pass through any non-protected NAS */
+       if (not match(nas, cr_NG_SECURITY_PROTECTED_NAS_MESSAGE)) {
+               return nas;
+       }
+
+       /* process any security-protected NAS */
+       secp_nas := nas.security_Protected_Nas_Message;
+       select (secp_nas.securityHeaderType) {
+       case ('0011'B) { /* IP with new 5GS security context */
+               nus.new_ctx := true;
+               nus.rx_count := 0;
+               nus.alg_int := NG_NAS_ALG_IP_EIA1; /* FIXME: from decoded inner 
message! */
+               if (not f_NG_NAS_check_ip(nus, secp_nas)) {
+                       Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
"f_NG_NAS_check_ip() failed");
+               }
+               nus.rx_count := nus.rx_count + 1;
+               return dec_NG_NAS_DL_Message_Type(secp_nas.plainNASMessage);
+               }
+       case ('0001'B) { /* IP only */
+               nus.new_ctx := false;
+               if (not f_NG_NAS_check_ip(nus, secp_nas)) {
+                       Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
"f_NG_NAS_check_ip() failed");
+               }
+               nus.rx_count := nus.rx_count + 1;
+               return dec_NG_NAS_DL_Message_Type(secp_nas.plainNASMessage);
+               }
+//     case ('0010'B) { /* IP + ciphered */
+//             nus.new_ctx := false;
+//             if (not f_NG_NAS_check_ip(nus, secp_nas)) {
+//                     Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
"f_NG_NAS_check_ip() failed");
+//             }
+//             nus.rx_count := nus.rx_count + 1;
+//             f_nas_encrypt(nus.alg_enc, nus.k_nas_enc, nus.rx_count, 0,
+//                           f_rx_is_downlink(nus), secp_nas.nAS_Message);
+//             return dec_NG_NAS_DL_Message_Type(secp_nas.plainNASMessage);
+//             }
+//     case ('0100'B) { /* IP + ciphered; new EPS security context */
+//             nus.new_ctx := true;
+//             nus.rx_count := 0;
+//             if (not f_NG_NAS_check_ip(nus, secp_nas)) {
+//                     Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
"f_NG_NAS_check_ip() failed");
+//             }
+//             f_nas_encrypt(nus.alg_enc, nus.k_nas_enc, nus.rx_count, 0,
+//                           f_rx_is_downlink(nus), secp_nas.nAS_Message);
+//             nus.rx_count := nus.rx_count + 1;
+//             return dec_NG_NAS_DL_Message_Type(secp_nas.plainNASMessage);
+//             }
+       //case ('0101'B) { /* IP + partially ciphered */ }
+       //case ('1100'B) { /* Service Request Message */ }
+       case else  {
+               Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, 
log2str("Implement SecHdrType for ", secp_nas));
+               mtc.stop; /* make compiler happy about not returning. */
+               }
+       }
+}
+
 }
diff --git a/library/NG_NAS_Osmo_Templates.ttcn 
b/library/NG_NAS_Osmo_Templates.ttcn
index 5887fa6..72878cb 100644
--- a/library/NG_NAS_Osmo_Templates.ttcn
+++ b/library/NG_NAS_Osmo_Templates.ttcn
@@ -134,4 +134,34 @@
        }
 }

+/* 24.501 cl. 8.2.25 */
+template (present) NG_NAS_DL_Message_Type
+cr_NG_SECURITY_MODE_COMMAND(template (present) NG_NAS_SecurityAlgorithms 
p_Algs := ?,
+                           template (present) NAS_KsiValue p_KeySetId := ?,
+                           template (present) NG_UE_SecurityCapability p_UECap 
:= ?,
+                           template IMEISV_Request p_IMEISV := *,
+                           template NAS_SecurityAlgorithms p_EPSAlgs := *,
+                           template AdditionalSecurityInfo p_AddInfo := *,
+                           template EAP_Message p_EAP := *,
+                           template ABBA p_ABBA := *,
+                           template S1_UE_SecurityCapability 
p_ReplayedSecurityCap := *) :=
+{
+       security_Mode_Command := {
+               protocolDiscriminator   := tsc_EPD_GMM,                     /* 
cl. 9.2       M V 1   */
+               spareHalfOctet          := tsc_SpareHalfOctet,              /* 
cl. 9.3      M V 1/2 */
+               securityHeaderType      := tsc_SHT_NoSecurityProtection,
+               messageType             := tsc_MT_NG_SecurityModeCommand,   /* 
cl. 9.7      M V 1   */
+               nasSecurityAlgorithms   := p_Algs,                          /* 
cl. 9.11.3.34 M V 1   */
+               spareHalfOctet2         := tsc_SpareHalfOctet,              /* 
cl. 9.3      M V 1/2 */
+               ngNasKSI                := {iei := ?, tsc := ?, nasKeySetId := 
p_KeySetId}, // FIXME FSCOM To be enhanced
+               ueSecurityCapability    := p_UECap,                         /* 
cl. 9.11.3.54 M LV 3-9 */
+               imeisvRequest           := p_IMEISV,                        /* 
cl. 9.11.3.28 O TV 1 IEI=E */
+               epsSecurityAlgorithms   := p_EPSAlgs,                       /* 
cl. 9.11.3.25 O TV 2 IEI=57 */
+               add5GSecurityInfo       := p_AddInfo,                       /* 
cl. 9.11.3.12 O TLV 3 IEI=36 */
+               eapMessage              := p_EAP,                           /* 
cl. 9.11.2.2  O TLV-E 7-1503 IEI=78 */
+               abba                    := p_ABBA,                          /* 
cl. 9.11.3.10 O TLV 4-n IEI=38 Dec18 */
+               replayedUESecurityCap   := p_ReplayedSecurityCap            /* 
cl. 9.11.3.48 O TLV 4-7 IEI=19 Dec18 */
+       }
+}
+
 }
diff --git a/library/ng_crypto/key_derivation.c 
b/library/ng_crypto/key_derivation.c
index 29e0849..9be5417 100644
--- a/library/ng_crypto/key_derivation.c
+++ b/library/ng_crypto/key_derivation.c
@@ -5,6 +5,38 @@

 #include "key_derivation.h"

+/* 3GPP TS 33.501 A.2 KAUSF derivation function */
+void kdf_kausf(const uint8_t *ck, const uint8_t *ik,
+              const uint8_t *serving_network_name, uint16_t 
serving_network_name_len,
+              const uint8_t *autn,
+              uint8_t *out)
+{
+       uint8_t s[1024];
+       uint8_t key[32];
+       size_t pos = 0;
+       uint16_t lenbe;
+       int i;
+
+       memcpy(&key[0], ck, 16);
+       memcpy(&key[16], ik, 16);
+
+       s[pos++] = 0x6A; /* FC Value */
+
+       memcpy(&s[pos], serving_network_name, serving_network_name_len);
+       pos += serving_network_name_len;
+       lenbe = htons(serving_network_name_len);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       memcpy(&s[pos], autn, 6);
+       pos += 6;
+       lenbe = htons(6);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       gnutls_hmac_fast(GNUTLS_MAC_SHA256, key, sizeof(key), s, pos, out);
+}
+
 /* 3GPP TS 33.501 A.4 RES* and XRES* derivation function */
 void kdf_xres_star(const uint8_t *serving_network_name,
                   uint16_t serving_network_name_len,
@@ -47,3 +79,78 @@

        memcpy(out, tmp_out+16, 16);
 }
+
+/* 3GPP TS 33.501 A.6 KSEAF derivation function */
+void kdf_kseaf(const uint8_t *kausf,
+              const uint8_t *serving_network_name, uint16_t 
serving_network_name_len,
+              uint8_t *out)
+{
+       uint8_t s[1024];
+       size_t pos = 0;
+       uint16_t lenbe;
+       int i;
+
+       s[pos++] = 0x6C; /* FC Value */
+
+       memcpy(&s[pos], serving_network_name, serving_network_name_len);
+       pos += serving_network_name_len;
+       lenbe = htons(serving_network_name_len);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       gnutls_hmac_fast(GNUTLS_MAC_SHA256, kausf, 32, s, pos, out);
+}
+
+/* 3GPP TS 33.501 A.7 KAMF derivation function */
+void kdf_kamf(const uint8_t *kseaf,
+             const uint8_t *supi, uint16_t supi_len,
+             const uint8_t *abba,
+             uint8_t *out)
+{
+       uint8_t s[1024];
+       size_t pos = 0;
+       uint16_t lenbe;
+       int i;
+
+       s[pos++] = 0x6D; /* FC Value */
+
+       memcpy(&s[pos], supi, supi_len);
+       pos += supi_len;
+       lenbe = htons(supi_len);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       memcpy(&s[pos], abba, 2);
+       pos += 2;
+       lenbe = htons(2);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       gnutls_hmac_fast(GNUTLS_MAC_SHA256, kseaf, 32, s, pos, out);
+}
+
+/* 3GPP TS 33.501 A.8 Algorithm key derivation functions */
+void kdf_ng_nas_algo(const uint8_t *kamf,
+                    uint8_t algo_type,
+                    uint8_t algo_id,
+                    uint8_t *out)
+{
+       uint8_t s[1024];
+       size_t pos = 0;
+       uint16_t lenbe;
+       int i;
+
+       s[pos++] = 0x69; /* FC Value */
+
+       s[pos++] = algo_type;
+       lenbe = htons(1);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       s[pos++] = algo_id;
+       lenbe = htons(1);
+       memcpy(&s[pos], &lenbe, 2);
+       pos += 2;
+
+       gnutls_hmac_fast(GNUTLS_MAC_SHA256, kamf, 32, s, pos, out);
+}
\ No newline at end of file
diff --git a/library/ng_crypto/key_derivation.h 
b/library/ng_crypto/key_derivation.h
index f78d746..d5279c2 100644
--- a/library/ng_crypto/key_derivation.h
+++ b/library/ng_crypto/key_derivation.h
@@ -3,6 +3,20 @@
 #include <stdint.h>
 #include <unistd.h>

+void kdf_kausf(const uint8_t *ck, const uint8_t *ik,
+              const uint8_t *serving_network_name, uint16_t 
serving_network_name_len,
+              const uint8_t *autn,
+              uint8_t *out);
+
+void kdf_kseaf(const uint8_t *kausf,
+              const uint8_t *serving_network_name, uint16_t 
serving_network_name_len,
+              uint8_t *out);
+
+void kdf_kamf(const uint8_t *kseaf,
+             const uint8_t *supi, uint16_t supi_len,
+             const uint8_t *abba,
+             uint8_t *out);
+
 void kdf_xres_star(const uint8_t *serving_network_name,
                   uint16_t serving_network_name_len,
                   const uint8_t *ck,
@@ -10,3 +24,8 @@
                   const uint8_t *rand,
                   const uint8_t *xres, size_t xres_len,
                   uint8_t *out);
+
+void kdf_ng_nas_algo(const uint8_t *kamf,
+                    uint8_t algo_type,
+                    uint8_t algo_id,
+                    uint8_t *out);

--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40440?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: I118081af10f260513734550854c3a1751e32cbb4
Gerrit-Change-Number: 40440
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pes...@sysmocom.de>

Reply via email to