blob: 5c16946946b70d5d64793e687a78159a7ff013a1 [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>
Alexander Couzenseff28ab2024-09-12 00:55:25 +020026#include <osmocom/vlr/vlr.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020027#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 */
Neels Hofmeyr923b6642022-09-28 00:15:45 +020054
55 uint32_t parent_event_success;
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +020056 uint32_t parent_event_no_auth_info;
Neels Hofmeyr923b6642022-09-28 00:15:45 +020057 uint32_t parent_event_failure;
Harald Welteb8b85a12016-06-17 00:06:42 +020058};
59
60/***********************************************************************
61 * Utility functions
62 ***********************************************************************/
63
64/* Always use either vlr_subscr_get_auth_tuple() or vlr_subscr_has_auth_tuple()
65 * instead, to ensure proper use count.
66 * Return an auth tuple with the lowest use_count among the auth tuples. If
Neels Hofmeyr33f53412017-10-29 02:11:18 +010067 * max_reuse_count >= 0, return NULL if all available auth tuples have a use
68 * count > max_reuse_count. If max_reuse_count is negative, return a currently
Harald Welteb8b85a12016-06-17 00:06:42 +020069 * least used auth tuple without enforcing a maximum use count. If there are
70 * no auth tuples, return NULL.
71 */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010072static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +010073_vlr_subscr_next_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +020074{
75 unsigned int count;
76 unsigned int idx;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010077 struct vlr_auth_tuple *at = NULL;
78 unsigned int key_seq = VLR_KEY_SEQ_INVAL;
Harald Welteb8b85a12016-06-17 00:06:42 +020079
80 if (!vsub)
81 return NULL;
82
83 if (vsub->last_tuple)
84 key_seq = vsub->last_tuple->key_seq;
85
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010086 if (key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020087 /* Start with 0 after increment modulo array size */
88 idx = ARRAY_SIZE(vsub->auth_tuples) - 1;
89 else
90 idx = key_seq;
91
92 for (count = ARRAY_SIZE(vsub->auth_tuples); count > 0; count--) {
93 idx = (idx + 1) % ARRAY_SIZE(vsub->auth_tuples);
94
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010095 if (vsub->auth_tuples[idx].key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020096 continue;
97
98 if (!at || vsub->auth_tuples[idx].use_count < at->use_count)
99 at = &vsub->auth_tuples[idx];
100 }
101
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100102 if (!at || (max_reuse_count >= 0 && at->use_count > max_reuse_count))
Harald Welteb8b85a12016-06-17 00:06:42 +0200103 return NULL;
104
105 return at;
106}
107
108/* Return an auth tuple and increment its use count. */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100109static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100110vlr_subscr_get_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200111{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100112 struct vlr_auth_tuple *at = _vlr_subscr_next_auth_tuple(vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100113 max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200114 if (!at)
115 return NULL;
116 at->use_count++;
117 return at;
118}
119
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100120/* Return whether an auth tuple with a matching use_count is available. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200121static bool vlr_subscr_has_auth_tuple(struct vlr_subscr *vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100122 int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200123{
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100124 return _vlr_subscr_next_auth_tuple(vsub, max_reuse_count) != NULL;
Harald Welteb8b85a12016-06-17 00:06:42 +0200125}
126
127static bool check_auth_resp(struct vlr_subscr *vsub, bool is_r99,
128 bool is_utran, const uint8_t *res,
129 uint8_t res_len)
130{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100131 struct vlr_auth_tuple *at = vsub->last_tuple;
Harald Welteb8b85a12016-06-17 00:06:42 +0200132 struct osmo_auth_vector *vec = &at->vec;
133 bool check_umts;
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100134 bool res_is_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200135 OSMO_ASSERT(at);
136
Neels Hofmeyra9099bc2018-03-10 04:22:50 +0100137 LOGVSUBP(LOGL_DEBUG, vsub, "AUTH on %s received %s: %s (%u bytes)\n",
138 is_utran ? "UTRAN" : "GERAN",
139 is_utran ? "RES" : "SRES/RES",
140 osmo_hexdump_nospc(res, res_len), res_len);
Harald Welteb8b85a12016-06-17 00:06:42 +0200141
142 /* RES must be present and at least 32bit */
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100143 if (!res || !res_len) {
144 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES missing\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200145 goto out_false;
146 }
147
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100148 /* We're deciding the UMTS AKA-ness of the response by the RES size. So let's make sure we can't
149 * mix them up by size. On UTRAN, we expect full length RES always, no way to mix up there. */
150 if (!is_utran && vec->res_len == sizeof(vec->sres))
151 LOGVSUBP(LOGL_ERROR, vsub, "Unforeseen situation: UMTS AKA's RES length"
152 " equals the size of SRES: %u -- this code wants to differentiate"
153 " the two by their size, which won't work properly now.\n", vec->res_len);
154
155 /* RES must be either vec->res_len (UMTS AKA) or sizeof(sres) (GSM AKA) */
156 if (res_len == vec->res_len)
157 res_is_umts_aka = true;
158 else if (res_len == sizeof(vec->sres))
159 res_is_umts_aka = false;
160 else {
161 if (is_utran)
162 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH RES has invalid length: %u."
163 " Expected %u (UMTS AKA)\n",
164 res_len, vec->res_len);
165 else
166 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES has invalid length: %u."
167 " Expected either %zu (GSM AKA) or %u (UMTS AKA)\n",
168 res_len, sizeof(vec->sres), vec->res_len);
169 goto out_false;
170 }
171
172 check_umts = (is_r99
173 && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)
174 && res_is_umts_aka);
175
176 /* Even on an R99 capable MS with a UMTS AKA capable USIM,
177 * the MS may still choose to only perform GSM AKA, as
178 * long as the bearer is GERAN -- never on UTRAN: */
179 if (is_utran && !check_umts) {
180 LOGVSUBP(LOGL_ERROR, vsub,
181 "AUTH via UTRAN, cannot allow GSM AKA"
182 " (MS is %sR99 capable, vec has %sUMTS AKA tokens, res_len=%u is %s)\n",
183 is_r99 ? "" : "NOT ",
184 (vec->auth_types & OSMO_AUTH_TYPE_UMTS) ? "" : "NO ",
185 res_len, (res_len == vec->res_len)? "valid" : "INVALID on UTRAN");
186 goto out_false;
Harald Welteb8b85a12016-06-17 00:06:42 +0200187 }
188
189 if (check_umts) {
190 if (res_len != vec->res_len
191 || memcmp(res, vec->res, res_len)) {
192 LOGVSUBP(LOGL_INFO, vsub, "UMTS AUTH failure:"
193 " mismatching res (expected res=%s)\n",
194 osmo_hexdump(vec->res, vec->res_len));
195 goto out_false;
196 }
197
198 LOGVSUBP(LOGL_INFO, vsub, "AUTH established UMTS security"
199 " context\n");
200 vsub->sec_ctx = VLR_SEC_CTX_UMTS;
201 return true;
202 } else {
203 if (res_len != sizeof(vec->sres)
204 || memcmp(res, vec->sres, sizeof(vec->sres))) {
205 LOGVSUBP(LOGL_INFO, vsub, "GSM AUTH failure:"
206 " mismatching sres (expected sres=%s)\n",
207 osmo_hexdump(vec->sres, sizeof(vec->sres)));
208 goto out_false;
209 }
210
211 LOGVSUBP(LOGL_INFO, vsub, "AUTH established GSM security"
212 " context\n");
213 vsub->sec_ctx = VLR_SEC_CTX_GSM;
214 return true;
215 }
216
217out_false:
218 vsub->sec_ctx = VLR_SEC_CTX_NONE;
219 return false;
220}
221
222static void auth_fsm_onenter_failed(struct osmo_fsm_inst *fi, uint32_t prev_state)
223{
224 struct auth_fsm_priv *afp = fi->priv;
225 struct vlr_subscr *vsub = afp->vsub;
226
227 /* If authentication hasn't even started, e.g. the HLR sent no auth
228 * info, then we also don't need to tell the HLR about an auth failure.
229 */
Max770fbd22018-01-24 12:48:33 +0100230 if (afp->auth_requested) {
231 int rc = vlr_subscr_tx_auth_fail_rep(vsub);
232 if (rc < 0)
233 LOGVSUBP(LOGL_ERROR, vsub, "Failed to communicate AUTH failure to HLR\n");
234 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200235}
236
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200237enum auth_fsm_result {
238 /* Authentication verified the subscriber. */
239 AUTH_FSM_PASSED = 0,
240 /* HLR does not have authentication info for this subscriber. */
241 AUTH_FSM_NO_AUTH_INFO,
242 /* Authentication was attempted but failed. */
243 AUTH_FSM_FAILURE,
244};
245
246const char *auth_fsm_result_str[] = {
247 [AUTH_FSM_PASSED] = "PASSED",
248 [AUTH_FSM_NO_AUTH_INFO] = "NO_AUTH_INFO",
249 [AUTH_FSM_FAILURE] = "FAILURE",
250};
Neels Hofmeyr15809592018-04-06 02:57:51 +0200251
Harald Welteb8b85a12016-06-17 00:06:42 +0200252/* Terminate the Auth FSM Instance and notify parent */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200253static void auth_fsm_term(struct osmo_fsm_inst *fi, enum auth_fsm_result result, enum gsm48_reject_value cause)
Harald Welteb8b85a12016-06-17 00:06:42 +0200254{
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200255 struct auth_fsm_priv *afp = fi->priv;
256
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200257 LOGPFSM(fi, "Authentication terminating with result %s%s%s\n",
258 auth_fsm_result_str[result],
259 cause ? ", cause " : "",
Vadim Yanitskiy398cb292024-02-14 17:53:45 +0700260 cause ? gsm48_reject_value_name(cause) : "");
Harald Welteb8b85a12016-06-17 00:06:42 +0200261
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200262 /* Do one final state transition (mostly for logging purpose)
263 * and set the parent_term_event according to result */
264 switch (result) {
265 case AUTH_FSM_PASSED:
Harald Welteb8b85a12016-06-17 00:06:42 +0200266 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTHENTICATED, 0, 0);
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200267 fi->proc.parent_term_event = afp->parent_event_success;
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200268 break;
269 case AUTH_FSM_NO_AUTH_INFO:
270 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
271 fi->proc.parent_term_event = afp->parent_event_no_auth_info;
272 break;
273 case AUTH_FSM_FAILURE:
Harald Welteb8b85a12016-06-17 00:06:42 +0200274 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200275 fi->proc.parent_term_event = afp->parent_event_failure;
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200276 break;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200277 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200278
279 /* return the result to the parent FSM */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200280 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, &cause);
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100281}
282
283static void auth_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
284{
285 struct auth_fsm_priv *afp = fi->priv;
286 struct vlr_subscr *vsub = afp->vsub;
Harald Welteb8b85a12016-06-17 00:06:42 +0200287 vsub->auth_fsm = NULL;
288}
289
290/* back-end function transmitting authentication. Caller ensures we have valid
291 * tuple */
292static int _vlr_subscr_authenticate(struct osmo_fsm_inst *fi)
293{
294 struct auth_fsm_priv *afp = fi->priv;
295 struct vlr_subscr *vsub = afp->vsub;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100296 struct vlr_auth_tuple *at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100297 bool use_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200298
299 /* Caller ensures we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100300 at = vlr_subscr_get_auth_tuple(vsub, afp->auth_tuple_max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200301 if (!at) {
302 LOGPFSML(fi, LOGL_ERROR, "A previous check ensured that an"
303 " auth tuple was available, but now there is in fact"
304 " none.\n");
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200305 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200306 return -1;
307 }
308
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100309 use_umts_aka = vlr_use_umts_aka(&at->vec, afp->is_r99);
310 LOGPFSM(fi, "got auth tuple: use_count=%d key_seq=%d"
311 " -- will use %s AKA (is_r99=%s, at->vec.auth_types=0x%x)\n",
312 at->use_count, at->key_seq,
313 use_umts_aka ? "UMTS" : "GSM", afp->is_r99 ? "yes" : "no", at->vec.auth_types);
Harald Welteb8b85a12016-06-17 00:06:42 +0200314
315 /* Transmit auth req to subscriber */
316 afp->auth_requested = true;
317 vsub->last_tuple = at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100318 vsub->vlr->ops.tx_auth_req(vsub->msc_conn_ref, at, use_umts_aka);
Harald Welteb8b85a12016-06-17 00:06:42 +0200319 return 0;
320}
321
322/***********************************************************************
323 * FSM State Action functions
324 ***********************************************************************/
325
326/* Initial State of TS 23.018 AUT_VLR */
327static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
328{
329 struct auth_fsm_priv *afp = fi->priv;
330 struct vlr_subscr *vsub = afp->vsub;
331
332 OSMO_ASSERT(event == VLR_AUTH_E_START);
333
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100334 /* Start off with the default max_reuse_count, possibly change that if we
Harald Welteb8b85a12016-06-17 00:06:42 +0200335 * need to re-use an old tuple. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100336 afp->auth_tuple_max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
Harald Welteb8b85a12016-06-17 00:06:42 +0200337
338 /* Check if we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100339 if (!vlr_subscr_has_auth_tuple(vsub, afp->auth_tuple_max_reuse_count)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200340 /* Obtain_Authentication_Sets_VLR */
Max770fbd22018-01-24 12:48:33 +0100341 int rc = vlr_subscr_req_sai(vsub, NULL, NULL);
342 if (rc < 0)
343 LOGPFSM(fi, "Failed to request Authentication Sets from VLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200344 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH_WAIT_AI,
345 GSM_29002_TIMER_M, 0);
346 } else {
347 /* go straight ahead with sending auth request */
348 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
349 vlr_timer(vsub->vlr, 3260), 3260);
350 _vlr_subscr_authenticate(fi);
351 }
352}
353
354/* Waiting for Authentication Info from HLR */
355static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
356 void *data)
357{
358 struct auth_fsm_priv *afp = fi->priv;
359 struct vlr_subscr *vsub = afp->vsub;
360 struct osmo_gsup_message *gsup = data;
361
362 if (event == VLR_AUTH_E_HLR_SAI_NACK)
363 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
364 gsup->cause,
365 get_value_string(gsm48_gmm_cause_names, gsup->cause));
366
367 /* We are in what corresponds to the
368 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
369 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
370 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
371 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
372 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
373 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
374 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100375 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200376 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100377 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200378 goto pass;
379 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200380 }
381
382 switch (event) {
383 case VLR_AUTH_E_HLR_SAI_ACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200384 if (!gsup->num_auth_vectors) {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200385 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Alexander Couzensa09f4982019-08-19 15:41:33 +0200386 return;
387 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200388 vlr_subscr_update_tuples(vsub, gsup);
389 goto pass;
Harald Welteb8b85a12016-06-17 00:06:42 +0200390 case VLR_AUTH_E_HLR_SAI_NACK:
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200391 /* HLR did not return Auth Info, hence cannot authenticate. (The caller may still decide to permit
392 * attaching without authentication) */
Alexander Couzenseac1b932024-09-12 16:51:12 +0200393 auth_fsm_term(fi, AUTH_FSM_NO_AUTH_INFO, vlr_gmm_cause_to_reject_cause_domain(gsup->cause, true));
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200394 break;
Alexander Couzensa09f4982019-08-19 15:41:33 +0200395 case VLR_AUTH_E_HLR_SAI_ABORT:
Alexander Couzenseac1b932024-09-12 16:51:12 +0200396 auth_fsm_term(fi, AUTH_FSM_FAILURE, vlr_gmm_cause_to_reject_cause_domain(gsup->cause, true));
Harald Welteb8b85a12016-06-17 00:06:42 +0200397 break;
398 }
399
400 return;
401pass:
402 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
403 vlr_timer(vsub->vlr, 3260), 3260);
404 _vlr_subscr_authenticate(fi);
405}
406
407/* Waiting for Authentication Response from MS */
408static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
409 void *data)
410{
411 struct auth_fsm_priv *afp = fi->priv;
412 struct vlr_subscr *vsub = afp->vsub;
413 struct vlr_instance *vlr = vsub->vlr;
414 struct vlr_auth_resp_par *par = data;
415 int rc;
416
417 switch (event) {
418 case VLR_AUTH_E_MS_AUTH_RESP:
419 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
420 par->res, par->res_len);
421 if (rc == false) {
422 if (!afp->by_imsi) {
423 vlr->ops.tx_id_req(vsub->msc_conn_ref,
424 GSM_MI_TYPE_IMSI);
425 osmo_fsm_inst_state_chg(fi,
426 VLR_SUB_AS_WAIT_ID_IMSI,
427 vlr_timer(vlr, 3270), 3270);
428 } else {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200429 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200430 }
431 } else {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200432 auth_fsm_term(fi, AUTH_FSM_PASSED, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200433 }
434 break;
435 case VLR_AUTH_E_MS_AUTH_FAIL:
436 if (par->auts) {
437 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100438 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200439 vsub->last_tuple->vec.rand);
440 osmo_fsm_inst_state_chg(fi,
441 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
442 GSM_29002_TIMER_M, 0);
443 } else
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200444 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200445 break;
446 }
447}
448
449/* Waiting for Authentication Info from HLR (resync case) */
450static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
451 uint32_t event, void *data)
452{
453 struct auth_fsm_priv *afp = fi->priv;
454 struct vlr_subscr *vsub = afp->vsub;
455 struct osmo_gsup_message *gsup = data;
456
457 /* We are in what corresponds to the
458 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
459 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
460 (event == VLR_AUTH_E_HLR_SAI_NACK &&
461 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
462 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
463 /* result = procedure error */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200464 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200465 }
466 switch (event) {
467 case VLR_AUTH_E_HLR_SAI_ACK:
468 vlr_subscr_update_tuples(vsub, gsup);
Pau Espin Pedroleb1b3ab2021-08-24 12:25:40 +0200469 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
470 vlr_timer(vsub->vlr, 3260), 3260);
471 _vlr_subscr_authenticate(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200472 break;
473 case VLR_AUTH_E_HLR_SAI_NACK:
474 auth_fsm_term(fi,
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200475 AUTH_FSM_FAILURE,
Harald Welteb8b85a12016-06-17 00:06:42 +0200476 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
Neels Hofmeyr15809592018-04-06 02:57:51 +0200477 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR
478 : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200479 break;
480 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200481}
482
483/* Waiting for AUTH RESP from MS (re-sync case) */
484static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
485 uint32_t event, void *data)
486{
487 struct auth_fsm_priv *afp = fi->priv;
488 struct vlr_subscr *vsub = afp->vsub;
489 struct vlr_auth_resp_par *par = data;
490 struct vlr_instance *vlr = vsub->vlr;
491 int rc;
492
493 switch (event) {
494 case VLR_AUTH_E_MS_AUTH_RESP:
495 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
496 par->res, par->res_len);
497 if (rc == false) {
498 if (!afp->by_imsi) {
499 vlr->ops.tx_id_req(vsub->msc_conn_ref,
500 GSM_MI_TYPE_IMSI);
501 osmo_fsm_inst_state_chg(fi,
502 VLR_SUB_AS_WAIT_ID_IMSI,
503 vlr_timer(vlr, 3270), 3270);
504 } else {
505 /* Result = Aborted */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200506 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200507 }
508 } else {
509 /* Result = Pass */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200510 auth_fsm_term(fi, AUTH_FSM_PASSED, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200511 }
512 break;
513 case VLR_AUTH_E_MS_AUTH_FAIL:
514 /* Second failure: Result = Fail */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200515 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200516 break;
517 }
518}
519
520/* AUT_VLR waiting for Obtain_IMSI_VLR result */
521static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
522 void *data)
523{
524 struct auth_fsm_priv *afp = fi->priv;
525 struct vlr_subscr *vsub = afp->vsub;
526 const char *mi_string = data;
527
528 switch (event) {
529 case VLR_AUTH_E_MS_ID_IMSI:
530 if (vsub->imsi[0]
531 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
532 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
533 " %s\n", mi_string);
534 } else {
535 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
536 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
537 }
538 /* retry with identity=IMSI */
539 afp->by_imsi = true;
540 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
541 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
542 break;
543 }
544}
545
546static const struct osmo_fsm_state auth_fsm_states[] = {
547 [VLR_SUB_AS_NEEDS_AUTH] = {
548 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
549 .in_event_mask = S(VLR_AUTH_E_START),
550 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
551 S(VLR_SUB_AS_WAIT_RESP),
552 .action = auth_fsm_needs_auth,
553 },
554 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
555 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
556 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
557 S(VLR_AUTH_E_HLR_SAI_NACK),
558 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
559 S(VLR_SUB_AS_WAIT_RESP),
560 .action = auth_fsm_wait_ai,
561 },
562 [VLR_SUB_AS_WAIT_RESP] = {
563 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
564 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
565 S(VLR_AUTH_E_MS_AUTH_FAIL),
566 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
567 S(VLR_SUB_AS_AUTH_FAILED) |
568 S(VLR_SUB_AS_AUTHENTICATED) |
569 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
570 .action = auth_fsm_wait_auth_resp,
571 },
572 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
573 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
574 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
575 S(VLR_AUTH_E_HLR_SAI_NACK),
576 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
577 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
578 .action = auth_fsm_wait_ai_resync,
579 },
580 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
581 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
582 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
583 S(VLR_AUTH_E_MS_AUTH_FAIL),
584 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
585 S(VLR_SUB_AS_AUTHENTICATED),
586 .action = auth_fsm_wait_auth_resp_resync,
587 },
588 [VLR_SUB_AS_WAIT_ID_IMSI] = {
589 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
590 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
591 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
592 .action = auth_fsm_wait_imsi,
593 },
594 [VLR_SUB_AS_AUTHENTICATED] = {
595 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
596 .in_event_mask = 0,
597 .out_state_mask = 0,
598 },
599 [VLR_SUB_AS_AUTH_FAILED] = {
600 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
601 .in_event_mask = 0,
602 .out_state_mask = 0,
603 .onenter = auth_fsm_onenter_failed,
604 },
605};
606
607struct osmo_fsm vlr_auth_fsm = {
608 .name = "VLR_Authenticate",
609 .states = auth_fsm_states,
610 .num_states = ARRAY_SIZE(auth_fsm_states),
611 .allstate_event_mask = 0,
612 .allstate_action = NULL,
613 .log_subsys = DVLR,
614 .event_names = fsm_auth_event_names,
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100615 .cleanup = auth_fsm_cleanup,
Harald Welteb8b85a12016-06-17 00:06:42 +0200616};
617
618/***********************************************************************
619 * User API (for SGSN/MSC code)
620 ***********************************************************************/
621
622/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
623struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
Harald Welteb8b85a12016-06-17 00:06:42 +0200624 struct osmo_fsm_inst *parent,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200625 uint32_t parent_event_success,
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200626 uint32_t parent_event_no_auth_info,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200627 uint32_t parent_event_failure,
Harald Welteb8b85a12016-06-17 00:06:42 +0200628 bool is_r99,
629 bool is_utran)
630{
631 struct osmo_fsm_inst *fi;
632 struct auth_fsm_priv *afp;
633
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200634 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent, parent_event_failure);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100635 if (!fi) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200636 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100637 return NULL;
638 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200639
640 afp = talloc_zero(fi, struct auth_fsm_priv);
641 if (!afp) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200642 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200643 return NULL;
644 }
645
646 afp->vsub = vsub;
647 if (vsub->imsi[0])
648 afp->by_imsi = true;
649 afp->is_r99 = is_r99;
650 afp->is_utran = is_utran;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200651 afp->parent_event_success = parent_event_success;
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200652 afp->parent_event_no_auth_info = parent_event_no_auth_info;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200653 afp->parent_event_failure = parent_event_failure;
Harald Welteb8b85a12016-06-17 00:06:42 +0200654 fi->priv = afp;
655 vsub->auth_fsm = fi;
656
657 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
658
659 return fi;
660}
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100661
662bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq)
663{
664 int max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
665 struct vlr_auth_tuple *at = vsub->last_tuple;
666
667 if (!at)
668 return false;
669 if ((max_reuse_count >= 0) && (at->use_count > max_reuse_count))
670 return false;
671 if (at->key_seq != key_seq)
672 return false;
673 at->use_count++;
674 return true;
675}