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
This commit is contained in:
parent
7554fd1b5e
commit
aa4ed67164
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue