Added support for AS ciphering

This commit is contained in:
Paul Sutton 2017-12-01 19:19:38 +00:00
parent 516fdc27f1
commit 1a323770c9
9 changed files with 150 additions and 135 deletions

View File

@ -32,9 +32,8 @@
#include <arpa/inet.h>
#include <sys/time.h>
#define MAC_LTE_DLT 147
#define RRC_LTE_DLT 148
#define NAS_LTE_DLT 149
#define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148
/* This structure gets written to the start of the file */
@ -74,30 +73,15 @@ typedef struct pcaprec_hdr_s {
#define SPS_RNTI 5
#define M_RNTI 6
#define MAC_LTE_START_STRING "mac-lte"
#define MAC_LTE_START_STRING "mac-lte"
#define MAC_LTE_PAYLOAD_TAG 0x01
#define MAC_LTE_RNTI_TAG 0x02
/* 2 bytes, network order */
#define MAC_LTE_UEID_TAG 0x03
/* 2 bytes, network order */
#define MAC_LTE_FRAME_SUBFRAME_TAG 0x04
/* 2 bytes, network order */
/* SFN is stored in 12 MSB and SF in 4 LSB */
#define MAC_LTE_PREDFINED_DATA_TAG 0x05
/* 1 byte */
#define MAC_LTE_RETX_TAG 0x06
/* 1 byte */
#define MAC_LTE_CRC_STATUS_TAG 0x07
/* 1 byte */
/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU
continues until the end of the frame) */
#define MAC_LTE_PAYLOAD_TAG 0x01
/* Context information for every MAC PDU that will be logged */
@ -112,7 +96,6 @@ typedef struct MAC_Context_Info_t {
unsigned short sysFrameNumber;
unsigned short subFrameNumber;
} MAC_Context_Info_t;
/* Context information for every NAS PDU that will be logged */
@ -121,11 +104,12 @@ typedef struct NAS_Context_Info_s {
} NAS_Context_Info_t;
/**************************************************************************/
/* API functions for opening/writing/closing MAC-LTE PCAP files */
/**************************************************************************
* API functions for opening/closing LTE PCAP files *
**************************************************************************/
/* Open the file and write file header */
inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
inline FILE *LTE_PCAP_Open(uint32_t DLT, const char *fileName)
{
pcap_hdr_t file_header =
{
@ -134,7 +118,7 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
0, /* timezone */
0, /* sigfigs - apparently all tools do this */
65535, /* snaplen - this should be long enough */
MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */
DLT /* Data Link Type (DLT). Set as unused value 147 for now */
};
FILE *fd = fopen(fileName, "w");
@ -149,9 +133,21 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
return fd;
}
/* Close the PCAP file */
inline void LTE_PCAP_Close(FILE *fd)
{
if(fd)
fclose(fd);
}
/**************************************************************************
* API functions for writing MAC-LTE PCAP files *
**************************************************************************/
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
inline int LTE_PCAP_MAC_WritePDU(FILE *fd, MAC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
char context_header[256];
@ -216,45 +212,15 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context,
return 1;
}
/* Close the PCAP file */
inline void MAC_LTE_PCAP_Close(FILE *fd)
{
if(fd)
fclose(fd);
}
/**************************************************************************/
/* API functions for opening/writing/closing NAS-LTE PCAP files */
/**************************************************************************
* API functions for writing NAS-EPS PCAP files *
**************************************************************************/
/* Open the file and write file header */
inline FILE *NAS_LTE_PCAP_Open(const char *fileName)
{
pcap_hdr_t file_header =
{
0xa1b2c3d4, /* magic number */
2, 4, /* version number is 2.4 */
0, /* timezone */
0, /* sigfigs - apparently all tools do this */
65535, /* snaplen - this should be long enough */
NAS_LTE_DLT /* Data Link Type (DLT). Set as unused value 149 for now */
};
FILE *fd = fopen(fileName, "w");
if (fd == NULL) {
printf("Failed to open file \"%s\" for writing\n", fileName);
return NULL;
}
/* Write the file header */
fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd);
return fd;
}
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int NAS_LTE_PCAP_WritePDU(FILE *fd, NAS_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
/* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */
inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
@ -281,11 +247,4 @@ inline int NAS_LTE_PCAP_WritePDU(FILE *fd, NAS_Context_Info_t *context,
return 1;
}
/* Close the PCAP file */
inline void NAS_LTE_PCAP_Close(FILE *fd)
{
if(fd)
fclose(fd);
}
#endif /* UEPCAP_H */

View File

@ -197,10 +197,11 @@ public:
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0;
virtual void config_security(uint32_t lcid,
uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_enc_,
uint8_t *k_int_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint32_t lcid) = 0;
virtual void enable_encryption(uint32_t lcid) = 0;
};

View File

@ -58,10 +58,11 @@ public:
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_enc,
uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void enable_integrity(uint32_t lcid);
void enable_encryption(uint32_t lcid);
// RLC interface

View File

@ -78,10 +78,11 @@ public:
// RRC interface
void write_sdu(byte_buffer_t *sdu);
void config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
void config_security(uint8_t *k_enc_,
uint8_t *k_int_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
void enable_integrity();
void enable_encryption();
// RLC interface
@ -102,13 +103,14 @@ private:
bool active;
uint32_t lcid;
srslte_pdcp_config_t cfg;
uint8_t sn_len_bytes;
bool do_integrity;
bool do_encryption;
uint32_t rx_count;
uint32_t tx_count;
uint8_t k_rrc_enc[32];
uint8_t k_rrc_int[32];
uint8_t k_enc[32];
uint8_t k_int[32];
CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
@ -133,6 +135,7 @@ private:
void run_thread();
uint8_t get_bearer_id(uint8_t lcid);
};
/****************************************************************************

View File

@ -40,14 +40,14 @@ void mac_pcap::enable(bool en)
}
void mac_pcap::open(const char* filename, uint32_t ue_id)
{
pcap_file = MAC_LTE_PCAP_Open(filename);
pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, filename);
ue_id = ue_id;
enable_write = true;
}
void mac_pcap::close()
{
fprintf(stdout, "Saving MAC PCAP file\n");
MAC_LTE_PCAP_Close(pcap_file);
LTE_PCAP_Close(pcap_file);
}
void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti,
@ -65,7 +65,7 @@ void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reT
(uint16_t)(tti%10) /* Subframe number */
};
if (pdu) {
MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}

View File

@ -12,14 +12,14 @@ void nas_pcap::enable()
}
void nas_pcap::open(const char* filename, uint32_t ue_id)
{
pcap_file = NAS_LTE_PCAP_Open(filename);
pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename);
ue_id = ue_id;
enable_write = true;
}
void nas_pcap::close()
{
fprintf(stdout, "Saving NAS PCAP file\n");
MAC_LTE_PCAP_Close(pcap_file);
LTE_PCAP_Close(pcap_file);
}
void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes)
@ -27,7 +27,7 @@ void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes)
if (enable_write) {
NAS_Context_Info_t context;
if (pdu) {
NAS_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
LTE_PCAP_NAS_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}

View File

@ -99,13 +99,19 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
}
void pdcp::config_security(uint32_t lcid,
uint8_t *k_rrc_enc,
uint8_t *k_rrc_int,
uint8_t *k_enc,
uint8_t *k_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
{
if(valid_lcid(lcid))
pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo);
}
void pdcp::enable_integrity(uint32_t lcid)
{
if(valid_lcid(lcid))
pdcp_array[lcid].enable_integrity();
}
void pdcp::enable_encryption(uint32_t lcid)

View File

