adding support for CHAP auth

master
Andre Puschmann 7 years ago
parent 2001bb1c49
commit d0457211ad

@ -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;
};

@ -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
*****************************************************************************/

@ -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
*****************************************************************************/

@ -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;

@ -127,6 +127,8 @@ private:
uint32_t ip_addr;
uint8_t eps_bearer_id;
uint8_t chap_id;
uint8_t transaction_id;
// Security

@ -83,7 +83,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"UECapabilityInformation message. Default 0xe6041c00")
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("nas.apn", bpo::value<string>(&args->apn)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.apn", bpo::value<string>(&args->apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.user", bpo::value<string>(&args->apn_user)->default_value(""), "Username for CHAP authentication")
("nas.pass", bpo::value<string>(&args->apn_pass)->default_value(""), "Password for CHAP authentication")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")

@ -205,7 +205,7 @@ 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);
srslte_nas_config_t nas_cfg(1, args->apn); /* RB_ID_SRB1 */
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 */);

@ -53,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_,
@ -1218,12 +1219,93 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) {
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);
strncpy(esm_info_resp.apn.apn, cfg.apn.c_str(), len);
esm_info_resp.apn.apn[len - 1] = '\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;
uint8_t chal_val[16] = { 0xed, 0x0b, 0x26, 0x26, 0xed, 0x0b, 0x26, 0x26,
0xed, 0x0b, 0x26, 0x26, 0xed, 0x0b, 0x26, 0x26 };
for (int i = 0; i < 16; i++) {
challenge[5 + i] = chal_val[i];
}
// 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
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) {
@ -1260,6 +1342,7 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) {
rrc->write_sdu(cfg.lcid, pdu);
ctxt.tx_count++;
chap_id++;
}

@ -277,6 +277,8 @@ int esm_info_request_test()
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

Loading…
Cancel
Save