aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-04-22 19:29:41 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-04-22 19:29:41 +0200
commitf45d5eaa623f6f2509389d0905d3b17cf019e607 (patch)
treebb82d0c4b870a9413db015c62e9aa33dba4654b0
parent5bd340eb5a176af428847949268869d71de8802c (diff)
GERAN: allow GSM SRES on UMTS AKA challenge
-rw-r--r--include/osmocom/sgsn/gprs_sgsn.h13
-rw-r--r--src/gprs/gprs_gmm.c39
-rw-r--r--src/gprs/sgsn_auth.c4
-rw-r--r--tests/sgsn/sgsn_test.c2
4 files changed, 34 insertions, 24 deletions
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h
index c47fb090..64e5619d 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 ff993cc2..f0912452 100644
--- a/src/gprs/gprs_gmm.c
+++ b/src/gprs/gprs_gmm.c
@@ -660,24 +660,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;
@@ -694,7 +694,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)
@@ -707,12 +707,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 */
@@ -776,15 +776,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;
@@ -1024,7 +1022,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);
@@ -1032,7 +1031,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);
@@ -1104,7 +1103,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);
}
@@ -1418,7 +1417,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 6fb32b71..694bece7 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 df4df3b6..0e5267ba 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;