adding hard SIM card support using PCSC

master
Andre Puschmann 7 years ago
parent cc866b6de1
commit 3fe6dad323

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

@ -0,0 +1,42 @@
# - 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 winscard.h
HINTS
/usr/include/PCSC
${PC_PCSCLITE_INCLUDEDIR}
${PC_PCSCLITE_INCLUDE_DIRS}
${PC_PCSCLITE_INCLUDE_DIRS}/PCSC
)
FIND_LIBRARY(PCSCLITE_LIBRARY NAMES pcsclite libpcsclite PCSC
HINTS
${PC_PCSCLITE_LIBDIR}
${PC_PCSCLITE_LIBRARY_DIRS}
)
# 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)

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

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

@ -172,6 +172,8 @@ private:
// Senders // Senders
void send_identity_response(); void send_identity_response();
void send_esm_information_response(); void send_esm_information_response();
void send_authentication_response(const uint8_t* res, const size_t res_len);
void send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param);
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
void send_security_mode_reject(uint8_t cause); void send_security_mode_reject(uint8_t cause);

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

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

@ -0,0 +1,110 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_USIM_BASE_H
#define SRSUE_USIM_BASE_H
#include <string>
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
namespace srsue {
typedef enum{
auth_algo_milenage = 0,
auth_algo_xor,
}auth_algo_t;
typedef struct{
std::string mode;
std::string algo;
std::string op;
std::string imsi;
std::string imei;
std::string k;
std::string pin;
}usim_args_t;
class usim_base
:public usim_interface_nas
,public usim_interface_rrc
{
public:
usim_base();
virtual ~usim_base();
static usim_base* get_instance(usim_args_t *args, srslte::log *usim_log_);
virtual void 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

@ -124,12 +124,13 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename") ("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename")
("log.file_max_size", bpo::value<int>(&args->log.file_max_size)->default_value(-1), "Maximum file size (in kilobytes). When passed, multiple files are created. Default -1 (single file)") ("log.file_max_size", bpo::value<int>(&args->log.file_max_size)->default_value(-1), "Maximum file size (in kilobytes). When passed, multiple files are created. Default -1 (single file)")
("usim.mode", bpo::value<string>(&args->usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)")
("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm") ("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant") ("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant")
("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI") ("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI")
("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI") ("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI")
("usim.k", bpo::value<string>(&args->usim.k), "USIM K") ("usim.k", bpo::value<string>(&args->usim.k), "USIM K")
("usim.pin", bpo::value<string>(&args->usim.pin), "PIN in case real SIM card is used")
/* Expert section */ /* Expert section */
("expert.ip_netmask", ("expert.ip_netmask",

@ -47,10 +47,12 @@ ue::~ue()
for (uint32_t i = 0; i < phy_log.size(); i++) { for (uint32_t i = 0; i < phy_log.size(); i++) {
delete(phy_log[i]); delete(phy_log[i]);
} }
if (usim) {
delete usim;
}
} }
bool ue::init(all_args_t *args_) bool ue::init(all_args_t *args_) {
{
args = args_; args = args_;
if (!args->log.filename.compare("stdout")) { if (!args->log.filename.compare("stdout")) {
@ -195,15 +197,15 @@ bool ue::init(all_args_t *args_)
mac.init(&phy, &rlc, &rrc, &mac_log); mac.init(&phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
usim = usim_base::get_instance(&args->usim, &usim_log);
usim.init(&args->usim, &usim_log); usim->init(&args->usim, &usim_log);
srslte_nas_config_t nas_cfg(1, args->apn); /* RB_ID_SRB1 */ srslte_nas_config_t nas_cfg(1, args->apn); /* RB_ID_SRB1 */
nas.init(&usim, &rrc, &gw, &nas_log, nas_cfg); nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask); gw.set_netmask(args->expert.ip_netmask);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &mac, &rrc_log);
// Get current band from provided EARFCN // Get current band from provided EARFCN
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
@ -244,7 +246,7 @@ void ue::stop()
{ {
if(started) if(started)
{ {
usim.stop(); usim->stop();
nas.stop(); nas.stop();
rrc.stop(); rrc.stop();

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

@ -695,14 +695,12 @@ void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT)); bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT));
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
nas_log->info("Received Authentication Request\n"); nas_log->info("Received Authentication Request\n");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
// Reuse the pdu for the response message // Deallocate PDU after parsing
pdu->reset(); pool->deallocate(pdu);
// Generate authentication response using RAND, AUTN & KSI-ASME // Generate authentication response using RAND, AUTN & KSI-ASME
uint16 mcc, mnc; uint16 mcc, mnc;
@ -711,11 +709,12 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc); nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc);
bool net_valid;
uint8_t res[16]; uint8_t res[16];
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, int res_len = 0;
&net_valid, res, ctxt.k_asme); nas_log->debug_hex(auth_req.rand, 16, "Authentication request RAND\n");
nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str()); nas_log->debug_hex(auth_req.autn, 16, "Authentication request AUTN\n");
auth_result_t auth_result = usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc,
res, &res_len, ctxt.k_asme);
if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) { if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) {
ctxt.ksi = auth_req.nas_ksi.nas_ksi; ctxt.ksi = auth_req.nas_ksi.nas_ksi;
} else { } else {
@ -723,23 +722,17 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->console("Warning: NAS mapped security context not currently supported\n"); nas_log->console("Warning: NAS mapped security context not currently supported\n");
} }
if (net_valid) { if (auth_result == AUTH_OK) {
nas_log->info("Network authentication successful\n"); nas_log->info("Network authentication successful\n");
for (int i = 0; i < 8; i++) { send_authentication_response(res, res_len);
auth_res.res[i] = res[i]; nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
} } else if (auth_result == AUTH_SYNCH_FAILURE) {
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->error("Network authentication synchronization failure.\n");
send_authentication_failure(LIBLTE_MME_EMM_CAUSE_SYNCH_FAILURE, res);
nas_log->info("Sending Authentication Response\n");
// Write NAS pcap
if (pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
rrc->write_sdu(lcid, pdu);
} else { } else {
nas_log->warning("Network authentication failure\n"); nas_log->warning("Network authentication failure\n");
nas_log->console("Warning: Network authentication failure\n"); nas_log->console("Warning: Network authentication failure\n");
pool->deallocate(pdu); send_authentication_failure(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE, NULL);
} }
} }
@ -1065,7 +1058,13 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN); strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
pdn_con_req.apn = apn; pdn_con_req.apn = apn;
} }
pdn_con_req.protocol_cnfg_opts_present = false;
// Request DNS Server
pdn_con_req.protocol_cnfg_opts_present = true;
pdn_con_req.protocol_cnfg_opts.opt[0].id = LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_P_CSCF_IPV4_ADDRESS_REQUEST;
pdn_con_req.protocol_cnfg_opts.opt[1].id = LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DNS_SERVER_IPV4_ADDRESS_REQUEST;
pdn_con_req.protocol_cnfg_opts.N_opts = 2;
pdn_con_req.device_properties_present = false; pdn_con_req.device_properties_present = false;
// Pack the message // Pack the message
@ -1089,6 +1088,57 @@ void nas::send_security_mode_reject(uint8_t cause) {
rrc->write_sdu(cfg.lcid, msg); rrc->write_sdu(cfg.lcid, msg);
} }
void nas::send_authentication_response(const uint8_t* res, const size_t res_len) {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_response().\n");
return;
}
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
for (uint32_t i = 0; i < res_len; i++) {
auth_res.res[i] = res[i];
}
auth_res.res_len = res_len;
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *)msg);
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending Authentication Response\n");
rrc->write_sdu(cfg.lcid, msg);
}
void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param) {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_failure().\n");
return;
}
LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT auth_failure;
auth_failure.emm_cause = cause;
if (auth_fail_param) {
memcpy(auth_failure.auth_fail_param, auth_fail_param, 14);
nas_log->debug_hex(auth_failure.auth_fail_param, 14, "auth_failure.auth_fail_param\n");
auth_failure.auth_fail_param_present = true;
} else {
auth_failure.auth_fail_param_present = false;
}
liblte_mme_pack_authentication_failure_msg(&auth_failure, (LIBLTE_BYTE_MSG_STRUCT *)msg);
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending authentication failure.\n");
rrc->write_sdu(cfg.lcid, msg);
}
void nas::send_identity_response() {} void nas::send_identity_response() {}
void nas::send_esm_information_response() {} void nas::send_esm_information_response() {}

File diff suppressed because it is too large Load Diff

@ -189,18 +189,18 @@ bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
return true; return true;
} }
void usim::generate_authentication_response(uint8_t *rand, auth_result_t usim::generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
if(auth_algo_xor == auth_algo) { if(auth_algo_xor == auth_algo) {
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); return gen_auth_res_xor(rand, autn_enb, mcc, mnc, res, res_len, k_asme);
} else { } else {
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); return gen_auth_res_milenage(rand, autn_enb, mcc, mnc, res, res_len, k_asme);
} }
} }
@ -322,19 +322,18 @@ void usim::generate_as_keys_ho(uint32_t pci,
Helpers Helpers
*******************************************************************************/ *******************************************************************************/
void usim::gen_auth_res_milenage( uint8_t *rand, auth_result_t usim::gen_auth_res_milenage(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
auth_result_t result = AUTH_OK;
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];
*net_valid = true;
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
security_milenage_f2345( k, security_milenage_f2345( k,
op, op,
@ -344,6 +343,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
ik, ik,
ak); ak);
*res_len = 8;
// Extract sqn from autn // Extract sqn from autn
for(i=0;i<6;i++) for(i=0;i<6;i++)
{ {
@ -382,7 +383,7 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
{ {
if(autn[i] != autn_enb[i]) if(autn[i] != autn_enb[i])
{ {
*net_valid = false; result = AUTH_FAILED;
} }
} }
@ -394,24 +395,25 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
mcc, mcc,
mnc, mnc,
k_asme); k_asme);
return result;
} }
// 3GPP TS 34.108 version 10.0.0 Section 8 // 3GPP TS 34.108 version 10.0.0 Section 8
void usim::gen_auth_res_xor(uint8_t *rand, auth_result_t usim::gen_auth_res_xor(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) uint8_t *k_asme)
{ {
auth_result_t result = AUTH_OK;
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];
uint8_t xdout[16]; uint8_t xdout[16];
uint8_t cdout[8]; uint8_t cdout[8];
*net_valid = true;
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) { for(i=0; i<16; i++) {
xdout[i] = k[i]^rand[i]; xdout[i] = k[i]^rand[i];
@ -425,6 +427,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
ak[i] = xdout[i+3]; ak[i] = xdout[i+3];
} }
*res_len = 8;
// Extract sqn from autn // Extract sqn from autn
for(i=0;i<6;i++) { for(i=0;i<6;i++) {
sqn[i] = autn_enb[i] ^ ak[i]; sqn[i] = autn_enb[i] ^ ak[i];
@ -466,7 +470,7 @@ void usim::gen_auth_res_xor(uint8_t *rand,
{ {
if(autn[i] != autn_enb[i]) if(autn[i] != autn_enb[i])
{ {
*net_valid = false; result = AUTH_FAILED;
} }
} }
@ -478,6 +482,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
mcc, mcc,
mnc, mnc,
k_asme); k_asme);
return result;
} }
void usim::str_to_hex(std::string str, uint8_t *hex) void usim::str_to_hex(std::string str, uint8_t *hex)

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

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

