From 4011e728d22a9affbe41fb2bfc8e69c14bd706ab Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 5 Jul 2016 15:19:12 +0200 Subject: [PATCH] SGSN: use unique AUTH REQ reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The A&C reference number specified in 3GPP TS 24.008 § 10.5.5.19 identifies particular request sent by network with the related response sent by MS. The value transparently copied from request to response by MS: the spec do not specify what exactly should be in there so we use rand() to decrease chance for collisions. Note: variable named 'rand' clashes with standard function rand() so it was renamed. Change-Id: I3638821a9b4a0532b28dbbb50faa30c4082579f6 Related: OS#1582 --- openbsc/include/openbsc/gprs_sgsn.h | 2 ++ openbsc/src/gprs/gprs_gmm.c | 30 +++++++++++++++++++++-------- openbsc/src/gprs/sgsn_main.c | 2 ++ openbsc/tests/sgsn/Makefile.am | 1 + openbsc/tests/sgsn/sgsn_test.c | 19 ++++++++++++++++++ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 0e574d816..96040849b 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -158,6 +158,8 @@ struct sgsn_mm_ctx { /* Iu: CK, IK, KSI */ /* CKSN */ enum gprs_ciph_algo ciph_algo; + /* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */ + uint8_t ac_ref_nr_used; struct { uint8_t len; diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 5db69ddad..7f10b0712 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -417,16 +419,16 @@ static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type) } /* Section 9.4.9: Authentication and Ciphering Request */ -static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rand, +static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd, uint8_t key_seq, uint8_t algo) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REQ"); struct gsm48_hdr *gh; struct gsm48_auth_ciph_req *acreq; - uint8_t *m_rand, *m_cksn; + uint8_t *m_rand, *m_cksn, rbyte; LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s)\n", - osmo_hexdump(rand, 16)); + osmo_hexdump(rnd, 16)); mmctx2msgid(msg, mm); @@ -438,13 +440,20 @@ static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rand, acreq->ciph_alg = algo & 0xf; acreq->imeisv_req = 0x1; acreq->force_stby = 0x0; - acreq->ac_ref_nr = 0x0; /* FIXME: increment this? */ + /* 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 " + "back to rand()\n"); + acreq->ac_ref_nr = rand(); + } else + acreq->ac_ref_nr = rbyte; + mm->ac_ref_nr_used = acreq->ac_ref_nr; /* 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); m_cksn = msgb_put(msg, 1); m_cksn[0] = (GSM48_IE_GMM_CIPH_CKSN << 4) | (key_seq & 0x07); @@ -490,14 +499,19 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, return 0; } + if (acr->ac_ref_nr != ctx->ac_ref_nr_used) { + LOGMMCTXP(LOGL_NOTICE, ctx, "Reference mismatch for Auth & Ciph" + " Response: %u received, %u expected\n", + acr->ac_ref_nr, ctx->ac_ref_nr_used); + return 0; + } + /* Stop T3360 */ mmctx_timer_stop(ctx, 3360); tlv_parse(&tp, &gsm48_gmm_att_tlvdef, acr->data, (msg->data + msg->len) - acr->data, 0, 0); - /* FIXME: compare ac_ref? */ - if (!TLVP_PRESENT(&tp, GSM48_IE_GMM_AUTH_SRES) || !TLVP_PRESENT(&tp, GSM48_IE_GMM_IMEISV)) { /* TODO: missing mandatory IE, return STATUS or REJ? */ diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index c852840db..44751363c 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -306,6 +307,7 @@ int main(int argc, char **argv) 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/Makefile.am b/openbsc/tests/sgsn/Makefile.am index e3cec5086..b6036c75c 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -7,6 +7,7 @@ noinst_PROGRAMS = sgsn_test sgsn_test_SOURCES = sgsn_test.c sgsn_test_LDFLAGS = \ + -Wl,--wrap=RAND_bytes \ -Wl,--wrap=sgsn_update_subscriber_data \ -Wl,--wrap=gprs_subscr_request_update_location \ -Wl,--wrap=gprs_subscr_request_auth_info \ diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index d568807dd..e8e05f6e9 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -101,6 +101,25 @@ int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, return 0; } +/* override, requires '-Wl,--wrap=RAND_bytes' */ +int __real_RAND_bytes(unsigned char *buf, int num); +int mock_RAND_bytes(unsigned char *buf, int num); +int (*RAND_bytes_cb)(unsigned char *, int) = + &mock_RAND_bytes; + +int __wrap_RAND_bytes(unsigned char *buf, int num) +{ + return (*RAND_bytes_cb)(buf, num); +} +/* make results of A&C ref predictable */ +int mock_RAND_bytes(unsigned char *buf, int num) +{ + if (num > 1) + return __real_RAND_bytes(buf, num); + buf[0] = 0; + return 1; +} + /* override, requires '-Wl,--wrap=sgsn_update_subscriber_data' */ void __real_sgsn_update_subscriber_data(struct sgsn_mm_ctx *); void (*update_subscriber_data_cb)(struct sgsn_mm_ctx *) =