diff --git a/CMakeLists.txt b/CMakeLists.txt
index df9cf4f32..e30c18d9d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,6 +131,16 @@ else(POLARSSL_FOUND)
endif (MBEDTLS_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
find_package(UHD)
if(UHD_FOUND)
diff --git a/LICENSE b/LICENSE
index 2def0e883..4ac29ae7d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -658,4 +658,40 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
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
-.
\ No newline at end of file
+.
+
+
+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 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.
\ No newline at end of file
diff --git a/README.md b/README.md
index a8f186a62..4a68f520a 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,7 @@ Note that depending on your flavor and version of Linux, the actual package name
* Optional requirements:
* 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:
* UHD: https://github.com/EttusResearch/uhd
diff --git a/cmake/modules/FindPCSCLite.cmake b/cmake/modules/FindPCSCLite.cmake
new file mode 100644
index 000000000..e335a7f41
--- /dev/null
+++ b/cmake/modules/FindPCSCLite.cmake
@@ -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)
\ No newline at end of file
diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h
index 4a168bca2..3d9640806 100644
--- a/lib/include/srslte/asn1/liblte_mme.h
+++ b/lib/include/srslte/asn1/liblte_mme.h
@@ -2810,6 +2810,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_S
// Structs
typedef struct{
uint8 res[16];
+ int res_len;
}LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT;
// Functions
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;
// Functions
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_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);
diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h
index 50eb024b5..5051cacbe 100644
--- a/lib/include/srslte/common/interfaces_common.h
+++ b/lib/include/srslte/common/interfaces_common.h
@@ -38,13 +38,17 @@ namespace srslte {
class srslte_nas_config_t
{
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_),
- apn(apn_)
+ apn(apn_),
+ user(user_),
+ pass(pass_)
{}
uint32_t lcid;
std::string apn;
+ std::string user;
+ std::string pass;
};
diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h
index f88d48a17..5dc8a6305 100644
--- a/lib/include/srslte/common/security.h
+++ b/lib/include/srslte/common/security.h
@@ -123,6 +123,11 @@ uint8_t security_128_eia2( uint8_t *key,
uint32_t msg_len,
uint8_t *mac);
+uint8_t security_md5(const uint8_t *input,
+ size_t len,
+ uint8_t *output);
+
+
/******************************************************************************
* Encryption / Decryption
*****************************************************************************/
diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h
index 601a13b37..9545d9424 100644
--- a/lib/include/srslte/interfaces/ue_interfaces.h
+++ b/lib/include/srslte/interfaces/ue_interfaces.h
@@ -43,6 +43,12 @@
namespace srsue {
+typedef enum {
+ AUTH_OK,
+ AUTH_FAILED,
+ AUTH_SYNCH_FAILURE
+} auth_result_t;
+
// 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_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 void generate_authentication_response(uint8_t *rand,
+ virtual auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb,
uint16_t mcc,
uint16_t mnc,
- bool *net_valid,
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,
diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc
index 0425e8a35..189f9138a 100644
--- a/lib/src/asn1/liblte_mme.cc
+++ b/lib/src/asn1/liblte_mme.cc
@@ -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
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res,
+ int res_len,
uint8 **ie_ptr)
{
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 &&
ie_ptr != NULL)
{
- (*ie_ptr)[0] = 8;
- for(i=0; i<8; i++)
+ (*ie_ptr)[0] = res_len;
+ *ie_ptr += 1;
+ for(i=0; iaddr[i] = (*ie_ptr)[2+i];
}
}
- *ie_ptr += (*ie_ptr)[0];
+ *ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS;
}
@@ -6195,7 +6197,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENT
msg_ptr++;
// 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
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)
{
// 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++;
// 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;
uint8 *msg_ptr = msg->msg;
+ uint8 sec_hdr_type;
if(msg != 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
esm_info_req->eps_bearer_id = (*msg_ptr >> 4);
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
*********************************************************************/
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_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 &&
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
*msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;
@@ -10115,6 +10142,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
return(err);
}
+
+
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)
{
@@ -10132,7 +10161,7 @@ LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG
{
msg_ptr++;
}else{
- msg_ptr += 7;
+ msg_ptr += 6;
}
// EPS Bearer ID
esm_info_resp->eps_bearer_id = (*msg_ptr >> 4);
diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc
index b10b5beab..63cd478c0 100644
--- a/lib/src/common/security.cc
+++ b/lib/src/common/security.cc
@@ -29,6 +29,13 @@
#include "srslte/common/liblte_security.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 {
/******************************************************************************
@@ -166,6 +173,19 @@ uint8_t security_128_eia2( uint8_t *key,
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
*****************************************************************************/
diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt
index 07d0a777f..1770c0f60 100644
--- a/lib/test/upper/CMakeLists.txt
+++ b/lib/test/upper/CMakeLists.txt
@@ -32,9 +32,9 @@ add_test(rlc_am_test rlc_am_test)
add_executable(rlc_stress_test rlc_stress_test.cc)
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_um_stress_test rlc_stress_test --mode=UM)
-add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --opp_sdu_ratio=1.0)
+add_test(rlc_am_stress_test rlc_stress_test --mode=AM --loglevel 1)
+add_test(rlc_um_stress_test rlc_stress_test --mode=UM --loglevel 1)
+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)
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)
diff --git a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc
index a509b8a70..2ba49ae01 100644
--- a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc
+++ b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc
@@ -283,8 +283,8 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECON
if (ecm_ctx->state == ECM_STATE_CONNECTED)
{
//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->info("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\n");
//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.
diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc
index b6220f33a..f4114603a 100644
--- a/srsepc/src/mme/s1ap_nas_transport.cc
+++ b/srsepc/src/mme/s1ap_nas_transport.cc
@@ -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)
{
- //Integrity protected NAS message, possibly chiphered.
+ //Integrity protected NAS message, possibly ciphered.
emm_ctx->security_ctxt.ul_nas_count++;
mac_valid = integrity_check(emm_ctx,nas_msg);
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);
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;
}
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);
if(esm_info_resp.apn_present)
{
- m_s1ap_log->info("ESM Info: APN %d\n",esm_info_resp.eps_bearer_id);
- m_s1ap_log->console("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 %s\n",esm_info_resp.apn.apn);
}
if(esm_info_resp.protocol_cnfg_opts_present)
{
@@ -1683,10 +1683,10 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
dw_nas->SubscriberProfileIDforRFP_present=false;
LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT esm_info_req;
- 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;
- 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++;
@@ -1709,6 +1709,7 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
);
memcpy(&nas_buffer->msg[1],mac,4);
+
//Copy NAS PDU to Downlink NAS Trasport message buffer
memcpy(dw_nas->NAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes);
dw_nas->NAS_PDU.n_octets = nas_buffer->N_bytes;
diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h
index e606e2630..8ddb227be 100644
--- a/srsue/hdr/ue.h
+++ b/srsue/hdr/ue.h
@@ -100,7 +100,7 @@ private:
srsue::rrc rrc;
srsue::nas nas;
srsue::gw gw;
- srsue::usim usim;
+ srsue::usim_base* usim;
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h
index aec33d60b..2f495d7d1 100644
--- a/srsue/hdr/ue_base.h
+++ b/srsue/hdr/ue_base.h
@@ -128,7 +128,9 @@ typedef struct {
usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
- std::string apn;
+ std::string apn_name;
+ std::string apn_user;
+ std::string apn_pass;
expert_args_t expert;
}all_args_t;
diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h
index ee9838dd4..e84b4002a 100644
--- a/srsue/hdr/upper/nas.h
+++ b/srsue/hdr/upper/nas.h
@@ -127,6 +127,8 @@ private:
uint32_t ip_addr;
uint8_t eps_bearer_id;
+ uint8_t chap_id;
+
uint8_t transaction_id;
// Security
@@ -171,7 +173,10 @@ private:
// Senders
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 send_security_mode_reject(uint8_t cause);
diff --git a/srsue/hdr/upper/pcsc_usim.h b/srsue/hdr/upper/pcsc_usim.h
new file mode 100644
index 000000000..862b740f1
--- /dev/null
+++ b/srsue/hdr/upper/pcsc_usim.h
@@ -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
+#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
+
+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 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
+ * GET RESPONSE: C0 00 00
+ * RUN GSM ALG: 88 00 00 00
+ * RUN UMTS ALG: 88 00 81 data: 0x10 | RAND | 0x10 | AUTN
+ * P1 = ID of alg in card
+ * P2 = ID of secret key
+ * READ BINARY: B0
+ * READ RECORD: B2
+ * P2 (mode) = '02' (next record), '03' (previous record),
+ * '04' (absolute mode)
+ * VERIFY CHV: 20 00 08
+ * CHANGE CHV: 24 00 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
diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h
index a5f703781..a95d0cf8a 100644
--- a/srsue/hdr/upper/usim.h
+++ b/srsue/hdr/upper/usim.h
@@ -28,6 +28,7 @@
#define SRSUE_USIM_H
#include
+#include "usim_base.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
@@ -35,26 +36,12 @@
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
- :public usim_interface_nas
- ,public usim_interface_rrc
+ :public usim_base
{
public:
usim();
- void init(usim_args_t *args, srslte::log *usim_log_);
+ int init(usim_args_t *args, srslte::log *usim_log_);
void stop();
// NAS interface
@@ -65,13 +52,13 @@ public:
bool get_imei_vec(uint8_t* imei_, uint32_t n);
bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
- void generate_authentication_response(uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme);
+ 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,
@@ -101,20 +88,20 @@ public:
private:
- void gen_auth_res_milenage( uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme);
- void gen_auth_res_xor( uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme);
+ 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);
void str_to_hex(std::string str, uint8_t *hex);
srslte::log *usim_log;
diff --git a/srsue/hdr/upper/usim_base.h b/srsue/hdr/upper/usim_base.h
new file mode 100644
index 000000000..e8583bd46
--- /dev/null
+++ b/srsue/hdr/upper/usim_base.h
@@ -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
+#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
diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc
index c0c325edd..14de5cb0d 100644
--- a/srsue/src/mac/mac.cc
+++ b/srsue/src/mac/mac.cc
@@ -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()
{
+ // 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];
if (value > 0) {
timers.get(timer_alignment)->set(this, value);
diff --git a/srsue/src/main.cc b/srsue/src/main.cc
index 4a1280300..31d5a2306 100644
--- a/srsue/src/main.cc
+++ b/srsue/src/main.cc
@@ -83,7 +83,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"UECapabilityInformation message. Default 0xe6041c00")
("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
- ("nas.apn", bpo::value(&args->apn)->default_value(""), "Set Access Point Name (APN) for data services")
+ ("nas.apn", bpo::value(&args->apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
+ ("nas.user", bpo::value(&args->apn_user)->default_value(""), "Username for CHAP authentication")
+ ("nas.pass", bpo::value(&args->apn_pass)->default_value(""), "Password for CHAP authentication")
("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value(&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(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename")
("log.file_max_size", bpo::value(&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(&args->usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)")
("usim.algo", bpo::value(&args->usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value(&args->usim.op), "USIM operator variant")
("usim.imsi", bpo::value(&args->usim.imsi), "USIM IMSI")
("usim.imei", bpo::value(&args->usim.imei), "USIM IMEI")
("usim.k", bpo::value(&args->usim.k), "USIM K")
-
+ ("usim.pin", bpo::value(&args->usim.pin), "PIN in case real SIM card is used")
/* Expert section */
("expert.ip_netmask",
diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc
index 647ff8053..602408f43 100644
--- a/srsue/src/ue.cc
+++ b/srsue/src/ue.cc
@@ -47,11 +47,13 @@ ue::~ue()
for (uint32_t i = 0; i < phy_log.size(); i++) {
delete(phy_log[i]);
}
+ if (usim) {
+ delete usim;
+ }
}
-bool ue::init(all_args_t *args_)
-{
- args = args_;
+bool ue::init(all_args_t *args_) {
+ args = args_;
if (!args->log.filename.compare("stdout")) {
logger = &logger_stdout;
@@ -131,6 +133,13 @@ bool ue::init(all_args_t *args_)
// 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
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant;
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 */);
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); /* RB_ID_SRB1 */
- nas.init(&usim, &rrc, &gw, &nas_log, nas_cfg);
+ srslte_nas_config_t nas_cfg(1, args->apn_name, args->apn_user, args->apn_pass); /* RB_ID_SRB1 */
+ nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
-
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
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
args->rrc.nof_supported_bands = 1;
@@ -243,7 +250,7 @@ void ue::stop()
{
if(started)
{
- usim.stop();
+ usim->stop();
nas.stop();
rrc.stop();
diff --git a/srsue/src/upper/CMakeLists.txt b/srsue/src/upper/CMakeLists.txt
index 43e6acf4c..766893bbd 100644
--- a/srsue/src/upper/CMakeLists.txt
+++ b/srsue/src/upper/CMakeLists.txt
@@ -18,6 +18,16 @@
# 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})
-install(TARGETS srsue_upper DESTINATION ${LIBRARY_DIR})
+
+if(HAVE_PCSC)
+ target_link_libraries(srsue_upper ${PCSCLITE_LIBRARY})
+endif(HAVE_PCSC)
+
+install(TARGETS srsue_upper DESTINATION ${LIBRARY_DIR})
\ No newline at end of file
diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc
index 067e6bfab..c4f7a4584 100644
--- a/srsue/src/upper/nas.cc
+++ b/srsue/src/upper/nas.cc
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include "srslte/asn1/liblte_rrc.h"
#include "srsue/hdr/upper/nas.h"
#include "srslte/common/security.h"
@@ -52,6 +53,7 @@ nas::nas()
ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
plmn_is_selected = false;
+ chap_id = 0;
}
void nas::init(usim_interface_nas *usim_,
@@ -82,6 +84,10 @@ void nas::init(usim_interface_nas *usim_,
have_guti = true;
have_ctxt = true;
}
+
+ // set seed for rand (used in CHAP auth)
+ srand(time(NULL));
+
running = true;
}
@@ -353,7 +359,13 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
}
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) {
@@ -517,7 +529,7 @@ void nas::cipher_decrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break;
default:
- nas_log->error("Ciphering algorithmus not known");
+ nas_log->error("Ciphering algorithmus not known\n");
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;
}
+ // 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
// act_def_eps_bearer_context_req.eps_qos.qci
// 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) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
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");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
- // Reuse the pdu for the response message
- pdu->reset();
+ // Deallocate PDU after parsing
+ pool->deallocate(pdu);
// Generate authentication response using RAND, AUTN & KSI-ASME
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);
- bool net_valid;
uint8_t res[16];
- usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc,
- &net_valid, res, ctxt.k_asme);
- nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
+ int res_len = 0;
+ nas_log->debug_hex(auth_req.rand, 16, "Authentication request RAND\n");
+ 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) {
ctxt.ksi = auth_req.nas_ksi.nas_ksi;
} 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");
}
- if (net_valid) {
+ if (auth_result == AUTH_OK) {
nas_log->info("Network authentication successful\n");
- for (int i = 0; i < 8; i++) {
- auth_res.res[i] = res[i];
- }
- liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
-
- 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);
+ send_authentication_response(res, res_len);
+ nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
+ } else if (auth_result == AUTH_SYNCH_FAILURE) {
+ nas_log->error("Network authentication synchronization failure.\n");
+ send_authentication_failure(LIBLTE_MME_EMM_CAUSE_SYNCH_FAILURE, res);
} else {
nas_log->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) {
- 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);
+
+ // send response
+ send_esm_information_response(esm_info_req.proc_transaction_id);
}
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.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.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.additional_guti_present = false;
attach_req.last_visited_registered_tai_present = false;
@@ -993,6 +1028,8 @@ void nas::gen_attach_request(byte_buffer_t *msg) {
}
} else {
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);
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);
@@ -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.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
+ pdn_con_req.apn_present = false;
// Set the optional flags
- pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
if (cfg.apn == "") {
- pdn_con_req.apn_present = false;
+ pdn_con_req.esm_info_transfer_flag_present = false;
} else {
- pdn_con_req.apn_present = true;
- LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0};
- strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
- pdn_con_req.apn = apn;
+ // request ESM info transfer is APN is specified
+ pdn_con_req.esm_info_transfer_flag_present = true;
+ pdn_con_req.esm_info_transfer_flag = LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_REQUIRED;
}
+
pdn_con_req.protocol_cnfg_opts_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);
}
+
+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_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++;
+}
/*******************************************************************************
diff --git a/srsue/src/upper/pcsc_usim.cc b/srsue/src/upper/pcsc_usim.cc
new file mode 100644
index 000000000..26b7f8a1a
--- /dev/null
+++ b/srsue/src/upper/pcsc_usim.cc
@@ -0,0 +1,1315 @@
+/**
+ *
+ * \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
+#include
+#include "srslte/common/bcd_helpers.h"
+
+#define CHECK_SIM_PIN 1
+
+using namespace srslte;
+
+namespace srsue{
+
+pcsc_usim::pcsc_usim() : initiated(false)
+{
+ bzero(ck, CK_LEN);
+ bzero(ik, IK_LEN);
+ bzero(auts, IK_LEN);
+}
+
+pcsc_usim::~pcsc_usim()
+{
+ sc.deinit();
+}
+
+int pcsc_usim::init(usim_args_t *args, srslte::log *log_)
+{
+ int ret = SRSLTE_ERROR;
+ log = log_;
+
+ if (sc.init(args, log_) != SRSLTE_SUCCESS) {
+ return ret;
+ }
+
+ // Read IMSI from SIM card
+ char tmp[15];
+ size_t tmp_len = 15; // set to max IMSI length
+ if (sc.get_imsi(tmp, &tmp_len)) {
+ log->error("Error reading IMSI from SIM.\n");
+ return ret;
+ }
+ imsi_str = tmp;
+
+ // Check extracted IMSI and convert
+ if(15 == imsi_str.length()) {
+ const char *imsi_c = imsi_str.c_str();
+ imsi = 0;
+ for(int i = 0; i < 15; i++)
+ {
+ imsi *= 10;
+ imsi += imsi_c[i] - '0';
+ }
+ } else {
+ log->error("Invalid length for IMSI: %zu should be %d\n", imsi_str.length(), 15);
+ log->console("Invalid length for IMSI: %zu should be %d\n", imsi_str.length(), 15);
+ return ret;
+ }
+
+ // Check IMEI
+ if(15 == args->imei.length()) {
+ const char *imei_c = args->imei.c_str();
+ imei = 0;
+ for(int i = 0; i < 15; i++)
+ {
+ imei *= 10;
+ imei += imei_c[i] - '0';
+ }
+ } else {
+ log->error("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15);
+ log->console("Invalid length for IMEI: %zu should be %d\n", args->imei.length(), 15);
+ return ret;
+ }
+
+ // Get MNC length
+ mnc_length = sc.get_mnc_len();
+ log->debug("MNC length %d\n", mnc_length);
+
+ initiated = true;
+ ret = SRSLTE_SUCCESS;
+
+ return ret;
+}
+
+void pcsc_usim::stop()
+{}
+
+
+/*******************************************************************************
+ NAS interface
+*******************************************************************************/
+
+std::string pcsc_usim::get_imsi_str()
+{
+ return imsi_str;
+}
+std::string pcsc_usim::get_imei_str()
+{
+ return imei_str;
+}
+
+bool pcsc_usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return false;
+ }
+
+ if(NULL == imsi_ || n < 15) {
+ log->error("Invalid parameters to get_imsi_vec");
+ return false;
+ }
+
+ uint64_t temp = imsi;
+ for(int i=14;i>=0;i--) {
+ imsi_[i] = temp % 10;
+ temp /= 10;
+ }
+ return true;
+}
+
+bool pcsc_usim::get_imei_vec(uint8_t* imei_, uint32_t n)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return false;
+ }
+
+ if(NULL == imei_ || n < 15) {
+ log->error("Invalid parameters to get_imei_vec");
+ return false;
+ }
+
+ uint64 temp = imei;
+ for(int i=14;i>=0;i--)
+ {
+ imei_[i] = temp % 10;
+ temp /= 10;
+ }
+ return true;
+}
+
+bool pcsc_usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return false;
+ }
+
+ uint8_t imsi_vec[15];
+ get_imsi_vec(imsi_vec, 15);
+
+ std::ostringstream mcc_str, mnc_str;
+
+ int mcc_len = 3;
+ for (int i=0;imcc);
+ string_to_mnc(mnc_str.str(), &home_plmn_id->mnc);
+
+ log->info("Read Home PLMN Id=%s\n",
+ plmn_id_to_string(*home_plmn_id).c_str());
+
+ return true;
+}
+
+auth_result_t pcsc_usim::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)
+{
+ auth_result_t ret = AUTH_FAILED;
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ 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:
+ log->info("SCARD: USIM authentication successful.\n");
+ break;
+ case -1:
+ log->error("SCARD: Failure during USIM UMTS authentication\n");
+ return ret;
+ case -2:
+ log->info("SCARD: USIM synchronization failure, AUTS generated\n");
+ log->debug_hex(auts, AKA_AUTS_LEN, "AUTS\n");
+ memcpy(res, auts, AKA_AUTS_LEN);
+ *res_len = AKA_AUTS_LEN;
+ return AUTH_SYNCH_FAILURE;
+ default:
+ log->warning("SCARD: Unknown USIM failure.\n");
+ return ret;
+ }
+
+ // FIXME: 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
+ log->debug_hex(ck, CK_LEN, "CK:\n");
+ log->debug_hex(ik, IK_LEN, "IK:\n");
+ log->debug_hex(ak, AK_LEN, "AK:\n");
+ log->debug_hex(sqn, SQN_LEN, "SQN:\n");
+ log->debug("mcc=%d, mnc=%d\n", mcc, mnc);
+ security_generate_k_asme( ck,
+ ik,
+ ak,
+ sqn,
+ mcc,
+ mnc,
+ k_asme);
+ log->debug_hex(k_asme, KEY_LEN, "K_ASME:\n");
+
+ ret = AUTH_OK;
+
+ return ret;
+}
+
+void pcsc_usim::generate_nas_keys(uint8_t *k_asme,
+ uint8_t *k_nas_enc,
+ uint8_t *k_nas_int,
+ CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
+ INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return;
+ }
+
+ // Generate K_nas_enc and K_nas_int
+ security_generate_k_nas( k_asme,
+ cipher_algo,
+ integ_algo,
+ k_nas_enc,
+ k_nas_int);
+}
+
+/*******************************************************************************
+ RRC interface
+*******************************************************************************/
+
+void pcsc_usim::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,
+ CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
+ INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return;
+ }
+
+ // Generate K_enb
+ security_generate_k_enb( k_asme,
+ count_ul,
+ k_enb);
+
+ memcpy(this->k_asme, k_asme, 32);
+
+ // Generate K_rrc_enc and K_rrc_int
+ security_generate_k_rrc( k_enb,
+ cipher_algo,
+ integ_algo,
+ k_rrc_enc,
+ k_rrc_int);
+
+ // Generate K_up_enc and K_up_int
+ security_generate_k_up( k_enb,
+ cipher_algo,
+ integ_algo,
+ k_up_enc,
+ k_up_int);
+
+ current_ncc = 0;
+}
+
+void pcsc_usim::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,
+ CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
+ INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
+{
+ if (!initiated) {
+ fprintf(stderr, "USIM not initiated!\n");
+ return;
+ }
+
+ uint8_t *enb_star_key = k_enb;
+
+ if (ncc < 0) {
+ ncc = current_ncc;
+ }
+
+ // Generate successive NH
+ while(current_ncc != (uint32_t) ncc) {
+ uint8_t *sync = NULL;
+ if (current_ncc) {
+ sync = nh;
+ } else {
+ sync = k_enb;
+ }
+ // Generate NH
+ security_generate_nh(k_asme,
+ sync,
+ nh);
+
+ current_ncc++;
+ if (current_ncc == 7) {
+ current_ncc = 0;
+ }
+ enb_star_key = nh;
+ }
+
+ // Generate K_enb
+ security_generate_k_enb_star( enb_star_key,
+ pci,
+ earfcn,
+ k_enb_star);
+
+ // K_enb becomes K_enb*
+ memcpy(k_enb, k_enb_star, 32);
+
+ // Generate K_rrc_enc and K_rrc_int
+ security_generate_k_rrc( k_enb,
+ cipher_algo,
+ integ_algo,
+ k_rrc_enc,
+ k_rrc_int);
+
+ // Generate K_up_enc and K_up_int
+ security_generate_k_up( k_enb,
+ cipher_algo,
+ integ_algo,
+ k_up_enc,
+ k_up_int);
+}
+
+/*******************************************************************************
+ Helpers
+*******************************************************************************/
+
+
+/*********************************
+ * PC/SC class
+ ********************************/
+
+// return 0 if initialization was successfull, -1 otherwies
+int pcsc_usim::scard::init(usim_args_t *args, srslte::log *log_)
+{
+ int ret_value = SRSLTE_ERROR;
+ int pos = 0; // SC reader
+ //int transaction = 1;
+ size_t blen;
+ log = log_;
+
+ long ret;
+ ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_context);
+ if (ret != SCARD_S_SUCCESS) {
+ log->error("SCardEstablishContext(): %s\n", pcsc_stringify_error(ret));
+ return ret_value;
+ }
+
+ unsigned long len;
+ ret = SCardListReaders(scard_context, NULL, NULL, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ log->error("SCardListReaders(): %s\n", pcsc_stringify_error(ret));
+ return ret_value;
+ }
+
+ char *readers = (char *)malloc(len);
+ if (readers == NULL) {
+ log->error("Malloc failed\n");
+ return ret_value;
+ }
+
+ ret = SCardListReaders(scard_context, NULL, readers, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ log->error("SCardListReaders() 2: %s\n", pcsc_stringify_error(ret));
+ goto clean_exit;
+ }
+ if (len < 3) {
+ log->info("No smart card readers available.\n");
+ return ret_value;
+ }
+
+ log->info("%s\n", readers);
+
+ // TODO: Implement reader selection
+ // (readers is a list of available readers. The last entry is terminated with double null)
+ pos = 0; // select first reader
+
+ // Connect to reader
+ ret = SCardConnect(scard_context, &readers[pos], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &scard_handle, &scard_protocol);
+ if (ret != SCARD_S_SUCCESS) {
+ if (ret == (long)SCARD_E_NO_SMARTCARD) {
+ log->error("No smart card inserted.\n");
+ } else {
+ log->error("%s\n", pcsc_stringify_error(ret));
+ }
+ }
+
+ free(readers);
+ readers = NULL;
+
+ log->info("Card=0x%x active_protocol=%lu (%s)\n",
+ (unsigned int)scard_handle, (unsigned long)scard_protocol, scard_protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
+
+ ret = SCardBeginTransaction(scard_handle);
+ if (ret != SCARD_S_SUCCESS) {
+ log->error("%s\n", pcsc_stringify_error(ret));
+ goto clean_exit;
+ }
+
+ // Verify USIM support
+ unsigned char buf[100];
+ blen = sizeof(buf);
+ if (_select_file(SCARD_FILE_MF, buf, &blen, SCARD_USIM, NULL, 0)) {
+ log->info("USIM is not supported. Trying to use GSM SIM");
+ sim_type = SCARD_GSM_SIM;
+ } else {
+ log->info("USIM is supported\n");
+ sim_type = SCARD_USIM;
+ }
+
+ if (sim_type == SCARD_GSM_SIM) {
+ blen = sizeof(buf);
+ if (select_file(SCARD_FILE_MF, buf, &blen)) {
+ log->debug("SCARD: Failed to read MF\n");
+ goto clean_exit;
+ }
+
+ blen = sizeof(buf);
+ if (select_file(SCARD_FILE_GSM_DF, buf, &blen)) {
+ log->debug("SCARD: Failed to read GSM DF\n");
+ goto clean_exit;
+ }
+ } else {
+ unsigned char aid[32];
+ int aid_len;
+
+ aid_len = get_aid(aid, sizeof(aid));
+ if (aid_len < 0) {
+ log->debug("SCARD: Failed to find AID for 3G USIM app - try to use standard 3G RID\n");
+ memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
+ aid_len = 5;
+ }
+
+ log->debug_hex(aid, aid_len, "SCARD: 3G USIM AID\n");
+
+ /* Select based on AID = 3G RID from EF_DIR. This is usually
+ * starting with A0 00 00 00 87. */
+ blen = sizeof(buf);
+ if (_select_file(0, buf, &blen, sim_type, aid, aid_len)) {
+ log->error("SCARD: Failed to read 3G USIM app\n");
+ log->error_hex(aid, aid_len, "SCARD: 3G USIM AID\n");
+ goto clean_exit;
+ }
+ }
+
+#if CHECK_SIM_PIN
+ // Verify whether CHV1 (PIN1) is needed to access the card.
+ ret = pin_needed(buf, blen);
+ if (ret < 0) {
+ log->debug("SCARD: Failed to determine whether PIN is needed\n");
+ goto clean_exit;
+ }
+ if (ret) {
+ log->debug("PIN1 needed for SIM access (retry counter=%d)\n", get_pin_retry_counter());
+ pin1_needed = true;
+ } else {
+ pin1_needed = false;
+ }
+
+ // stop before pin retry counter reaches zero
+ if (pin1_needed && get_pin_retry_counter() <= 1) {
+ log->error("PIN1 needed for SIM access (retry counter=%d), emergency stop.\n", get_pin_retry_counter());
+ goto clean_exit;
+ }
+
+ // Set pin
+ if (pin1_needed) {
+ // verify PIN
+ ret = verify_pin(args->pin.c_str());
+ if (ret != SCARD_S_SUCCESS) {
+ log->debug("SCARD: Could not verify PIN\n");
+ goto clean_exit;
+ }
+ }
+#else
+ pin1_needed = false;
+#endif
+
+ ret = SCardEndTransaction(scard_handle, SCARD_LEAVE_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ log->debug("SCARD: Could not end transaction: 0x%x\n", (unsigned int) ret);
+ goto clean_exit;
+ }
+
+ ret_value = SRSLTE_SUCCESS;
+
+clean_exit:
+ if (readers) {
+ free(readers);
+ }
+
+ return ret_value;
+}
+
+
+int pcsc_usim::scard::_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 ret;
+ unsigned char resp[3];
+ unsigned char cmd[50] = { SIM_CMD_SELECT };
+ int cmdlen;
+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+ size_t len, rlen;
+
+ if (sim_type == SCARD_USIM) {
+ cmd[0] = USIM_CLA;
+ cmd[3] = 0x04;
+ get_resp[0] = USIM_CLA;
+ }
+
+ log->debug("SCARD: select file %04x\n", file_id);
+ if (aid) {
+ log->debug_hex(aid, aidlen, "SCARD: select file by AID");
+ if (5 + aidlen > sizeof(cmd))
+ return -1;
+ cmd[2] = 0x04; /* Select by AID */
+ cmd[4] = aidlen; /* len */
+ memcpy(cmd + 5, aid, aidlen);
+ cmdlen = 5 + aidlen;
+ } else {
+ cmd[5] = file_id >> 8;
+ cmd[6] = file_id & 0xff;
+ cmdlen = 7;
+ }
+ len = sizeof(resp);
+ ret = transmit(cmd, cmdlen, resp, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ log->error("SCARD: SCardTransmit failed %s\n", pcsc_stringify_error(ret));
+ return -1;
+ }
+
+ if (len != 2) {
+ log->error("SCARD: unexpected resp len %d (expected 2)\n", (int)len);
+ return -1;
+ }
+
+ if (resp[0] == 0x98 && resp[1] == 0x04) {
+ /* Security status not satisfied (PIN_WLAN) */
+ log->warning("SCARD: Security status not satisfied.\n");
+ return -1;
+ }
+
+ if (resp[0] == 0x6e) {
+ log->debug("SCARD: used CLA not supported.\n");
+ return -1;
+ }
+
+ if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
+ log->warning("SCARD: unexpected response 0x%02x (expected 0x61, 0x6c, or 0x9f)\n", resp[0]);
+ return -1;
+ }
+
+ /* Normal ending of command; resp[1] bytes available */
+ get_resp[4] = resp[1];
+ log->debug("SCARD: trying to get response (%d bytes)\n", resp[1]);
+
+ rlen = *buf_len;
+ ret = transmit(get_resp, sizeof(get_resp), buf, &rlen);
+ if (ret == SCARD_S_SUCCESS) {
+ *buf_len = resp[1] < rlen ? resp[1] : rlen;
+ return 0;
+ }
+
+ log->warning("SCARD: SCardTransmit err=0x%lx\n", ret);
+ return -1;
+}
+
+
+int pcsc_usim::scard::select_file(unsigned short file_id,unsigned char *buf, size_t *buf_len)
+{
+ return _select_file(file_id, buf, buf_len, sim_type, NULL, 0);
+}
+
+
+long pcsc_usim::scard::transmit(unsigned char *_send, size_t send_len, unsigned char *_recv, size_t *recv_len)
+{
+ long ret;
+ unsigned long rlen;
+
+ log->debug_hex(_send, send_len, "SCARD: scard_transmit: send\n");
+ rlen = *recv_len;
+ ret = SCardTransmit(scard_handle,
+ scard_protocol == SCARD_PROTOCOL_T1 ?
+ SCARD_PCI_T1 : SCARD_PCI_T0,
+ _send, (unsigned long) send_len,
+ NULL, _recv, &rlen);
+ *recv_len = rlen;
+ if (ret == SCARD_S_SUCCESS) {
+ log->debug_hex(_recv, rlen, "SCARD: SCardTransmit: recv\n");
+ } else {
+ log->error("SCARD: SCardTransmit failed %s\n", pcsc_stringify_error(ret));
+ }
+ return ret;
+}
+
+int pcsc_usim::scard::pin_needed(unsigned char *hdr, size_t hlen)
+{
+ if (sim_type == SCARD_GSM_SIM) {
+ if (hlen > SCARD_CHV1_OFFSET && !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
+ return 1;
+ return 0;
+ }
+
+ if (sim_type == SCARD_USIM) {
+ int ps_do;
+ if (parse_fsp_templ(hdr, hlen, &ps_do, NULL))
+ return -1;
+ /* TODO: there could be more than one PS_DO entry because of
+ * multiple PINs in key reference.. */
+ if (ps_do > 0 && (ps_do & 0x80))
+ return 1;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+
+int pcsc_usim::scard::get_pin_retry_counter()
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 };
+ size_t len;
+ uint16_t val;
+
+ log->info("SCARD: fetching PIN retry counter\n");
+
+ if (sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[4] = 0; /* Empty data */
+
+ len = sizeof(resp);
+ ret = transmit(cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if (len != 2) {
+ log->error("SCARD: failed to fetch PIN retry counter\n");
+ return -1;
+ }
+
+ val = to_uint16(resp);
+ if (val == 0x63c0 || val == 0x6983) {
+ log->debug("SCARD: PIN has been blocked\n");
+ return 0;
+ }
+
+ if (val >= 0x63c0 && val <= 0x63cf)
+ return val & 0x000f;
+
+ log->info("SCARD: Unexpected PIN retry counter response value 0x%x\n", val);
+ return 0;
+}
+
+
+
+int pcsc_usim::scard::get_aid(unsigned char *aid, size_t maxlen)
+{
+ int rlen, rec;
+ struct efdir {
+ unsigned char appl_template_tag; /* 0x61 */
+ unsigned char appl_template_len;
+ unsigned char appl_id_tag; /* 0x4f */
+ unsigned char aid_len;
+ unsigned char rid[5];
+ unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
+ } *efdir;
+ unsigned char buf[127], *aid_pos;
+ size_t blen;
+ unsigned int aid_len = 0;
+
+ efdir = (struct efdir *) buf;
+ aid_pos = &buf[4];
+ blen = sizeof(buf);
+ if (select_file(SCARD_FILE_EF_DIR, buf, &blen)) {
+ log->debug("SCARD: Failed to read EF_DIR\n");
+ return -1;
+ }
+ log->debug_hex(buf, blen, "SCARD: EF_DIR select\n");
+
+ for (rec = 1; rec < 10; rec++) {
+ rlen = get_record_len(rec, SIM_RECORD_MODE_ABSOLUTE);
+ if (rlen < 0) {
+ log->debug("SCARD: Failed to get EF_DIR record length\n");
+ return -1;
+ }
+ blen = sizeof(buf);
+ if (rlen > (int) blen) {
+ log->debug("SCARD: Too long EF_DIR record\n");
+ return -1;
+ }
+ if (read_record(buf, rlen, rec, SIM_RECORD_MODE_ABSOLUTE) < 0) {
+ log->debug("SCARD: Failed to read EF_DIR record %d", rec);
+ return -1;
+ }
+ log->debug_hex(buf, rlen, "SCARD: EF_DIR record\n");
+
+ if (efdir->appl_template_tag != 0x61) {
+ log->debug("SCARD: Unexpected application template tag 0x%x", efdir->appl_template_tag);
+ continue;
+ }
+
+ if (efdir->appl_template_len > rlen - 2) {
+ log->debug("SCARD: Too long application template (len=%d rlen=%d)", efdir->appl_template_len, rlen);
+ continue;
+ }
+
+ if (efdir->appl_id_tag != 0x4f) {
+ log->debug("SCARD: Unexpected application identifier tag 0x%x", efdir->appl_id_tag);
+ continue;
+ }
+
+ aid_len = efdir->aid_len;
+ if (aid_len < 1 || aid_len > 16) {
+ log->debug("SCARD: Invalid AID length %u\n", aid_len);
+ continue;
+ }
+
+ log->debug_hex(aid_pos, aid_len, "SCARD: AID from EF_DIR record\n");
+
+ if (efdir->appl_code[0] == 0x10 && efdir->appl_code[1] == 0x02) {
+ log->debug("SCARD: 3G USIM app found from EF_DIR record %d\n", rec);
+ break;
+ }
+ }
+
+ if (rec >= 10) {
+ log->debug("SCARD: 3G USIM app not found from EF_DIR records\n");
+ return -1;
+ }
+
+ if (aid_len > maxlen) {
+ log->debug("SCARD: Too long AID\n");
+ return -1;
+ }
+
+ memcpy(aid, aid_pos, aid_len);
+
+ return aid_len;
+}
+
+int pcsc_usim::scard::get_record_len(unsigned char recnum, unsigned char mode)
+{
+ unsigned char buf[255];
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen;
+ long ret;
+
+ if (sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = sizeof(buf);
+
+ blen = sizeof(buf);
+ ret = transmit(cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ log->debug("SCARD: failed to determine file length for record %d\n", recnum);
+ return -1;
+ }
+
+ log->debug_hex(buf, blen, "SCARD: file length determination response\n");
+
+ if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
+ log->error("SCARD: unexpected response to file length determination\n");
+ return -1;
+ }
+
+ return buf[1];
+}
+
+
+int pcsc_usim::scard::read_record(unsigned char *data, size_t len, unsigned char recnum, unsigned char mode)
+{
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ if (sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = len;
+
+ buf = (unsigned char*)malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ ret = transmit(cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ free(buf);
+ return -2;
+ }
+ if (blen != len + 2) {
+ log->debug("SCARD: record read returned unexpected length %ld (expected %ld)\n", (long) blen, (long) len + 2);
+ free(buf);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ log->debug("SCARD: record read returned unexpected status %02x %02x (expected 90 00)\n", buf[len], buf[len + 1]);
+ free(buf);
+ return -4;
+ }
+
+ memcpy(data, buf, len);
+ free(buf);
+
+ return 0;
+}
+
+
+/**
+ * scard_get_imsi - Read IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @imsi: Buffer for IMSI
+ * @len: Length of imsi buffer; set to IMSI length on success
+ * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
+ * selection returns invalid result code, -3 if parsing FSP template file fails
+ * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
+ * to needed length), -5 if reading IMSI file fails.
+ *
+ * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
+ * file is PIN protected, scard_set_pin() must have been used to set the
+ * correct PIN code before calling scard_get_imsi().
+ */
+int pcsc_usim::scard::get_imsi(char *imsi, size_t *len)
+{
+ unsigned char buf[100];
+ size_t blen, imsilen, i;
+ char *pos;
+
+ log->debug("SCARD: reading IMSI from (GSM) EF-IMSI\n");
+ blen = sizeof(buf);
+ if (select_file(SCARD_FILE_GSM_EF_IMSI, buf, &blen))
+ return -1;
+ if (blen < 4) {
+ log->warning("SCARD: too short (GSM) EF-IMSI header (len=%ld)\n", (long) blen);
+ return -2;
+ }
+
+ if (sim_type == SCARD_GSM_SIM) {
+ blen = to_uint16(&buf[2]);
+ } else {
+ int file_size;
+ if (parse_fsp_templ(buf, blen, NULL, &file_size))
+ return -3;
+ blen = file_size;
+ }
+ if (blen < 2 || blen > sizeof(buf)) {
+ log->debug("SCARD: invalid IMSI file length=%ld\n", (long) blen);
+ return -3;
+ }
+
+ imsilen = (blen - 2) * 2 + 1;
+ log->debug("SCARD: IMSI file length=%ld imsilen=%ld\n", (long) blen, (long) imsilen);
+ if (blen < 2 || imsilen > *len) {
+ *len = imsilen;
+ return -4;
+ }
+
+ if (read_file(buf, blen))
+ return -5;
+
+ pos = imsi;
+ *pos++ = '0' + (buf[1] >> 4 & 0x0f);
+ for (i = 2; i < blen; i++) {
+ unsigned char digit;
+
+ digit = buf[i] & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+
+ digit = buf[i] >> 4 & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+ }
+ *len = imsilen;
+
+ return 0;
+}
+
+int pcsc_usim::scard::read_file(unsigned char *data, size_t len)
+{
+ unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ cmd[4] = len;
+
+ buf = (unsigned char*)malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ if (sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ ret = transmit(cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ free(buf);
+ return -2;
+ }
+ if (blen != len + 2) {
+ log->error("SCARD: file read returned unexpected length %ld (expected %ld)\n", (long) blen, (long) len + 2);
+ free(buf);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ log->error("SCARD: file read returned unexpected status %02x %02x (expected 90 00)\n", buf[len], buf[len + 1]);
+ free(buf);
+ return -4;
+ }
+
+ memcpy(data, buf, len);
+ free(buf);
+
+ return 0;
+}
+
+
+int pcsc_usim::scard::parse_fsp_templ(unsigned char *buf, size_t buf_len, int *ps_do, int *file_len)
+{
+ unsigned char *pos, *end;
+
+ if (ps_do)
+ *ps_do = -1;
+ if (file_len)
+ *file_len = -1;
+
+ pos = buf;
+ end = pos + buf_len;
+ if (*pos != USIM_FSP_TEMPL_TAG) {
+ log->error("SCARD: file header did not start with FSP template tag\n");
+ return -1;
+ }
+ pos++;
+ if (pos >= end)
+ return -1;
+ if (pos[0] < end - pos)
+ end = pos + 1 + pos[0];
+ pos++;
+ log->debug_hex(pos, end - pos, "SCARD: file header FSP template\n");
+
+ while (end - pos >= 2) {
+ unsigned char type, len;
+
+ type = pos[0];
+ len = pos[1];
+ log->debug("SCARD: file header TLV 0x%02x len=%d\n", type, len);
+ pos += 2;
+
+ if (len > (unsigned int) (end - pos))
+ break;
+
+ switch (type) {
+ case USIM_TLV_FILE_DESC:
+ log->debug_hex(pos, len, "SCARD: File Descriptor TLV\n");
+ break;
+ case USIM_TLV_FILE_ID:
+ log->debug_hex(pos, len, "SCARD: File Identifier TLV\n");
+ break;
+ case USIM_TLV_DF_NAME:
+ log->debug_hex(pos, len, "SCARD: DF name (AID) TLV\n");
+ break;
+ case USIM_TLV_PROPR_INFO:
+ log->debug_hex(pos, len,"SCARD: Proprietary information TLV\n");
+ break;
+ case USIM_TLV_LIFE_CYCLE_STATUS:
+ log->debug_hex(pos, len, "SCARD: Life Cycle Status Integer TLV\n");
+ break;
+ case USIM_TLV_FILE_SIZE:
+ log->debug_hex(pos, len, "SCARD: File size TLV\n");
+ if ((len == 1 || len == 2) && file_len) {
+ if (len == 1) {
+ *file_len = (int) pos[0];
+ } else {
+ *file_len = to_uint16(pos);
+ }
+ log->debug("SCARD: file_size=%d\n", *file_len);
+ }
+ break;
+ case USIM_TLV_TOTAL_FILE_SIZE:
+ log->debug_hex(pos, len, "SCARD: Total file size TLV\n");
+ break;
+ case USIM_TLV_PIN_STATUS_TEMPLATE:
+ log->debug_hex(pos, len, "SCARD: PIN Status Template DO TLV\n");
+ if (len >= 2 && pos[0] == USIM_PS_DO_TAG &&
+ pos[1] >= 1 && ps_do) {
+ log->debug("SCARD: PS_DO=0x%02x\n", pos[2]);
+ *ps_do = (int) pos[2];
+ }
+ break;
+ case USIM_TLV_SHORT_FILE_ID:
+ log->debug_hex(pos, len, "SCARD: Short File Identifier (SFI) TLV\n");
+ break;
+ case USIM_TLV_SECURITY_ATTR_8B:
+ case USIM_TLV_SECURITY_ATTR_8C:
+ case USIM_TLV_SECURITY_ATTR_AB:
+ log->debug_hex(pos, len, "SCARD: Security attribute TLV\n");
+ break;
+ default:
+ log->debug_hex(pos, len,"SCARD: Unrecognized TLV\n");
+ break;
+ }
+
+ pos += len;
+
+ if (pos == end)
+ return 0;
+ }
+ return -1;
+}
+
+
+
+/**
+ * scard_deinit - Deinitialize SIM/USIM connection
+ * @scard: Pointer to private data from scard_init()
+ *
+ * This function closes the SIM/USIM connect opened with scard_init().
+ */
+void pcsc_usim::scard::deinit()
+{
+ long ret;
+
+ log->debug("SCARD: deinitializing smart card interface\n");
+
+ ret = SCardDisconnect(scard_handle, SCARD_UNPOWER_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ log->debug("SCARD: Failed to disconnect smart card (err=%ld)\n", ret);
+ }
+
+ ret = SCardReleaseContext(scard_context);
+ if (ret != SCARD_S_SUCCESS) {
+ log->debug("Failed to release smart card context (err=%ld)\n", ret);
+ }
+}
+
+
+
+/**
+ * scard_get_mnc_len - Read length of MNC in the IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * Returns: length (>0) on success, -1 if administrative data file cannot be
+ * selected, -2 if administrative data file selection returns invalid result
+ * code, -3 if parsing FSP template file fails (USIM only), -4 if length of
+ * the file is unexpected, -5 if reading file fails, -6 if MNC length is not
+ * in range (i.e. 2 or 3), -7 if MNC length is not available.
+ *
+ */
+int pcsc_usim::scard::get_mnc_len()
+{
+ unsigned char buf[100];
+ size_t blen;
+ int file_size;
+
+ log->debug("SCARD: reading MNC len from (GSM) EF-AD\n");
+ blen = sizeof(buf);
+ if (select_file(SCARD_FILE_GSM_EF_AD, buf, &blen))
+ return -1;
+ if (blen < 4) {
+ log->debug("SCARD: too short (GSM) EF-AD header (len=%ld)\n", (long) blen);
+ return -2;
+ }
+
+ if (sim_type == SCARD_GSM_SIM) {
+ file_size = to_uint16(&buf[2]);
+ } else {
+ if (parse_fsp_templ(buf, blen, NULL, &file_size))
+ return -3;
+ }
+ if (file_size == 3) {
+ log->debug("SCARD: MNC length not available\n");
+ return -7;
+ }
+ if (file_size < 4 || file_size > (int) sizeof(buf)) {
+ log->debug("SCARD: invalid file length=%ld\n", (long) file_size);
+ return -4;
+ }
+
+ if (read_file(buf, file_size))
+ return -5;
+ buf[3] = buf[3] & 0x0f; /* upper nibble reserved for future use */
+ if (buf[3] < 2 || buf[3] > 3) {
+ log->debug("SCARD: invalid MNC length=%ld\n", (long) buf[3]);
+ return -6;
+ }
+ log->debug("SCARD: MNC length=%ld\n", (long) buf[3]);
+ return buf[3];
+}
+
+
+/**
+ * scard_umts_auth - Run UMTS authentication command on USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @autn: 16-byte AUTN value from HLR/AuC
+ * @res: 16-byte buffer for RES
+ * @res_len: Variable that will be set to RES length
+ * @ik: 16-byte buffer for IK
+ * @ck: 16-byte buffer for CK
+ * @auts: 14-byte buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
+ * failure
+ *
+ * This function performs AKA authentication using USIM card and the provided
+ * RAND and AUTN values from HLR/AuC. If authentication command can be
+ * completed successfully, RES, IK, and CK values will be written into provided
+ * buffers and res_len is set to length of received RES value. If USIM reports
+ * synchronization failure, the received AUTS value will be written into auts
+ * buffer. In this case, RES, IK, and CK are not valid.
+ */
+int pcsc_usim::scard::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)
+{
+ unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = { USIM_CMD_RUN_UMTS_ALG };
+ unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
+ unsigned char resp[3], buf[64], *pos, *end;
+ size_t len;
+ long ret;
+
+
+ if (sim_type == SCARD_GSM_SIM) {
+ log->debug("SCARD: Non-USIM card - cannot do UMTS auth\n");
+ return -1;
+ }
+
+ log->debug_hex(_rand, AKA_RAND_LEN, "SCARD: UMTS auth - RAND\n");
+ log->debug_hex(autn, AKA_AUTN_LEN, "SCARD: UMTS auth - AUTN\n");
+ cmd[5] = AKA_RAND_LEN;
+ memcpy(cmd + 6, _rand, AKA_RAND_LEN);
+ cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
+ memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
+
+ len = sizeof(resp);
+ ret = transmit(cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -1;
+
+ if (len <= sizeof(resp))
+ log->debug_hex(resp, len, "SCARD: UMTS alg response\n");
+
+ if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
+ // Authentication error, application specific
+ log->warning("SCARD: UMTS auth failed - MAC != XMAC\n");
+ return -1;
+ } else if (len != 2 || resp[0] != 0x61) {
+ log->warning("SCARD: unexpected response for UMTS auth request (len=%ld resp=%02x %02x)\n",
+ (long) len, resp[0], resp[1]);
+ return -1;
+ }
+ get_resp[4] = resp[1];
+
+ len = sizeof(buf);
+ ret = transmit(get_resp, sizeof(get_resp), buf, &len);
+ if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
+ return -1;
+
+ log->debug_hex(buf, len, "SCARD: UMTS get response result\n");
+ if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && buf[1] == AKA_AUTS_LEN) {
+ log->debug("SCARD: UMTS Synchronization-Failure\n");
+ memcpy(auts, buf + 2, AKA_AUTS_LEN);
+ log->debug_hex(auts, AKA_AUTS_LEN, "SCARD: AUTS\n");
+ *res_len = AKA_AUTS_LEN;
+ return -2;
+ } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
+ pos = buf + 1;
+ end = buf + len;
+
+ /* RES */
+ if (pos[0] > RES_MAX_LEN || pos[0] > end - pos) {
+ log->debug("SCARD: Invalid RES\n");
+ return -1;
+ }
+ *res_len = *pos++;
+ memcpy(res, pos, *res_len);
+ pos += *res_len;
+ log->debug_hex(res, *res_len, "SCARD: RES\n");
+
+ /* CK */
+ if (pos[0] != CK_LEN || CK_LEN > end - pos) {
+ log->debug("SCARD: Invalid CK\n");
+ return -1;
+ }
+ pos++;
+ memcpy(ck, pos, CK_LEN);
+ pos += CK_LEN;
+ log->debug_hex(ck, CK_LEN, "SCARD: CK\n");
+
+ /* IK */
+ if (pos[0] != IK_LEN || IK_LEN > end - pos) {
+ log->debug("SCARD: Invalid IK\n");
+ return -1;
+ }
+ pos++;
+ memcpy(ik, pos, IK_LEN);
+ pos += IK_LEN;
+ log->debug_hex(ik, IK_LEN, "SCARD: IK\n");
+
+ if (end > pos) {
+ log->debug_hex(pos, end - pos, "SCARD: Ignore extra data in end\n");
+ }
+
+ return 0;
+ }
+
+ log->debug("SCARD: Unrecognized response\n");
+ return -1;
+}
+
+
+int pcsc_usim::scard::verify_pin(const char *pin)
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
+ size_t len;
+
+ log->debug("SCARD: verifying PIN\n");
+
+ if (pin == NULL || strlen(pin) > 8)
+ return -1;
+
+ if (sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ memcpy(cmd + 5, pin, strlen(pin));
+ memset(cmd + 5 + strlen(pin), 0xff, 8 - strlen(pin));
+
+ len = sizeof(resp);
+ ret = transmit(cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
+ log->debug("SCARD: PIN verification failed\n");
+ return -1;
+ }
+
+ log->debug("SCARD: PIN verified successfully\n");
+ return SCARD_S_SUCCESS;
+}
+
+
+} // namespace srsue
diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc
index 2b8a3d581..f3cca7622 100644
--- a/srsue/src/upper/rrc.cc
+++ b/srsue/src/upper/rrc.cc
@@ -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) {
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->console("PCCH message received %d bytes\n", pdu->N_bytes);
LIBLTE_RRC_PCCH_MSG_STRUCT 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,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
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 (RRC_STATE_IDLE == state) {
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
uint8_t 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_int, 32, "RRC integrity key - k_rrc_int");
rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc");
diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc
index 3e0e086e5..644f955fa 100644
--- a/srsue/src/upper/usim.cc
+++ b/srsue/src/upper/usim.cc
@@ -36,7 +36,7 @@ namespace srsue{
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_;
imsi_str = args->imsi;
@@ -89,6 +89,8 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
auth_algo = auth_algo_xor;
}
initiated = true;
+
+ return SRSLTE_SUCCESS;
}
void usim::stop()
@@ -189,18 +191,18 @@ bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
return true;
}
-void usim::generate_authentication_response(uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme)
+auth_result_t usim::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)
{
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 {
- 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
*******************************************************************************/
-void usim::gen_auth_res_milenage( uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme)
+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 result = AUTH_OK;
uint32_t i;
uint8_t sqn[6];
- *net_valid = true;
-
// Use RAND and K to compute RES, CK, IK and AK
security_milenage_f2345( k,
op,
@@ -344,6 +345,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
ik,
ak);
+ *res_len = 8;
+
// Extract sqn from autn
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])
{
- *net_valid = false;
+ result = AUTH_FAILED;
}
}
@@ -394,24 +397,25 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
mcc,
mnc,
k_asme);
+
+ return result;
}
// 3GPP TS 34.108 version 10.0.0 Section 8
-void usim::gen_auth_res_xor(uint8_t *rand,
- uint8_t *autn_enb,
- uint16_t mcc,
- uint16_t mnc,
- bool *net_valid,
- uint8_t *res,
- uint8_t *k_asme)
+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 result = AUTH_OK;
uint32_t i;
uint8_t sqn[6];
uint8_t xdout[16];
uint8_t cdout[8];
- *net_valid = true;
-
// Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; 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];
}
+ *res_len = 8;
+
// Extract sqn from autn
for(i=0;i<6;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])
{
- *net_valid = false;
+ result = AUTH_FAILED;
}
}
@@ -478,6 +484,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
mcc,
mnc,
k_asme);
+
+ return result;
}
void usim::str_to_hex(std::string str, uint8_t *hex)
diff --git a/srsue/src/upper/usim_base.cc b/srsue/src/upper/usim_base.cc
new file mode 100644
index 000000000..d6672cf3b
--- /dev/null
+++ b/srsue/src/upper/usim_base.cc
@@ -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
+#include
+#ifdef HAVE_PCSC
+#include
+#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
diff --git a/srsue/test/upper/CMakeLists.txt b/srsue/test/upper/CMakeLists.txt
index 00fb54576..a099ff4c8 100644
--- a/srsue/test/upper/CMakeLists.txt
+++ b/srsue/test/upper/CMakeLists.txt
@@ -22,6 +22,11 @@ add_executable(usim_test usim_test.cc)
target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy)
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)
target_link_libraries(rrc_reconfig_test srsue_upper srslte_upper srslte_phy)
add_test(rrc_reconfig_test rrc_reconfig_test)
diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc
index 94ecb4788..38a7f6ca3 100644
--- a/srsue/test/upper/nas_test.cc
+++ b/srsue/test/upper/nas_test.cc
@@ -26,6 +26,7 @@
#include
#include
+#include "srsue/hdr/upper/usim_base.h"
#include "srsue/hdr/upper/usim.h"
#include "srsue/hdr/upper/nas.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,
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 mnc = 65281;
@@ -197,13 +200,16 @@ int mme_attach_request_test()
nas_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);
rrc_log.set_hex_limit(100000);
+ usim_log.set_hex_limit(100000);
rrc_dummy rrc_dummy;
gw_dummy gw;
srsue::usim usim;
usim_args_t args;
+ args.mode = "soft";
args.algo = "xor";
args.imei = "353490069873319";
args.imsi = "001010123456789";
@@ -212,6 +218,7 @@ int mme_attach_request_test()
usim.init(&args, &usim_log);
srslte_nas_config_t nas_cfg;
+ nas_cfg.apn = "test123";
srsue::nas nas;
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)
{
if (security_command_test()) {
@@ -248,5 +312,10 @@ int main(int argc, char **argv)
return -1;
}
+ if (esm_info_request_test()) {
+ printf("ESM info request test failed.\n");
+ return -1;
+ }
+
return 0;
}
diff --git a/srsue/test/upper/pcsc_usim_test.cc b/srsue/test/upper/pcsc_usim_test.cc
new file mode 100644
index 000000000..b28b5e749
--- /dev/null
+++ b/srsue/test/upper/pcsc_usim_test.cc
@@ -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
+#include "srsue/hdr/upper/pcsc_usim.h"
+#include "srslte/common/log_filter.h"
+#include
+#include
+
+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;
+}
diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc
index 225bee36d..97a3eef6f 100644
--- a/srsue/test/upper/usim_test.cc
+++ b/srsue/test/upper/usim_test.cc
@@ -70,18 +70,18 @@ int main(int argc, char **argv)
srslte::log_filter usim_log("USIM");
bool net_valid;
uint8_t res[16];
+ int res_len;
uint8_t k_asme[32];
usim_args_t args;
args.algo = "milenage";
- args.imei = "35609204079301";
+ args.imei = "356092040793011";
args.imsi = "208930000000001";
args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
args.op = "11111111111111111111111111111111";
srsue::usim usim;
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);
}
diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example
index b2cd36ffe..11fbdc0e6 100644
--- a/srsue/ue.conf.example
+++ b/srsue/ue.conf.example
@@ -86,20 +86,22 @@ file_max_size = -1
#####################################################################
# USIM configuration
#
+# mode: USIM mode (soft/pcsc)
# algo: Authentication algorithm (xor/milenage)
# op: 128-bit Operator Variant Algorithm Configuration Field (hex)
-# amf: 16-bit Authentication Management Field (hex)
# k: 128-bit subscriber key (hex)
# imsi: 15 digit International Mobile Subscriber Identity
# imei: 15 digit International Mobile Station Equipment Identity
+# pin: PIN in case real SIM card is used
#####################################################################
[usim]
+mode = soft
algo = xor
op = 63BFA50EE6523365FF14C1F45F88737D
k = 00112233445566778899aabbccddeeff
imsi = 001010123456789
imei = 353490069873319
-
+#pin = 1234
#####################################################################
# RRC configuration