@ -26,7 +26,9 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <srsue/hdr/upper/usim_base.h>
#include "srsue/hdr/upper/usim.h" #include "srsue/hdr/upper/usim.h"
#include "srsue/hdr/upper/pcsc_usim.h"
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/upper/nas.h"
#include "srslte/upper/rlc.h" #include "srslte/upper/rlc.h"
#include "srsue/hdr/upper/rrc.h" #include "srsue/hdr/upper/rrc.h"
@ -195,13 +197,16 @@ int mme_attach_request_test()
nas_log.set_level(srslte::LOG_LEVEL_DEBUG); nas_log.set_level(srslte::LOG_LEVEL_DEBUG);
rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); rrc_log.set_level(srslte::LOG_LEVEL_DEBUG);
usim_log.set_level(srslte::LOG_LEVEL_DEBUG);
nas_log.set_hex_limit(100000); nas_log.set_hex_limit(100000);
rrc_log.set_hex_limit(100000); rrc_log.set_hex_limit(100000);
usim_log.set_hex_limit(100000);
rrc_dummy rrc_dummy; rrc_dummy rrc_dummy;
gw_dummy gw; gw_dummy gw;
srsue::usim usim; srsue::pcsc_usim usim;
usim_args_t args; usim_args_t args;
args.mode = "pcsc";
args.algo = "xor"; args.algo = "xor";
args.imei = "353490069873319"; args.imei = "353490069873319";
args.imsi = "001010123456789"; args.imsi = "001010123456789";

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

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

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

Loading…
Cancel
Save