From aa4ed671643c1d7bcd0ae05faa9aef236d9ad5ff Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sun, 22 Apr 2018 19:29:41 +0200 Subject: GERAN: allow GSM SRES on UMTS AKA challenge Store the established security context type (GSM or UMTS) instead of the boolean flag is_authenticated. Provide the previous boolean query with thin sgsn_mm_ctx_is_authenticated() function. Knowing which security context was established will be necessary for OS#3224, i.e. using the proper ciphering key, which is not yet tested properly, and probably not correct at this stage. This change will make new SGSN_Tests.TC_attach_umts_aka_gsm_sres pass. Related: OS#3193 OS#3224 Change-Id: I36807bad3bc55c0030d4f09cb2c369714f24bec7 --- include/osmocom/sgsn/gprs_sgsn.h | 13 ++++++++++++- src/gprs/gprs_gmm.c | 39 +++++++++++++++++++-------------------- src/gprs/sgsn_auth.c | 4 ++-- tests/sgsn/sgsn_test.c | 2 +- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h index c47fb0905..64e5619d6 100644 --- a/include/osmocom/sgsn/gprs_sgsn.h +++ b/include/osmocom/sgsn/gprs_sgsn.h @@ -224,7 +224,7 @@ struct sgsn_mm_ctx { * whether one of them can be dropped. */ enum sgsn_auth_state auth_state; - int is_authenticated; + enum osmo_sub_auth_type sec_ctx; /* the string representation of the current hlr */ char hlr[GSM_EXTENSION_LENGTH]; @@ -235,6 +235,17 @@ struct sgsn_mm_ctx { struct gprs_subscr *subscr; }; +static inline bool sgsn_mm_ctx_is_authenticated(struct sgsn_mm_ctx *ctx) +{ + switch (ctx->sec_ctx) { + case OSMO_AUTH_TYPE_GSM: + case OSMO_AUTH_TYPE_UMTS: + return true; + default: + return false; + } +} + #define LOGMMCTXP(level, mm, fmt, args...) \ LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \ (mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args) diff --git a/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c index 642c738d0..28fba7151 100644 --- a/src/gprs/gprs_gmm.c +++ b/src/gprs/gprs_gmm.c @@ -662,24 +662,24 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm) } /* check if the received authentication response matches */ -static bool check_auth_resp(struct sgsn_mm_ctx *ctx, - bool is_utran, - const struct osmo_auth_vector *vec, - const uint8_t *res, uint8_t res_len) +static enum osmo_sub_auth_type check_auth_resp(struct sgsn_mm_ctx *ctx, + bool is_utran, + const struct osmo_auth_vector *vec, + const uint8_t *res, uint8_t res_len) { const uint8_t *expect_res; uint8_t expect_res_len; enum osmo_sub_auth_type expect_type; const char *expect_str; - if (!vec) - return true; /* really!? */ - /* On UTRAN (3G) we always expect UMTS AKA. On GERAN (2G) we sent AUTN * and expect UMTS AKA if there is R99 capability and our vector - * supports UMTS AKA, otherwise we expect GSM AKA. */ + * supports UMTS AKA, otherwise we expect GSM AKA. + * However, on GERAN, even if we sent a UMTS AKA Authentication Request, the MS may decide to + * instead reply with a GSM AKA SRES response. */ if (is_utran - || (mmctx_is_r99(ctx) && (vec->auth_types & OSMO_AUTH_TYPE_UMTS))) { + || (mmctx_is_r99(ctx) && (vec->auth_types & OSMO_AUTH_TYPE_UMTS) + && (res_len > sizeof(vec->sres)))) { expect_type = OSMO_AUTH_TYPE_UMTS; expect_str = "UMTS RES"; expect_res = vec->res; @@ -696,7 +696,7 @@ static bool check_auth_resp(struct sgsn_mm_ctx *ctx, " not provide the expected auth type:" " expected %s = 0x%x, auth_types are 0x%x\n", expect_str, expect_type, vec->auth_types); - return false; + return OSMO_AUTH_TYPE_NONE; } if (!res) @@ -709,12 +709,12 @@ static bool check_auth_resp(struct sgsn_mm_ctx *ctx, goto auth_mismatch; /* Authorized! */ - return true; + return expect_type; auth_mismatch: LOGMMCTXP(LOGL_ERROR, ctx, "Auth mismatch: expected %s = %s\n", expect_str, osmo_hexdump_nospc(expect_res, expect_res_len)); - return false; + return OSMO_AUTH_TYPE_NONE; } /* Section 9.4.10: Authentication and Ciphering Response */ @@ -778,15 +778,13 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, LOGMMCTXP(LOGL_DEBUG, ctx, "checking auth: received %s = %s\n", res_name, osmo_hexdump(res, res_len)); - rc = check_auth_resp(ctx, false, &at->vec, res, res_len); - if (!rc) { + ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len); + if (!sgsn_mm_ctx_is_authenticated(ctx)) { rc = gsm48_tx_gmm_auth_ciph_rej(ctx); mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT"); return rc; } - ctx->is_authenticated = 1; - if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) ctx->iu.new_key = 1; @@ -1026,7 +1024,8 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) return 0; } - if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && !ctx->is_authenticated) { + if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE + && !sgsn_mm_ctx_is_authenticated(ctx)) { struct gsm_auth_tuple *at = &ctx->auth_triplet; mmctx_timer_start(ctx, 3360, sgsn->cfg.timers.T3360); @@ -1034,7 +1033,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) false); } - if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && ctx->is_authenticated && + if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && sgsn_mm_ctx_is_authenticated(ctx) && ctx->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) { /* Check again for authorization */ sgsn_auth_request(ctx); @@ -1106,7 +1105,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *ctx) { - ctx->is_authenticated = 0; + ctx->sec_ctx = OSMO_AUTH_TYPE_NONE; gsm48_gmm_authorize(ctx); } @@ -1420,7 +1419,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); /* Inform LLC layer about new TLLI but keep old active */ - if (ctx->is_authenticated) + if (sgsn_mm_ctx_is_authenticated(ctx)) gprs_llme_copy_key(ctx, ctx->gb.llme); gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new); diff --git a/src/gprs/sgsn_auth.c b/src/gprs/sgsn_auth.c index 6fb32b711..694bece7a 100644 --- a/src/gprs/sgsn_auth.c +++ b/src/gprs/sgsn_auth.c @@ -114,7 +114,7 @@ enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) return mmctx->auth_state; if (sgsn->cfg.require_authentication && - (!mmctx->is_authenticated || + (!sgsn_mm_ctx_is_authenticated(mmctx) || mmctx->subscr->sgsn_data->auth_triplets_updated)) return SGSN_AUTH_AUTHENTICATE; @@ -175,7 +175,7 @@ int sgsn_auth_request(struct sgsn_mm_ctx *mmctx) OSMO_ASSERT(mmctx->subscr != NULL); - if (sgsn->cfg.require_authentication && !mmctx->is_authenticated) { + if (sgsn->cfg.require_authentication && !sgsn_mm_ctx_is_authenticated(mmctx)) { /* Find next tuple */ at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq); diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c index df4df3b65..0e5267ba1 100644 --- a/tests/sgsn/sgsn_test.c +++ b/tests/sgsn/sgsn_test.c @@ -1132,7 +1132,7 @@ int my_subscr_request_auth_info_fake_auth(struct sgsn_mm_ctx *mmctx, const uint8 { /* Fake an authentication */ OSMO_ASSERT(mmctx->subscr); - mmctx->is_authenticated = 1; + mmctx->sec_ctx = OSMO_AUTH_TYPE_GSM; gprs_subscr_update_auth_info(mmctx->subscr); return 0; -- cgit v1.2.3