blob: 5207464d82069f08f5bdeec314a95d2b754f9e7f [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 */
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 " : "",
260 cause ? get_value_string(gsm48_gmm_cause_names, 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;
Alexander Couzensa09f4982019-08-19 15:41:33 +0200361 enum gsm48_reject_value gsm48_rej;
Harald Welteb8b85a12016-06-17 00:06:42 +0200362
363 if (event == VLR_AUTH_E_HLR_SAI_NACK)
364 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
365 gsup->cause,
366 get_value_string(gsm48_gmm_cause_names, gsup->cause));
367
368 /* We are in what corresponds to the
369 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
370 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
371 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
372 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
373 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
374 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
375 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100376 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200377 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100378 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200379 goto pass;
380 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200381 }
382
383 switch (event) {
384 case VLR_AUTH_E_HLR_SAI_ACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200385 if (!gsup->num_auth_vectors) {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200386 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Alexander Couzensa09f4982019-08-19 15:41:33 +0200387 return;
388 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200389 vlr_subscr_update_tuples(vsub, gsup);
390 goto pass;
Harald Welteb8b85a12016-06-17 00:06:42 +0200391 case VLR_AUTH_E_HLR_SAI_NACK:
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200392 /* HLR did not return Auth Info, hence cannot authenticate. (The caller may still decide to permit
393 * attaching without authentication) */
Vadim Yanitskiyd8b75fb2024-02-14 17:50:10 +0700394 vlr_gmm_cause_to_mm_cause(gsup->cause, &gsm48_rej);
395 auth_fsm_term(fi, AUTH_FSM_NO_AUTH_INFO, gsm48_rej);
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200396 break;
Alexander Couzensa09f4982019-08-19 15:41:33 +0200397 case VLR_AUTH_E_HLR_SAI_ABORT:
398 vlr_gmm_cause_to_mm_cause(gsup->cause, &gsm48_rej);
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200399 auth_fsm_term(fi, AUTH_FSM_FAILURE, gsm48_rej);
Harald Welteb8b85a12016-06-17 00:06:42 +0200400 break;
401 }
402
403 return;
404pass:
405 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
406 vlr_timer(vsub->vlr, 3260), 3260);
407 _vlr_subscr_authenticate(fi);
408}
409
410/* Waiting for Authentication Response from MS */
411static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
412 void *data)
413{
414 struct auth_fsm_priv *afp = fi->priv;
415 struct vlr_subscr *vsub = afp->vsub;
416 struct vlr_instance *vlr = vsub->vlr;
417 struct vlr_auth_resp_par *par = data;
418 int rc;
419
420 switch (event) {
421 case VLR_AUTH_E_MS_AUTH_RESP:
422 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
423 par->res, par->res_len);
424 if (rc == false) {
425 if (!afp->by_imsi) {
426 vlr->ops.tx_id_req(vsub->msc_conn_ref,
427 GSM_MI_TYPE_IMSI);
428 osmo_fsm_inst_state_chg(fi,
429 VLR_SUB_AS_WAIT_ID_IMSI,
430 vlr_timer(vlr, 3270), 3270);
431 } else {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200432 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200433 }
434 } else {
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200435 auth_fsm_term(fi, AUTH_FSM_PASSED, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200436 }
437 break;
438 case VLR_AUTH_E_MS_AUTH_FAIL:
439 if (par->auts) {
440 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100441 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200442 vsub->last_tuple->vec.rand);
443 osmo_fsm_inst_state_chg(fi,
444 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
445 GSM_29002_TIMER_M, 0);
446 } else
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200447 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200448 break;
449 }
450}
451
452/* Waiting for Authentication Info from HLR (resync case) */
453static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
454 uint32_t event, void *data)
455{
456 struct auth_fsm_priv *afp = fi->priv;
457 struct vlr_subscr *vsub = afp->vsub;
458 struct osmo_gsup_message *gsup = data;
459
460 /* We are in what corresponds to the
461 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
462 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
463 (event == VLR_AUTH_E_HLR_SAI_NACK &&
464 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
465 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
466 /* result = procedure error */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200467 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200468 }
469 switch (event) {
470 case VLR_AUTH_E_HLR_SAI_ACK:
471 vlr_subscr_update_tuples(vsub, gsup);
Pau Espin Pedroleb1b3ab2021-08-24 12:25:40 +0200472 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
473 vlr_timer(vsub->vlr, 3260), 3260);
474 _vlr_subscr_authenticate(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200475 break;
476 case VLR_AUTH_E_HLR_SAI_NACK:
477 auth_fsm_term(fi,
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200478 AUTH_FSM_FAILURE,
Harald Welteb8b85a12016-06-17 00:06:42 +0200479 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
Neels Hofmeyr15809592018-04-06 02:57:51 +0200480 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR
481 : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200482 break;
483 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200484}
485
486/* Waiting for AUTH RESP from MS (re-sync case) */
487static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
488 uint32_t event, void *data)
489{
490 struct auth_fsm_priv *afp = fi->priv;
491 struct vlr_subscr *vsub = afp->vsub;
492 struct vlr_auth_resp_par *par = data;
493 struct vlr_instance *vlr = vsub->vlr;
494 int rc;
495
496 switch (event) {
497 case VLR_AUTH_E_MS_AUTH_RESP:
498 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
499 par->res, par->res_len);
500 if (rc == false) {
501 if (!afp->by_imsi) {
502 vlr->ops.tx_id_req(vsub->msc_conn_ref,
503 GSM_MI_TYPE_IMSI);
504 osmo_fsm_inst_state_chg(fi,
505 VLR_SUB_AS_WAIT_ID_IMSI,
506 vlr_timer(vlr, 3270), 3270);
507 } else {
508 /* Result = Aborted */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200509 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200510 }
511 } else {
512 /* Result = Pass */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200513 auth_fsm_term(fi, AUTH_FSM_PASSED, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200514 }
515 break;
516 case VLR_AUTH_E_MS_AUTH_FAIL:
517 /* Second failure: Result = Fail */
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200518 auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200519 break;
520 }
521}
522
523/* AUT_VLR waiting for Obtain_IMSI_VLR result */
524static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
525 void *data)
526{
527 struct auth_fsm_priv *afp = fi->priv;
528 struct vlr_subscr *vsub = afp->vsub;
529 const char *mi_string = data;
530
531 switch (event) {
532 case VLR_AUTH_E_MS_ID_IMSI:
533 if (vsub->imsi[0]
534 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
535 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
536 " %s\n", mi_string);
537 } else {
538 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
539 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
540 }
541 /* retry with identity=IMSI */
542 afp->by_imsi = true;
543 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
544 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
545 break;
546 }
547}
548
549static const struct osmo_fsm_state auth_fsm_states[] = {
550 [VLR_SUB_AS_NEEDS_AUTH] = {
551 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
552 .in_event_mask = S(VLR_AUTH_E_START),
553 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
554 S(VLR_SUB_AS_WAIT_RESP),
555 .action = auth_fsm_needs_auth,
556 },
557 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
558 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
559 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
560 S(VLR_AUTH_E_HLR_SAI_NACK),
561 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
562 S(VLR_SUB_AS_WAIT_RESP),
563 .action = auth_fsm_wait_ai,
564 },
565 [VLR_SUB_AS_WAIT_RESP] = {
566 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
567 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
568 S(VLR_AUTH_E_MS_AUTH_FAIL),
569 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
570 S(VLR_SUB_AS_AUTH_FAILED) |
571 S(VLR_SUB_AS_AUTHENTICATED) |
572 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
573 .action = auth_fsm_wait_auth_resp,
574 },
575 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
576 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
577 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
578 S(VLR_AUTH_E_HLR_SAI_NACK),
579 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
580 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
581 .action = auth_fsm_wait_ai_resync,
582 },
583 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
584 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
585 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
586 S(VLR_AUTH_E_MS_AUTH_FAIL),
587 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
588 S(VLR_SUB_AS_AUTHENTICATED),
589 .action = auth_fsm_wait_auth_resp_resync,
590 },
591 [VLR_SUB_AS_WAIT_ID_IMSI] = {
592 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
593 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
594 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
595 .action = auth_fsm_wait_imsi,
596 },
597 [VLR_SUB_AS_AUTHENTICATED] = {
598 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
599 .in_event_mask = 0,
600 .out_state_mask = 0,
601 },
602 [VLR_SUB_AS_AUTH_FAILED] = {
603 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
604 .in_event_mask = 0,
605 .out_state_mask = 0,
606 .onenter = auth_fsm_onenter_failed,
607 },
608};
609
610struct osmo_fsm vlr_auth_fsm = {
611 .name = "VLR_Authenticate",
612 .states = auth_fsm_states,
613 .num_states = ARRAY_SIZE(auth_fsm_states),
614 .allstate_event_mask = 0,
615 .allstate_action = NULL,
616 .log_subsys = DVLR,
617 .event_names = fsm_auth_event_names,
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100618 .cleanup = auth_fsm_cleanup,
Harald Welteb8b85a12016-06-17 00:06:42 +0200619};
620
621/***********************************************************************
622 * User API (for SGSN/MSC code)
623 ***********************************************************************/
624
625/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
626struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
Harald Welteb8b85a12016-06-17 00:06:42 +0200627 struct osmo_fsm_inst *parent,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200628 uint32_t parent_event_success,
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200629 uint32_t parent_event_no_auth_info,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200630 uint32_t parent_event_failure,
Harald Welteb8b85a12016-06-17 00:06:42 +0200631 bool is_r99,
632 bool is_utran)
633{
634 struct osmo_fsm_inst *fi;
635 struct auth_fsm_priv *afp;
636
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200637 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent, parent_event_failure);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100638 if (!fi) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200639 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100640 return NULL;
641 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200642
643 afp = talloc_zero(fi, struct auth_fsm_priv);
644 if (!afp) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200645 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200646 return NULL;
647 }
648
649 afp->vsub = vsub;
650 if (vsub->imsi[0])
651 afp->by_imsi = true;
652 afp->is_r99 = is_r99;
653 afp->is_utran = is_utran;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200654 afp->parent_event_success = parent_event_success;
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200655 afp->parent_event_no_auth_info = parent_event_no_auth_info;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200656 afp->parent_event_failure = parent_event_failure;
Harald Welteb8b85a12016-06-17 00:06:42 +0200657 fi->priv = afp;
658 vsub->auth_fsm = fi;
659
660 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
661
662 return fi;
663}
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100664
665bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq)
666{
667 int max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
668 struct vlr_auth_tuple *at = vsub->last_tuple;
669
670 if (!at)
671 return false;
672 if ((max_reuse_count >= 0) && (at->use_count > max_reuse_count))
673 return false;
674 if (at->key_seq != key_seq)
675 return false;
676 at->use_count++;
677 return true;
678}