blob: 0583d7ce20866b0a6d195c163423537de94c17bd [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;
56 uint32_t parent_event_failure;
Harald Welteb8b85a12016-06-17 00:06:42 +020057};
58
59/***********************************************************************
60 * Utility functions
61 ***********************************************************************/
62
63/* Always use either vlr_subscr_get_auth_tuple() or vlr_subscr_has_auth_tuple()
64 * instead, to ensure proper use count.
65 * Return an auth tuple with the lowest use_count among the auth tuples. If
Neels Hofmeyr33f53412017-10-29 02:11:18 +010066 * max_reuse_count >= 0, return NULL if all available auth tuples have a use
67 * count > max_reuse_count. If max_reuse_count is negative, return a currently
Harald Welteb8b85a12016-06-17 00:06:42 +020068 * least used auth tuple without enforcing a maximum use count. If there are
69 * no auth tuples, return NULL.
70 */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010071static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +010072_vlr_subscr_next_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +020073{
74 unsigned int count;
75 unsigned int idx;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010076 struct vlr_auth_tuple *at = NULL;
77 unsigned int key_seq = VLR_KEY_SEQ_INVAL;
Harald Welteb8b85a12016-06-17 00:06:42 +020078
79 if (!vsub)
80 return NULL;
81
82 if (vsub->last_tuple)
83 key_seq = vsub->last_tuple->key_seq;
84
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010085 if (key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020086 /* Start with 0 after increment modulo array size */
87 idx = ARRAY_SIZE(vsub->auth_tuples) - 1;
88 else
89 idx = key_seq;
90
91 for (count = ARRAY_SIZE(vsub->auth_tuples); count > 0; count--) {
92 idx = (idx + 1) % ARRAY_SIZE(vsub->auth_tuples);
93
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +010094 if (vsub->auth_tuples[idx].key_seq == VLR_KEY_SEQ_INVAL)
Harald Welteb8b85a12016-06-17 00:06:42 +020095 continue;
96
97 if (!at || vsub->auth_tuples[idx].use_count < at->use_count)
98 at = &vsub->auth_tuples[idx];
99 }
100
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100101 if (!at || (max_reuse_count >= 0 && at->use_count > max_reuse_count))
Harald Welteb8b85a12016-06-17 00:06:42 +0200102 return NULL;
103
104 return at;
105}
106
107/* Return an auth tuple and increment its use count. */
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100108static struct vlr_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100109vlr_subscr_get_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200110{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100111 struct vlr_auth_tuple *at = _vlr_subscr_next_auth_tuple(vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100112 max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200113 if (!at)
114 return NULL;
115 at->use_count++;
116 return at;
117}
118
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100119/* Return whether an auth tuple with a matching use_count is available. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200120static bool vlr_subscr_has_auth_tuple(struct vlr_subscr *vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100121 int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200122{
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100123 return _vlr_subscr_next_auth_tuple(vsub, max_reuse_count) != NULL;
Harald Welteb8b85a12016-06-17 00:06:42 +0200124}
125
126static bool check_auth_resp(struct vlr_subscr *vsub, bool is_r99,
127 bool is_utran, const uint8_t *res,
128 uint8_t res_len)
129{
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100130 struct vlr_auth_tuple *at = vsub->last_tuple;
Harald Welteb8b85a12016-06-17 00:06:42 +0200131 struct osmo_auth_vector *vec = &at->vec;
132 bool check_umts;
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100133 bool res_is_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200134 OSMO_ASSERT(at);
135
Neels Hofmeyra9099bc2018-03-10 04:22:50 +0100136 LOGVSUBP(LOGL_DEBUG, vsub, "AUTH on %s received %s: %s (%u bytes)\n",
137 is_utran ? "UTRAN" : "GERAN",
138 is_utran ? "RES" : "SRES/RES",
139 osmo_hexdump_nospc(res, res_len), res_len);
Harald Welteb8b85a12016-06-17 00:06:42 +0200140
141 /* RES must be present and at least 32bit */
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100142 if (!res || !res_len) {
143 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES missing\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200144 goto out_false;
145 }
146
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100147 /* We're deciding the UMTS AKA-ness of the response by the RES size. So let's make sure we can't
148 * mix them up by size. On UTRAN, we expect full length RES always, no way to mix up there. */
149 if (!is_utran && vec->res_len == sizeof(vec->sres))
150 LOGVSUBP(LOGL_ERROR, vsub, "Unforeseen situation: UMTS AKA's RES length"
151 " equals the size of SRES: %u -- this code wants to differentiate"
152 " the two by their size, which won't work properly now.\n", vec->res_len);
153
154 /* RES must be either vec->res_len (UMTS AKA) or sizeof(sres) (GSM AKA) */
155 if (res_len == vec->res_len)
156 res_is_umts_aka = true;
157 else if (res_len == sizeof(vec->sres))
158 res_is_umts_aka = false;
159 else {
160 if (is_utran)
161 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH RES has invalid length: %u."
162 " Expected %u (UMTS AKA)\n",
163 res_len, vec->res_len);
164 else
165 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES has invalid length: %u."
166 " Expected either %zu (GSM AKA) or %u (UMTS AKA)\n",
167 res_len, sizeof(vec->sres), vec->res_len);
168 goto out_false;
169 }
170
171 check_umts = (is_r99
172 && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)
173 && res_is_umts_aka);
174
175 /* Even on an R99 capable MS with a UMTS AKA capable USIM,
176 * the MS may still choose to only perform GSM AKA, as
177 * long as the bearer is GERAN -- never on UTRAN: */
178 if (is_utran && !check_umts) {
179 LOGVSUBP(LOGL_ERROR, vsub,
180 "AUTH via UTRAN, cannot allow GSM AKA"
181 " (MS is %sR99 capable, vec has %sUMTS AKA tokens, res_len=%u is %s)\n",
182 is_r99 ? "" : "NOT ",
183 (vec->auth_types & OSMO_AUTH_TYPE_UMTS) ? "" : "NO ",
184 res_len, (res_len == vec->res_len)? "valid" : "INVALID on UTRAN");
185 goto out_false;
Harald Welteb8b85a12016-06-17 00:06:42 +0200186 }
187
188 if (check_umts) {
189 if (res_len != vec->res_len
190 || memcmp(res, vec->res, res_len)) {
191 LOGVSUBP(LOGL_INFO, vsub, "UMTS AUTH failure:"
192 " mismatching res (expected res=%s)\n",
193 osmo_hexdump(vec->res, vec->res_len));
194 goto out_false;
195 }
196
197 LOGVSUBP(LOGL_INFO, vsub, "AUTH established UMTS security"
198 " context\n");
199 vsub->sec_ctx = VLR_SEC_CTX_UMTS;
200 return true;
201 } else {
202 if (res_len != sizeof(vec->sres)
203 || memcmp(res, vec->sres, sizeof(vec->sres))) {
204 LOGVSUBP(LOGL_INFO, vsub, "GSM AUTH failure:"
205 " mismatching sres (expected sres=%s)\n",
206 osmo_hexdump(vec->sres, sizeof(vec->sres)));
207 goto out_false;
208 }
209
210 LOGVSUBP(LOGL_INFO, vsub, "AUTH established GSM security"
211 " context\n");
212 vsub->sec_ctx = VLR_SEC_CTX_GSM;
213 return true;
214 }
215
216out_false:
217 vsub->sec_ctx = VLR_SEC_CTX_NONE;
218 return false;
219}
220
221static void auth_fsm_onenter_failed(struct osmo_fsm_inst *fi, uint32_t prev_state)
222{
223 struct auth_fsm_priv *afp = fi->priv;
224 struct vlr_subscr *vsub = afp->vsub;
225
226 /* If authentication hasn't even started, e.g. the HLR sent no auth
227 * info, then we also don't need to tell the HLR about an auth failure.
228 */
Max770fbd22018-01-24 12:48:33 +0100229 if (afp->auth_requested) {
230 int rc = vlr_subscr_tx_auth_fail_rep(vsub);
231 if (rc < 0)
232 LOGVSUBP(LOGL_ERROR, vsub, "Failed to communicate AUTH failure to HLR\n");
233 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200234}
235
Neels Hofmeyr15809592018-04-06 02:57:51 +0200236static const char *vlr_auth_fsm_result_name(enum gsm48_reject_value result)
237{
238 if (!result)
239 return "PASSED";
240 return get_value_string(gsm48_gmm_cause_names, result);
241}
242
Harald Welteb8b85a12016-06-17 00:06:42 +0200243/* Terminate the Auth FSM Instance and notify parent */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200244static void auth_fsm_term(struct osmo_fsm_inst *fi, enum gsm48_reject_value result)
Harald Welteb8b85a12016-06-17 00:06:42 +0200245{
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200246 struct auth_fsm_priv *afp = fi->priv;
247
Harald Welteb8b85a12016-06-17 00:06:42 +0200248 LOGPFSM(fi, "Authentication terminating with result %s\n",
Neels Hofmeyr15809592018-04-06 02:57:51 +0200249 vlr_auth_fsm_result_name(result));
Harald Welteb8b85a12016-06-17 00:06:42 +0200250
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200251 /* Do one final state transition (mostly for logging purpose) and set the parent_term_event according to success
252 * or failure. */
253 if (!result) {
254 /* No reject value means success */
Harald Welteb8b85a12016-06-17 00:06:42 +0200255 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTHENTICATED, 0, 0);
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200256 fi->proc.parent_term_event = afp->parent_event_success;
257 } else {
Harald Welteb8b85a12016-06-17 00:06:42 +0200258 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200259 fi->proc.parent_term_event = afp->parent_event_failure;
260 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200261
262 /* return the result to the parent FSM */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200263 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, &result);
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100264}
265
266static void auth_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
267{
268 struct auth_fsm_priv *afp = fi->priv;
269 struct vlr_subscr *vsub = afp->vsub;
Harald Welteb8b85a12016-06-17 00:06:42 +0200270 vsub->auth_fsm = NULL;
271}
272
273/* back-end function transmitting authentication. Caller ensures we have valid
274 * tuple */
275static int _vlr_subscr_authenticate(struct osmo_fsm_inst *fi)
276{
277 struct auth_fsm_priv *afp = fi->priv;
278 struct vlr_subscr *vsub = afp->vsub;
Neels Hofmeyr8b6e5362018-11-30 02:57:33 +0100279 struct vlr_auth_tuple *at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100280 bool use_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200281
282 /* Caller ensures we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100283 at = vlr_subscr_get_auth_tuple(vsub, afp->auth_tuple_max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200284 if (!at) {
285 LOGPFSML(fi, LOGL_ERROR, "A previous check ensured that an"
286 " auth tuple was available, but now there is in fact"
287 " none.\n");
Neels Hofmeyr15809592018-04-06 02:57:51 +0200288 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200289 return -1;
290 }
291
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100292 use_umts_aka = vlr_use_umts_aka(&at->vec, afp->is_r99);
293 LOGPFSM(fi, "got auth tuple: use_count=%d key_seq=%d"
294 " -- will use %s AKA (is_r99=%s, at->vec.auth_types=0x%x)\n",
295 at->use_count, at->key_seq,
296 use_umts_aka ? "UMTS" : "GSM", afp->is_r99 ? "yes" : "no", at->vec.auth_types);
Harald Welteb8b85a12016-06-17 00:06:42 +0200297
298 /* Transmit auth req to subscriber */
299 afp->auth_requested = true;
300 vsub->last_tuple = at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100301 vsub->vlr->ops.tx_auth_req(vsub->msc_conn_ref, at, use_umts_aka);
Harald Welteb8b85a12016-06-17 00:06:42 +0200302 return 0;
303}
304
305/***********************************************************************
306 * FSM State Action functions
307 ***********************************************************************/
308
309/* Initial State of TS 23.018 AUT_VLR */
310static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
311{
312 struct auth_fsm_priv *afp = fi->priv;
313 struct vlr_subscr *vsub = afp->vsub;
314
315 OSMO_ASSERT(event == VLR_AUTH_E_START);
316
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100317 /* Start off with the default max_reuse_count, possibly change that if we
Harald Welteb8b85a12016-06-17 00:06:42 +0200318 * need to re-use an old tuple. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100319 afp->auth_tuple_max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
Harald Welteb8b85a12016-06-17 00:06:42 +0200320
321 /* Check if we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100322 if (!vlr_subscr_has_auth_tuple(vsub, afp->auth_tuple_max_reuse_count)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200323 /* Obtain_Authentication_Sets_VLR */
Max770fbd22018-01-24 12:48:33 +0100324 int rc = vlr_subscr_req_sai(vsub, NULL, NULL);
325 if (rc < 0)
326 LOGPFSM(fi, "Failed to request Authentication Sets from VLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200327 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH_WAIT_AI,
328 GSM_29002_TIMER_M, 0);
329 } else {
330 /* go straight ahead with sending auth request */
331 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
332 vlr_timer(vsub->vlr, 3260), 3260);
333 _vlr_subscr_authenticate(fi);
334 }
335}
336
337/* Waiting for Authentication Info from HLR */
338static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
339 void *data)
340{
341 struct auth_fsm_priv *afp = fi->priv;
342 struct vlr_subscr *vsub = afp->vsub;
343 struct osmo_gsup_message *gsup = data;
Alexander Couzensa09f4982019-08-19 15:41:33 +0200344 enum gsm48_reject_value gsm48_rej;
Harald Welteb8b85a12016-06-17 00:06:42 +0200345
346 if (event == VLR_AUTH_E_HLR_SAI_NACK)
347 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
348 gsup->cause,
349 get_value_string(gsm48_gmm_cause_names, gsup->cause));
350
351 /* We are in what corresponds to the
352 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
353 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
354 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
355 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
356 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
357 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
358 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100359 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200360 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100361 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200362 goto pass;
363 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200364 }
365
366 switch (event) {
367 case VLR_AUTH_E_HLR_SAI_ACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200368 if (!gsup->num_auth_vectors) {
369 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
370 return;
371 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200372 vlr_subscr_update_tuples(vsub, gsup);
373 goto pass;
374 break;
375 case VLR_AUTH_E_HLR_SAI_NACK:
Alexander Couzensa09f4982019-08-19 15:41:33 +0200376 case VLR_AUTH_E_HLR_SAI_ABORT:
377 vlr_gmm_cause_to_mm_cause(gsup->cause, &gsm48_rej);
378 auth_fsm_term(fi, gsm48_rej);
Harald Welteb8b85a12016-06-17 00:06:42 +0200379 break;
380 }
381
382 return;
383pass:
384 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
385 vlr_timer(vsub->vlr, 3260), 3260);
386 _vlr_subscr_authenticate(fi);
387}
388
389/* Waiting for Authentication Response from MS */
390static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
391 void *data)
392{
393 struct auth_fsm_priv *afp = fi->priv;
394 struct vlr_subscr *vsub = afp->vsub;
395 struct vlr_instance *vlr = vsub->vlr;
396 struct vlr_auth_resp_par *par = data;
397 int rc;
398
399 switch (event) {
400 case VLR_AUTH_E_MS_AUTH_RESP:
401 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
402 par->res, par->res_len);
403 if (rc == false) {
404 if (!afp->by_imsi) {
405 vlr->ops.tx_id_req(vsub->msc_conn_ref,
406 GSM_MI_TYPE_IMSI);
407 osmo_fsm_inst_state_chg(fi,
408 VLR_SUB_AS_WAIT_ID_IMSI,
409 vlr_timer(vlr, 3270), 3270);
410 } else {
Neels Hofmeyr15809592018-04-06 02:57:51 +0200411 auth_fsm_term(fi, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200412 }
413 } else {
Neels Hofmeyr15809592018-04-06 02:57:51 +0200414 auth_fsm_term(fi, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200415 }
416 break;
417 case VLR_AUTH_E_MS_AUTH_FAIL:
418 if (par->auts) {
419 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100420 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200421 vsub->last_tuple->vec.rand);
422 osmo_fsm_inst_state_chg(fi,
423 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
424 GSM_29002_TIMER_M, 0);
425 } else
Neels Hofmeyr15809592018-04-06 02:57:51 +0200426 auth_fsm_term(fi, GSM48_REJECT_ILLEGAL_MS);
Harald Welteb8b85a12016-06-17 00:06:42 +0200427 break;
428 }
429}
430
431/* Waiting for Authentication Info from HLR (resync case) */
432static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
433 uint32_t event, void *data)
434{
435 struct auth_fsm_priv *afp = fi->priv;
436 struct vlr_subscr *vsub = afp->vsub;
437 struct osmo_gsup_message *gsup = data;
438
439 /* We are in what corresponds to the
440 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
441 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
442 (event == VLR_AUTH_E_HLR_SAI_NACK &&
443 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
444 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
445 /* result = procedure error */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200446 auth_fsm_term(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200447 }
448 switch (event) {
449 case VLR_AUTH_E_HLR_SAI_ACK:
450 vlr_subscr_update_tuples(vsub, gsup);
Pau Espin Pedroleb1b3ab2021-08-24 12:25:40 +0200451 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
452 vlr_timer(vsub->vlr, 3260), 3260);
453 _vlr_subscr_authenticate(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200454 break;
455 case VLR_AUTH_E_HLR_SAI_NACK:
456 auth_fsm_term(fi,
457 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
Neels Hofmeyr15809592018-04-06 02:57:51 +0200458 GSM48_REJECT_IMSI_UNKNOWN_IN_HLR
459 : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200460 break;
461 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200462}
463
464/* Waiting for AUTH RESP from MS (re-sync case) */
465static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
466 uint32_t event, void *data)
467{
468 struct auth_fsm_priv *afp = fi->priv;
469 struct vlr_subscr *vsub = afp->vsub;
470 struct vlr_auth_resp_par *par = data;
471 struct vlr_instance *vlr = vsub->vlr;
472 int rc;
473
474 switch (event) {
475 case VLR_AUTH_E_MS_AUTH_RESP:
476 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
477 par->res, par->res_len);
478 if (rc == false) {
479 if (!afp->by_imsi) {
480 vlr->ops.tx_id_req(vsub->msc_conn_ref,
481 GSM_MI_TYPE_IMSI);
482 osmo_fsm_inst_state_chg(fi,
483 VLR_SUB_AS_WAIT_ID_IMSI,
484 vlr_timer(vlr, 3270), 3270);
485 } else {
486 /* Result = Aborted */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200487 auth_fsm_term(fi, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200488 }
489 } else {
490 /* Result = Pass */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200491 auth_fsm_term(fi, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200492 }
493 break;
494 case VLR_AUTH_E_MS_AUTH_FAIL:
495 /* Second failure: Result = Fail */
Neels Hofmeyr15809592018-04-06 02:57:51 +0200496 auth_fsm_term(fi, GSM48_REJECT_SYNCH_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200497 break;
498 }
499}
500
501/* AUT_VLR waiting for Obtain_IMSI_VLR result */
502static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
503 void *data)
504{
505 struct auth_fsm_priv *afp = fi->priv;
506 struct vlr_subscr *vsub = afp->vsub;
507 const char *mi_string = data;
508
509 switch (event) {
510 case VLR_AUTH_E_MS_ID_IMSI:
511 if (vsub->imsi[0]
512 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
513 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
514 " %s\n", mi_string);
515 } else {
516 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
517 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
518 }
519 /* retry with identity=IMSI */
520 afp->by_imsi = true;
521 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
522 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
523 break;
524 }
525}
526
527static const struct osmo_fsm_state auth_fsm_states[] = {
528 [VLR_SUB_AS_NEEDS_AUTH] = {
529 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
530 .in_event_mask = S(VLR_AUTH_E_START),
531 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
532 S(VLR_SUB_AS_WAIT_RESP),
533 .action = auth_fsm_needs_auth,
534 },
535 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
536 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
537 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
538 S(VLR_AUTH_E_HLR_SAI_NACK),
539 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
540 S(VLR_SUB_AS_WAIT_RESP),
541 .action = auth_fsm_wait_ai,
542 },
543 [VLR_SUB_AS_WAIT_RESP] = {
544 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
545 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
546 S(VLR_AUTH_E_MS_AUTH_FAIL),
547 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
548 S(VLR_SUB_AS_AUTH_FAILED) |
549 S(VLR_SUB_AS_AUTHENTICATED) |
550 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
551 .action = auth_fsm_wait_auth_resp,
552 },
553 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
554 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
555 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
556 S(VLR_AUTH_E_HLR_SAI_NACK),
557 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
558 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
559 .action = auth_fsm_wait_ai_resync,
560 },
561 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
562 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
563 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
564 S(VLR_AUTH_E_MS_AUTH_FAIL),
565 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
566 S(VLR_SUB_AS_AUTHENTICATED),
567 .action = auth_fsm_wait_auth_resp_resync,
568 },
569 [VLR_SUB_AS_WAIT_ID_IMSI] = {
570 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
571 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
572 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
573 .action = auth_fsm_wait_imsi,
574 },
575 [VLR_SUB_AS_AUTHENTICATED] = {
576 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
577 .in_event_mask = 0,
578 .out_state_mask = 0,
579 },
580 [VLR_SUB_AS_AUTH_FAILED] = {
581 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
582 .in_event_mask = 0,
583 .out_state_mask = 0,
584 .onenter = auth_fsm_onenter_failed,
585 },
586};
587
588struct osmo_fsm vlr_auth_fsm = {
589 .name = "VLR_Authenticate",
590 .states = auth_fsm_states,
591 .num_states = ARRAY_SIZE(auth_fsm_states),
592 .allstate_event_mask = 0,
593 .allstate_action = NULL,
594 .log_subsys = DVLR,
595 .event_names = fsm_auth_event_names,
Neels Hofmeyr868f5052018-12-28 00:20:20 +0100596 .cleanup = auth_fsm_cleanup,
Harald Welteb8b85a12016-06-17 00:06:42 +0200597};
598
599/***********************************************************************
600 * User API (for SGSN/MSC code)
601 ***********************************************************************/
602
603/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
604struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
Harald Welteb8b85a12016-06-17 00:06:42 +0200605 struct osmo_fsm_inst *parent,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200606 uint32_t parent_event_success,
607 uint32_t parent_event_failure,
Harald Welteb8b85a12016-06-17 00:06:42 +0200608 bool is_r99,
609 bool is_utran)
610{
611 struct osmo_fsm_inst *fi;
612 struct auth_fsm_priv *afp;
613
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200614 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent, parent_event_failure);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100615 if (!fi) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200616 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100617 return NULL;
618 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200619
620 afp = talloc_zero(fi, struct auth_fsm_priv);
621 if (!afp) {
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200622 osmo_fsm_inst_dispatch(parent, parent_event_failure, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +0200623 return NULL;
624 }
625
626 afp->vsub = vsub;
627 if (vsub->imsi[0])
628 afp->by_imsi = true;
629 afp->is_r99 = is_r99;
630 afp->is_utran = is_utran;
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200631 afp->parent_event_success = parent_event_success;
632 afp->parent_event_failure = parent_event_failure;
Harald Welteb8b85a12016-06-17 00:06:42 +0200633 fi->priv = afp;
634 vsub->auth_fsm = fi;
635
636 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
637
638 return fi;
639}
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100640
641bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq)
642{
643 int max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
644 struct vlr_auth_tuple *at = vsub->last_tuple;
645
646 if (!at)
647 return false;
648 if ((max_reuse_count >= 0) && (at->use_count > max_reuse_count))
649 return false;
650 if (at->key_seq != key_seq)
651 return false;
652 at->use_count++;
653 return true;
654}