Merge branch 'next' into embms_merge_final

master
Andre Puschmann 7 years ago
commit 9ce3be974a

@ -131,6 +131,16 @@ else(POLARSSL_FOUND)
endif (MBEDTLS_FOUND) endif (MBEDTLS_FOUND)
endif(POLARSSL_FOUND) endif(POLARSSL_FOUND)
# Hard-SIM support
find_package(PCSCLite)
if (PCSCLITE_FOUND)
message(STATUS "Building with PCSC support.")
add_definitions(-DHAVE_PCSC)
set(HAVE_PCSC TRUE)
include_directories(${PCSCLITE_INCLUDE_DIR})
#link_directories(${PCSCLITE_LIBRARIES})
endif (PCSCLITE_FOUND)
# UHD # UHD
find_package(UHD) find_package(UHD)
if(UHD_FOUND) if(UHD_FOUND)

@ -659,3 +659,39 @@ specific requirements.
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>.
The license terms used for the scard class (in pcsc_usim) derived from wpa_supplicant
-------------------------------------------------------------------------------------
Modified BSD license (no advertisement clause):
Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -108,6 +108,7 @@ Note that depending on your flavor and version of Linux, the actual package name
* Optional requirements: * Optional requirements:
* srsgui: https://github.com/srslte/srsgui - for real-time plotting. * srsgui: https://github.com/srslte/srsgui - for real-time plotting.
* libpcsclite-dev https://pcsclite.apdu.fr/ - for accessing smart card readers
* RF front-end driver: * RF front-end driver:
* UHD: https://github.com/EttusResearch/uhd * UHD: https://github.com/EttusResearch/uhd

@ -0,0 +1,48 @@
# - Find PCSC-Lite
# Find the native PCSC-Lite includes and library
#
# PCSCLITE_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
# PCSCLITE_LIBRARIES - List of libraries when using PCSC-Lite.
# PCSCLITE_FOUND - True if PCSC-Lite found.
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_PCSCLITE libpcsclite)
IF(NOT PCSCLITE_FOUND)
FIND_PATH(PCSCLITE_INCLUDE_DIR
NAMES winscard.h
HINTS /usr/include/PCSC
/usr/local/include/PCSC
${PC_PCSCLITE_INCLUDEDIR}
${PC_PCSCLITE_INCLUDE_DIRS}
${PC_PCSCLITE_INCLUDE_DIRS}/PCSC
${CMAKE_INSTALL_PREFIX}/include
)
FIND_LIBRARY(PCSCLITE_LIBRARY NAMES pcsclite libpcsclite PCSC
HINTS ${PC_PCSCLITE_LIBDIR}
${PC_PCSCLITE_LIBRARY_DIRS}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
PATHS /usr/local/lib
/usr/local/lib64
/usr/lib
/usr/lib64
)
# handle the QUIETLY and REQUIRED arguments and set PCSCLITE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSCLITE DEFAULT_MSG PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR)
IF(PCSCLITE_FOUND)
SET(PCSCLITE_LIBRARIES ${PCSCLITE_LIBRARY})
ELSE(PCSCLITE_FOUND)
SET(PCSCLITE_LIBRARIES )
ENDIF(PCSCLITE_FOUND)
message(STATUS "PCSC LIBRARIES: " ${PCSCLITE_LIBRARY})
message(STATUS "PCSC INCLUDE DIRS: " ${PCSCLITE_INCLUDE_DIR})
MARK_AS_ADVANCED( PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR )
ENDIF(NOT PCSCLITE_FOUND)

@ -2810,6 +2810,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_S
// Structs // Structs
typedef struct{ typedef struct{
uint8 res[16]; uint8 res[16];
int res_len;
}LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT; }LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp,
@ -3791,6 +3792,8 @@ typedef struct{
}LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT; }LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg); LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp); LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);

@ -38,13 +38,17 @@ namespace srslte {
class srslte_nas_config_t class srslte_nas_config_t
{ {
public: public:
srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "") srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "", std::string user_ = "", std::string pass_ = "")
:lcid(lcid_), :lcid(lcid_),
apn(apn_) apn(apn_),
user(user_),
pass(pass_)
{} {}
uint32_t lcid; uint32_t lcid;
std::string apn; std::string apn;
std::string user;
std::string pass;
}; };

@ -123,6 +123,11 @@ uint8_t security_128_eia2( uint8_t *key,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac); uint8_t *mac);
uint8_t security_md5(const uint8_t *input,
size_t len,
uint8_t *output);
/****************************************************************************** /******************************************************************************
* Encryption / Decryption * Encryption / Decryption
*****************************************************************************/ *****************************************************************************/

