SGSN: encrypt/decrypt only necessary frames

According to 3GPP TS 24.008 § 4.7.1.2 some GMM frames are not supposed
to be ciphered. Propagate information about the necessity for
encryption between MM <-> LLC to ensure only proper frames are
encrypted/decrypted/dropped.

Change-Id: I0358905e60d1b182f75caec81bfcc72bbbbb2aa1
Related: OS#1582
This commit is contained in:
Max 2016-07-06 11:59:18 +02:00 committed by Harald Welte
parent b997f84443
commit 82040101eb
6 changed files with 51 additions and 34 deletions

View File

@ -4,13 +4,16 @@
#include <osmocom/core/msgb.h>
#include <openbsc/gprs_sgsn.h>
#include <stdbool.h>
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause);
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
uint8_t cause, uint8_t pco_len, uint8_t *pco_v);
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
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_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable);
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
struct gprs_llc_llme *llme);

View File

@ -2,6 +2,7 @@
#define _GPRS_LLC_H
#include <stdint.h>
#include <stdbool.h>
#include <openbsc/gprs_sgsn.h>
/* Section 4.7 LLC Layer Structure */
@ -211,7 +212,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
/* LL-UNITDATA.req */
int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
void *mmctx);
struct sgsn_mm_ctx *mmctx, bool encryptable);
/* Chapter 7.2.1.2 LLGMM-RESET.req */
int gprs_llgmm_reset(struct gprs_llc_llme *llme);

View File

@ -26,7 +26,7 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <stdbool.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@ -132,13 +132,13 @@ time_t gprs_max_time_to_idle(void)
/* Send a message through the underlying layer */
static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
struct sgsn_mm_ctx *mm)
struct sgsn_mm_ctx *mm, bool encryptable)
{
if (mm)
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
/* caller needs to provide TLLI, BVCI and NSEI */
return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm, encryptable);
}
/* copy identifiers from old message to new message, this
@ -196,7 +196,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause,
}
gh->data[0] = cause;
return gsm48_gmm_sendmsg(msg, 0, mmctx);
return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
}
static int gsm48_tx_gmm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
@ -234,7 +234,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
msgb_tv_put(msg, GSM48_IE_GMM_CAUSE, cause);
return gsm48_gmm_sendmsg(msg, 0, mmctx);
return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
}
static int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx,
@ -330,7 +330,7 @@ static int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
/* Optional: MS-identity (combined attach) */
/* Optional: GMM cause (partial attach result for combined attach) */
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
/* Chapter 9.4.5: Attach reject */
@ -347,7 +347,7 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
gh->msg_type = GSM48_MT_GMM_ATTACH_REJ;
gh->data[0] = gmm_cause;
return gsm48_gmm_sendmsg(msg, 0, NULL);
return gsm48_gmm_sendmsg(msg, 0, NULL, false);
}
static int gsm48_tx_gmm_att_rej_oldmsg(const struct msgb *old_msg,
uint8_t gmm_cause)
@ -379,7 +379,7 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
gh->data[0] = force_stby;
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
@ -415,7 +415,7 @@ static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
/* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */
gh->data[0] = id_type & 0xf;
return gsm48_gmm_sendmsg(msg, 1, mm);
return gsm48_gmm_sendmsg(msg, 1, mm, false);
}
/* 3GPP TS 24.008 Section 9.4.9: Authentication and Ciphering Request */
@ -463,7 +463,7 @@ static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd,
/* 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);
return gsm48_gmm_sendmsg(msg, 1, mm, false);
}
/* Section 9.4.11: Authentication and Ciphering Reject */
@ -480,7 +480,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
gh->proto_discr = GSM48_PDISC_MM_GPRS;
gh->msg_type = GSM48_MT_GMM_AUTH_CIPH_REJ;
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, false);
}
/* Section 9.4.10: Authentication and Ciphering Response */
@ -1094,7 +1094,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3314));
/* Option: MS ID, ... */
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
/* Chapter 9.4.17: Routing area update reject */
@ -1114,7 +1114,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
gh->data[1] = 0; /* ? */
/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
return gsm48_gmm_sendmsg(msg, 0, NULL);
return gsm48_gmm_sendmsg(msg, 0, NULL, false);
}
static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
@ -1328,13 +1328,20 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
/* GPRS Mobility Management */
static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
struct gprs_llc_llme *llme)
struct gprs_llc_llme *llme, bool drop_cipherable)
{
struct sgsn_signal_data sig_data;
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
int rc;
/* MMCTX can be NULL when called */
if (drop_cipherable && gsm48_hdr_gmm_cipherable(gh)) {
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping cleartext GMM %s which "
"is expected to be encrypted for TLLI 0x%08x\n",
get_value_string(gprs_msgt_gmm_names, gh->msg_type),
llme->tlli);
return -EBADMSG;
}
if (llme && !mmctx &&
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
@ -1646,7 +1653,7 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
/* Optional: Packet Flow Identifier */
return gsm48_gmm_sendmsg(msg, 0, pdp->mm);
return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);
}
/* Section 9.5.3: Activate PDP Context reject */
@ -1669,7 +1676,7 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
if (pco_len && pco_v)
msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
/* Section 9.5.8: Deactivate PDP Context Request */
@ -1690,7 +1697,7 @@ static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
msgb_v_put(msg, sm_cause);
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause)
{
@ -1714,7 +1721,7 @@ static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;
return gsm48_gmm_sendmsg(msg, 0, mm);
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)
{
@ -2163,7 +2170,8 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
}
/* Main entry point for incoming 04.08 GPRS messages from Gb */
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme)
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t pdisc = gsm48_hdr_pdisc(gh);
@ -2183,7 +2191,7 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme)
switch (pdisc) {
case GSM48_PDISC_MM_GPRS:
rc = gsm0408_rcv_gmm(mmctx, msg, llme);
rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
break;
case GSM48_PDISC_SM_GPRS:
rc = gsm0408_rcv_gsm(mmctx, msg, llme);

View File

@ -21,6 +21,7 @@
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <openssl/rand.h>
@ -346,9 +347,12 @@ static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
}
/* Transmit a UI frame over the given SAPI */
/* Transmit a UI frame over the given SAPI:
'encryptable' indicates whether particular message can be encrypted according
to 3GPP TS 24.008 § 4.7.1.2
*/
int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
void *mmctx)
struct sgsn_mm_ctx *mmctx, bool encryptable)
{
struct gprs_llc_lle *lle;
uint8_t *fcs, *llch;
@ -409,7 +413,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
fcs[2] = (fcs_calc >> 16) & 0xff;
/* encrypt information field + FCS, if needed! */
if (lle->llme->algo != GPRS_ALGO_GEA0) {
if (lle->llme->algo != GPRS_ALGO_GEA0 && encryptable) {
uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
uint16_t crypt_len = (fcs + 3) - (llch + 3);
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
@ -567,6 +571,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
struct gprs_llc_hdr *lh = (struct gprs_llc_hdr *) msgb_llch(msg);
struct gprs_llc_hdr_parsed llhp;
struct gprs_llc_lle *lle;
bool drop_cipherable = false;
int rc = 0;
/* Identifiers from DOWN: NSEI, BVCI, TLLI */
@ -640,11 +645,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
for (i = 0; i < crypt_len; i++)
*(llhp.data + i) ^= cipher_out[i];
} else {
if (lle->llme->algo != GPRS_ALGO_GEA0) {
LOGP(DLLC, LOGL_NOTICE, "unencrypted frame for LLC "
"that is supposed to be encrypted. Dropping.\n");
return 0;
}
if (lle->llme->algo != GPRS_ALGO_GEA0 &&
lle->llme->cksn != GSM_KEY_SEQ_INVAL)
drop_cipherable = true;
}
/* We have to do the FCS check _after_ decryption */
@ -669,7 +672,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
switch (llhp.sapi) {
case GPRS_SAPI_GMM:
/* send LL_UNITDATA_IND to GMM */
rc = gsm0408_gprs_rcvmsg_gb(msg, lle->llme);
rc = gsm0408_gprs_rcvmsg_gb(msg, lle->llme,
drop_cipherable);
break;
case GPRS_SAPI_SNDCP3:
case GPRS_SAPI_SNDCP5:

View File

@ -22,6 +22,7 @@
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/linuxlist.h>
@ -417,7 +418,7 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs)
/* set the MORE bit of the SNDCP header accordingly */
sch->more = more;
rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext);
rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext, true);
/* abort in case of error, do not advance frag_nr / next_byte */
if (rc < 0) {
msgb_free(fs->msg);
@ -498,7 +499,7 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
sch->type = 1;
sch->nsapi = nsapi;
return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext);
return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext, true);
}
/* Section 5.1.2.17 LL-UNITDATA.ind */

View File

@ -215,7 +215,7 @@ static void send_0408_message(struct gprs_llc_llme *llme, uint32_t tlli,
msg = create_msg(data, data_len);
msgb_tlli(msg) = tlli;
bssgp_create_cell_id(msgb_bcid(msg), bssgp_raid, 0);
gsm0408_gprs_rcvmsg_gb(msg, llme);
gsm0408_gprs_rcvmsg_gb(msg, llme, false);
msgb_free(msg);
}