diff --git a/srsue/hdr/stack/upper/nas_ext.h b/srsue/hdr/stack/upper/nas_ext.h index 5802f130e..cb20575d9 100644 --- a/srsue/hdr/stack/upper/nas_ext.h +++ b/srsue/hdr/stack/upper/nas_ext.h @@ -90,6 +90,10 @@ private: 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_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); + void handle_usim_gen_nas_keys_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len); + void rrctl_send_confirm(rrctl::proto::msg_type type); void rrctl_send_error(rrctl::proto::msg_type type); }; diff --git a/srsue/src/stack/upper/nas_ext.cc b/srsue/src/stack/upper/nas_ext.cc index 3fdd7f84e..47c56ab2e 100644 --- a/srsue/src/stack/upper/nas_ext.cc +++ b/srsue/src/stack/upper/nas_ext.cc @@ -85,6 +85,8 @@ void nas_ext::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interf break; case rrctl::proto::RRCTL_SEC_MODE: case rrctl::proto::RRCTL_EXT_USIM: + handle_rrctl_ext_usim(payload, length); + break; case rrctl::proto::RRCTL_CONN_RELEASE: default: nas_log->warning("%s is not handled\n", desc.c_str()); @@ -213,6 +215,110 @@ void nas_ext::handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg } } +void nas_ext::handle_rrctl_ext_usim(const uint8_t* _msg, size_t len) +{ + enum rrctl::proto::ext_usim_msg_type msg_type; + const struct rrctl::proto::ext_usim_msg* msg; + std::string msg_desc; + + if (len < 4) { /* XXX: type + padding */ + nas_log->error("Received too short (U)SIM specific message (len=%zu)\n", len); + rrctl_send_error(rrctl::proto::RRCTL_EXT_USIM); + return; + } + + /* Skip the header */ + len -= 4; + + msg = reinterpret_cast (_msg); + msg_type = static_cast (msg->type); + + switch (msg_type) { + case rrctl::proto::EXT_USIM_GEN_AUTH_RESP: + handle_usim_gen_auth_resp_req(msg, len); + break; + case rrctl::proto::EXT_USIM_RAW_APDU: + case rrctl::proto::EXT_USIM_READ_FILE: + case rrctl::proto::EXT_USIM_UPDATE_FILE: + case rrctl::proto::EXT_USIM_RESERVED: + default: + nas_log->warning("(U)SIM specific message 0x%02x is not handled\n", msg->type); + } +} + +void nas_ext::handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len) +{ + const struct rrctl::proto::ext_usim_gen_auth_resp_req* req; + struct rrctl::proto::ext_usim_gen_auth_resp_rsp* rsp; + struct rrctl::proto::ext_usim_msg* rsp_msg; + std::pair mcc_mnc; + struct rrctl::proto::msg_hdr* hdr; + srslte::byte_buffer_t pdu; + + /* Allocate the response message in advance */ + hdr = rrctl::codec::enc_hdr(pdu, rrctl::proto::RRCTL_EXT_USIM, rrctl::proto::RRCTL_CNF, 4); + rsp_msg = reinterpret_cast (&pdu.msg[pdu.N_bytes]); + rsp_msg->type = msg->type; + pdu.N_bytes += 4; + + if (len < sizeof(*req)) { + nas_log->error("Received too short (U)SIM GenAuthResp.req (len=%zu)\n", len); + hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR; + iface->write(pdu); + return; + } + + rsp = &rsp_msg->u.gen_auth_resp_rsp; + req = &msg->u.gen_auth_resp_req; + + // Parse PLMN ID + try { + /* HACK: generalize this function */ + rrctl::codec::dec_plmn_select_req(mcc_mnc, &req->mcc[0], len); + } catch (const rrctl::codec::error& e) { + nas_log->warning("Failed to parse MCC/MNC: %s\n", e.what()); + hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR; + iface->write(pdu); + return; + } + + uint8_t k_asme[32]; + uint8_t res[16]; + int res_len; + + /* NOTE: this is a blocking call => no other RRCTL messages can be processed in parallel? + * FIXME: the authors of srsUE apparently are not aware of 'const', so we have to cast. */ + auth_result_t auth_res = usim->generate_authentication_response((uint8_t*) &req->rand[0], + (uint8_t*) &req->autn[0], + mcc_mnc.first, mcc_mnc.second, + &res[0], &res_len, &k_asme[0]); + switch (auth_res) { + case AUTH_OK: + nas_log->info("Authentication vector has been generated successfully\n"); + + pdu.N_bytes += sizeof(*rsp); + pdu.append_bytes(&k_asme[0], sizeof(k_asme)); + pdu.append_bytes(&res[0], res_len); + rsp->res_len = (uint8_t) res_len; + break; + case AUTH_SYNCH_FAILURE: + nas_log->warning("Synchronization is required to generate an authentication vector\n"); + + pdu.N_bytes += sizeof(*rsp); + pdu.append_bytes(&res[0], res_len); + rsp->res_len = (uint8_t) res_len; + rsp->out_of_sync = true; + break; + case AUTH_FAILED: + default: + nas_log->warning("Could not generate an authentication vector\n"); + hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR; + } + + hdr->len = htons(pdu.N_bytes - sizeof(*hdr)); + iface->write(pdu); +} + void nas_ext::get_metrics(nas_metrics_t* m) { nas_metrics_t metrics = {};