blob: dcdf584686981d65c0ef35632598e3f010527cfe [file] [log] [blame]
Martin Hauke3f07dac2019-11-14 17:49:08 +01001/* Osmocom Visitor Location Register (VLR) Authentication FSM */
Harald Welteb8b85a12016-06-17 00:06:42 +02002
3/* (C) 2016 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22
23#include <osmocom/core/fsm.h>
24#include <osmocom/core/utils.h>
25#include <osmocom/gsm/gsup.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020026#include <osmocom/msc/vlr.h>
27#include <osmocom/msc/debug.h>
Harald Welteb8b85a12016-06-17 00:06:42 +020028
29#include "vlr_core.h"
30#include "vlr_auth_fsm.h"
31
32#define S(x) (1 << (x))
33
34static const struct value_string fsm_auth_event_names[] = {
35 OSMO_VALUE_STRING(VLR_AUTH_E_START),
36 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_ACK),
37 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_NACK),
38 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_ABORT),
39 OSMO_VALUE_STRING(VLR_AUTH_E_MS_AUTH_RESP),
40 OSMO_VALUE_STRING(VLR_AUTH_E_MS_AUTH_FAIL),
41 OSMO_VALUE_STRING(VLR_AUTH_E_MS_ID_IMSI),
42 { 0, NULL }
43};
44
Harald Welteb8b85a12016-06-17 00:06:42 +020045/* private state of the auth_fsm_instance */
46struct auth_fsm_priv {
47 struct vlr_subscr *vsub;
48 bool by_imsi;
49 bool is_r99;
50 bool is_utran;
51 bool auth_requested;
52
Neels Hofmeyr33f53412017-10-29 02:11:18 +010053 int auth_tuple_max_reuse_count; /* see vlr->cfg instead */
Harald Welteb8b85a12016-06-17 00:06:42 +020054};
55
56/***********************************************************************
57 * Utility functions
58 ***********************************************************************/
59
60/* Always use either vlr_subscr_get_auth_tuple() or vlr_subscr_has_auth_tuple()
61 * instead, to ensure proper use count.
62 * Return an auth tuple with the lowest use_count among the auth tuples. If
Neels Hofmeyr33f53412017-10-29 02:11:18 +010063 * max_reuse_count >= 0, return NULL if all available auth tuples have a use
64 * count > max_reuse_count. If max_reuse_count is negative, return a currently
Harald Welteb8b85a12016-06-17 00:06:42 +020065 * least used auth tuple without enforcing a maximum use count. If there are
66 * no auth tuples, return NULL.
67 */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010068static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +010069_vlr_subscr_next_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +020070{
71 unsigned int count;
72 unsigned int idx;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010073 struct vlr_auth_tuple *at = NULL;
74 unsigned int key_seq = VLR_KEY_SEQ_INVAL;
Harald Welteb8b85a12016-06-17 00:06:42 +020075
76 if (!vsub)
77 return NULL;
78
79 if (vsub->last_tuple)
80 key_seq = vsub->last_tuple->key_seq;
81
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010082 if (key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020083 /* Start with 0 after increment modulo array size */
84 idx = ARRAY_SIZE(vsub->auth_tuples) - 1;
85 else
86 idx = key_seq;
87
88 for (count = ARRAY_SIZE(vsub->auth_tuples); count > 0; count--) {
89 idx = (idx + 1) % ARRAY_SIZE(vsub->auth_tuples);
90
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010091 if (vsub->auth_tuples[idx].key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020092 continue;
93
94 if (!at || vsub->auth_tuples[idx].use_count < at->use_count)
95 at = &vsub->auth_tuples[idx];
96 }
97
Neels Hofmeyr33f53412017-10-29 02:11:18 +010098 if (!at || (max_reuse_count >= 0 && at->use_count > max_reuse_count))
Harald Welteb8b85a12016-06-17 00:06:42 +020099 return NULL;
100
101 return at;
102}
103
104/* Return an auth tuple and increment its use count. */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100105static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100106vlr_subscr_get_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200107{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100108 struct vlr_auth_tuple *at = _vlr_subscr_next_auth_tuple(vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100109 max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200110 if (!at)
111 return NULL;
112 at->use_count++;
113 return at;
114}
115
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100116/* Return whether an auth tuple with a matching use_count is available. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200117static bool vlr_subscr_has_auth_tuple(struct vlr_subscr *vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100118 int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200119{
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100120 return _vlr_subscr_next_auth_tuple(vsub, max_reuse_count) != NULL;
Harald Welteb8b85a12016-06-17 00:06:42 +0200121}
122
123static bool check_auth_resp(struct vlr_subscr *vsub, bool is_r99,
124 bool is_utran, const uint8_t *res,
125 uint8_t res_len)
126{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100127 struct vlr_auth_tuple *at = vsub->last_tuple;
Harald Welteb8b85a12016-06-17 00:06:42 +0200128 struct osmo_auth_vector *vec = &at->vec;
129 bool check_umts;
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100130 bool res_is_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200131 OSMO_ASSERT(at);
132
Neels Hofmeyra9099bc2018-03-10 04:22:50 +0100133 LOGVSUBP(LOGL_DEBUG, vsub, "AUTH on %s received %s: %s (%u bytes)\n",
134 is_utran ? "UTRAN" : "GERAN",
135 is_utran ? "RES" : "SRES/RES",
136 osmo_hexdump_nospc(res, res_len), res_len);
Harald Welteb8b85a12016-06-17 00:06:42 +0200137
138 /* RES must be present and at least 32bit */
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100139 if (!res || !res_len) {
140 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES missing\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200141 goto out_false;
142 }
143
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100144 /* We're deciding the UMTS AKA-ness of the response by the RES size. So let's make sure we can't
145 * mix them up by size. On UTRAN, we expect full length RES always, no way to mix up there. */
146 if (!is_utran && vec->res_len == sizeof(vec->sres))
147 LOGVSUBP(LOGL_ERROR, vsub, "Unforeseen situation: UMTS AKA's RES length"
148 " equals the size of SRES: %u -- this code wants to differentiate"
149 " the two by their size, which won't work properly now.\n", vec->res_len);
150
151 /* RES must be either vec->res_len (UMTS AKA) or sizeof(sres) (GSM AKA) */
152 if (res_len == vec->res_len)
153 res_is_umts_aka = true;
154 else if (res_len == sizeof(vec->sres))
155 res_is_umts_aka = false;
156 else {
157 if (is_utran)
158 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH RES has invalid length: %u."
159 " Expected %u (UMTS AKA)\n",
160 res_len, vec->res_len);
161 else
162 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES has invalid length: %u."
163 " Expected either %zu (GSM AKA) or %u (UMTS AKA)\n",
164 res_len, sizeof(vec->sres), vec->res_len);
165 goto out_false;
166 }
167
168 check_umts = (is_r99
169 && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)
170 && res_is_umts_aka);
171
172 /* Even on an R99 capable MS with a UMTS AKA capable USIM,
173 * the MS may still choose to only perform GSM AKA, as
174 * long as the bearer is GERAN -- never on UTRAN: */
175 if (is_utran && !check_umts) {
176 LOGVSUBP(LOGL_ERROR, vsub,
177 "AUTH via UTRAN, cannot allow GSM AKA"
178 " (MS is %sR99 capable, vec has %sUMTS AKA tokens, res_len=%u is %s)\n",
179 is_r99 ? "" : "NOT ",
180 (vec->auth_types & OSMO_AUTH_TYPE_UMTS) ? "" : "NO ",
181 res_len, (res_len == vec->res_len)? "valid" : "INVALID on UTRAN");
182 goto out_false;
Harald Welteb8b85a12016-06-17 00:06:42 +0200183 }
184
185 if (check_umts) {
186 if (res_len != vec->res_len
187 || memcmp(res, vec->res, res_len)) {
188 LOGVSUBP(LOGL_INFO, vsub, "UMTS AUTH failure:"
189 " mismatching res (expected res=%s)\n",
190 osmo_hexdump(vec->res, vec->res_len));
191 goto out_false;
192 }
193
194 LOGVSUBP(LOGL_INFO, vsub, "AUTH established UMTS security"
195 " context\n");
196 vsub->sec_ctx = VLR_SEC_CTX_UMTS;
197 return true;
198 } else {
199 if (res_len != sizeof(vec->sres)
200 || memcmp(res, vec->sres, sizeof(vec->sres))) {
201 LOGVSUBP(LOGL_INFO, vsub, "GSM AUTH failure:"
202 " mismatching sres (expected sres=%s)\n",
203 osmo_hexdump(vec->sres, sizeof(vec->sres)));
204 goto out_false;
205 }
206
207 LOGVSUBP(LOGL_INFO, vsub, "AUTH established GSM security"
208 " context\n");
209 vsub->sec_ctx = VLR_SEC_CTX_GSM;
210 return true;
211 }
212
213out_false:
214 vsub->sec_ctx = VLR_SEC_CTX_NONE;
215 return false;
216}
217
218static void auth_fsm_onenter_failed(struct osmo_fsm_inst *fi, uint32_t prev_state)
219{
220 struct auth_fsm_priv *afp = fi->priv;
221 struct vlr_subscr *vsub = afp->vsub;
222
223 /* If authentication hasn't even started, e.g. the HLR sent no auth
224 * info, then we also don't need to tell the HLR about an auth failure.
225 */
Max770fbd22018-01-24 12:48:33 +0100226 if (afp->auth_requested) {
227 int rc = vlr_subscr_tx_auth_fail_rep(vsub);
228 if (rc < 0)
229 LOGVSUBP(LOGL_ERROR, vsub, "Failed to communicate AUTH failure to HLR\n");
230 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200231}
232
Neels Hofmeyr15809592018-04-06 02:57:51 +0200233static const char *vlr_auth_fsm_result_name(enum gsm48_reject_value result)
234{
235 if (!result)
236 return "PASSED";
237 return get_value_string(gsm48_gmm_cause_names, result);
238}
239
Harald Welteb8b85a12016-06-17 00:06:42 +0200240/* Terminate the Auth FSM Instance and notify parent */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200241static void auth_fsm_term(struct osmo_fsm_inst *fi, enum gsm48_reject_value result)
Harald Welteb8b85a12016-06-17 00:06:42 +0200242{
Harald Welteb8b85a12016-06-17 00:06:42 +0200243 LOGPFSM(fi, "Authentication terminating with result %s\n",
Neels Hofmeyr15809592018-04-06 02:57:51 +0200244 vlr_auth_fsm_result_name(result));
Harald Welteb8b85a12016-06-17 00:06:42 +0200245
246 /* Do one final state transition (mostly for logging purpose) */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200247 if (!result)
Harald Welteb8b85a12016-06-17 00:06:42 +0200248 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTHENTICATED, 0, 0);
249 else
250 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
251
252 /* return the result to the parent FSM */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200253 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, &result);
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100254}
255
256static void auth_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
257{
258 struct auth_fsm_priv *afp = fi->priv;
259 struct vlr_subscr *vsub = afp->vsub;
Harald Welteb8b85a12016-06-17 00:06:42 +0200260 vsub->auth_fsm = NULL;
261}
262
263/* back-end function transmitting authentication. Caller ensures we have valid
264 * tuple */
265static int _vlr_subscr_authenticate(struct osmo_fsm_inst *fi)
266{
267 struct auth_fsm_priv *afp = fi->priv;
268 struct vlr_subscr *vsub = afp->vsub;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100269 struct vlr_auth_tuple *at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100270 bool use_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200271
272 /* Caller ensures we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100273 at = vlr_subscr_get_auth_tuple(vsub, afp->auth_tuple_max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200274 if (!at) {
275 LOGPFSML(fi, LOGL_ERROR, "A previous check ensured that an"
276 " auth tuple was available, but now there is in fact"
277 " none.\n");
Neels Hofmeyr15809592018-04-06 02:57:51 +0200278 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200279 return -1;
280 }
281
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100282 use_umts_aka = vlr_use_umts_aka(&at->vec, afp->is_r99);
283 LOGPFSM(fi, "got auth tuple: use_count=%d key_seq=%d"
284 " -- will use %s AKA (is_r99=%s, at->vec.auth_types=0x%x)\n",
285 at->use_count, at->key_seq,
286 use_umts_aka ? "UMTS" : "GSM", afp->is_r99 ? "yes" : "no", at->vec.auth_types);
Harald Welteb8b85a12016-06-17 00:06:42 +0200287
288 /* Transmit auth req to subscriber */
289 afp->auth_requested = true;
290 vsub->last_tuple = at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100291 vsub->vlr->ops.tx_auth_req(vsub->msc_conn_ref, at, use_umts_aka);
Harald Welteb8b85a12016-06-17 00:06:42 +0200292 return 0;
293}
294
295/***********************************************************************
296 * FSM State Action functions
297 ***********************************************************************/
298
299/* Initial State of TS 23.018 AUT_VLR */
300static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
301{
302 struct auth_fsm_priv *afp = fi->priv;
303 struct vlr_subscr *vsub = afp->vsub;
304
305 OSMO_ASSERT(event == VLR_AUTH_E_START);
306
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100307 /* Start off with the default max_reuse_count, possibly change that if we
Harald Welteb8b85a12016-06-17 00:06:42 +0200308 * need to re-use an old tuple. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100309 afp->auth_tuple_max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
Harald Welteb8b85a12016-06-17 00:06:42 +0200310
311 /* Check if we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100312 if (!vlr_subscr_has_auth_tuple(vsub, afp->auth_tuple_max_reuse_count)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200313 /* Obtain_Authentication_Sets_VLR */
Max770fbd22018-01-24 12:48:33 +0100314 int rc = vlr_subscr_req_sai(vsub, NULL, NULL);
315 if (rc < 0)
316 LOGPFSM(fi, "Failed to request Authentication Sets from VLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200317 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH_WAIT_AI,
318 GSM_29002_TIMER_M, 0);
319 } else {
320 /* go straight ahead with sending auth request */
321 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
322 vlr_timer(vsub->vlr, 3260), 3260);
323 _vlr_subscr_authenticate(fi);
324 }
325}
326
327/* Waiting for Authentication Info from HLR */
328static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
329 void *data)
330{
331 struct auth_fsm_priv *afp = fi->priv;
332 struct vlr_subscr *vsub = afp->vsub;
333 struct osmo_gsup_message *gsup = data;
Alexander Couzensa09f4982019-08-19 15:41:33 +0200334 enum gsm48_reject_value gsm48_rej;
Harald Welteb8b85a12016-06-17 00:06:42 +0200335
336 if (event == VLR_AUTH_E_HLR_SAI_NACK)
337 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
338 gsup->cause,
339 get_value_string(gsm48_gmm_cause_names, gsup->cause));
340
341 /* We are in what corresponds to the
342 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
343 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
344 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
345 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
346 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
347 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
348 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100349 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200350 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100351 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200352 goto pass;
353 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200354 }
355
356 switch (event) {
357 case VLR_AUTH_E_HLR_SAI_ACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200358 if (!gsup->num_auth_vectors) {
359 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
360 return;
361 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200362 vlr_subscr_update_tuples(vsub, gsup);
363 goto pass;
364 break;
365 case VLR_AUTH_E_HLR_SAI_NACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200366 case VLR_AUTH_E_HLR_SAI_ABORT:
367 vlr_gmm_cause_to_mm_cause(gsup->cause, &gsm48_rej);
368 auth_fsm_term(fi, gsm48_rej);
Harald Welteb8b85a12016-06-17 00:06:42 +0200369 break;
370 }
371
372 return;
373pass:
374 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
375 vlr_timer(vsub->vlr, 3260), 3260);
376 _vlr_subscr_authenticate(fi);
377}
378
379/* Waiting for Authentication Response from MS */
380static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
381 void *data)
382{
383 struct auth_fsm_priv *afp = fi->priv;
384 struct vlr_subscr *vsub = afp->vsub;
385 struct vlr_instance *vlr = vsub->vlr;
386 struct vlr_auth_resp_par *par = data;
387 int rc;
388
389 switch (event) {
390 case VLR_AUTH_E_MS_AUTH_RESP:
391 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
392 par->res, par->res_len);
393 if (rc == false) {
394 if (!afp->by_imsi) {
395 vlr->ops.tx_id_req(vsub->msc_conn_ref,
396 GSM_MI_TYPE_IMSI);
397 osmo_fsm_inst_state_chg(fi,
398 VLR_SUB_AS_WAIT_ID_IMSI,
399 vlr_timer(vlr, 3270), 3270);
400 } else {
Neels Hofmeyr15809592018-04-06 02:57:51 +0200401 auth_fsm_term(fi, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200402 }
403 } else {
Neels Hofmeyr15809592018-04-06 02:57:51 +0200404 auth_fsm_term(fi, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200405 }
406 break;
407 case VLR_AUTH_E_MS_AUTH_FAIL:
408 if (par->auts) {
409 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100410 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200411 vsub->last_tuple->vec.rand);
412 osmo_fsm_inst_state_chg(fi,
413 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
414 GSM_29002_TIMER_M, 0);
415 } else
Neels Hofmeyr15809592018-04-06 02:57:51 +0200416 auth_fsm_term(fi, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200417 break;
418 }
419}
420
421/* Waiting for Authentication Info from HLR (resync case) */
422static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
423 uint32_t event, void *data)
424{
425 struct auth_fsm_priv *afp = fi->priv;
426 struct vlr_subscr *vsub = afp->vsub;
427 struct osmo_gsup_message *gsup = data;
428
429 /* We are in what corresponds to the
430 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
431 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
432 (event == VLR_AUTH_E_HLR_SAI_NACK &&
433 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
434 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
435 /* result = procedure error */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200436 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200437 }
438 switch (event) {
439 case VLR_AUTH_E_HLR_SAI_ACK:
440 vlr_subscr_update_tuples(vsub, gsup);
441 goto pass;
442 break;
443 case VLR_AUTH_E_HLR_SAI_NACK:
444 auth_fsm_term(fi,
445 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
Neels Hofmeyr15809592018-04-06 02:57:51 +0200446 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR
447 : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200448 break;
449 }
450
451 return;
452pass:
453 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
454 vlr_timer(vsub->vlr, 3260), 3260);
455 _vlr_subscr_authenticate(fi);
456}
457
458/* Waiting for AUTH RESP from MS (re-sync case) */
459static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
460 uint32_t event, void *data)
461{
462 struct auth_fsm_priv *afp = fi->priv;
463 struct vlr_subscr *vsub = afp->vsub;
464 struct vlr_auth_resp_par *par = data;
465 struct vlr_instance *vlr = vsub->vlr;
466 int rc;
467
468 switch (event) {
469 case VLR_AUTH_E_MS_AUTH_RESP:
470 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
471 par->res, par->res_len);
472 if (rc == false) {
473 if (!afp->by_imsi) {
474 vlr->ops.tx_id_req(vsub->msc_conn_ref,
475 GSM_MI_TYPE_IMSI);
476 osmo_fsm_inst_state_chg(fi,
477 VLR_SUB_AS_WAIT_ID_IMSI,
478 vlr_timer(vlr, 3270), 3270);
479 } else {
480 /* Result = Aborted */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200481 auth_fsm_term(fi, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200482 }
483 } else {
484 /* Result = Pass */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200485 auth_fsm_term(fi, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200486 }
487 break;
488 case VLR_AUTH_E_MS_AUTH_FAIL:
489 /* Second failure: Result = Fail */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200490 auth_fsm_term(fi, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200491 break;
492 }
493}
494
495/* AUT_VLR waiting for Obtain_IMSI_VLR result */
496static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
497 void *data)
498{
499 struct auth_fsm_priv *afp = fi->priv;
500 struct vlr_subscr *vsub = afp->vsub;
501 const char *mi_string = data;
502
503 switch (event) {
504 case VLR_AUTH_E_MS_ID_IMSI:
505 if (vsub->imsi[0]
506 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
507 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
508 " %s\n", mi_string);
509 } else {
510 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
511 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
512 }
513 /* retry with identity=IMSI */
514 afp->by_imsi = true;
515 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
516 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
517 break;
518 }
519}
520
521static const struct osmo_fsm_state auth_fsm_states[] = {
522 [VLR_SUB_AS_NEEDS_AUTH] = {
523 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
524 .in_event_mask = S(VLR_AUTH_E_START),
525 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
526 S(VLR_SUB_AS_WAIT_RESP),
527 .action = auth_fsm_needs_auth,
528 },
529 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
530 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
531 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
532 S(VLR_AUTH_E_HLR_SAI_NACK),
533 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
534 S(VLR_SUB_AS_WAIT_RESP),
535 .action = auth_fsm_wait_ai,
536 },
537 [VLR_SUB_AS_WAIT_RESP] = {
538 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
539 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
540 S(VLR_AUTH_E_MS_AUTH_FAIL),
541 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
542 S(VLR_SUB_AS_AUTH_FAILED) |
543 S(VLR_SUB_AS_AUTHENTICATED) |
544 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
545 .action = auth_fsm_wait_auth_resp,
546 },
547 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
548 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
549 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
550 S(VLR_AUTH_E_HLR_SAI_NACK),
551 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
552 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
553 .action = auth_fsm_wait_ai_resync,
554 },
555 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
556 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
557 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
558 S(VLR_AUTH_E_MS_AUTH_FAIL),
559 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
560 S(VLR_SUB_AS_AUTHENTICATED),
561 .action = auth_fsm_wait_auth_resp_resync,
562 },
563 [VLR_SUB_AS_WAIT_ID_IMSI] = {
564 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
565 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
566 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
567 .action = auth_fsm_wait_imsi,
568 },
569 [VLR_SUB_AS_AUTHENTICATED] = {
570 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
571 .in_event_mask = 0,
572 .out_state_mask = 0,
573 },
574 [VLR_SUB_AS_AUTH_FAILED] = {
575 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
576 .in_event_mask = 0,
577 .out_state_mask = 0,
578 .onenter = auth_fsm_onenter_failed,
579 },
580};
581
582struct osmo_fsm vlr_auth_fsm = {
583 .name = "VLR_Authenticate",
584 .states = auth_fsm_states,
585 .num_states = ARRAY_SIZE(auth_fsm_states),
586 .allstate_event_mask = 0,
587 .allstate_action = NULL,
588 .log_subsys = DVLR,
589 .event_names = fsm_auth_event_names,
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100590 .cleanup = auth_fsm_cleanup,
Harald Welteb8b85a12016-06-17 00:06:42 +0200591};
592
593/***********************************************************************
594 * User API (for SGSN/MSC code)
595 ***********************************************************************/
596
597/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
598struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
599 uint32_t log_level,
600 struct osmo_fsm_inst *parent,
601 uint32_t parent_term_event,
602 bool is_r99,
603 bool is_utran)
604{
605 struct osmo_fsm_inst *fi;
606 struct auth_fsm_priv *afp;
607
608 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent,
609 parent_term_event);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100610 if (!fi) {
611 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
612 return NULL;
613 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200614
615 afp = talloc_zero(fi, struct auth_fsm_priv);
616 if (!afp) {
617 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
618 return NULL;
619 }
620
621 afp->vsub = vsub;
622 if (vsub->imsi[0])
623 afp->by_imsi = true;
624 afp->is_r99 = is_r99;
625 afp->is_utran = is_utran;
626 fi->priv = afp;
627 vsub->auth_fsm = fi;
628
629 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
630
631 return fi;
632}
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100633
634bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq)
635{
636 int max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
637 struct vlr_auth_tuple *at = vsub->last_tuple;
638
639 if (!at)
640 return false;
641 if ((max_reuse_count >= 0) && (at->use_count > max_reuse_count))
642 return false;
643 if (at->key_seq != key_seq)
644 return false;
645 at->use_count++;
646 return true;
647}