@ -43,6 +43,12 @@
namespace srsue { namespace srsue {
typedef enum {
AUTH_OK,
AUTH_FAILED,
AUTH_SYNCH_FAILURE
} auth_result_t;
// UE interface // UE interface
class ue_interface class ue_interface
{ {
@ -57,12 +63,12 @@ public:
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
virtual void generate_authentication_response(uint8_t *rand, virtual auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) = 0; uint8_t *k_asme) = 0;
virtual void generate_nas_keys(uint8_t *k_asme, virtual void generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc, uint8_t *k_nas_enc,

@ -1027,6 +1027,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_rand_ie(uint8 **ie_
Document Reference: 24.301 v10.2.0 Section 9.9.3.4 Document Reference: 24.301 v10.2.0 Section 9.9.3.4
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res, LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res,
int res_len,
uint8 **ie_ptr) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -1035,12 +1036,13 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *r
if(res != NULL && if(res != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
(*ie_ptr)[0] = 8; (*ie_ptr)[0] = res_len;
for(i=0; i<8; i++) *ie_ptr += 1;
for(i=0; i<res_len; i++)
{ {
(*ie_ptr)[i+1] = res[i]; (*ie_ptr)[i] = res[i];
} }
*ie_ptr += 9; *ie_ptr += res_len;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -4416,7 +4418,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_address_ie(uint8
pdn_addr->addr[i] = (*ie_ptr)[2+i]; pdn_addr->addr[i] = (*ie_ptr)[2+i];
} }
} }
*ie_ptr += (*ie_ptr)[0]; *ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -6195,7 +6197,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENT
msg_ptr++; msg_ptr++;
// Authentication Response Parameter (RES) // Authentication Response Parameter (RES)
liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, &msg_ptr); liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, auth_resp->res_len, &msg_ptr);
// Fill in the number of bytes used // Fill in the number of bytes used
msg->N_bytes = msg_ptr - msg->msg; msg->N_bytes = msg_ptr - msg->msg;
@ -9961,7 +9963,7 @@ LIBLTE_ERROR_ENUM srslte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INF
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{ {
// Protocol Discriminator and Security Header Type // Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++; msg_ptr++;
// MAC will be filled in later // MAC will be filled in later
@ -10040,10 +10042,19 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg; uint8 *msg_ptr = msg->msg;
uint8 sec_hdr_type;
if(msg != NULL && if(msg != NULL &&
esm_info_req != NULL) esm_info_req != NULL)
{ {
// Security Header Type
sec_hdr_type = (msg->msg[0] & 0xF0) >> 4;
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) {
msg_ptr++;
} else{
msg_ptr += 6;
}
// EPS Bearer ID // EPS Bearer ID
esm_info_req->eps_bearer_id = (*msg_ptr >> 4); esm_info_req->eps_bearer_id = (*msg_ptr >> 4);
msg_ptr++; msg_ptr++;
@ -10071,6 +10082,8 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_
Document Reference: 24.301 v10.2.0 Section 8.3.14 Document Reference: 24.301 v10.2.0 Section 8.3.14
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg) LIBLTE_BYTE_MSG_STRUCT *msg)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -10079,6 +10092,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
if(esm_info_resp != NULL && if(esm_info_resp != NULL &&
msg != NULL) msg != NULL)
{ {
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and EPS Bearer ID // Protocol Discriminator and EPS Bearer ID
*msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); *msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++; msg_ptr++;
@ -10115,6 +10142,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
return(err); return(err);
} }
LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp) LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp)
{ {
@ -10132,7 +10161,7 @@ LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG
{ {
msg_ptr++; msg_ptr++;
}else{ }else{
msg_ptr += 7; msg_ptr += 6;
} }
// EPS Bearer ID // EPS Bearer ID
esm_info_resp->eps_bearer_id = (*msg_ptr >> 4); esm_info_resp->eps_bearer_id = (*msg_ptr >> 4);

@ -29,6 +29,13 @@
#include "srslte/common/liblte_security.h" #include "srslte/common/liblte_security.h"
#include "srslte/common/snow_3g.h" #include "srslte/common/snow_3g.h"
#ifdef HAVE_MBEDTLS
#include "mbedtls/md5.h"
#endif
#ifdef HAVE_POLARSSL
#include "polarssl/md5.h"
#endif
namespace srslte { namespace srslte {
/****************************************************************************** /******************************************************************************
@ -166,6 +173,19 @@ uint8_t security_128_eia2( uint8_t *key,
mac); mac);
} }
uint8_t security_md5(const uint8_t *input, size_t len, uint8_t *output)
{
memset(output, 0x00, 16);
#ifdef HAVE_MBEDTLS
mbedtls_md5(input, len, output);
#endif // HAVE_MBEDTLS
#ifdef HAVE_POLARSSL
md5(input, len, output);
#endif
return SRSLTE_SUCCESS;
}
/****************************************************************************** /******************************************************************************
* Encryption / Decryption * Encryption / Decryption
*****************************************************************************/ *****************************************************************************/

@ -32,9 +32,9 @@ add_test(rlc_am_test rlc_am_test)
add_executable(rlc_stress_test rlc_stress_test.cc) add_executable(rlc_stress_test rlc_stress_test.cc)
target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES})
add_test(rlc_am_stress_test rlc_stress_test --mode=AM) add_test(rlc_am_stress_test rlc_stress_test --mode=AM --loglevel 1)
add_test(rlc_um_stress_test rlc_stress_test --mode=UM) add_test(rlc_um_stress_test rlc_stress_test --mode=UM --loglevel 1)
add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --opp_sdu_ratio=1.0) add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --loglevel 1 --opp_sdu_ratio=1.0)
add_executable(rlc_um_data_test rlc_um_data_test.cc) add_executable(rlc_um_data_test rlc_um_data_test.cc)
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)

@ -283,8 +283,8 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECON
if (ecm_ctx->state == ECM_STATE_CONNECTED) if (ecm_ctx->state == ECM_STATE_CONNECTED)
{ {
//There are active E-RABs, send release access mearers request //There are active E-RABs, send release access mearers request
m_s1ap_log->console("There are active E-RABs, send release access mearers request"); m_s1ap_log->console("There are active E-RABs, send release access mearers request\n");
m_s1ap_log->info("There are active E-RABs, send release access mearers request"); m_s1ap_log->info("There are active E-RABs, send release access mearers request\n");
//The handle_release_access_bearers_response function will make sure to mark E-RABS DEACTIVATED //The handle_release_access_bearers_response function will make sure to mark E-RABS DEACTIVATED
//It will release the UEs downstream S1-u and keep the upstream S1-U connection active. //It will release the UEs downstream S1-u and keep the upstream S1-U connection active.

@ -284,7 +284,7 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
} }
else if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) else if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED)
{ {
//Integrity protected NAS message, possibly chiphered. //Integrity protected NAS message, possibly ciphered.
emm_ctx->security_ctxt.ul_nas_count++; emm_ctx->security_ctxt.ul_nas_count++;
mac_valid = integrity_check(emm_ctx,nas_msg); mac_valid = integrity_check(emm_ctx,nas_msg);
if(!mac_valid){ if(!mac_valid){
@ -1068,7 +1068,7 @@ s1ap_nas_transport::handle_nas_security_mode_complete(srslte::byte_buffer_t *nas
{ {
pack_esm_information_request(reply_buffer, emm_ctx, ecm_ctx); pack_esm_information_request(reply_buffer, emm_ctx, ecm_ctx);
m_s1ap_log->console("Sending ESM information request\n"); m_s1ap_log->console("Sending ESM information request\n");
m_s1ap_log->info("Sending ESM information request\n"); m_s1ap_log->info_hex(reply_buffer->msg, reply_buffer->N_bytes, "Sending ESM information request\n");
*reply_flag = true; *reply_flag = true;
} }
else else
@ -1145,8 +1145,8 @@ s1ap_nas_transport::handle_esm_information_response(srslte::byte_buffer_t *nas_m
m_s1ap_log->info("ESM Info: EPS bearer id %d\n",esm_info_resp.eps_bearer_id); m_s1ap_log->info("ESM Info: EPS bearer id %d\n",esm_info_resp.eps_bearer_id);
if(esm_info_resp.apn_present) if(esm_info_resp.apn_present)
{ {
m_s1ap_log->info("ESM Info: APN %d\n",esm_info_resp.eps_bearer_id); m_s1ap_log->info("ESM Info: APN %s\n",esm_info_resp.apn.apn);
m_s1ap_log->console("ESM Info: APN %d\n",esm_info_resp.eps_bearer_id); m_s1ap_log->console("ESM Info: APN %s\n",esm_info_resp.apn.apn);
} }
if(esm_info_resp.protocol_cnfg_opts_present) if(esm_info_resp.protocol_cnfg_opts_present)
{ {
@ -1686,7 +1686,7 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
esm_info_req.eps_bearer_id = 0; esm_info_req.eps_bearer_id = 0;
esm_info_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; esm_info_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id;
uint8_t sec_hdr_type=2; uint8_t sec_hdr_type = LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED;
ue_emm_ctx->security_ctxt.dl_nas_count++; ue_emm_ctx->security_ctxt.dl_nas_count++;
@ -1709,6 +1709,7 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
); );
memcpy(&nas_buffer->msg[1],mac,4); memcpy(&nas_buffer->msg[1],mac,4);
//Copy NAS PDU to Downlink NAS Trasport message buffer //Copy NAS PDU to Downlink NAS Trasport message buffer
memcpy(dw_nas->NAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes); memcpy(dw_nas->NAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes);
dw_nas->NAS_PDU.n_octets = nas_buffer->N_bytes; dw_nas->NAS_PDU.n_octets = nas_buffer->N_bytes;

@ -100,7 +100,7 @@ private:
srsue::rrc rrc; srsue::rrc rrc;
srsue::nas nas; srsue::nas nas;
srsue::gw gw; srsue::gw gw;
srsue::usim usim; srsue::usim_base* usim;
srslte::logger_stdout logger_stdout; srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file; srslte::logger_file logger_file;

@ -128,7 +128,9 @@ typedef struct {
usim_args_t usim; usim_args_t usim;
rrc_args_t rrc; rrc_args_t rrc;
std::string ue_category_str; std::string ue_category_str;
std::string apn; std::string apn_name;
std::string apn_user;
std::string apn_pass;
expert_args_t expert; expert_args_t expert;
}all_args_t; }all_args_t;

@ -127,6 +127,8 @@ private:
uint32_t ip_addr; uint32_t ip_addr;
uint8_t eps_bearer_id; uint8_t eps_bearer_id;
uint8_t chap_id;
uint8_t transaction_id; uint8_t transaction_id;
// Security // Security
@ -171,7 +173,10 @@ private:
// Senders // Senders
void send_identity_response(); void send_identity_response();
void send_esm_information_response(); void send_service_request();
void send_esm_information_response(const uint8 proc_transaction_id);
void send_authentication_response(const uint8_t* res, const size_t res_len);
void send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param);
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
void send_security_mode_reject(uint8_t cause); void send_security_mode_reject(uint8_t cause);

@ -0,0 +1,270 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_PCSC_USIM_H
#define SRSUE_PCSC_USIM_H
#include <string>
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
#include "srsue/hdr/upper/usim.h"
#include <winscard.h>
namespace srsue {
#define AKA_RAND_LEN 16
#define AKA_AUTN_LEN 16
#define AKA_AUTS_LEN 14
#define RES_MAX_LEN 16
#define MAC_LEN 8
#define IK_LEN 16
#define CK_LEN 16
#define AK_LEN 6
#define SQN_LEN 6
#define KEY_LEN 32
typedef enum {
SCARD_GSM_SIM,
SCARD_USIM
} sim_types_t;
static inline uint16_t to_uint16(const uint8_t *a)
{
return (a[0] << 8) | a[1];
}
class pcsc_usim
:public usim_base
{
public:
pcsc_usim();
~pcsc_usim();
int init(usim_args_t *args, srslte::log *usim_log_);
void stop();
// NAS interface
std::string get_imsi_str();
std::string get_imei_str();
bool get_imsi_vec(uint8_t* imsi_, uint32_t n);
bool get_imei_vec(uint8_t* imei_, uint32_t n);
bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
uint16_t mcc,
uint16_t mnc,
uint8_t *res,
int *res_len,
uint8_t *k_asme);
void generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc,
uint8_t *k_nas_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
// RRC interface
void generate_as_keys(uint8_t *k_asme,
uint32_t count_ul,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void generate_as_keys_ho(uint32_t pci,
uint32_t earfcn,
int ncc,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
private:
srslte::log *log;
// User data
uint8_t amf[2]; // 3GPP 33.102 v10.0.0 Annex H
uint8_t op[16];
uint64_t imsi;
uint64_t imei;
uint8_t k[16];
std::string imsi_str;
std::string imei_str;
uint32_t mnc_length;
// Security variables
uint8_t rand[AKA_RAND_LEN];
uint8_t ck[CK_LEN];
uint8_t ik[IK_LEN];
uint8_t ak[AK_LEN];
uint8_t mac[MAC_LEN];
uint8_t autn[AKA_AUTN_LEN];
uint8_t k_asme[KEY_LEN];
uint8_t nh[KEY_LEN];
uint8_t k_enb[KEY_LEN];
uint8_t k_enb_star[KEY_LEN];
uint8_t auts[AKA_AUTS_LEN];
uint32_t current_ncc;
bool initiated;
// Smartcard sub-class which is a port of the PC/SC smartcard implementation
// of WPA Supplicant written by Jouni Malinen <j@w1.fi> and licensed under BSD
// Source: https://w1.fi/cvs.html
class scard {
public:
scard() : log(NULL) {};
~scard() {};
int init(usim_args_t *args, srslte::log *log_);
void deinit();
int select_file(unsigned short file_id,unsigned char *buf, size_t *buf_len);
int _select_file(unsigned short file_id, unsigned char *buf, size_t *buf_len, sim_types_t sim_type, unsigned char *aid, size_t aidlen);
long transmit(unsigned char *_send, size_t send_len, unsigned char *_recv, size_t *recv_len);
int get_aid(unsigned char *aid, size_t maxlen);
int get_record_len(unsigned char recnum, unsigned char mode);
int read_record(unsigned char *data, size_t len, unsigned char recnum, unsigned char mode);
int get_imsi(char *imsi, size_t *len);
int parse_fsp_templ(unsigned char *buf, size_t buf_len, int *ps_do, int *file_len);
int read_file(unsigned char *data, size_t len);
int get_mnc_len();
int umts_auth(const unsigned char *_rand,
const unsigned char *autn,
unsigned char *res, int *res_len,
unsigned char *ik, unsigned char *ck, unsigned char *auts);
int pin_needed(unsigned char *hdr, size_t hlen);
int verify_pin(const char *pin);
int get_pin_retry_counter();
private:
/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
* SIM commands:
* Command APDU: CLA INS P1 P2 P3 Data
* CLA (class of instruction): A0 for GSM, 00 for USIM
* INS (instruction)
* P1 P2 P3 (parameters, P3 = length of Data)
* Response APDU: Data SW1 SW2
* SW1 SW2 (Status words)
* Commands (INS P1 P2 P3):
* SELECT: A4 00 00 02 <file_id, 2 bytes>
* GET RESPONSE: C0 00 00 <len>
* RUN GSM ALG: 88 00 00 00 <RAND len = 10>
* RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
* P1 = ID of alg in card
* P2 = ID of secret key
* READ BINARY: B0 <offset high> <offset low> <len>
* READ RECORD: B2 <record number> <mode> <len>
* P2 (mode) = '02' (next record), '03' (previous record),
* '04' (absolute mode)
* VERIFY CHV: 20 00 <CHV number> 08
* CHANGE CHV: 24 00 <CHV number> 10
* DISABLE CHV: 26 00 01 08
* ENABLE CHV: 28 00 01 08
* UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
* SLEEP: FA 00 00 00
*/
/* GSM SIM commands */
#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02
#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10
#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00
#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00
#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00
#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
/* USIM commands */
#define USIM_CLA 0x00
#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
#define SIM_RECORD_MODE_ABSOLUTE 0x04
#define USIM_FSP_TEMPL_TAG 0x62
#define USIM_TLV_FILE_DESC 0x82
#define USIM_TLV_FILE_ID 0x83
#define USIM_TLV_DF_NAME 0x84
#define USIM_TLV_PROPR_INFO 0xA5
#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A
#define USIM_TLV_FILE_SIZE 0x80
#define USIM_TLV_TOTAL_FILE_SIZE 0x81
#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
#define USIM_TLV_SHORT_FILE_ID 0x88
#define USIM_TLV_SECURITY_ATTR_8B 0x8B
#define USIM_TLV_SECURITY_ATTR_8C 0x8C
#define USIM_TLV_SECURITY_ATTR_AB 0xAB
#define USIM_PS_DO_TAG 0x90
/* GSM files
* File type in first octet:
* 3F = Master File
* 7F = Dedicated File
* 2F = Elementary File under the Master File
* 6F = Elementary File under a Dedicated File
*/
#define SCARD_FILE_MF 0x3F00
#define SCARD_FILE_GSM_DF 0x7F20
#define SCARD_FILE_UMTS_DF 0x7F50
#define SCARD_FILE_GSM_EF_IMSI 0x6F07
#define SCARD_FILE_GSM_EF_AD 0x6FAD
#define SCARD_FILE_EF_DIR 0x2F00
#define SCARD_FILE_EF_ICCID 0x2FE2
#define SCARD_FILE_EF_CK 0x6FE1
#define SCARD_FILE_EF_IK 0x6FE2
#define SCARD_CHV1_OFFSET 13
#define SCARD_CHV1_FLAG 0x80
SCARDCONTEXT scard_context;
SCARDHANDLE scard_handle;
long unsigned scard_protocol;
sim_types_t sim_type;
bool pin1_needed;
srslte::log *log;
};
scard sc;
};
} // namespace srsue
#endif // SRSUE_PCSC_USIM_H

@ -28,6 +28,7 @@
#define SRSUE_USIM_H #define SRSUE_USIM_H
#include <string> #include <string>
#include "usim_base.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
@ -35,26 +36,12 @@
namespace srsue { namespace srsue {
typedef enum{
auth_algo_milenage = 0,
auth_algo_xor,
}auth_algo_t;
typedef struct{
std::string algo;
std::string op;
std::string imsi;
std::string imei;
std::string k;
}usim_args_t;
class usim class usim
:public usim_interface_nas :public usim_base
,public usim_interface_rrc
{ {
public: public:
usim(); usim();
void init(usim_args_t *args, srslte::log *usim_log_); int init(usim_args_t *args, srslte::log *usim_log_);
void stop(); void stop();
// NAS interface // NAS interface
@ -65,12 +52,12 @@ public:
bool get_imei_vec(uint8_t* imei_, uint32_t n); bool get_imei_vec(uint8_t* imei_, uint32_t n);
bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
void generate_authentication_response(uint8_t *rand, auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme); uint8_t *k_asme);
void generate_nas_keys(uint8_t *k_asme, void generate_nas_keys(uint8_t *k_asme,
@ -101,19 +88,19 @@ public:
private: private:
void gen_auth_res_milenage( uint8_t *rand, auth_result_t gen_auth_res_milenage(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme); uint8_t *k_asme);
void gen_auth_res_xor( uint8_t *rand, auth_result_t gen_auth_res_xor(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme); uint8_t *k_asme);
void str_to_hex(std::string str, uint8_t *hex); void str_to_hex(std::string str, uint8_t *hex);

@ -0,0 +1,110 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_USIM_BASE_H
#define SRSUE_USIM_BASE_H
#include <string>
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
namespace srsue {
typedef enum{
auth_algo_milenage = 0,
auth_algo_xor,
}auth_algo_t;
typedef struct{
std::string mode;
std::string algo;
std::string op;
std::string imsi;
std::string imei;
std::string k;
std::string pin;
}usim_args_t;
class usim_base
:public usim_interface_nas
,public usim_interface_rrc
{
public:
usim_base();
virtual ~usim_base();
static usim_base* get_instance(usim_args_t *args, srslte::log *usim_log_);
virtual int init(usim_args_t *args, srslte::log *usim_log_) = 0;
virtual void stop() = 0;
// NAS interface
virtual std::string get_imsi_str() = 0;
virtual std::string get_imei_str() = 0;
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
virtual auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
uint16_t mcc,
uint16_t mnc,
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,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
// RRC interface
virtual void generate_as_keys(uint8_t *k_asme,
uint32_t count_ul,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
virtual void generate_as_keys_ho(uint32_t pci,
uint32_t earfcn,
int ncc,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_up_enc,
uint8_t *k_up_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
};
} // namespace srsue
#endif // SRSUE_USIM_BASE_H

@ -358,6 +358,11 @@ void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* a
void mac::setup_timers() void mac::setup_timers()
{ {
// stop currently running time alignment timer
if (timers.get(timer_alignment)->is_running()) {
timers.get(timer_alignment)->stop();
}
int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer]; int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer];
if (value > 0) { if (value > 0) {
timers.get(timer_alignment)->set(this, value); timers.get(timer_alignment)->set(this, value);

@ -83,7 +83,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"UECapabilityInformation message. Default 0xe6041c00") "UECapabilityInformation message. Default 0xe6041c00")
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") ("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("nas.apn", bpo::value<string>(&args->apn)->default_value(""), "Set Access Point Name (APN) for data services") ("nas.apn", bpo::value<string>(&args->apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.user", bpo::value<string>(&args->apn_user)->default_value(""), "Username for CHAP authentication")
("nas.pass", bpo::value<string>(&args->apn_pass)->default_value(""), "Password for CHAP authentication")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") ("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
@ -124,12 +126,13 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename") ("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename")
("log.file_max_size", bpo::value<int>(&args->log.file_max_size)->default_value(-1), "Maximum file size (in kilobytes). When passed, multiple files are created. Default -1 (single file)") ("log.file_max_size", bpo::value<int>(&args->log.file_max_size)->default_value(-1), "Maximum file size (in kilobytes). When passed, multiple files are created. Default -1 (single file)")
("usim.mode", bpo::value<string>(&args->usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)")
("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm") ("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant") ("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant")
("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI") ("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI")
("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI") ("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI")
("usim.k", bpo::value<string>(&args->usim.k), "USIM K") ("usim.k", bpo::value<string>(&args->usim.k), "USIM K")
("usim.pin", bpo::value<string>(&args->usim.pin), "PIN in case real SIM card is used")
/* Expert section */ /* Expert section */
("expert.ip_netmask", ("expert.ip_netmask",

@ -47,10 +47,12 @@ ue::~ue()
for (uint32_t i = 0; i < phy_log.size(); i++) { for (uint32_t i = 0; i < phy_log.size(); i++) {
delete(phy_log[i]); delete(phy_log[i]);
} }
if (usim) {
delete usim;
}
} }
bool ue::init(all_args_t *args_) bool ue::init(all_args_t *args_) {
{
args = args_; args = args_;
if (!args->log.filename.compare("stdout")) { if (!args->log.filename.compare("stdout")) {
@ -131,6 +133,13 @@ bool ue::init(all_args_t *args_)
// Init layers // Init layers
// Init USIM first to allow early exit in case reader couldn't be found
usim = usim_base::get_instance(&args->usim, &usim_log);
if (usim->init(&args->usim, &usim_log)) {
usim_log.console("Failed to initialize USIM.\n");
return false;
}
// PHY inits in background, start before radio // PHY inits in background, start before radio
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant;
phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy);
@ -196,14 +205,12 @@ bool ue::init(all_args_t *args_)
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
usim.init(&args->usim, &usim_log); srslte_nas_config_t nas_cfg(1, args->apn_name, args->apn_user, args->apn_pass); /* RB_ID_SRB1 */
srslte_nas_config_t nas_cfg(1, args->apn); /* RB_ID_SRB1 */ nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
nas.init(&usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask); gw.set_netmask(args->expert.ip_netmask);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &gw, &mac, &rrc_log);
// Get current band from provided EARFCN // Get current band from provided EARFCN
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
args->rrc.nof_supported_bands = 1; args->rrc.nof_supported_bands = 1;
@ -243,7 +250,7 @@ void ue::stop()
{ {
if(started) if(started)
{ {
usim.stop(); usim->stop();
nas.stop(); nas.stop();
rrc.stop(); rrc.stop();

@ -18,6 +18,16 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
file(GLOB SOURCES "*.cc") set(SOURCES gw.cc nas.cc rrc.cc usim_base.cc usim.cc)
if(HAVE_PCSC)
list(APPEND SOURCES "pcsc_usim.cc")
endif(HAVE_PCSC)
add_library(srsue_upper STATIC ${SOURCES}) add_library(srsue_upper STATIC ${SOURCES})
if(HAVE_PCSC)
target_link_libraries(srsue_upper ${PCSCLITE_LIBRARY})
endif(HAVE_PCSC)
install(TARGETS srsue_upper DESTINATION ${LIBRARY_DIR}) install(TARGETS srsue_upper DESTINATION ${LIBRARY_DIR})

@ -30,6 +30,7 @@
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <srslte/asn1/liblte_mme.h>
#include "srslte/asn1/liblte_rrc.h" #include "srslte/asn1/liblte_rrc.h"
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/upper/nas.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
@ -52,6 +53,7 @@ nas::nas()
ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0; ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0; ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
plmn_is_selected = false; plmn_is_selected = false;
chap_id = 0;
} }
void nas::init(usim_interface_nas *usim_, void nas::init(usim_interface_nas *usim_,
@ -82,6 +84,10 @@ void nas::init(usim_interface_nas *usim_,
have_guti = true; have_guti = true;
have_ctxt = true; have_ctxt = true;
} }
// set seed for rand (used in CHAP auth)
srand(time(NULL));
running = true; running = true;
} }
@ -353,7 +359,13 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
} }
uint32_t nas::get_ul_count() { uint32_t nas::get_ul_count() {
return ctxt.tx_count; // UL count for RRC key derivation depends on ESM information transfer procedure
if (cfg.apn.empty()) {
// No ESM info transfer has been sent
return ctxt.tx_count - 1;
} else {
return ctxt.tx_count - 2;
}
} }
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
@ -517,7 +529,7 @@ void nas::cipher_decrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break; break;
default: default:
nas_log->error("Ciphering algorithmus not known"); nas_log->error("Ciphering algorithmus not known\n");
break; break;
} }
} }
@ -622,6 +634,24 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
transaction_id = act_def_eps_bearer_context_req.proc_transaction_id; transaction_id = act_def_eps_bearer_context_req.proc_transaction_id;
} }
// Search for DNS entry in protocol config options
if (act_def_eps_bearer_context_req.protocol_cnfg_opts_present) {
for (uint32_t i = 0; i < act_def_eps_bearer_context_req.protocol_cnfg_opts.N_opts; i++) {
if (act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].id == LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DNS_SERVER_IPV4_ADDRESS) {
uint32_t dns_addr = 0;
dns_addr |= act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[0] << 24;
dns_addr |= act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[1] << 16;
dns_addr |= act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[2] << 8;
dns_addr |= act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[3];
nas_log->info("DNS: %u.%u.%u.%u\n",
act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[0],
act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[1],
act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[2],
act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[i].contents[3]);
}
}
}
//FIXME: Handle the following parameters //FIXME: Handle the following parameters
// act_def_eps_bearer_context_req.eps_qos.qci // act_def_eps_bearer_context_req.eps_qos.qci
// act_def_eps_bearer_context_req.eps_qos.br_present // act_def_eps_bearer_context_req.eps_qos.br_present
@ -695,14 +725,12 @@ void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT)); bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT));
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
nas_log->info("Received Authentication Request\n"); nas_log->info("Received Authentication Request\n");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
// Reuse the pdu for the response message // Deallocate PDU after parsing
pdu->reset(); pool->deallocate(pdu);
// Generate authentication response using RAND, AUTN & KSI-ASME // Generate authentication response using RAND, AUTN & KSI-ASME
uint16 mcc, mnc; uint16 mcc, mnc;
@ -711,11 +739,12 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc); nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc);
bool net_valid;
uint8_t res[16]; uint8_t res[16];
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, int res_len = 0;
&net_valid, res, ctxt.k_asme); nas_log->debug_hex(auth_req.rand, 16, "Authentication request RAND\n");
nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str()); nas_log->debug_hex(auth_req.autn, 16, "Authentication request AUTN\n");
auth_result_t auth_result = usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc,
res, &res_len, ctxt.k_asme);
if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) { if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) {
ctxt.ksi = auth_req.nas_ksi.nas_ksi; ctxt.ksi = auth_req.nas_ksi.nas_ksi;
} else { } else {
@ -723,23 +752,17 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->console("Warning: NAS mapped security context not currently supported\n"); nas_log->console("Warning: NAS mapped security context not currently supported\n");
} }
if (net_valid) { if (auth_result == AUTH_OK) {
nas_log->info("Network authentication successful\n"); nas_log->info("Network authentication successful\n");
for (int i = 0; i < 8; i++) { send_authentication_response(res, res_len);
auth_res.res[i] = res[i]; nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
} } else if (auth_result == AUTH_SYNCH_FAILURE) {
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->error("Network authentication synchronization failure.\n");
send_authentication_failure(LIBLTE_MME_EMM_CAUSE_SYNCH_FAILURE, res);
nas_log->info("Sending Authentication Response\n");
// Write NAS pcap
if (pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
rrc->write_sdu(lcid, pdu);
} else { } else {
nas_log->warning("Network authentication failure\n"); nas_log->warning("Network authentication failure\n");
nas_log->console("Warning: Network authentication failure\n"); nas_log->console("Warning: Network authentication failure\n");
pool->deallocate(pdu); send_authentication_failure(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE, NULL);
} }
} }
@ -910,8 +933,15 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
} }
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n"); LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT esm_info_req;
liblte_mme_unpack_esm_information_request_msg((LIBLTE_BYTE_MSG_STRUCT *)pdu, &esm_info_req);
nas_log->info("ESM information request received for beaser=%d, transaction_id=%d\n", esm_info_req.eps_bearer_id, esm_info_req.proc_transaction_id);
ctxt.rx_count++;
pool->deallocate(pdu); pool->deallocate(pdu);
// send response
send_esm_information_response(esm_info_req.proc_transaction_id);
} }
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
@ -946,7 +976,12 @@ void nas::gen_attach_request(byte_buffer_t *msg) {
attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos
attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos
attach_req.ue_network_cap.ucs2_present = false;
attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G)
attach_req.ue_network_cap.lpp_present = false;
attach_req.ue_network_cap.lcs_present = false;
attach_req.ue_network_cap.onexsrvcc_present = false;
attach_req.ue_network_cap.nf_present = false;
attach_req.old_p_tmsi_signature_present = false; attach_req.old_p_tmsi_signature_present = false;
attach_req.additional_guti_present = false; attach_req.additional_guti_present = false;
attach_req.last_visited_registered_tai_present = false; attach_req.last_visited_registered_tai_present = false;
@ -993,6 +1028,8 @@ void nas::gen_attach_request(byte_buffer_t *msg) {
} }
} else { } else {
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI;
attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
attach_req.nas_ksi.nas_ksi = 0;
usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15);
nas_log->info("Requesting IMSI attach (IMSI=%s)\n", usim->get_imsi_str().c_str()); nas_log->info("Requesting IMSI attach (IMSI=%s)\n", usim->get_imsi_str().c_str());
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg);
@ -1054,17 +1091,17 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
pdn_con_req.proc_transaction_id = 0x01; // First transaction ID pdn_con_req.proc_transaction_id = 0x01; // First transaction ID
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4; pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST; pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
pdn_con_req.apn_present = false;
// Set the optional flags // Set the optional flags
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
if (cfg.apn == "") { if (cfg.apn == "") {
pdn_con_req.apn_present = false; pdn_con_req.esm_info_transfer_flag_present = false;
} else { } else {
pdn_con_req.apn_present = true; // request ESM info transfer is APN is specified
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0}; pdn_con_req.esm_info_transfer_flag_present = true;
strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN); pdn_con_req.esm_info_transfer_flag = LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_REQUIRED;
pdn_con_req.apn = apn;
} }
pdn_con_req.protocol_cnfg_opts_present = false; pdn_con_req.protocol_cnfg_opts_present = false;
pdn_con_req.device_properties_present = false; pdn_con_req.device_properties_present = false;
@ -1089,9 +1126,227 @@ void nas::send_security_mode_reject(uint8_t cause) {
rrc->write_sdu(cfg.lcid, msg); rrc->write_sdu(cfg.lcid, msg);
} }
void nas::send_authentication_response(const uint8_t* res, const size_t res_len) {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_response().\n");
return;
}
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
for (uint32_t i = 0; i < res_len; i++) {
auth_res.res[i] = res[i];
}
auth_res.res_len = res_len;
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *)msg);
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending Authentication Response\n");
rrc->write_sdu(cfg.lcid, msg);
}
void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param) {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_failure().\n");
return;
}
LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT auth_failure;
auth_failure.emm_cause = cause;
if (auth_fail_param) {
memcpy(auth_failure.auth_fail_param, auth_fail_param, 14);
nas_log->debug_hex(auth_failure.auth_fail_param, 14, "auth_failure.auth_fail_param\n");
auth_failure.auth_fail_param_present = true;
} else {
auth_failure.auth_fail_param_present = false;
}
liblte_mme_pack_authentication_failure_msg(&auth_failure, (LIBLTE_BYTE_MSG_STRUCT *)msg);
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending authentication failure.\n");
rrc->write_sdu(cfg.lcid, msg);
}
void nas::send_identity_response() {} void nas::send_identity_response() {}
void nas::send_esm_information_response() {} void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n");
return;
}
// Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending service request\n");
rrc->write_sdu(cfg.lcid, msg);
ctxt.tx_count++;
}
void nas::send_esm_information_response(const uint8 proc_transaction_id) {
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT esm_info_resp;
esm_info_resp.proc_transaction_id = proc_transaction_id;
esm_info_resp.eps_bearer_id = 0; // respone shall always have no bearer assigned
if (cfg.apn == "") {
esm_info_resp.apn_present = false;
} else {
nas_log->debug("Including APN %s in ESM info response\n", cfg.apn.c_str());
esm_info_resp.apn_present = true;
int len = std::min((int)cfg.apn.length(), LIBLTE_STRING_LEN-1);
strncpy(esm_info_resp.apn.apn, cfg.apn.c_str(), len);
esm_info_resp.apn.apn[len] = '\0';
}
if (cfg.user != "" && cfg.user.length() < LIBLTE_STRING_LEN &&
cfg.pass != "" && cfg.pass.length() < LIBLTE_STRING_LEN) {
nas_log->debug("Including CHAP authentication for user %s in ESM info response\n", cfg.user.c_str());
// Generate CHAP challenge
uint16_t len = 1 /* CHAP code */ +
1 /* ID */ +
2 /* complete length */ +
1 /* data value size */ +
16 /* data value */ +
cfg.user.length();
uint8_t challenge[len] = {};
challenge[0] = 0x01; // challenge code
challenge[1] = chap_id; // ID
challenge[2] = (len >> 8) & 0xff;
challenge[3] = len & 0xff;
challenge[4] = 16;
// Append random challenge value
for (int i = 0; i < 16; i++) {
challenge[5 + i] = rand() & 0xFF;
}
// add user as name field
for (size_t i = 0; i < cfg.user.length(); i++) {
const char *name = cfg.user.c_str();
challenge[21 + i] = name[i];
}
// Generate response
uint8_t response[len] = {};
response[0] = 0x02; // response code
response[1] = chap_id;
response[2] = (len >> 8) & 0xff;
response[3] = len & 0xff;
response[4] = 16;
// Generate response value
uint16_t resp_val_len = 16 /* MD5 len */ +
1 /* ID */ +
cfg.pass.length();
uint8_t resp_val[resp_val_len];
resp_val[0] = chap_id;
// add secret
for (size_t i = 0; i < cfg.pass.length(); i++) {
const char* pass = cfg.pass.c_str();
resp_val[1 + i] = pass[i];
}
// copy original challenge behind secret
uint8_t *chal_val = &challenge[5];
memcpy(&resp_val[1+cfg.pass.length()], chal_val, 16);
// Compute MD5 of resp_val and add to response
security_md5(resp_val, resp_val_len, &response[5]);
// add user as name field again
for (size_t i = 0; i < cfg.user.length(); i++) {
const char *name = cfg.user.c_str();
response[21 + i] = name[i];
}
// Add challenge and resposne to ESM info response
esm_info_resp.protocol_cnfg_opts_present = true;
esm_info_resp.protocol_cnfg_opts.opt[0].id = LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_CHAP;
memcpy(esm_info_resp.protocol_cnfg_opts.opt[0].contents, challenge, sizeof(challenge));
esm_info_resp.protocol_cnfg_opts.opt[0].len = sizeof(challenge);
esm_info_resp.protocol_cnfg_opts.opt[1].id = LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_CHAP;
memcpy(esm_info_resp.protocol_cnfg_opts.opt[1].contents, response, sizeof(response));
esm_info_resp.protocol_cnfg_opts.opt[1].len = sizeof(response);
esm_info_resp.protocol_cnfg_opts.N_opts = 2;
} else {
esm_info_resp.protocol_cnfg_opts_present = false;
}
byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
return;
}
if (liblte_mme_pack_esm_information_response_msg(&esm_info_resp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *)pdu)) {
nas_log->error("Error packing ESM information response.\n");
return;
}
if(pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
cipher_encrypt(pdu);
if (pdu->N_bytes > 5) {
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
&pdu->msg[1]);
} else {
nas_log->error("Invalid PDU size %d\n", pdu->N_bytes);
return;
}
nas_log->info_hex(pdu->msg, pdu->N_bytes, "Sending ESM information response\n");
rrc->write_sdu(cfg.lcid, pdu);
ctxt.tx_count++;
chap_id++;
}
/******************************************************************************* /*******************************************************************************

File diff suppressed because it is too large Load Diff

@ -1784,7 +1784,6 @@ void rrc::process_pcch(byte_buffer_t *pdu) {
if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) { if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) {
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "PCCH message received %d bytes\n", pdu->N_bytes); rrc_log->info_hex(pdu->msg, pdu->N_bytes, "PCCH message received %d bytes\n", pdu->N_bytes);
rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us());
rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes);
LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg;
ZERO_OBJECT(pcch_msg); ZERO_OBJECT(pcch_msg);
@ -1807,9 +1806,6 @@ void rrc::process_pcch(byte_buffer_t *pdu) {
rrc_log->info("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, rrc_log->info("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi);
rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi);
if (ueIdentity.mmec == s_tmsi_paged->mmec && ueIdentity.m_tmsi == s_tmsi_paged->m_tmsi) { if (ueIdentity.mmec == s_tmsi_paged->mmec && ueIdentity.m_tmsi == s_tmsi_paged->m_tmsi) {
if (RRC_STATE_IDLE == state) { if (RRC_STATE_IDLE == state) {
rrc_log->info("S-TMSI match in paging message\n"); rrc_log->info("S-TMSI match in paging message\n");
@ -2026,7 +2022,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
// Generate AS security keys // Generate AS security keys
uint8_t k_asme[32]; uint8_t k_asme[32];
nas->get_k_asme(k_asme, 32); nas->get_k_asme(k_asme, 32);
usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); usim->generate_as_keys(k_asme, nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc"); rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc");
rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int");
rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc");

@ -36,7 +36,7 @@ namespace srsue{
usim::usim() : initiated(false) usim::usim() : initiated(false)
{} {}
void usim::init(usim_args_t *args, srslte::log *usim_log_) int usim::init(usim_args_t *args, srslte::log *usim_log_)
{ {
usim_log = usim_log_; usim_log = usim_log_;
imsi_str = args->imsi; imsi_str = args->imsi;
@ -89,6 +89,8 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
auth_algo = auth_algo_xor; auth_algo = auth_algo_xor;
} }
initiated = true; initiated = true;
return SRSLTE_SUCCESS;
} }
void usim::stop() void usim::stop()
@ -189,18 +191,18 @@ bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
return true; return true;
} }
void usim::generate_authentication_response(uint8_t *rand, auth_result_t usim::generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
if(auth_algo_xor == auth_algo) { if(auth_algo_xor == auth_algo) {
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); return gen_auth_res_xor(rand, autn_enb, mcc, mnc, res, res_len, k_asme);
} else { } else {
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); return gen_auth_res_milenage(rand, autn_enb, mcc, mnc, res, res_len, k_asme);
} }
} }
@ -322,19 +324,18 @@ void usim::generate_as_keys_ho(uint32_t pci,
Helpers Helpers
*******************************************************************************/ *******************************************************************************/
void usim::gen_auth_res_milenage( uint8_t *rand, auth_result_t usim::gen_auth_res_milenage(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
auth_result_t result = AUTH_OK;
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];
*net_valid = true;
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
security_milenage_f2345( k, security_milenage_f2345( k,
op, op,
@ -344,6 +345,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
ik, ik,
ak); ak);
*res_len = 8;
// Extract sqn from autn // Extract sqn from autn
for(i=0;i<6;i++) for(i=0;i<6;i++)
{ {
@ -382,7 +385,7 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
{ {
if(autn[i] != autn_enb[i]) if(autn[i] != autn_enb[i])
{ {
*net_valid = false; result = AUTH_FAILED;
} }
} }
@ -394,24 +397,25 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
mcc, mcc,
mnc, mnc,
k_asme); k_asme);
return result;
} }
// 3GPP TS 34.108 version 10.0.0 Section 8 // 3GPP TS 34.108 version 10.0.0 Section 8
void usim::gen_auth_res_xor(uint8_t *rand, auth_result_t usim::gen_auth_res_xor(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
auth_result_t result = AUTH_OK;
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];
uint8_t xdout[16]; uint8_t xdout[16];
uint8_t cdout[8]; uint8_t cdout[8];
*net_valid = true;
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) { for(i=0; i<16; i++) {
xdout[i] = k[i]^rand[i]; xdout[i] = k[i]^rand[i];
@ -425,6 +429,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
ak[i] = xdout[i+3]; ak[i] = xdout[i+3];
} }
*res_len = 8;
// Extract sqn from autn // Extract sqn from autn
for(i=0;i<6;i++) { for(i=0;i<6;i++) {
sqn[i] = autn_enb[i] ^ ak[i]; sqn[i] = autn_enb[i] ^ ak[i];
@ -466,7 +472,7 @@ void usim::gen_auth_res_xor(uint8_t *rand,
{ {
if(autn[i] != autn_enb[i]) if(autn[i] != autn_enb[i])
{ {
*net_valid = false; result = AUTH_FAILED;
} }
} }
@ -478,6 +484,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
mcc, mcc,
mnc, mnc,
k_asme); k_asme);
return result;
} }
void usim::str_to_hex(std::string str, uint8_t *hex) void usim::str_to_hex(std::string str, uint8_t *hex)

@ -0,0 +1,59 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <srsue/hdr/upper/usim_base.h>
#include <srsue/hdr/upper/usim.h>
#ifdef HAVE_PCSC
#include <srsue/hdr/upper/pcsc_usim.h>
#endif
namespace srsue{
usim_base* usim_base::get_instance(usim_args_t *args, srslte::log *usim_log_)
{
usim_base* instance = NULL;
if (args->mode == "soft") {
instance = new usim();
}
#if HAVE_PCSC
else if (args->mode == "pcsc") {
instance = new pcsc_usim();
}
#endif
else {
// default to soft USIM
instance = new usim();
}
return(instance);
}
usim_base::usim_base() {
}
usim_base::~usim_base() {
}
} // namespace srsue

@ -22,6 +22,11 @@ add_executable(usim_test usim_test.cc)
target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy) target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy)
add_test(usim_test usim_test) add_test(usim_test usim_test)
if(HAVE_PCSC)
add_executable(pcsc_usim_test pcsc_usim_test.cc)
target_link_libraries(pcsc_usim_test srsue_upper srslte_upper srslte_phy)
endif(HAVE_PCSC)
add_executable(rrc_reconfig_test rrc_reconfig_test.cc) add_executable(rrc_reconfig_test rrc_reconfig_test.cc)
target_link_libraries(rrc_reconfig_test srsue_upper srslte_upper srslte_phy) target_link_libraries(rrc_reconfig_test srsue_upper srslte_upper srslte_phy)
add_test(rrc_reconfig_test rrc_reconfig_test) add_test(rrc_reconfig_test rrc_reconfig_test)

@ -26,6 +26,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include "srsue/hdr/upper/usim_base.h"
#include "srsue/hdr/upper/usim.h" #include "srsue/hdr/upper/usim.h"
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/upper/nas.h"
#include "srslte/upper/rlc.h" #include "srslte/upper/rlc.h"
@ -59,6 +60,8 @@ uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42,
0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01, 0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01,
0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 }; 0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 };
uint8_t esm_info_req_pdu[] = { 0x27, 0x1d, 0xbf, 0x7e, 0x05, 0x01, 0x02, 0x5a, 0xd9 };
uint16 mcc = 61441; uint16 mcc = 61441;
uint16 mnc = 65281; uint16 mnc = 65281;
@ -197,13 +200,16 @@ int mme_attach_request_test()
nas_log.set_level(srslte::LOG_LEVEL_DEBUG); nas_log.set_level(srslte::LOG_LEVEL_DEBUG);
rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); rrc_log.set_level(srslte::LOG_LEVEL_DEBUG);
usim_log.set_level(srslte::LOG_LEVEL_DEBUG);
nas_log.set_hex_limit(100000); nas_log.set_hex_limit(100000);
rrc_log.set_hex_limit(100000); rrc_log.set_hex_limit(100000);
usim_log.set_hex_limit(100000);
rrc_dummy rrc_dummy; rrc_dummy rrc_dummy;
gw_dummy gw; gw_dummy gw;
srsue::usim usim; srsue::usim usim;
usim_args_t args; usim_args_t args;
args.mode = "soft";
args.algo = "xor"; args.algo = "xor";
args.imei = "353490069873319"; args.imei = "353490069873319";
args.imsi = "001010123456789"; args.imsi = "001010123456789";
@ -212,6 +218,7 @@ int mme_attach_request_test()
usim.init(&args, &usim_log); usim.init(&args, &usim_log);
srslte_nas_config_t nas_cfg; srslte_nas_config_t nas_cfg;
nas_cfg.apn = "test123";
srsue::nas nas; srsue::nas nas;
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
@ -236,6 +243,63 @@ int mme_attach_request_test()
} }
int esm_info_request_test()
{
int ret = SRSLTE_ERROR;
srslte::log_filter nas_log("NAS");
srslte::log_filter rrc_log("RRC");
srslte::log_filter mac_log("MAC");
srslte::log_filter usim_log("USIM");
nas_log.set_level(srslte::LOG_LEVEL_DEBUG);
rrc_log.set_level(srslte::LOG_LEVEL_DEBUG);
nas_log.set_hex_limit(100000);
rrc_log.set_hex_limit(100000);
rrc_dummy rrc_dummy;
gw_dummy gw;
usim_args_t args;
args.algo = "xor";
args.imei = "353490069873319";
args.imsi = "001010123456789";
args.k = "00112233445566778899aabbccddeeff";
args.op = "63BFA50EE6523365FF14C1F45F88737D";
// init USIM
srsue::usim usim;
bool net_valid;
uint8_t res[16];
usim.init(&args, &usim_log);
srslte::byte_buffer_pool *pool;
pool = byte_buffer_pool::get_instance();
srsue::nas nas;
srslte_nas_config_t cfg;
cfg.apn = "srslte";
cfg.user = "srsuser";
cfg.pass = "srspass";
nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg);
// push ESM info request PDU to NAS to generate response
byte_buffer_t* tmp = pool->allocate();
memcpy(tmp->msg, esm_info_req_pdu, sizeof(esm_info_req_pdu));
tmp->N_bytes = sizeof(esm_info_req_pdu);
nas.write_pdu(LCID, tmp);
// check length of generated NAS SDU
if (rrc_dummy.get_last_sdu_len() > 3) {
ret = SRSLTE_SUCCESS;
}
pool->cleanup();
return ret;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (security_command_test()) { if (security_command_test()) {
@ -248,5 +312,10 @@ int main(int argc, char **argv)
return -1; return -1;
} }
if (esm_info_request_test()) {
printf("ESM info request test failed.\n");
return -1;
}
return 0; return 0;
} }

@ -0,0 +1,66 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include "srsue/hdr/upper/pcsc_usim.h"
#include "srslte/common/log_filter.h"
#include <assert.h>
#include <srsue/hdr/upper/usim_base.h>
using namespace srsue;
using namespace std;
uint8_t rand_enb[] = {0xbc, 0x4c, 0xb0, 0x27, 0xb3, 0x4b, 0x7f, 0x51, 0x21, 0x5e, 0x56, 0x5f, 0x67, 0x3f, 0xde, 0x4f};
uint8_t autn_enb[] = {0x5a, 0x17, 0x77, 0x3c, 0x62, 0x57, 0x90, 0x01, 0xcf, 0x47, 0xf7, 0x6d, 0xb3, 0xa0, 0x19, 0x46};
int main(int argc, char **argv)
{
srslte::log_filter usim_log("USIM");
usim_log.set_level(srslte::LOG_LEVEL_DEBUG);
usim_log.set_hex_limit(100000);
uint8_t res[16];
int res_len;
uint8_t k_asme[32];
uint16 mcc = 0;
uint16 mnc = 0;
usim_args_t args;
args.pin = "6129";
args.imei = "353490069873319";
srsue::pcsc_usim usim;
if (usim.init(&args, &usim_log)) {
printf("Error initializing PC/SC USIM.\n");
return SRSLTE_ERROR;
};
std::string imsi = usim.get_imsi_str();
cout << "IMSI: " << imsi << endl;
auth_result_t result = usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme);
return SRSLTE_SUCCESS;
}

@ -70,18 +70,18 @@ int main(int argc, char **argv)
srslte::log_filter usim_log("USIM"); srslte::log_filter usim_log("USIM");
bool net_valid; bool net_valid;
uint8_t res[16]; uint8_t res[16];
int res_len;
uint8_t k_asme[32]; uint8_t k_asme[32];
usim_args_t args; usim_args_t args;
args.algo = "milenage"; args.algo = "milenage";
args.imei = "35609204079301"; args.imei = "356092040793011";
args.imsi = "208930000000001"; args.imsi = "208930000000001";
args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
args.op = "11111111111111111111111111111111"; args.op = "11111111111111111111111111111111";
srsue::usim usim; srsue::usim usim;
usim.init(&args, &usim_log); usim.init(&args, &usim_log);
usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, k_asme);
assert(net_valid == true); assert(usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, res, &res_len, k_asme) == AUTH_OK);
} }

@ -86,20 +86,22 @@ file_max_size = -1
##################################################################### #####################################################################
# USIM configuration # USIM configuration
# #
# mode: USIM mode (soft/pcsc)
# algo: Authentication algorithm (xor/milenage) # algo: Authentication algorithm (xor/milenage)
# op: 128-bit Operator Variant Algorithm Configuration Field (hex) # op: 128-bit Operator Variant Algorithm Configuration Field (hex)
# amf: 16-bit Authentication Management Field (hex)
# k: 128-bit subscriber key (hex) # k: 128-bit subscriber key (hex)
# imsi: 15 digit International Mobile Subscriber Identity # imsi: 15 digit International Mobile Subscriber Identity
# imei: 15 digit International Mobile Station Equipment Identity # imei: 15 digit International Mobile Station Equipment Identity
# pin: PIN in case real SIM card is used
##################################################################### #####################################################################
[usim] [usim]
mode = soft
algo = xor algo = xor
op = 63BFA50EE6523365FF14C1F45F88737D op = 63BFA50EE6523365FF14C1F45F88737D
k = 00112233445566778899aabbccddeeff k = 00112233445566778899aabbccddeeff
imsi = 001010123456789 imsi = 001010123456789
imei = 353490069873319 imei = 353490069873319
#pin = 1234
##################################################################### #####################################################################
# RRC configuration # RRC configuration

Loading…
Cancel
Save