srsue/extnas: implement encryption and signing of NAS messages
This commit is contained in:
parent
19ed00e9bb
commit
fbb2ed3aa9
|
@ -88,6 +88,7 @@ private:
|
|||
void handle_rrctl_conn_release(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
|
||||
void handle_rrctl_ext_usim(const uint8_t* msg, size_t len);
|
||||
void handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len);
|
||||
|
|
|
@ -84,6 +84,8 @@ void nas_ext::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interf
|
|||
handle_rrctl_param(disc, payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_SEC_MODE:
|
||||
handle_rrctl_sec_mode(disc, payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_EXT_USIM:
|
||||
handle_rrctl_ext_usim(payload, length);
|
||||
break;
|
||||
|
@ -115,7 +117,9 @@ void nas_ext::rrctl_send_error(rrctl::proto::msg_type type)
|
|||
|
||||
void nas_ext::handle_rrctl_reset(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
// TODO: do we need to reset anything?
|
||||
/* Reset security state (no EEA, no EIA) */
|
||||
memset(&ctxt, 0x00, sizeof(ctxt));
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_RESET);
|
||||
}
|
||||
|
||||
|
@ -162,6 +166,9 @@ void nas_ext::handle_rrctl_conn_establish(rrctl::proto::msg_disc disc, const uin
|
|||
return;
|
||||
}
|
||||
|
||||
set_k_enb_count(ctxt.tx_count);
|
||||
ctxt.tx_count++;
|
||||
|
||||
// Allocate a new NAS PDU on heap
|
||||
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
nas_pdu->append_bytes(pdu, pdu_len);
|
||||
|
@ -181,7 +188,15 @@ void nas_ext::handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg,
|
|||
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
nas_pdu->append_bytes(msg, len);
|
||||
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_encrypt(nas_pdu.get());
|
||||
// Apply pre-configured EIA algorythm (if enabled)
|
||||
integrity_generate(&k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK,
|
||||
&nas_pdu->msg[5], nas_pdu->N_bytes - 5, &nas_pdu->msg[1]);
|
||||
|
||||
rrc->write_sdu(std::move(nas_pdu));
|
||||
ctxt.tx_count++;
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_DATA);
|
||||
}
|
||||
|
||||
|
@ -215,6 +230,53 @@ void nas_ext::handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg
|
|||
}
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::msg_sec_mode_req* req;
|
||||
|
||||
req = reinterpret_cast<const struct rrctl::proto::msg_sec_mode_req*> (msg);
|
||||
|
||||
if (len < sizeof(*req)) { /* XXX: mandatory fields only */
|
||||
nas_log->error("Received malformed PARAM.req (len=%zu)\n", len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the header */
|
||||
len -= sizeof(*req);
|
||||
|
||||
nas_log->info("Rx SecurityMode.req (EEA%u, EIA%u)\n", req->eea, req->eia);
|
||||
|
||||
ctxt.cipher_algo = static_cast<srslte::CIPHERING_ALGORITHM_ID_ENUM> (req->eea);
|
||||
ctxt.integ_algo = static_cast<srslte::INTEGRITY_ALGORITHM_ID_ENUM> (req->eia);
|
||||
|
||||
if (req->flags & SEC_MODE_F_RESET_RX_CTR)
|
||||
ctxt.rx_count = 0;
|
||||
if (req->flags & SEC_MODE_F_RESET_TX_CTR)
|
||||
ctxt.tx_count = 0;
|
||||
|
||||
if (req->eea != 0x00 or req->eia != 0x00) {
|
||||
/* Ensure that Kasme is present */
|
||||
if (len != sizeof(ctxt.k_asme)) {
|
||||
nas_log->error("Kasme is expected, but not present");
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctxt.k_asme[0], &req->k_asme[0], sizeof(ctxt.k_asme));
|
||||
|
||||
/* Derive both Knas_enc and Knas_int from Kasme */
|
||||
/* NOTE: how is this related to (U)SIM at all?!? */
|
||||
usim->generate_nas_keys(&ctxt.k_asme[0], // in
|
||||
&k_nas_enc[0], // out
|
||||
&k_nas_int[0], // out
|
||||
ctxt.cipher_algo,
|
||||
ctxt.integ_algo);
|
||||
}
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_SEC_MODE);
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_ext_usim(const uint8_t* _msg, size_t len)
|
||||
{
|
||||
enum rrctl::proto::ext_usim_msg_type msg_type;
|
||||
|
@ -296,6 +358,8 @@ void nas_ext::handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_
|
|||
case AUTH_OK:
|
||||
nas_log->info("Authentication vector has been generated successfully\n");
|
||||
|
||||
set_k_enb_count(0);
|
||||
|
||||
pdu.N_bytes += sizeof(*rsp);
|
||||
pdu.append_bytes(&k_asme[0], sizeof(k_asme));
|
||||
pdu.append_bytes(&res[0], res_len);
|
||||
|
@ -380,9 +444,27 @@ bool nas_ext::paging(srslte::s_tmsi_t* ue_identity)
|
|||
void nas_ext::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
srslte::byte_buffer_t msg;
|
||||
uint8 pd, sec_hdr_type;
|
||||
|
||||
nas_log->info_hex(pdu->msg, pdu->N_bytes, "Received DL %s PDU from RRC\n", rrc->get_rb_name(lcid).c_str());
|
||||
|
||||
// Parse the message security header
|
||||
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*) pdu.get(), &pd, &sec_hdr_type);
|
||||
switch (sec_hdr_type) {
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY:
|
||||
break;
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED:
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_decrypt(pdu.get());
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Received DL NAS PDU with unknown sec_hdr=%02x\n", sec_hdr_type);
|
||||
}
|
||||
|
||||
rrctl::codec::enc_data_ind(msg, pdu->msg, pdu->N_bytes, lcid);
|
||||
iface->write(msg);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue