SGSN: add preliminary support for GPRS encryption
It is already functional enough to allow testing with real phones. However, note - there are several limitations in the current implementation: * only default value for IOV-UI is supported at the moment * AUTN-based key material is not supported Related: OS#1582 Change-Id: I8900b906693496e4e6b35be5a86937c58039ed9e
This commit is contained in:
parent
5aa5196fbf
commit
b997f84443
|
@ -12,7 +12,8 @@ int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
|||
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme);
|
||||
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg);
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
|
||||
struct gprs_llc_llme *llme);
|
||||
void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
|
||||
void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause);
|
||||
void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause);
|
||||
|
|
|
@ -215,7 +215,8 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
|
|||
|
||||
/* Chapter 7.2.1.2 LLGMM-RESET.req */
|
||||
int gprs_llgmm_reset(struct gprs_llc_llme *llme);
|
||||
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi);
|
||||
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
|
||||
struct gprs_llc_llme *llme);
|
||||
|
||||
/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
|
||||
int gprs_llgmm_assign(struct gprs_llc_llme *llme,
|
||||
|
|
|
@ -357,9 +357,6 @@ int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn);
|
|||
|
||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
|
||||
|
||||
/* Force re-attachment based on msgb meta data */
|
||||
int sgsn_force_reattach_oldmsg(struct msgb *oldmsg);
|
||||
|
||||
/*
|
||||
* ctrl interface related work
|
||||
*/
|
||||
|
|
|
@ -418,9 +418,9 @@ static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
|
|||
return gsm48_gmm_sendmsg(msg, 1, mm);
|
||||
}
|
||||
|
||||
/* Section 9.4.9: Authentication and Ciphering Request */
|
||||
/* 3GPP TS 24.008 Section 9.4.9: Authentication and Ciphering Request */
|
||||
static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd,
|
||||
uint8_t key_seq, uint8_t algo)
|
||||
uint8_t key_seq, bool force_standby)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REQ");
|
||||
struct gsm48_hdr *gh;
|
||||
|
@ -437,9 +437,11 @@ static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd,
|
|||
gh->msg_type = GSM48_MT_GMM_AUTH_CIPH_REQ;
|
||||
|
||||
acreq = (struct gsm48_auth_ciph_req *) msgb_put(msg, sizeof(*acreq));
|
||||
acreq->ciph_alg = algo & 0xf;
|
||||
acreq->ciph_alg = mm->ciph_algo & 0xf;
|
||||
/* § 10.5.5.10: */
|
||||
acreq->imeisv_req = 0x1;
|
||||
acreq->force_stby = 0x0;
|
||||
/* § 10.5.5.7: */
|
||||
acreq->force_stby = force_standby;
|
||||
/* 3GPP TS 24.008 § 10.5.5.19: */
|
||||
if (RAND_bytes(&rbyte, 1) != 1) {
|
||||
LOGP(DMM, LOGL_NOTICE, "RAND_bytes failed for A&C ref, falling "
|
||||
|
@ -454,11 +456,11 @@ static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd,
|
|||
m_rand = msgb_put(msg, 16+1);
|
||||
m_rand[0] = GSM48_IE_GMM_AUTH_RAND;
|
||||
memcpy(m_rand + 1, rnd, 16);
|
||||
|
||||
/* § 10.5.1.2: */
|
||||
m_cksn = msgb_put(msg, 1);
|
||||
m_cksn[0] = (GSM48_IE_GMM_CIPH_CKSN << 4) | (key_seq & 0x07);
|
||||
}
|
||||
|
||||
/* FIXME: add AUTN for 3g auth according to 3GPP TS 24.008 § 10.5.3.1.1 */
|
||||
/* FIXME: make sure we don't send any other messages to the MS */
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 1, mm);
|
||||
|
@ -652,8 +654,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
|||
|
||||
mmctx_timer_start(ctx, 3360, sgsn->cfg.timers.T3360);
|
||||
return gsm48_tx_gmm_auth_ciph_req(ctx, at->vec.rand,
|
||||
at->key_seq,
|
||||
GPRS_ALGO_GEA0);
|
||||
at->key_seq, false);
|
||||
}
|
||||
|
||||
if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && ctx->is_authenticated &&
|
||||
|
@ -959,7 +960,15 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||
ctx->ms_radio_access_capa.len);
|
||||
ctx->ms_network_capa.len = msnc_len;
|
||||
memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
|
||||
|
||||
if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
|
||||
ctx->ciph_algo)) {
|
||||
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
|
||||
"type %s because MS do not support required %s "
|
||||
"encryption\n", gsm48_mi_type_name(mi_type),
|
||||
get_value_string(gprs_cipher_names,ctx->ciph_algo));
|
||||
goto rejected;
|
||||
}
|
||||
#ifdef PTMSI_ALLOC
|
||||
/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
|
||||
/* Don't change the P-TMSI if a P-TMSI re-assignment is under way */
|
||||
|
@ -1355,7 +1364,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
}
|
||||
|
||||
/* Force the MS to re-attach */
|
||||
rc = sgsn_force_reattach_oldmsg(msg);
|
||||
rc = gsm0408_gprs_force_reattach_oldmsg(msg, llme);
|
||||
|
||||
/* TLLI unassignment */
|
||||
gprs_llgmm_unassign(llme);
|
||||
|
@ -1534,8 +1543,7 @@ static void mmctx_timer_cb(void *_mm)
|
|||
}
|
||||
at = &mm->auth_triplet;
|
||||
|
||||
gsm48_tx_gmm_auth_ciph_req(mm, at->vec.rand, at->key_seq,
|
||||
GPRS_ALGO_GEA0);
|
||||
gsm48_tx_gmm_auth_ciph_req(mm, at->vec.rand, at->key_seq, false);
|
||||
osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3360, 0);
|
||||
break;
|
||||
case 3370: /* waiting for IDENTITY RESPONSE */
|
||||
|
@ -2094,7 +2102,7 @@ static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
if (gh->msg_type == GSM48_MT_GSM_STATUS)
|
||||
return 0;
|
||||
|
||||
return sgsn_force_reattach_oldmsg(msg);
|
||||
return gsm0408_gprs_force_reattach_oldmsg(msg, llme);
|
||||
}
|
||||
|
||||
switch (gh->msg_type) {
|
||||
|
@ -2128,10 +2136,11 @@ static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg)
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
|
||||
struct gprs_llc_llme *llme)
|
||||
{
|
||||
int rc;
|
||||
gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM);
|
||||
gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme);
|
||||
|
||||
rc = gsm48_tx_gmm_detach_req_oldmsg(
|
||||
msg, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
|
@ -598,7 +600,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
|||
case GPRS_SAPI_SNDCP9:
|
||||
case GPRS_SAPI_SNDCP11:
|
||||
/* Ask an upper layer for help. */
|
||||
return sgsn_force_reattach_oldmsg(msg);
|
||||
return gsm0408_gprs_force_reattach_oldmsg(msg,
|
||||
lle->llme);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -769,13 +772,18 @@ int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
|
|||
int gprs_llgmm_reset(struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
|
||||
int random = rand();
|
||||
struct gprs_llc_lle *lle = &llme->lle[1];
|
||||
|
||||
if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) {
|
||||
LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, "
|
||||
"falling back to rand()\n");
|
||||
llme->iov_ui = rand();
|
||||
}
|
||||
|
||||
/* First XID component must be RESET */
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
|
||||
/* randomly select new IOV-UI */
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui);
|
||||
|
||||
/* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */
|
||||
lle->vu_recv = 0;
|
||||
|
@ -787,15 +795,21 @@ int gprs_llgmm_reset(struct gprs_llc_llme *llme)
|
|||
return gprs_llc_tx_xid(lle, msg, 1);
|
||||
}
|
||||
|
||||
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi)
|
||||
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
|
||||
struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
|
||||
int random = rand();
|
||||
|
||||
if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) {
|
||||
LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, "
|
||||
"falling back to rand()\n");
|
||||
llme->iov_ui = rand();
|
||||
}
|
||||
|
||||
/* First XID component must be RESET */
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
|
||||
/* randomly select new IOV-UI */
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
|
||||
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui);
|
||||
|
||||
/* FIXME: Start T200, wait for XID response */
|
||||
|
||||
|
|
|
@ -169,6 +169,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
|
|||
ctx->gb.tlli = tlli;
|
||||
ctx->mm_state = GMM_DEREGISTERED;
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ciph_algo = sgsn->cfg.cipher;
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
|
@ -604,11 +605,6 @@ int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn)
|
|||
return num;
|
||||
}
|
||||
|
||||
int sgsn_force_reattach_oldmsg(struct msgb *oldmsg)
|
||||
{
|
||||
return gsm0408_gprs_force_reattach_oldmsg(oldmsg);
|
||||
}
|
||||
|
||||
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
OSMO_ASSERT(mmctx != NULL);
|
||||
|
|
Loading…
Reference in New Issue