diff --git a/lib/include/srsran/common/security.h b/lib/include/srsran/common/security.h index b72117d81..fa1bd52b6 100644 --- a/lib/include/srsran/common/security.h +++ b/lib/include/srsran/common/security.h @@ -128,59 +128,79 @@ int kdf_common(const uint8_t fc, const std::vector& P3, uint8_t* output); +uint8_t security_generate_k_asme(const uint8_t* ck, + const uint8_t* ik, + const uint8_t* ak_xor_sqn, + const uint16_t mcc, + const uint16_t mnc, + uint8_t* k_asme); + +uint8_t security_generate_k_ausf(const uint8_t* ck, + const uint8_t* ik, + const uint8_t* ak_xor_sqn, + const char* serving_network_name, + uint8_t* k_ausf); + +uint8_t security_generate_k_amf(const uint8_t* k_seaf, + const char* supi_, + const uint8_t* abba_, + const uint32_t abba_len, + uint8_t* k_amf); + +uint8_t security_generate_k_seaf(const uint8_t* k_ausf, const char* serving_network_name, uint8_t* k_seaf); + +uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count, uint8_t* k_enb); + uint8_t -security_generate_k_asme(uint8_t* ck, uint8_t* ik, uint8_t* ak_xor_sqn, uint16_t mcc, uint16_t mnc, uint8_t* k_asme); - -uint8_t security_generate_k_ausf(uint8_t* ck, - uint8_t* ik, - uint8_t* ak_xor_sqn, - const char* serving_network_name, - uint8_t* k_ausf); - -uint8_t security_generate_k_enb(uint8_t* k_asme, uint32_t nas_count, uint8_t* k_enb); - -uint8_t security_generate_k_enb_star(uint8_t* k_enb, uint32_t pci, uint32_t earfcn, uint8_t* k_enb_star); - -uint8_t security_generate_nh(uint8_t* k_asme, uint8_t* sync, uint8_t* nh); - -uint8_t security_generate_k_nas(uint8_t* k_asme, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_nas_enc, - uint8_t* k_nas_int); - -uint8_t security_generate_k_rrc(uint8_t* k_enb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_rrc_enc, - uint8_t* k_rrc_int); - -uint8_t security_generate_k_up(uint8_t* k_enb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_up_enc, - uint8_t* k_up_int); - -uint8_t security_generate_k_nr_rrc(uint8_t* k_gnb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_rrc_enc, - uint8_t* k_rrc_int); - -uint8_t security_generate_k_nr_up(uint8_t* k_gnb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_up_enc, - uint8_t* k_up_int); - -uint8_t security_generate_sk_gnb(uint8_t* k_enb, uint8_t* sk_gnb, uint16_t scg_count); -uint8_t security_generate_res_star(uint8_t* ck, - uint8_t* ik, - const char* serving_network_name, - uint8_t* rand, - uint8_t* res, - size_t res_len, - uint8_t* res_star); +security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci, const uint32_t earfcn, uint8_t* k_enb_star); + +uint8_t security_generate_nh(const uint8_t* k_asme, const uint8_t* sync, uint8_t* nh); + +uint8_t security_generate_k_nas(const uint8_t* k_asme, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_nas_enc, + uint8_t* k_nas_int); + +uint8_t security_generate_k_nas_5g(const uint8_t* k_amf, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_nas_enc, + uint8_t* k_nas_int); + +uint8_t security_generate_k_rrc(const uint8_t* k_enb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_rrc_enc, + uint8_t* k_rrc_int); + +uint8_t security_generate_k_up(const uint8_t* k_enb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_up_enc, + uint8_t* k_up_int); + +uint8_t security_generate_k_nr_rrc(const uint8_t* k_gnb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_rrc_enc, + uint8_t* k_rrc_int); + +uint8_t security_generate_k_nr_up(const uint8_t* k_gnb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_up_enc, + uint8_t* k_up_int); + +uint8_t security_generate_sk_gnb(const uint8_t* k_enb, const uint16_t scg_count, uint8_t* sk_gnb); + +uint8_t security_generate_res_star(const uint8_t* ck, + const uint8_t* ik, + const char* serving_network_name, + const uint8_t* rand, + const uint8_t* res, + const size_t res_len, + uint8_t* res_star); /****************************************************************************** * Integrity Protection *****************************************************************************/ diff --git a/lib/include/srsran/interfaces/ue_usim_interfaces.h b/lib/include/srsran/interfaces/ue_usim_interfaces.h index b2d53b2c0..5a7fd84bc 100644 --- a/lib/include/srsran/interfaces/ue_usim_interfaces.h +++ b/lib/include/srsran/interfaces/ue_usim_interfaces.h @@ -42,18 +42,26 @@ public: uint8_t* res, int* res_len, uint8_t* k_asme) = 0; - virtual void generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; - virtual bool generate_res_star(uint8_t* rand, - uint8_t* res, - int res_len, - const char* serving_network_name, - uint8_t* res_start, - uint32_t* res_star_len) = 0; + virtual auth_result_t generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf) = 0; + + virtual void generate_nas_keys(uint8_t* k_asme, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; + + virtual bool generate_nas_keys_5g(uint8_t* k_amf, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; }; // USIM interface for RRC diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index 42769e64c..ae02f6703 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -58,8 +58,12 @@ namespace srsran { * Key Generation *****************************************************************************/ -uint8_t -security_generate_k_asme(uint8_t* ck, uint8_t* ik, uint8_t* ak_xor_sqn_, uint16_t mcc, uint16_t mnc, uint8_t* k_asme) +uint8_t security_generate_k_asme(const uint8_t* ck, + const uint8_t* ik, + const uint8_t* ak_xor_sqn_, + const uint16_t mcc, + const uint16_t mnc, + uint8_t* k_asme) { if (ck == NULL || ik == NULL || ak_xor_sqn_ == NULL || k_asme == NULL) { log_error("Invalid inputs"); @@ -100,11 +104,11 @@ security_generate_k_asme(uint8_t* ck, uint8_t* ik, uint8_t* ak_xor_sqn_, uint16_ return SRSRAN_SUCCESS; } -uint8_t security_generate_k_ausf(uint8_t* ck, - uint8_t* ik, - uint8_t* ak_xor_sqn_, - const char* serving_network_name, - uint8_t* k_ausf) +uint8_t security_generate_k_ausf(const uint8_t* ck, + const uint8_t* ik, + const uint8_t* ak_xor_sqn_, + const char* serving_network_name, + uint8_t* k_ausf) { if (ck == NULL || ik == NULL || ak_xor_sqn_ == NULL || serving_network_name == NULL || k_ausf == NULL) { log_error("Invalid inputs"); @@ -128,7 +132,7 @@ uint8_t security_generate_k_ausf(uint8_t* ck, memcpy(ak_xor_sqn.data(), ak_xor_sqn_, ak_xor_sqn.size()); uint8_t output[32]; - if (kdf_common(FC_5G_RES_STAR_DERIVATION, key, ssn, ak_xor_sqn, output) != SRSRAN_SUCCESS) { + if (kdf_common(FC_5G_KAUSF_DERIVATION, key, ssn, ak_xor_sqn, output) != SRSRAN_SUCCESS) { log_error("Failed to run kdf_common"); return SRSRAN_ERROR; } @@ -137,7 +141,60 @@ uint8_t security_generate_k_ausf(uint8_t* ck, return SRSRAN_SUCCESS; } -uint8_t security_generate_k_enb(uint8_t* k_asme, uint32_t nas_count_, uint8_t* k_enb) +uint8_t security_generate_k_seaf(const uint8_t* k_ausf, const char* serving_network_name, uint8_t* k_seaf) +{ + if (k_ausf == NULL || serving_network_name == NULL || k_seaf == NULL) { + log_error("Invalid inputs"); + return SRSRAN_ERROR; + } + + std::array key; + memcpy(key.data(), k_ausf, 32); + + // Serving Network Name + std::vector ssn; + ssn.resize(strlen(serving_network_name)); + memcpy(ssn.data(), serving_network_name, ssn.size()); + + if (kdf_common(FC_5G_KSEAF_DERIVATION, key, ssn, k_seaf) != SRSRAN_SUCCESS) { + log_error("Failed to run kdf_common"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + +uint8_t security_generate_k_amf(const uint8_t* k_seaf, + const char* supi_, + const uint8_t* abba_, + const uint32_t abba_len, + uint8_t* k_amf) +{ + if (k_seaf == NULL || supi_ == NULL || abba_ == NULL || k_amf == NULL) { + log_error("Invalid inputs"); + return SRSRAN_ERROR; + } + + std::array key; + memcpy(key.data(), k_seaf, 32); + + // SUPI + std::vector supi; + supi.resize(strlen(supi_)); + memcpy(supi.data(), supi_, supi.size()); + + // ABBA + std::vector abba; + abba.resize(abba_len); + memcpy(abba.data(), abba_, abba.size()); + + if (kdf_common(FC_5G_KAMF_DERIVATION, key, supi, abba, k_amf) != SRSRAN_SUCCESS) { + log_error("Failed to run kdf_common"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + +uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count_, uint8_t* k_enb) { if (k_asme == NULL || k_enb == NULL) { log_error("Invalid inputs"); @@ -162,7 +219,8 @@ uint8_t security_generate_k_enb(uint8_t* k_asme, uint32_t nas_count_, uint8_t* k return SRSRAN_SUCCESS; } -uint8_t security_generate_k_enb_star(uint8_t* k_enb, uint32_t pci_, uint32_t earfcn_, uint8_t* k_enb_star) +uint8_t +security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci_, const uint32_t earfcn_, uint8_t* k_enb_star) { if (k_enb == NULL || k_enb_star == NULL) { log_error("Invalid inputs"); @@ -190,7 +248,7 @@ uint8_t security_generate_k_enb_star(uint8_t* k_enb, uint32_t pci_, uint32_t ear return SRSRAN_SUCCESS; } -uint8_t security_generate_nh(uint8_t* k_asme, uint8_t* sync_, uint8_t* nh) +uint8_t security_generate_nh(const uint8_t* k_asme, const uint8_t* sync_, uint8_t* nh) { if (k_asme == NULL || sync_ == NULL || nh == NULL) { log_error("Invalid inputs"); @@ -211,11 +269,11 @@ uint8_t security_generate_nh(uint8_t* k_asme, uint8_t* sync_, uint8_t* nh) return SRSRAN_SUCCESS; } -uint8_t security_generate_k_nas(uint8_t* k_asme, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_nas_enc, - uint8_t* k_nas_int) +uint8_t security_generate_k_nas(const uint8_t* k_asme, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_nas_enc, + uint8_t* k_nas_int) { if (k_asme == NULL || k_nas_enc == NULL || k_nas_int == NULL) { log_error("Invalid inputs"); @@ -260,11 +318,60 @@ uint8_t security_generate_k_nas(uint8_t* k_asme, return SRSRAN_SUCCESS; } -uint8_t security_generate_k_rrc(uint8_t* k_enb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_rrc_enc, - uint8_t* k_rrc_int) +uint8_t security_generate_k_nas_5g(const uint8_t* k_amf, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_nas_enc, + uint8_t* k_nas_int) +{ + if (k_amf == NULL || k_nas_enc == NULL || k_nas_int == NULL) { + log_error("Invalid inputs"); + return SRSRAN_ERROR; + } + std::array key; + + memcpy(key.data(), k_amf, 32); + + // Derive NAS ENC + // algorithm type distinguisher + std::vector algo_distinguisher; + algo_distinguisher.resize(1); + algo_distinguisher[0] = ALGO_5G_DISTINGUISHER_NAS_ENC_ALG; + + // algorithm type distinguisher + std::vector algorithm_identity; + algorithm_identity.resize(1); + algorithm_identity[0] = enc_alg_id; + + if (kdf_common(FC_5G_ALGORITHM_KEY_DERIVATION, key, algo_distinguisher, algorithm_identity, k_nas_enc) != + SRSRAN_SUCCESS) { + log_error("Failed to run kdf_common"); + return SRSRAN_ERROR; + } + + // Derive NAS INT + // algorithm type distinguisher + algo_distinguisher.resize(1); + algo_distinguisher[0] = ALGO_5G_DISTINGUISHER_NAS_INT_ALG; + + // algorithm type distinguisher + algorithm_identity.resize(1); + algorithm_identity[0] = int_alg_id; + + // Derive NAS int + if (kdf_common(FC_5G_ALGORITHM_KEY_DERIVATION, key, algo_distinguisher, algorithm_identity, k_nas_int) != + SRSRAN_SUCCESS) { + log_error("Failed to run kdf_common"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + +uint8_t security_generate_k_rrc(const uint8_t* k_enb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_rrc_enc, + uint8_t* k_rrc_int) { if (k_enb == NULL || k_rrc_enc == NULL || k_rrc_int == NULL) { log_error("Invalid inputs"); @@ -309,11 +416,11 @@ uint8_t security_generate_k_rrc(uint8_t* k_enb, return SRSRAN_SUCCESS; } -uint8_t security_generate_k_up(uint8_t* k_enb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_up_enc, - uint8_t* k_up_int) +uint8_t security_generate_k_up(const uint8_t* k_enb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_up_enc, + uint8_t* k_up_int) { if (k_enb == NULL || k_up_enc == NULL || k_up_int == NULL) { log_error("Invalid inputs"); @@ -358,7 +465,7 @@ uint8_t security_generate_k_up(uint8_t* k_enb, return SRSRAN_SUCCESS; } -uint8_t security_generate_sk_gnb(uint8_t* k_enb, uint8_t* sk_gnb, uint16_t scg_count_) +uint8_t security_generate_sk_gnb(const uint8_t* k_enb, const uint16_t scg_count_, uint8_t* sk_gnb) { if (k_enb == NULL || sk_gnb == NULL) { log_error("Invalid inputs"); @@ -385,11 +492,11 @@ uint8_t security_generate_sk_gnb(uint8_t* k_enb, uint8_t* sk_gnb, uint16_t scg_c return SRSRAN_SUCCESS; } -uint8_t security_generate_k_nr_rrc(uint8_t* k_gnb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_rrc_enc, - uint8_t* k_rrc_int) +uint8_t security_generate_k_nr_rrc(const uint8_t* k_gnb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_rrc_enc, + uint8_t* k_rrc_int) { if (k_gnb == NULL || k_rrc_enc == NULL || k_rrc_int == NULL) { log_error("Invalid inputs"); @@ -434,11 +541,11 @@ uint8_t security_generate_k_nr_rrc(uint8_t* k_gnb, return SRSRAN_SUCCESS; } -uint8_t security_generate_k_nr_up(uint8_t* k_gnb, - CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, - INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, - uint8_t* k_up_enc, - uint8_t* k_up_int) +uint8_t security_generate_k_nr_up(const uint8_t* k_gnb, + const CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + const INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t* k_up_enc, + uint8_t* k_up_int) { if (k_gnb == NULL || k_up_enc == NULL || k_up_int == NULL) { log_error("Invalid inputs"); @@ -483,13 +590,13 @@ uint8_t security_generate_k_nr_up(uint8_t* k_gnb, return SRSRAN_SUCCESS; } -uint8_t security_generate_res_star(uint8_t* ck, - uint8_t* ik, - const char* serving_network_name, - uint8_t* rand_, - uint8_t* res_, - size_t res_len_, - uint8_t* res_star) +uint8_t security_generate_res_star(const uint8_t* ck, + const uint8_t* ik, + const char* serving_network_name, + const uint8_t* rand_, + const uint8_t* res_, + const size_t res_len_, + uint8_t* res_star) { if (ck == NULL || ik == NULL || serving_network_name == NULL || rand_ == NULL || res_ == NULL || res_star == NULL) { log_error("Invalid inputs"); diff --git a/lib/test/common/test_security_kdf.cc b/lib/test/common/test_security_kdf.cc index ca1676acd..06612fd30 100644 --- a/lib/test/common/test_security_kdf.cc +++ b/lib/test/common/test_security_kdf.cc @@ -40,7 +40,7 @@ int test_set_ksg() 0x9e, 0x5d, 0x28, 0xaf, 0x0e, 0x83, 0x22, 0xeb, 0x57, 0x3a, 0xda, 0x36, 0xf2, 0x1a, 0x5a, 0x89}; uint8_t sk_gnb_o[32]; uint16_t scg_counter = 0; - err_lte = srsran::security_generate_sk_gnb(k_enb, sk_gnb_o, scg_counter); + err_lte = srsran::security_generate_sk_gnb(k_enb, scg_counter, sk_gnb_o); TESTASSERT(err_lte == SRSRAN_SUCCESS); logger.info(&sk_gnb_o[0], sizeof(sk_gnb_o), "sk gnb o:"); uint8_t sk_gnb[] = {0x45, 0xcb, 0xc3, 0xf8, 0xa8, 0x11, 0x93, 0xfd, 0x5c, 0x52, 0x29, 0x30, 0x0d, 0x59, 0xed, 0xf8, @@ -298,12 +298,126 @@ int test_generate_res_star() uint8_t res_star[] = {0xb0, 0xe3, 0x5b, 0x23, 0xdb, 0xd7, 0xa1, 0x8c, 0x84, 0x8b, 0xfa, 0xd9, 0x11, 0x35, 0xe3, 0xfd}; - logger.info(res_star, 16, "RES STAR:"); + logger.info(res_star_o, 16, "RES STAR:"); TESTASSERT(arrcmp(res_star_o, res_star, sizeof(res_star)) == 0); return SRSRAN_SUCCESS; } +int test_generate_k_ausf() +{ + auto& logger = srslog::fetch_basic_logger("LOG", false); + uint8_t k_ausf_o[32]; + + uint8_t ck[] = {0x56, 0x1e, 0x05, 0xef, 0xbd, 0xf2, 0xef, 0xeb, 0x2d, 0x55, 0x8f, 0x04, 0x1c, 0x53, 0xc4, 0x45}; + uint8_t ik[] = {0x01, 0xe0, 0xf2, 0xf5, 0x53, 0x54, 0x31, 0x31, 0x2d, 0x57, 0x27, 0x98, 0x14, 0xcf, 0xcd, 0x89}; + uint8_t ak_xor_sqn[] = {0x30, 0x5e, 0xb0, 0x6b, 0x73, 0x07}; + std::string ssn = "5G:mnc070.mcc901.3gppnetwork.org"; + + TESTASSERT(srsran::security_generate_k_ausf(ck, ik, ak_xor_sqn, ssn.c_str(), k_ausf_o) == SRSRAN_SUCCESS); + + uint8_t k_ausf[] = {0xa2, 0xce, 0xb2, 0x0f, 0x79, 0x28, 0xbf, 0x15, 0x4d, 0x4b, 0x54, 0x8a, 0xee, 0x6d, 0x10, 0xa9, + 0x76, 0x01, 0x84, 0x7f, 0xd7, 0x2d, 0x2b, 0xc9, 0x01, 0x98, 0x2c, 0x08, 0x6e, 0xa0, 0xf3, 0x46}; + // TODO check the out put with k AMF + logger.info(k_ausf_o, 32, "K AUSF:"); + TESTASSERT(arrcmp(k_ausf_o, k_ausf, sizeof(k_ausf)) == 0); + + return SRSRAN_SUCCESS; +} + +int test_generate_k_seaf() +{ + auto& logger = srslog::fetch_basic_logger("LOG", false); + uint8_t k_seaf_o[32]; + + uint8_t k_ausf[] = {0xd9, 0xc8, 0xff, 0x91, 0xb6, 0x9e, 0x25, 0x0e, 0x25, 0x6e, 0x92, 0x46, 0x6a, 0xcf, 0x80, 0xa1, + 0xd8, 0x2b, 0x65, 0xf0, 0x94, 0xb7, 0xc0, 0x71, 0x19, 0x9c, 0x03, 0x12, 0xe0, 0x67, 0xff, 0x3b}; + std::string ssn = "5G:mnc070.mcc901.3gppnetwork.org"; + + TESTASSERT(srsran::security_generate_k_seaf(k_ausf, ssn.c_str(), k_seaf_o) == SRSRAN_SUCCESS); + + uint8_t k_seaf[] = {0x6c, 0x50, 0xbf, 0xa5, 0xf3, 0x2a, 0x89, 0xad, 0xe1, 0xee, 0x6c, 0x70, 0x7d, 0xe6, 0xdc, 0xfe, + 0xa0, 0x79, 0x0a, 0xfb, 0x6d, 0x14, 0xf9, 0xe5, 0x59, 0x43, 0xae, 0xda, 0x58, 0x33, 0x45, 0x48}; + + logger.info(k_seaf_o, 32, "K SEAF:"); + TESTASSERT(arrcmp(k_seaf_o, k_seaf, sizeof(k_seaf)) == 0); + + return SRSRAN_SUCCESS; +} + +int test_generate_k_amf() +{ + auto& logger = srslog::fetch_basic_logger("LOG", false); + uint8_t k_amf_o[32]; + + uint8_t k_seaf[] = {0x6c, 0x50, 0xbf, 0xa5, 0xf3, 0x2a, 0x89, 0xad, 0xe1, 0xee, 0x6c, 0x70, 0x7d, 0xe6, 0xdc, 0xfe, + 0xa0, 0x79, 0x0a, 0xfb, 0x6d, 0x14, 0xf9, 0xe5, 0x59, 0x43, 0xae, 0xda, 0x58, 0x33, 0x45, 0x48}; + + uint8_t abba[] = {0x00, 0x00}; + std::string supi = "901700000021309"; + + TESTASSERT(srsran::security_generate_k_amf(k_seaf, supi.c_str(), abba, sizeof(abba), k_amf_o) == SRSRAN_SUCCESS); + + uint8_t k_amf[] = {0x46, 0x23, 0x7e, 0xf0, 0x51, 0xd6, 0xa1, 0x6a, 0x39, 0x27, 0x52, 0x5f, 0xa6, 0x5c, 0xc3, 0x95, + 0x44, 0xcd, 0xfd, 0x79, 0x90, 0xb9, 0x46, 0xad, 0x79, 0x65, 0x30, 0xe6, 0xd7, 0x87, 0xa0, 0xda}; + + logger.info(k_amf_o, 32, "K AMF:"); + TESTASSERT(arrcmp(k_amf_o, k_amf, sizeof(k_amf)) == 0); + + return SRSRAN_SUCCESS; +} + +int test_generate_k_amf_2() +{ + auto& logger = srslog::fetch_basic_logger("LOG", false); + uint8_t k_amf_o[32]; + + uint8_t k_seaf[] = {0x30, 0x2a, 0xb7, 0xc9, 0x4f, 0xae, 0x97, 0xe0, 0x43, 0xb3, 0x70, 0xd3, 0xeb, 0x1f, 0x54, 0x68, + 0xf6, 0xa1, 0xd4, 0x55, 0xd6, 0x56, 0xa4, 0xca, 0xb3, 0x51, 0xea, 0xcf, 0xb9, 0xf7, 0xe1, 0x36}; + + uint8_t abba[] = {0x00, 0x00}; + std::string supi = "001010123456780"; + + TESTASSERT(srsran::security_generate_k_amf(k_seaf, supi.c_str(), abba, sizeof(abba), k_amf_o) == SRSRAN_SUCCESS); + + uint8_t k_amf[] = {0x8f, 0x2a, 0x5d, 0x6c, 0x12, 0x60, 0x8d, 0x8a, 0x0a, 0x8d, 0x33, 0x0a, 0x71, 0x9d, 0xee, 0x07, + 0x22, 0x6b, 0x47, 0x41, 0x7b, 0x66, 0x1a, 0xf5, 0x84, 0x90, 0xea, 0xb0, 0x7a, 0xa4, 0x37, 0xa4}; + + logger.info(k_amf_o, 32, "K AMF:"); + TESTASSERT(arrcmp(k_amf_o, k_amf, sizeof(k_amf)) == 0); + + return SRSRAN_SUCCESS; +} + +int test_generate_nas_5g() +{ + auto& logger = srslog::fetch_basic_logger("LOG", false); + uint8_t k_nas_int_o[32]; + uint8_t k_nas_enc_o[32]; + + uint8_t k_amf[] = {0x7d, 0x86, 0x18, 0x52, 0xb4, 0x2a, 0x86, 0xb5, 0x96, 0xfe, 0x22, 0xc8, 0xf5, 0x0b, 0x9b, 0x89, + 0x5a, 0x1e, 0x21, 0x71, 0x6b, 0x61, 0xb8, 0xd1, 0x22, 0x78, 0x5e, 0x25, 0xba, 0xfc, 0x0d, 0x07}; + + TESTASSERT(srsran::security_generate_k_nas_5g(k_amf, + srsran::CIPHERING_ALGORITHM_ID_ENUM::CIPHERING_ALGORITHM_ID_EEA0, + srsran::INTEGRITY_ALGORITHM_ID_ENUM::INTEGRITY_ALGORITHM_ID_128_EIA2, + k_nas_enc_o, + k_nas_int_o) == SRSRAN_SUCCESS); + + uint8_t k_nas_enc[] = {0x83, 0x85, 0x6a, 0x01, 0x81, 0x59, 0x55, 0x21, 0xc9, 0xd3, 0x2a, + 0x19, 0x3f, 0x59, 0xc8, 0xa8, 0xfc, 0x7e, 0x99, 0xb9, 0x8b, 0x8c, + 0x04, 0x20, 0x1f, 0x4f, 0x9d, 0x81, 0x43, 0x3b, 0x6b, 0x38}; + uint8_t k_nas_int[] = {0x25, 0xc5, 0x8e, 0x27, 0xe7, 0xd2, 0xc4, 0x95, 0xf3, 0xd7, 0x35, + 0x29, 0x3a, 0x82, 0xbf, 0xfa, 0xa5, 0x3e, 0xe8, 0x84, 0xb9, 0x8d, + 0x36, 0x6b, 0x02, 0x89, 0x23, 0x1e, 0xc4, 0x19, 0x1e, 0xd3}; + + logger.info(k_nas_enc_o, 32, "k_nas_enc_o:"); + TESTASSERT(arrcmp(k_nas_enc_o, k_nas_enc, sizeof(k_nas_enc)) == 0); + logger.info(k_nas_int_o, 32, "k_nas_int_o:"); + TESTASSERT(arrcmp(k_nas_int_o, k_nas_int, sizeof(k_nas_int)) == 0); + return SRSRAN_SUCCESS; +} + int main(int argc, char** argv) { auto& logger = srslog::fetch_basic_logger("LOG", false); @@ -321,6 +435,11 @@ int main(int argc, char** argv) TESTASSERT(test_generate_k_nh() == SRSRAN_SUCCESS); TESTASSERT(test_generate_res_star() == SRSRAN_SUCCESS); + TESTASSERT(test_generate_k_ausf() == SRSRAN_SUCCESS); + TESTASSERT(test_generate_k_seaf() == SRSRAN_SUCCESS); + TESTASSERT(test_generate_k_amf() == SRSRAN_SUCCESS); + TESTASSERT(test_generate_k_amf_2() == SRSRAN_SUCCESS); + TESTASSERT(test_generate_nas_5g() == SRSRAN_SUCCESS); TESTASSERT(test_set_ksg() == SRSRAN_SUCCESS); TESTASSERT(test_set_nr_rrc_up() == SRSRAN_SUCCESS); diff --git a/srsue/hdr/stack/upper/pcsc_usim.h b/srsue/hdr/stack/upper/pcsc_usim.h index bd47a5ac8..e595bad1c 100644 --- a/srsue/hdr/stack/upper/pcsc_usim.h +++ b/srsue/hdr/stack/upper/pcsc_usim.h @@ -44,7 +44,14 @@ public: uint8_t* res, int* res_len, uint8_t* k_asme); - + // NAS interface + auth_result_t generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf); // Helpers virtual std::string get_mnc_str(const uint8_t* imsi_vec, std::string mcc_str) final; diff --git a/srsue/hdr/stack/upper/usim.h b/srsue/hdr/stack/upper/usim.h index 72982f883..97edbe297 100644 --- a/srsue/hdr/stack/upper/usim.h +++ b/srsue/hdr/stack/upper/usim.h @@ -36,21 +36,18 @@ public: int* res_len, uint8_t* k_asme); + auth_result_t generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf); + private: - auth_result_t gen_auth_res_milenage(uint8_t* rand, - uint8_t* autn_enb, - uint16_t mcc, - uint16_t mnc, - uint8_t* res, - int* res_len, - uint8_t* k_asme); - auth_result_t gen_auth_res_xor(uint8_t* rand, - uint8_t* autn_enb, - uint16_t mcc, - uint16_t mnc, - uint8_t* res, - int* res_len, - uint8_t* k_asme); + auth_result_t + gen_auth_res_milenage(uint8_t* rand, uint8_t* autn_enb, uint8_t* res, int* res_len, uint8_t* ak_xor_sqn); + auth_result_t gen_auth_res_xor(uint8_t* rand, uint8_t* autn_enb, uint8_t* res, int* res_len, uint8_t* ak_xor_sqn); // Helpers virtual std::string get_mnc_str(const uint8_t* imsi_vec, std::string mcc_str) final; diff --git a/srsue/hdr/stack/upper/usim_base.h b/srsue/hdr/stack/upper/usim_base.h index cb2927172..f9516073f 100644 --- a/srsue/hdr/stack/upper/usim_base.h +++ b/srsue/hdr/stack/upper/usim_base.h @@ -101,12 +101,19 @@ public: bool update_nr_context(srsran::as_security_config_t* sec_cfg) final; // 5G NAS interface - bool generate_res_star(uint8_t* rand, - uint8_t* res, - int res_len, - const char* serving_network_name, - uint8_t* res_start, - uint32_t* res_star_len) final; + virtual auth_result_t generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf) = 0; + + bool generate_nas_keys_5g(uint8_t* k_amf, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); // Helpers std::string get_mcc_str(const uint8_t* imsi_vec); virtual std::string get_mnc_str(const uint8_t* imsi_vec, std::string mcc_str) = 0; diff --git a/srsue/src/stack/upper/pcsc_usim.cc b/srsue/src/stack/upper/pcsc_usim.cc index 780194ca8..3cc963b1e 100644 --- a/srsue/src/stack/upper/pcsc_usim.cc +++ b/srsue/src/stack/upper/pcsc_usim.cc @@ -151,6 +151,76 @@ auth_result_t pcsc_usim::generate_authentication_response(uint8_t* rand, return ret; } +auth_result_t pcsc_usim::generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf) +{ + uint8_t res[16]; + uint8_t k_ausf[32]; + uint8_t k_seaf[32]; + int res_len; + + auth_result_t ret = AUTH_FAILED; + if (!initiated) { + ERROR("USIM not initiated!"); + return ret; + } + + // Use RAND and AUTN to compute RES, CK, IK using SIM card + switch (sc.umts_auth(rand, autn_enb, res, &res_len, ik, ck, auts)) { + case 0: + logger.info("SCARD: USIM authentication successful."); + break; + case -1: + logger.error("SCARD: Failure during USIM UMTS authentication"); + return ret; + case -2: + logger.info("SCARD: USIM synchronization failure, AUTS generated"); + logger.debug(auts, AKA_AUTS_LEN, "AUTS"); + memcpy(res, auts, AKA_AUTS_LEN); + res_len = AKA_AUTS_LEN; + return AUTH_SYNCH_FAILURE; + default: + logger.warning("SCARD: Unknown USIM failure."); + return ret; + } + + // TODO: Extract ak and seq from auts + memset(ak, 0x00, AK_LEN); + + // Extract sqn from autn + uint8_t sqn[SQN_LEN]; + for (int i = 0; i < 6; i++) { + sqn[i] = autn_enb[i] ^ ak[i]; + } + + // Generate K_asme + logger.debug(ck, CK_LEN, "CK:"); + logger.debug(ik, IK_LEN, "IK:"); + logger.debug(ak, AK_LEN, "AK:"); + logger.debug(sqn, SQN_LEN, "SQN:"); + logger.debug("SSN=%s", serving_network_name); + // Generate RES STAR + security_generate_res_star(ck, ik, serving_network_name, rand, res, res_len, res_star); + logger.debug(res_star, 16, "RES STAR"); + // Generate K_ausf + security_generate_k_ausf(ck, ik, sqn, serving_network_name, k_ausf); + logger.debug(k_ausf, 32, "K AUSF"); + // Generate K_seaf + security_generate_k_seaf(k_ausf, serving_network_name, k_seaf); + logger.debug(k_seaf, 32, "K SEAF"); + // Generate K_seaf + security_generate_k_amf(k_ausf, imsi_str.c_str(), abba, abba_len, k_amf); + logger.debug(k_amf, 32, "K AMF"); + + ret = AUTH_OK; + return ret; +} + std::string pcsc_usim::get_mnc_str(const uint8_t* imsi_vec, std::string mcc_str) { uint32_t mcc_len = 3; diff --git a/srsue/src/stack/upper/usim.cc b/srsue/src/stack/upper/usim.cc index 048524271..f96e25f5a 100644 --- a/srsue/src/stack/upper/usim.cc +++ b/srsue/src/stack/upper/usim.cc @@ -101,24 +101,68 @@ auth_result_t usim::generate_authentication_response(uint8_t* rand, int* res_len, uint8_t* k_asme_) { + auth_result_t auth_result; + uint8_t ak_xor_sqn[6]; + + if (auth_algo_xor == auth_algo) { + auth_result = gen_auth_res_xor(rand, autn_enb, res, res_len, ak_xor_sqn); + } else { + auth_result = gen_auth_res_milenage(rand, autn_enb, res, res_len, ak_xor_sqn); + } + + if (auth_result == AUTH_OK) { + // Generate K_asme + security_generate_k_asme(ck, ik, ak_xor_sqn, mcc, mnc, k_asme_); + } + return auth_result; +} + +auth_result_t usim::generate_authentication_response_5g(uint8_t* rand, + uint8_t* autn_enb, + const char* serving_network_name, + uint8_t* abba, + uint32_t abba_len, + uint8_t* res_star, + uint8_t* k_amf) +{ + auth_result_t auth_result; + uint8_t ak_xor_sqn[6]; + uint8_t res[16]; + uint8_t k_ausf[32]; + uint8_t k_seaf[32]; + int res_len; + if (auth_algo_xor == auth_algo) { - return gen_auth_res_xor(rand, autn_enb, mcc, mnc, res, res_len, k_asme_); + auth_result = gen_auth_res_xor(rand, autn_enb, res, &res_len, ak_xor_sqn); } else { - return gen_auth_res_milenage(rand, autn_enb, mcc, mnc, res, res_len, k_asme_); + auth_result = gen_auth_res_milenage(rand, autn_enb, res, &res_len, ak_xor_sqn); } + + if (auth_result == AUTH_OK) { + // Generate RES STAR + security_generate_res_star(ck, ik, serving_network_name, rand, res, res_len, res_star); + logger.debug(res_star, 16, "RES STAR"); + // Generate K_ausf + security_generate_k_ausf(ck, ik, ak_xor_sqn, serving_network_name, k_ausf); + logger.debug(k_ausf, 32, "K AUSF"); + // Generate K_seaf + security_generate_k_seaf(k_ausf, serving_network_name, k_seaf); + logger.debug(k_seaf, 32, "K SEAF"); + // Generate K_seaf + logger.debug(abba, abba_len, "ABBA:"); + logger.debug("IMSI: %s", imsi_str.c_str()); + security_generate_k_amf(k_seaf, imsi_str.c_str(), abba, abba_len, k_amf); + logger.debug(k_amf, 32, "K AMF"); + } + return auth_result; } /******************************************************************************* Helpers *******************************************************************************/ -auth_result_t usim::gen_auth_res_milenage(uint8_t* rand, - uint8_t* autn_enb, - uint16_t mcc, - uint16_t mnc, - uint8_t* res, - int* res_len, - uint8_t* k_asme) +auth_result_t +usim::gen_auth_res_milenage(uint8_t* rand, uint8_t* autn_enb, uint8_t* res, int* res_len, uint8_t* ak_xor_sqn) { auth_result_t result = AUTH_OK; uint32_t i; @@ -159,24 +203,22 @@ auth_result_t usim::gen_auth_res_milenage(uint8_t* rand, } } - uint8_t ak_xor_sqn[6]; for (i = 0; i < 6; i++) { ak_xor_sqn[i] = sqn[i] ^ ak[i]; } - // Generate K_asme - security_generate_k_asme(ck, ik, ak_xor_sqn, mcc, mnc, k_asme); + + logger.debug(ck, CK_LEN, "CK:"); + logger.debug(ik, IK_LEN, "IK:"); + logger.debug(ak, AK_LEN, "AK:"); + logger.debug(sqn, 6, "sqn:"); + logger.debug(amf, 2, "amf:"); + logger.debug(mac, 8, "mac:"); return result; } // 3GPP TS 34.108 version 10.0.0 Section 8 -auth_result_t usim::gen_auth_res_xor(uint8_t* rand, - uint8_t* autn_enb, - uint16_t mcc, - uint16_t mnc, - uint8_t* res, - int* res_len, - uint8_t* k_asme_) +auth_result_t usim::gen_auth_res_xor(uint8_t* rand, uint8_t* autn_enb, uint8_t* res, int* res_len, uint8_t* ak_xor_sqn) { auth_result_t result = AUTH_OK; uint8_t sqn[6]; @@ -230,14 +272,10 @@ auth_result_t usim::gen_auth_res_xor(uint8_t* rand, logger.debug(amf, 2, "amf:"); logger.debug(mac, 8, "mac:"); - uint8_t ak_xor_sqn[6]; for (uint32_t i = 0; i < 6; i++) { ak_xor_sqn[i] = sqn[i] ^ ak[i]; } - // Generate K_asme - security_generate_k_asme(ck, ik, ak_xor_sqn, mcc, mnc, k_asme_); - return result; } diff --git a/srsue/src/stack/upper/usim_base.cc b/srsue/src/stack/upper/usim_base.cc index 2cb80423a..479ed6b3d 100644 --- a/srsue/src/stack/upper/usim_base.cc +++ b/srsue/src/stack/upper/usim_base.cc @@ -348,6 +348,21 @@ void usim_base::restore_keys_from_failed_ho(srsran::as_security_config_t* as_ctx return; } +bool usim_base::generate_nas_keys_5g(uint8_t* k_amf, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + if (!initiated) { + logger.error("USIM not initiated!"); + return false; + } + // Generate K_nas_enc and K_nas_int + security_generate_k_nas_5g(k_amf, cipher_algo, integ_algo, k_nas_enc, k_nas_int); + return true; +} + /* * NR RRC Interface */ @@ -360,7 +375,7 @@ bool usim_base::generate_nr_context(uint16_t sk_counter, srsran::as_security_con } logger.info("Generating Keys. SCG Counter %d", sk_counter); - srsran::security_generate_sk_gnb(k_enb_ctx.k_enb.data(), k_gnb_ctx.sk_gnb.data(), sk_counter); + srsran::security_generate_sk_gnb(k_enb_ctx.k_enb.data(), sk_counter, k_gnb_ctx.sk_gnb.data()); logger.info(k_gnb_ctx.sk_gnb.data(), 32, "k_sk_gnb"); if (update_nr_context(sec_cfg) == false) { return false; @@ -396,30 +411,4 @@ bool usim_base::update_nr_context(srsran::as_security_config_t* sec_cfg) return true; } -bool usim_base::generate_res_star(uint8_t* rand, - uint8_t* res, - int res_len, - const char* serving_network_name, - uint8_t* res_star, - uint32_t* res_star_len) -{ - if (!initiated) { - logger.error("USIM not initiated!"); - return false; - } - - logger.info("Generate res_star"); - - logger.info(rand, 16, "RAND"); - logger.info(res, res_len, "RES"); - logger.info( - (uint8_t*)serving_network_name, strlen(serving_network_name), "Serving Network Name %s", serving_network_name); - - srsran::security_generate_res_star(ck, ik, serving_network_name, rand, res, res_len, res_star); - *res_star_len = 16; - logger.info(res_star, *res_star_len, "res_star"); - - return true; -} - } // namespace srsue