This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Max gerrit-no-reply at lists.osmocom.orgHello Jenkins Builder,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/460
to look at the new patch set (#3).
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
* A&C reference number is not validated
* AUTN-based key material is not supported
FCS-related corrections were contributed by Dieter Spaar.
Change-Id: I8900b906693496e4e6b35be5a86937c58039ed9e
Related: OS#1582
---
M openbsc/include/openbsc/gprs_gmm.h
M openbsc/include/openbsc/gprs_llc.h
M openbsc/include/openbsc/gprs_sgsn.h
M openbsc/src/gprs/gprs_gmm.c
M openbsc/src/gprs/gprs_llc.c
M openbsc/src/gprs/gprs_sgsn.c
M openbsc/src/gprs/gprs_sndcp.c
M openbsc/src/gprs/sgsn_main.c
M openbsc/tests/sgsn/sgsn_test.c
9 files changed, 137 insertions(+), 96 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/60/460/3
diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h
index e0d8f77..c453bce 100644
--- a/openbsc/include/openbsc/gprs_gmm.h
+++ b/openbsc/include/openbsc/gprs_gmm.h
@@ -10,9 +10,11 @@
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);
+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);
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index 8cd0c26..8a44741 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -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 */
@@ -155,7 +156,10 @@
/* Crypto parameters */
enum gprs_ciph_algo algo;
- uint8_t kc[8];
+ uint8_t kc[16];
+ uint8_t cksn;
+ /* 3GPP TS 44.064 § 8.9.2: */
+ uint32_t iov_ui;
/* over which BSSGP BTS ctx do we need to transmit */
uint16_t bvci;
@@ -208,16 +212,16 @@
/* 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);
-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,
- uint32_t old_tlli, uint32_t new_tlli,
- enum gprs_ciph_algo alg, const uint8_t *kc);
+ uint32_t old_tlli, uint32_t new_tlli);
int gprs_llgmm_unassign(struct gprs_llc_llme *llme);
int gprs_llc_init(const char *cipher_plugin_path);
@@ -240,6 +244,7 @@
}
/* LLC low level functions */
+void gprs_llme_set_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
/* parse a GPRS LLC header, also check for invalid frames */
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 0e574d8..f8ce2b1 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -355,9 +355,6 @@
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
*/
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index 5db69dd..1419729 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -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>
@@ -130,13 +130,13 @@
/* 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
@@ -194,7 +194,7 @@
}
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)
@@ -232,7 +232,7 @@
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,
@@ -328,7 +328,7 @@
/* 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 */
@@ -345,7 +345,7 @@
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)
@@ -377,7 +377,7 @@
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)
@@ -413,12 +413,12 @@
/* 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);
}
-/* Section 9.4.9: Authentication and Ciphering Request */
-static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rand,
- uint8_t key_seq, uint8_t algo)
+/* 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, bool force_standby)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REQ");
struct gsm48_hdr *gh;
@@ -426,7 +426,7 @@
uint8_t *m_rand, *m_cksn;
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s)\n",
- osmo_hexdump(rand, 16));
+ osmo_hexdump(rnd, 16));
mmctx2msgid(msg, mm);
@@ -435,24 +435,29 @@
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;
- acreq->ac_ref_nr = 0x0; /* FIXME: increment this? */
+ /* § 10.5.5.7: */
+ acreq->force_stby = force_standby;
+ /* 3GPP TS 24.008 § 10.5.5.19 */
+ acreq->ac_ref_nr = rand();
+ /* FIXME: store ref_nr and check that received response matches it */
/* Only if authentication is requested we need to set RAND + CKSN */
- if (rand) {
+ if (rnd) {
m_rand = msgb_put(msg, 16+1);
m_rand[0] = GSM48_IE_GMM_AUTH_RAND;
- memcpy(m_rand+1, rand, 16);
-
+ 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);
+ return gsm48_gmm_sendmsg(msg, 1, mm, false);
}
/* Section 9.4.11: Authentication and Ciphering Reject */
@@ -469,7 +474,7 @@
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 */
@@ -638,8 +643,7 @@
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 &&
@@ -962,8 +966,10 @@
ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
/* Inform LLC layer about new TLLI but keep old active */
- gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new,
- GPRS_ALGO_GEA0, NULL);
+ if (ctx->is_authenticated) {
+ gprs_llme_set_key(ctx, ctx->gb.llme);
+ }
+ gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new);
}
ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
@@ -1069,7 +1075,7 @@
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 */
@@ -1089,7 +1095,7 @@
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,
@@ -1262,8 +1268,7 @@
/* Inform LLC layer about new TLLI but keep old active */
gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli,
- mmctx->gb.tlli_new, GPRS_ALGO_GEA0,
- NULL);
+ mmctx->gb.tlli_new);
}
/* Look at PDP Context Status IE and see if MS's view of
@@ -1304,13 +1309,19 @@
/* 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)) {
+ LOGP(DMM, LOGL_NOTICE, "Dropping cleartext GMM %s which is "
+ "expected to be encrypted\n",
+ get_value_string(gprs_mt_gmm_names, gh->msg_type));
+ return -EBADMSG;
+ }
if (llme && !mmctx &&
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
@@ -1340,7 +1351,7 @@
}
/* 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);
@@ -1398,9 +1409,9 @@
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Unassign the old TLLI */
mmctx->gb.tlli = mmctx->gb.tlli_new;
+ gprs_llme_set_key(mmctx, mmctx->gb.llme);
gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
- mmctx->gb.tlli_new,
- GPRS_ALGO_GEA0, NULL);
+ mmctx->gb.tlli_new);
}
mmctx->mm_state = GMM_REGISTERED_NORMAL;
rc = 0;
@@ -1421,8 +1432,8 @@
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Unassign the old TLLI */
mmctx->gb.tlli = mmctx->gb.tlli_new;
- gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new,
- GPRS_ALGO_GEA0, NULL);
+ gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
+ mmctx->gb.tlli_new);
}
mmctx->mm_state = GMM_REGISTERED_NORMAL;
rc = 0;
@@ -1519,8 +1530,7 @@
}
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 */
@@ -1623,7 +1633,7 @@
/* 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 */
@@ -1646,7 +1656,7 @@
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 */
@@ -1667,7 +1677,7 @@
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)
{
@@ -1691,7 +1701,7 @@
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)
{
@@ -2079,7 +2089,7 @@
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) {
@@ -2113,10 +2123,11 @@
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);
@@ -2139,7 +2150,8 @@
}
/* 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);
@@ -2159,7 +2171,7 @@
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);
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 64d22b3..ad7ecdf 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdint.h>
+#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/linuxlist.h>
@@ -236,6 +237,7 @@
llme->old_tlli = 0xffffffff;
llme->state = GPRS_LLMS_UNASSIGNED;
llme->age_timestamp = GPRS_LLME_RESET_AGE;
+ llme->cksn = GSM_KEY_SEQ_INVAL;
for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
lle_init(llme, i);
@@ -343,9 +345,12 @@
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;
@@ -365,6 +370,8 @@
msgb_free(msg);
return -EFBIG;
}
+
+ gprs_llme_set_key(mmctx, lle->llme);
/* Update LLE's (BVCI, NSEI) tuple */
lle->llme->bvci = msgb_bvci(msg);
@@ -404,8 +411,7 @@
fcs[2] = (fcs_calc >> 16) & 0xff;
/* encrypt information field + FCS, if needed! */
- if (lle->llme->algo != GPRS_ALGO_GEA0) {
- uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
+ if (lle->llme->algo != GPRS_ALGO_GEA0 && encryptable) {
uint16_t crypt_len = (fcs + 3) - (llch + 3);
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
uint32_t iv;
@@ -413,7 +419,7 @@
uint8_t *kc = lle->llme->kc;
/* Compute the 'Input' Paraemeter */
- iv = gprs_cipher_gen_input_ui(iov_ui, sapi, nu, oc);
+ iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi, nu, oc);
/* Compute the keystream that we need to XOR with the data */
rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
@@ -424,12 +430,16 @@
return rc;
}
+ /* Mark frame as encrypted and update FCS */
+ llch[2] |= 0x02;
+ fcs_calc = gprs_llc_fcs(llch, fcs - llch);
+ fcs[0] = fcs_calc & 0xff;
+ fcs[1] = (fcs_calc >> 8) & 0xff;
+ fcs[2] = (fcs_calc >> 16) & 0xff;
+
/* XOR the cipher output with the information field + FCS */
for (i = 0; i < crypt_len; i++)
*(llch + 3 + i) ^= cipher_out[i];
-
- /* Mark frame as encrypted */
- ctrl[1] |= 0x02;
}
/* Identifiers passed down: (BVCI, NSEI) */
@@ -562,6 +572,7 @@
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 */
@@ -595,7 +606,8 @@
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;
}
@@ -607,7 +619,6 @@
/* decrypt information field + FCS, if needed! */
if (llhp.is_encrypted) {
- uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
uint16_t crypt_len = llhp.data_len + 3;
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
uint32_t iv;
@@ -620,7 +631,7 @@
return 0;
}
- iv = gprs_cipher_gen_input_ui(iov_ui, lle->sapi, llhp.seq_tx,
+ iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, lle->sapi, llhp.seq_tx,
lle->oc_ui_recv);
rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
kc, iv, GPRS_CIPH_MS2SGSN);
@@ -633,11 +644,16 @@
/* XOR the cipher output with the information field + FCS */
for (i = 0; i < crypt_len; i++)
*(llhp.data + i) ^= cipher_out[i];
+
+ llhp.fcs = *(llhp.data + crypt_len - 3);
+ llhp.fcs |= *(llhp.data + crypt_len - 2) << 8;
+ llhp.fcs |= *(llhp.data + crypt_len - 1) << 16;
} else {
- if (lle->llme->algo != GPRS_ALGO_GEA0) {
+ if (lle->llme->algo != GPRS_ALGO_GEA0 &&
+ lle->llme->cksn != GSM_KEY_SEQ_INVAL) {
LOGP(DLLC, LOGL_NOTICE, "unencrypted frame for LLC "
- "that is supposed to be encrypted. Dropping.\n");
- return 0;
+ "that could be expected to be encrypted.\n");
+ drop_cipherable = true;
}
}
@@ -663,7 +679,8 @@
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:
@@ -687,17 +704,28 @@
return rc;
}
+/* Propagate crypto parameter MM -> LLME */
+void gprs_llme_set_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
+{
+ if (!mm)
+ return;
+ if (mm->ciph_algo != GPRS_ALGO_GEA0) {
+ llme->algo = mm->ciph_algo;
+ if (llme->cksn != mm->auth_triplet.key_seq &&
+ mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
+ memcpy(llme->kc, mm->auth_triplet.vec.kc,
+ gprs_cipher_key_length(mm->ciph_algo));
+ llme->cksn = mm->auth_triplet.key_seq;
+ }
+ } else
+ llme->cksn = GSM_KEY_SEQ_INVAL;
+}
+
/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
int gprs_llgmm_assign(struct gprs_llc_llme *llme,
- uint32_t old_tlli, uint32_t new_tlli,
- enum gprs_ciph_algo alg, const uint8_t *kc)
+ uint32_t old_tlli, uint32_t new_tlli)
{
unsigned int i;
-
- /* Update the crypto parameters */
- llme->algo = alg;
- if (alg != GPRS_ALGO_GEA0)
- memcpy(llme->kc, kc, sizeof(llme->kc));
if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
/* TLLI Assignment 8.3.1 */
@@ -748,21 +776,19 @@
/* TLLI unassignment */
int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
{
- return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0,
- NULL);
+ return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff);
}
/* Chapter 7.2.1.2 LLGMM-RESET.req */
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];
-
+ 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;
@@ -774,15 +800,16 @@
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();
+ 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 */
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 98439de..c2f2d5b 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -169,6 +169,7 @@
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);
@@ -244,7 +245,7 @@
if (llme) {
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
- gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
+ gprs_llgmm_assign(llme, tlli, 0xffffffff);
}
}
@@ -602,11 +603,6 @@
}
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)
diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
index 46d779b..75f95c9 100644
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -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 @@
/* 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 @@
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 */
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index c852840..544870b 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <getopt.h>
#include <errno.h>
+#include <time.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
@@ -305,7 +306,7 @@
struct ctrl_handle *ctrl;
struct gsm_network dummy_network;
int rc;
-
+ srand(time(NULL));
tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index d568807..ac545dd 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -196,7 +196,7 @@
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);
}
--
To view, visit https://gerrit.osmocom.org/460
To unsubscribe, visit https://gerrit.osmocom.org/settings
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I8900b906693496e4e6b35be5a86937c58039ed9e
Gerrit-PatchSet: 3
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder