blob: f001eacd1a4760262f95343c9cebfd59a22e4e44 [file] [log] [blame]
Harald Welteb8b85a12016-06-17 00:06:42 +02001/* Osmocom Visitor Location Register (VLR) Autentication FSM */
2
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
45const struct value_string vlr_auth_fsm_result_names[] = {
46 OSMO_VALUE_STRING(VLR_AUTH_RES_ABORTED),
47 OSMO_VALUE_STRING(VLR_AUTH_RES_UNKNOWN_SUBSCR),
48 OSMO_VALUE_STRING(VLR_AUTH_RES_PROC_ERR),
49 OSMO_VALUE_STRING(VLR_AUTH_RES_AUTH_FAILED),
50 OSMO_VALUE_STRING(VLR_AUTH_RES_PASSED),
51 {0, NULL}
52};
53
54/* private state of the auth_fsm_instance */
55struct auth_fsm_priv {
56 struct vlr_subscr *vsub;
57 bool by_imsi;
58 bool is_r99;
59 bool is_utran;
60 bool auth_requested;
61
Neels Hofmeyr33f53412017-10-29 02:11:18 +010062 int auth_tuple_max_reuse_count; /* see vlr->cfg instead */
Harald Welteb8b85a12016-06-17 00:06:42 +020063};
64
65/***********************************************************************
66 * Utility functions
67 ***********************************************************************/
68
69/* Always use either vlr_subscr_get_auth_tuple() or vlr_subscr_has_auth_tuple()
70 * instead, to ensure proper use count.
71 * Return an auth tuple with the lowest use_count among the auth tuples. If
Neels Hofmeyr33f53412017-10-29 02:11:18 +010072 * max_reuse_count >= 0, return NULL if all available auth tuples have a use
73 * count > max_reuse_count. If max_reuse_count is negative, return a currently
Harald Welteb8b85a12016-06-17 00:06:42 +020074 * least used auth tuple without enforcing a maximum use count. If there are
75 * no auth tuples, return NULL.
76 */
77static struct gsm_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +010078_vlr_subscr_next_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +020079{
80 unsigned int count;
81 unsigned int idx;
82 struct gsm_auth_tuple *at = NULL;
83 unsigned int key_seq = GSM_KEY_SEQ_INVAL;
84
85 if (!vsub)
86 return NULL;
87
88 if (vsub->last_tuple)
89 key_seq = vsub->last_tuple->key_seq;
90
91 if (key_seq == GSM_KEY_SEQ_INVAL)
92 /* Start with 0 after increment modulo array size */
93 idx = ARRAY_SIZE(vsub->auth_tuples) - 1;
94 else
95 idx = key_seq;
96
97 for (count = ARRAY_SIZE(vsub->auth_tuples); count > 0; count--) {
98 idx = (idx + 1) % ARRAY_SIZE(vsub->auth_tuples);
99
100 if (vsub->auth_tuples[idx].key_seq == GSM_KEY_SEQ_INVAL)
101 continue;
102
103 if (!at || vsub->auth_tuples[idx].use_count < at->use_count)
104 at = &vsub->auth_tuples[idx];
105 }
106
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100107 if (!at || (max_reuse_count >= 0 && at->use_count > max_reuse_count))
Harald Welteb8b85a12016-06-17 00:06:42 +0200108 return NULL;
109
110 return at;
111}
112
113/* Return an auth tuple and increment its use count. */
114static struct gsm_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100115vlr_subscr_get_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200116{
117 struct gsm_auth_tuple *at = _vlr_subscr_next_auth_tuple(vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100118 max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200119 if (!at)
120 return NULL;
121 at->use_count++;
122 return at;
123}
124
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100125/* Return whether an auth tuple with a matching use_count is available. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200126static bool vlr_subscr_has_auth_tuple(struct vlr_subscr *vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100127 int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200128{
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100129 return _vlr_subscr_next_auth_tuple(vsub, max_reuse_count) != NULL;
Harald Welteb8b85a12016-06-17 00:06:42 +0200130}
131
132static bool check_auth_resp(struct vlr_subscr *vsub, bool is_r99,
133 bool is_utran, const uint8_t *res,
134 uint8_t res_len)
135{
136 struct gsm_auth_tuple *at = vsub->last_tuple;
137 struct osmo_auth_vector *vec = &at->vec;
138 bool check_umts;
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100139 bool res_is_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200140 OSMO_ASSERT(at);
141
Neels Hofmeyra9099bc2018-03-10 04:22:50 +0100142 LOGVSUBP(LOGL_DEBUG, vsub, "AUTH on %s received %s: %s (%u bytes)\n",
143 is_utran ? "UTRAN" : "GERAN",
144 is_utran ? "RES" : "SRES/RES",
145 osmo_hexdump_nospc(res, res_len), res_len);
Harald Welteb8b85a12016-06-17 00:06:42 +0200146
147 /* RES must be present and at least 32bit */
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100148 if (!res || !res_len) {
149 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES missing\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200150 goto out_false;
151 }
152
Neels Hofmeyr11d2ce32018-03-10 00:25:20 +0100153 /* We're deciding the UMTS AKA-ness of the response by the RES size. So let's make sure we can't
154 * mix them up by size. On UTRAN, we expect full length RES always, no way to mix up there. */
155 if (!is_utran && vec->res_len == sizeof(vec->sres))
156 LOGVSUBP(LOGL_ERROR, vsub, "Unforeseen situation: UMTS AKA's RES length"
157 " equals the size of SRES: %u -- this code wants to differentiate"
158 " the two by their size, which won't work properly now.\n", vec->res_len);
159
160 /* RES must be either vec->res_len (UMTS AKA) or sizeof(sres) (GSM AKA) */
161 if (res_len == vec->res_len)
162 res_is_umts_aka = true;
163 else if (res_len == sizeof(vec->sres))
164 res_is_umts_aka = false;
165 else {
166 if (is_utran)
167 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH RES has invalid length: %u."
168 " Expected %u (UMTS AKA)\n",
169 res_len, vec->res_len);
170 else
171 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH SRES/RES has invalid length: %u."
172 " Expected either %zu (GSM AKA) or %u (UMTS AKA)\n",
173 res_len, sizeof(vec->sres), vec->res_len);
174 goto out_false;
175 }
176
177 check_umts = (is_r99
178 && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)
179 && res_is_umts_aka);
180
181 /* Even on an R99 capable MS with a UMTS AKA capable USIM,
182 * the MS may still choose to only perform GSM AKA, as
183 * long as the bearer is GERAN -- never on UTRAN: */
184 if (is_utran && !check_umts) {
185 LOGVSUBP(LOGL_ERROR, vsub,
186 "AUTH via UTRAN, cannot allow GSM AKA"
187 " (MS is %sR99 capable, vec has %sUMTS AKA tokens, res_len=%u is %s)\n",
188 is_r99 ? "" : "NOT ",
189 (vec->auth_types & OSMO_AUTH_TYPE_UMTS) ? "" : "NO ",
190 res_len, (res_len == vec->res_len)? "valid" : "INVALID on UTRAN");
191 goto out_false;
Harald Welteb8b85a12016-06-17 00:06:42 +0200192 }
193
194 if (check_umts) {
195 if (res_len != vec->res_len
196 || memcmp(res, vec->res, res_len)) {
197 LOGVSUBP(LOGL_INFO, vsub, "UMTS AUTH failure:"
198 " mismatching res (expected res=%s)\n",
199 osmo_hexdump(vec->res, vec->res_len));
200 goto out_false;
201 }
202
203 LOGVSUBP(LOGL_INFO, vsub, "AUTH established UMTS security"
204 " context\n");
205 vsub->sec_ctx = VLR_SEC_CTX_UMTS;
206 return true;
207 } else {
208 if (res_len != sizeof(vec->sres)
209 || memcmp(res, vec->sres, sizeof(vec->sres))) {
210 LOGVSUBP(LOGL_INFO, vsub, "GSM AUTH failure:"
211 " mismatching sres (expected sres=%s)\n",
212 osmo_hexdump(vec->sres, sizeof(vec->sres)));
213 goto out_false;
214 }
215
216 LOGVSUBP(LOGL_INFO, vsub, "AUTH established GSM security"
217 " context\n");
218 vsub->sec_ctx = VLR_SEC_CTX_GSM;
219 return true;
220 }
221
222out_false:
223 vsub->sec_ctx = VLR_SEC_CTX_NONE;
224 return false;
225}
226
227static void auth_fsm_onenter_failed(struct osmo_fsm_inst *fi, uint32_t prev_state)
228{
229 struct auth_fsm_priv *afp = fi->priv;
230 struct vlr_subscr *vsub = afp->vsub;
231
232 /* If authentication hasn't even started, e.g. the HLR sent no auth
233 * info, then we also don't need to tell the HLR about an auth failure.
234 */
Max770fbd22018-01-24 12:48:33 +0100235 if (afp->auth_requested) {
236 int rc = vlr_subscr_tx_auth_fail_rep(vsub);
237 if (rc < 0)
238 LOGVSUBP(LOGL_ERROR, vsub, "Failed to communicate AUTH failure to HLR\n");
239 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200240}
241
Harald Welteb8b85a12016-06-17 00:06:42 +0200242/* Terminate the Auth FSM Instance and notify parent */
243static void auth_fsm_term(struct osmo_fsm_inst *fi, enum vlr_auth_fsm_result res)
244{
245 struct auth_fsm_priv *afp = fi->priv;
246 struct vlr_subscr *vsub = afp->vsub;
247
248 LOGPFSM(fi, "Authentication terminating with result %s\n",
249 vlr_auth_fsm_result_name(res));
250
251 /* Do one final state transition (mostly for logging purpose) */
252 if (res == VLR_AUTH_RES_PASSED)
253 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTHENTICATED, 0, 0);
254 else
255 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
256
257 /* return the result to the parent FSM */
258 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, &res);
259 vsub->auth_fsm = NULL;
260}
261
262/* back-end function transmitting authentication. Caller ensures we have valid
263 * tuple */
264static int _vlr_subscr_authenticate(struct osmo_fsm_inst *fi)
265{
266 struct auth_fsm_priv *afp = fi->priv;
267 struct vlr_subscr *vsub = afp->vsub;
268 struct gsm_auth_tuple *at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100269 bool use_umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200270
271 /* Caller ensures we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100272 at = vlr_subscr_get_auth_tuple(vsub, afp->auth_tuple_max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200273 if (!at) {
274 LOGPFSML(fi, LOGL_ERROR, "A previous check ensured that an"
275 " auth tuple was available, but now there is in fact"
276 " none.\n");
277 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
278 return -1;
279 }
280
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100281 use_umts_aka = vlr_use_umts_aka(&at->vec, afp->is_r99);
282 LOGPFSM(fi, "got auth tuple: use_count=%d key_seq=%d"
283 " -- will use %s AKA (is_r99=%s, at->vec.auth_types=0x%x)\n",
284 at->use_count, at->key_seq,
285 use_umts_aka ? "UMTS" : "GSM", afp->is_r99 ? "yes" : "no", at->vec.auth_types);
Harald Welteb8b85a12016-06-17 00:06:42 +0200286
287 /* Transmit auth req to subscriber */
288 afp->auth_requested = true;
289 vsub->last_tuple = at;
Neels Hofmeyrfe718bc2018-03-11 01:24:33 +0100290 vsub->vlr->ops.tx_auth_req(vsub->msc_conn_ref, at, use_umts_aka);
Harald Welteb8b85a12016-06-17 00:06:42 +0200291 return 0;
292}
293
294/***********************************************************************
295 * FSM State Action functions
296 ***********************************************************************/
297
298/* Initial State of TS 23.018 AUT_VLR */
299static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
300{
301 struct auth_fsm_priv *afp = fi->priv;
302 struct vlr_subscr *vsub = afp->vsub;
303
304 OSMO_ASSERT(event == VLR_AUTH_E_START);
305
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100306 /* Start off with the default max_reuse_count, possibly change that if we
Harald Welteb8b85a12016-06-17 00:06:42 +0200307 * need to re-use an old tuple. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100308 afp->auth_tuple_max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
Harald Welteb8b85a12016-06-17 00:06:42 +0200309
310 /* Check if we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100311 if (!vlr_subscr_has_auth_tuple(vsub, afp->auth_tuple_max_reuse_count)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200312 /* Obtain_Authentication_Sets_VLR */
Max770fbd22018-01-24 12:48:33 +0100313 int rc = vlr_subscr_req_sai(vsub, NULL, NULL);
314 if (rc < 0)
315 LOGPFSM(fi, "Failed to request Authentication Sets from VLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200316 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH_WAIT_AI,
317 GSM_29002_TIMER_M, 0);
318 } else {
319 /* go straight ahead with sending auth request */
320 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
321 vlr_timer(vsub->vlr, 3260), 3260);
322 _vlr_subscr_authenticate(fi);
323 }
324}
325
326/* Waiting for Authentication Info from HLR */
327static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
328 void *data)
329{
330 struct auth_fsm_priv *afp = fi->priv;
331 struct vlr_subscr *vsub = afp->vsub;
332 struct osmo_gsup_message *gsup = data;
333
334 if (event == VLR_AUTH_E_HLR_SAI_NACK)
335 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
336 gsup->cause,
337 get_value_string(gsm48_gmm_cause_names, gsup->cause));
338
339 /* We are in what corresponds to the
340 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
341 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
342 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
343 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
344 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
345 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
346 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100347 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200348 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100349 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200350 goto pass;
351 }
352 /* result = procedure error */
353 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
354 return;
355 }
356
357 switch (event) {
358 case VLR_AUTH_E_HLR_SAI_ACK:
359 vlr_subscr_update_tuples(vsub, gsup);
360 goto pass;
361 break;
362 case VLR_AUTH_E_HLR_SAI_NACK:
363 auth_fsm_term(fi,
364 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
365 VLR_AUTH_RES_UNKNOWN_SUBSCR
366 : VLR_AUTH_RES_PROC_ERR);
367 break;
368 }
369
370 return;
371pass:
372 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
373 vlr_timer(vsub->vlr, 3260), 3260);
374 _vlr_subscr_authenticate(fi);
375}
376
377/* Waiting for Authentication Response from MS */
378static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
379 void *data)
380{
381 struct auth_fsm_priv *afp = fi->priv;
382 struct vlr_subscr *vsub = afp->vsub;
383 struct vlr_instance *vlr = vsub->vlr;
384 struct vlr_auth_resp_par *par = data;
385 int rc;
386
387 switch (event) {
388 case VLR_AUTH_E_MS_AUTH_RESP:
389 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
390 par->res, par->res_len);
391 if (rc == false) {
392 if (!afp->by_imsi) {
393 vlr->ops.tx_id_req(vsub->msc_conn_ref,
394 GSM_MI_TYPE_IMSI);
395 osmo_fsm_inst_state_chg(fi,
396 VLR_SUB_AS_WAIT_ID_IMSI,
397 vlr_timer(vlr, 3270), 3270);
398 } else {
399 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
400 }
401 } else {
402 auth_fsm_term(fi, VLR_AUTH_RES_PASSED);
403 }
404 break;
405 case VLR_AUTH_E_MS_AUTH_FAIL:
406 if (par->auts) {
407 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100408 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200409 vsub->last_tuple->vec.rand);
410 osmo_fsm_inst_state_chg(fi,
411 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
412 GSM_29002_TIMER_M, 0);
413 } else
414 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
415 break;
416 }
417}
418
419/* Waiting for Authentication Info from HLR (resync case) */
420static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
421 uint32_t event, void *data)
422{
423 struct auth_fsm_priv *afp = fi->priv;
424 struct vlr_subscr *vsub = afp->vsub;
425 struct osmo_gsup_message *gsup = data;
426
427 /* We are in what corresponds to the
428 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
429 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
430 (event == VLR_AUTH_E_HLR_SAI_NACK &&
431 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
432 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
433 /* result = procedure error */
434 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
435 }
436 switch (event) {
437 case VLR_AUTH_E_HLR_SAI_ACK:
438 vlr_subscr_update_tuples(vsub, gsup);
439 goto pass;
440 break;
441 case VLR_AUTH_E_HLR_SAI_NACK:
442 auth_fsm_term(fi,
443 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
444 VLR_AUTH_RES_UNKNOWN_SUBSCR
445 : VLR_AUTH_RES_PROC_ERR);
446 break;
447 }
448
449 return;
450pass:
451 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
452 vlr_timer(vsub->vlr, 3260), 3260);
453 _vlr_subscr_authenticate(fi);
454}
455
456/* Waiting for AUTH RESP from MS (re-sync case) */
457static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
458 uint32_t event, void *data)
459{
460 struct auth_fsm_priv *afp = fi->priv;
461 struct vlr_subscr *vsub = afp->vsub;
462 struct vlr_auth_resp_par *par = data;
463 struct vlr_instance *vlr = vsub->vlr;
464 int rc;
465
466 switch (event) {
467 case VLR_AUTH_E_MS_AUTH_RESP:
468 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
469 par->res, par->res_len);
470 if (rc == false) {
471 if (!afp->by_imsi) {
472 vlr->ops.tx_id_req(vsub->msc_conn_ref,
473 GSM_MI_TYPE_IMSI);
474 osmo_fsm_inst_state_chg(fi,
475 VLR_SUB_AS_WAIT_ID_IMSI,
476 vlr_timer(vlr, 3270), 3270);
477 } else {
478 /* Result = Aborted */
479 auth_fsm_term(fi, VLR_AUTH_RES_ABORTED);
480 }
481 } else {
482 /* Result = Pass */
483 auth_fsm_term(fi, VLR_AUTH_RES_PASSED);
484 }
485 break;
486 case VLR_AUTH_E_MS_AUTH_FAIL:
487 /* Second failure: Result = Fail */
488 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
489 break;
490 }
491}
492
493/* AUT_VLR waiting for Obtain_IMSI_VLR result */
494static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
495 void *data)
496{
497 struct auth_fsm_priv *afp = fi->priv;
498 struct vlr_subscr *vsub = afp->vsub;
499 const char *mi_string = data;
500
501 switch (event) {
502 case VLR_AUTH_E_MS_ID_IMSI:
503 if (vsub->imsi[0]
504 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
505 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
506 " %s\n", mi_string);
507 } else {
508 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
509 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
510 }
511 /* retry with identity=IMSI */
512 afp->by_imsi = true;
513 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
514 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
515 break;
516 }
517}
518
519static const struct osmo_fsm_state auth_fsm_states[] = {
520 [VLR_SUB_AS_NEEDS_AUTH] = {
521 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
522 .in_event_mask = S(VLR_AUTH_E_START),
523 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
524 S(VLR_SUB_AS_WAIT_RESP),
525 .action = auth_fsm_needs_auth,
526 },
527 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
528 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
529 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
530 S(VLR_AUTH_E_HLR_SAI_NACK),
531 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
532 S(VLR_SUB_AS_WAIT_RESP),
533 .action = auth_fsm_wait_ai,
534 },
535 [VLR_SUB_AS_WAIT_RESP] = {
536 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
537 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
538 S(VLR_AUTH_E_MS_AUTH_FAIL),
539 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
540 S(VLR_SUB_AS_AUTH_FAILED) |
541 S(VLR_SUB_AS_AUTHENTICATED) |
542 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
543 .action = auth_fsm_wait_auth_resp,
544 },
545 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
546 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
547 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
548 S(VLR_AUTH_E_HLR_SAI_NACK),
549 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
550 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
551 .action = auth_fsm_wait_ai_resync,
552 },
553 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
554 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
555 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
556 S(VLR_AUTH_E_MS_AUTH_FAIL),
557 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
558 S(VLR_SUB_AS_AUTHENTICATED),
559 .action = auth_fsm_wait_auth_resp_resync,
560 },
561 [VLR_SUB_AS_WAIT_ID_IMSI] = {
562 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
563 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
564 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
565 .action = auth_fsm_wait_imsi,
566 },
567 [VLR_SUB_AS_AUTHENTICATED] = {
568 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
569 .in_event_mask = 0,
570 .out_state_mask = 0,
571 },
572 [VLR_SUB_AS_AUTH_FAILED] = {
573 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
574 .in_event_mask = 0,
575 .out_state_mask = 0,
576 .onenter = auth_fsm_onenter_failed,
577 },
578};
579
580struct osmo_fsm vlr_auth_fsm = {
581 .name = "VLR_Authenticate",
582 .states = auth_fsm_states,
583 .num_states = ARRAY_SIZE(auth_fsm_states),
584 .allstate_event_mask = 0,
585 .allstate_action = NULL,
586 .log_subsys = DVLR,
587 .event_names = fsm_auth_event_names,
588};
589
590/***********************************************************************
591 * User API (for SGSN/MSC code)
592 ***********************************************************************/
593
594/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
595struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
596 uint32_t log_level,
597 struct osmo_fsm_inst *parent,
598 uint32_t parent_term_event,
599 bool is_r99,
600 bool is_utran)
601{
602 struct osmo_fsm_inst *fi;
603 struct auth_fsm_priv *afp;
604
605 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent,
606 parent_term_event);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100607 if (!fi) {
608 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
609 return NULL;
610 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200611
612 afp = talloc_zero(fi, struct auth_fsm_priv);
613 if (!afp) {
614 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
615 return NULL;
616 }
617
618 afp->vsub = vsub;
619 if (vsub->imsi[0])
620 afp->by_imsi = true;
621 afp->is_r99 = is_r99;
622 afp->is_utran = is_utran;
623 fi->priv = afp;
624 vsub->auth_fsm = fi;
625
626 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
627
628 return fi;
629}