@ -56,6 +56,12 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_,
rx_count = 0;
do_integrity = false;
do_encryption = false;
if(cfg.is_control) {
cfg.sn_len = 5;
sn_len_bytes = 1;
} else {
sn_len_bytes = (cfg.sn_len+7)/8;
}
start(PDCP_THREAD_PRIO);
@ -87,46 +93,57 @@ bool pdcp_entity::is_active()
void pdcp_entity::write_sdu(byte_buffer_t *sdu)
{
log->info_hex(sdu->msg, sdu->N_bytes,
"TX %s SDU, do_integrity = %s, do_encryption = %s", get_rb_name(lcid),
"TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s",
get_rb_name(lcid), tx_count,
(do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false");
if (cfg.is_control) {
pdcp_pack_control_pdu(tx_count, sdu);
if(do_integrity)
{
if(do_integrity) {
integrity_generate(sdu->msg,
sdu->N_bytes-4,
&sdu->msg[sdu->N_bytes-4]);
}
tx_count++;
}
if (cfg.is_data) {
if(12 == cfg.sn_len) {
pdcp_pack_data_pdu_long_sn(tx_count++, sdu);
pdcp_pack_data_pdu_long_sn(tx_count, sdu);
} else {
pdcp_pack_data_pdu_short_sn(tx_count++, sdu);
pdcp_pack_data_pdu_short_sn(tx_count, sdu);
}
}
if(do_encryption) {
cipher_encrypt(&sdu->msg[sn_len_bytes],
sdu->N_bytes-sn_len_bytes,
&sdu->msg[sn_len_bytes]);
log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU (encrypted)", get_rb_name(lcid));
}
tx_count++;
rlc->write_sdu(lcid, sdu);
}
void pdcp_entity::config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
void pdcp_entity::config_security(uint8_t *k_enc_,
uint8_t *k_int_,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_)
{
do_integrity = true;
for(int i=0; i<32; i++)
{
k_rrc_enc[i] = k_rrc_enc_[i];
k_rrc_int[i] = k_rrc_int_[i];
k_enc[i] = k_enc_[i];
k_int[i] = k_int_[i];
}
cipher_algo = cipher_algo_;
integ_algo = integ_algo_;
}
void pdcp_entity::enable_integrity()
{
do_integrity = true;
}
void pdcp_entity::enable_encryption()
{
do_encryption = true;
@ -142,24 +159,26 @@ void pdcp_entity::integrity_generate( uint8_t *msg,
uint32_t msg_len,
uint8_t *mac)
{
uint8_t bearer;
switch(integ_algo)
{
case INTEGRITY_ALGORITHM_ID_EIA0:
break;
case INTEGRITY_ALGORITHM_ID_128_EIA1:
security_128_eia1(&k_rrc_int[16],
security_128_eia1(&k_int[16],
tx_count,
lcid-1,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
mac);
break;
case INTEGRITY_ALGORITHM_ID_128_EIA2:
security_128_eia2(&k_rrc_int[16],
security_128_eia2(&k_int[16],
tx_count,
lcid-1,
cfg.direction,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
mac);
@ -183,19 +202,19 @@ bool pdcp_entity::integrity_verify(uint8_t *msg,
case INTEGRITY_ALGORITHM_ID_EIA0:
break;
case INTEGRITY_ALGORITHM_ID_128_EIA1:
security_128_eia1(&k_rrc_int[16],
security_128_eia1(&k_int[16],
count,
lcid-1,
( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
msg,
msg_len,
mac_exp);
break;
case INTEGRITY_ALGORITHM_ID_128_EIA2:
security_128_eia2(&k_rrc_int[16],
security_128_eia2(&k_int[16],
count,
lcid-1,
( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
msg,
msg_len,
mac_exp);
@ -240,20 +259,20 @@ void pdcp_entity::cipher_encrypt(uint8_t *msg,
case CIPHERING_ALGORITHM_ID_EEA0:
break;
case CIPHERING_ALGORITHM_ID_128_EEA1:
security_128_eea1(&(k_rrc_enc[16]),
security_128_eea1(&(k_enc[16]),
tx_count,
lcid - 1,
cfg.direction,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
ct_tmp.msg);
memcpy(ct, ct_tmp.msg, msg_len);
break;
case CIPHERING_ALGORITHM_ID_128_EEA2:
security_128_eea2(&(k_rrc_enc[16]),
security_128_eea2(&(k_enc[16]),
tx_count,
lcid - 1,
cfg.direction,
get_bearer_id(lcid),
cfg.direction,
msg,
msg_len,
ct_tmp.msg);
@ -275,19 +294,19 @@ void pdcp_entity::cipher_decrypt(uint8_t *ct,
case CIPHERING_ALGORITHM_ID_EEA0:
break;
case CIPHERING_ALGORITHM_ID_128_EEA1:
security_128_eea1(&(k_rrc_enc[16]),
security_128_eea1(&(k_enc[16]),
count,
lcid - 1,
( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
ct,
ct_len,
msg_tmp.msg);
break;
case CIPHERING_ALGORITHM_ID_128_EEA2:
security_128_eea2(&(k_rrc_enc[16]),
security_128_eea2(&(k_enc[16]),
count,
lcid - 1,
( cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
get_bearer_id(lcid),
(cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK),
ct,
ct_len,
msg_tmp.msg);
@ -306,39 +325,35 @@ void pdcp_entity::run_thread()
while(running) {
rx_pdu_queue.read(&pdu);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid));
// Handle SRB messages
switch(lcid)
{
case RB_ID_SRB0:
// Simply pass on to RRC
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid));
rrc->write_pdu(RB_ID_SRB0, pdu);
break;
case RB_ID_SRB1: // Intentional fall-through
case RB_ID_SRB2:
uint32_t sn;
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid));
if (do_encryption) {
cipher_decrypt(&(pdu->msg[1]),
pdu->msg[0],
pdu->N_bytes - 1,
&(pdu->msg[1]));
cipher_decrypt(&(pdu->msg[sn_len_bytes]),
rx_count,
pdu->N_bytes - sn_len_bytes,
&(pdu->msg[sn_len_bytes]));
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid));
}
if (do_integrity) {
integrity_verify(pdu->msg,
pdu->msg[0],
rx_count,
pdu->N_bytes - 4,
&(pdu->msg[pdu->N_bytes - 4]));
}
pdcp_unpack_control_pdu(pdu, &sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d",
get_rb_name(lcid), sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn);
rrc->write_pdu(lcid, pdu);
break;
}
@ -347,18 +362,35 @@ void pdcp_entity::run_thread()
if(lcid >= RB_ID_DRB1)
{
uint32_t sn;
if (do_encryption) {
cipher_decrypt(&(pdu->msg[sn_len_bytes]),
rx_count,
pdu->N_bytes - sn_len_bytes,
&(pdu->msg[sn_len_bytes]));
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid));
}
if(12 == cfg.sn_len)
{
pdcp_unpack_data_pdu_long_sn(pdu, &sn);
} else {
pdcp_unpack_data_pdu_short_sn(pdu, &sn);
}
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", get_rb_name(lcid), sn);
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn);
gw->write_pdu(lcid, pdu);
}
rx_count++;
}
}
uint8_t pdcp_entity::get_bearer_id(uint8_t lcid)
{
if(lcid <= RB_ID_SRB2) {
return lcid - 1;
} else {
return lcid - RB_ID_SRB2 - 1;
}
}
/****************************************************************************

View File

@ -1164,11 +1164,21 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg;
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg;
// Configure PDCP for security
rrc_log->info("Received Security Mode Command eea: %s, eia: %s\n",
ciphering_algorithm_id_text[cipher_algo],
integrity_algorithm_id_text[integ_algo]);
// 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);
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");
// Configure PDCP for security
pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
pdcp->enable_integrity(lcid);
send_security_mode_complete(lcid, pdu);
pdcp->enable_encryption(lcid);
break;
@ -1626,6 +1636,8 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) {
pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag
if(RB_ID_SRB2 == srb_cnfg->srb_id) {
pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
pdcp->enable_integrity(srb_cnfg->srb_id);
pdcp->enable_encryption(srb_cnfg->srb_id);
}
// Setup RLC
@ -1692,7 +1704,8 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) {
}
}
pdcp->add_bearer(lcid, pdcp_cfg);
// TODO: setup PDCP security (using k_up_enc)
pdcp->config_security(lcid, k_up_enc, k_up_int, cipher_algo, integ_algo);
pdcp->enable_encryption(lcid);
// Setup RLC
rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg));