blob: af03ace1b2dd46c2ea768d0208aafbb42e4a9858 [file] [log] [blame]
Harald Welte007a71e2012-07-18 19:47:56 +02001/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org>
Harald Welted82e0eb2011-12-06 21:53:42 +01002 *
3 * All Rights Reserved
4 *
Harald Weltee08da972017-11-13 01:00:26 +09005 * SPDX-License-Identifier: GPL-2.0+
6 *
Harald Welted82e0eb2011-12-06 21:53:42 +01007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 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 General Public License for more details.
16 *
Harald Welted82e0eb2011-12-06 21:53:42 +010017 */
18
Max38b17232017-12-01 19:06:21 +010019#include "config.h"
20
Harald Welted82e0eb2011-12-06 21:53:42 +010021#include <errno.h>
22#include <stdint.h>
Harald Welted318e612011-12-07 12:16:27 +010023#include <string.h>
Harald Welted82e0eb2011-12-06 21:53:42 +010024
25#include <osmocom/core/utils.h>
26#include <osmocom/core/linuxlist.h>
27#include <osmocom/core/plugin.h>
28
29#include <osmocom/crypt/auth.h>
30
Harald Welte007a71e2012-07-18 19:47:56 +020031/*! \addtogroup auth
32 * @{
Neels Hofmeyr87e45502017-06-20 00:17:59 +020033 * GSM/GPRS/3G authentication core infrastructure
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020034 *
35 * \file auth_core.c */
Harald Welte007a71e2012-07-18 19:47:56 +020036
Harald Welted82e0eb2011-12-06 21:53:42 +010037static LLIST_HEAD(osmo_auths);
38
39static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM];
40
Neels Hofmeyr87e45502017-06-20 00:17:59 +020041/*! Register an authentication algorithm implementation with the core
Harald Welte007a71e2012-07-18 19:47:56 +020042 * \param[in] impl Structure describing implementation and it's callbacks
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +020043 * \returns 0 on success, or a negative error code on failure
Harald Welte007a71e2012-07-18 19:47:56 +020044 *
45 * This function is called by an authentication implementation plugin to
46 * register itself with the authentication core.
47 */
Harald Welted82e0eb2011-12-06 21:53:42 +010048int osmo_auth_register(struct osmo_auth_impl *impl)
49{
50 if (impl->algo >= ARRAY_SIZE(selected_auths))
51 return -ERANGE;
52
53 llist_add_tail(&impl->list, &osmo_auths);
54
55 /* check if we want to select this implementation over others */
56 if (!selected_auths[impl->algo] ||
57 (selected_auths[impl->algo]->priority > impl->priority))
58 selected_auths[impl->algo] = impl;
59
60 return 0;
61}
62
Neels Hofmeyr87e45502017-06-20 00:17:59 +020063/*! Load all available authentication plugins from the given path
Harald Welte007a71e2012-07-18 19:47:56 +020064 * \param[in] path Path name of the directory containing the plugins
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +020065 * \returns number of plugins loaded in case of success, negative in case of error
Harald Welte007a71e2012-07-18 19:47:56 +020066 *
67 * This function will load all plugins contained in the specified path.
68 */
Harald Welted82e0eb2011-12-06 21:53:42 +010069int osmo_auth_load(const char *path)
70{
71 /* load all plugins available from path */
Max38b17232017-12-01 19:06:21 +010072#if !defined(EMBEDDED)
Harald Welted82e0eb2011-12-06 21:53:42 +010073 return osmo_plugin_load_all(path);
Max38b17232017-12-01 19:06:21 +010074#else
75 return -1;
76#endif
Harald Welted82e0eb2011-12-06 21:53:42 +010077}
78
Neels Hofmeyr87e45502017-06-20 00:17:59 +020079/*! Determine if a given authentication algorithm is supported
Harald Welte007a71e2012-07-18 19:47:56 +020080 * \param[in] algo Algorithm which should be checked
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +020081 * \returns 1 if algo is supported, 0 if not, negative error on failure
Harald Welte007a71e2012-07-18 19:47:56 +020082 *
83 * This function is used by an application to determine at runtime if a
84 * given authentication algorithm is supported or not.
85 */
Harald Welted82e0eb2011-12-06 21:53:42 +010086int osmo_auth_supported(enum osmo_auth_algo algo)
87{
88 if (algo >= ARRAY_SIZE(selected_auths))
89 return -ERANGE;
90
91 if (selected_auths[algo])
92 return 1;
93
94 return 0;
95}
96
Maxaf25c372018-12-19 20:12:19 +010097/* 3GPP TS 33.102 §6.8.2.3 C5 function to derive UMTS IK from GSM Kc */
Harald Weltecd9cb902016-04-20 10:39:00 +020098static inline void c5_function(uint8_t *ik, const uint8_t *kc)
99{
100 unsigned int i;
101
102 for (i = 0; i < 4; i++)
103 ik[i] = kc[i] ^ kc[i+4];
104 memcpy(ik+4, kc, 8);
105 for (i = 12; i < 16; i++)
106 ik[i] = ik[i-12];
107}
108
Maxaf25c372018-12-19 20:12:19 +0100109/* 3GPP TS 33.102 §6.8.2.3 C4 function to derive UMTS CK from GSM Kc */
Maxceae1232016-06-27 18:12:49 +0200110void osmo_c4(uint8_t *ck, const uint8_t *kc)
Harald Weltecd9cb902016-04-20 10:39:00 +0200111{
112 memcpy(ck, kc, 8);
113 memcpy(ck+8, kc, 8);
114}
115
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200116/*! Generate 3G CK + IK from 2G authentication vector
Harald Weltecd9cb902016-04-20 10:39:00 +0200117 * \param vec Authentication Vector to be modified
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +0200118 * \returns 1 if the vector was changed, 0 otherwise
Harald Weltecd9cb902016-04-20 10:39:00 +0200119 *
120 * This function performs the C5 and C4 functions to derive the UMTS key
121 * material from the GSM key material in the supplied vector, _if_ the input
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +0200122 * vector doesn't yet have UMTS authentication capability.
123 */
Harald Weltecd9cb902016-04-20 10:39:00 +0200124int osmo_auth_3g_from_2g(struct osmo_auth_vector *vec)
125{
126 if ((vec->auth_types & OSMO_AUTH_TYPE_GSM) &&
127 !(vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
128 c5_function(vec->ik, vec->kc);
Maxceae1232016-06-27 18:12:49 +0200129 osmo_c4(vec->ck, vec->kc);
Harald Weltecd9cb902016-04-20 10:39:00 +0200130 /* We cannot actually set OSMO_AUTH_TYPE_UMTS as we have no
131 * AUTN and no RES, and thus can only perform GSM
132 * authentication with this tuple.
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +0200133 */
Harald Weltecd9cb902016-04-20 10:39:00 +0200134 return 1;
135 }
136
137 return 0;
138}
139
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200140/*! Generate authentication vector
Harald Welte007a71e2012-07-18 19:47:56 +0200141 * \param[out] vec Generated authentication vector
142 * \param[in] aud Subscriber-specific key material
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100143 * \param[in] _rand Random challenge to be used
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +0200144 * \returns 0 on success, negative error on failure
Harald Welte007a71e2012-07-18 19:47:56 +0200145 *
146 * This function performs the core cryptographic function of the AUC,
147 * computing authentication triples/quintuples based on the permanent
148 * subscriber data and a random value. The result is what is forwarded
149 * by the AUC via HLR and VLR to the MSC which will then be able to
150 * invoke authentication with the MS
151 */
Harald Welted82e0eb2011-12-06 21:53:42 +0100152int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
153 struct osmo_sub_auth_data *aud,
154 const uint8_t *_rand)
155{
Harald Welte781bd5d2011-12-06 22:23:52 +0100156 struct osmo_auth_impl *impl = selected_auths[aud->algo];
Harald Welte4afdd5d2011-12-07 02:38:18 +0100157 int rc;
Harald Welted82e0eb2011-12-06 21:53:42 +0100158
159 if (!impl)
160 return -ENOENT;
161
Harald Welte4afdd5d2011-12-07 02:38:18 +0100162 rc = impl->gen_vec(vec, aud, _rand);
163 if (rc < 0)
164 return rc;
165
166 memcpy(vec->rand, _rand, sizeof(vec->rand));
167
168 return 0;
Harald Welted82e0eb2011-12-06 21:53:42 +0100169}
170
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200171/*! Generate authentication vector and re-sync sequence
Harald Welte007a71e2012-07-18 19:47:56 +0200172 * \param[out] vec Generated authentication vector
173 * \param[in] aud Subscriber-specific key material
Harald Welte007a71e2012-07-18 19:47:56 +0200174 * \param[in] auts AUTS value sent by the SIM/MS
Neels Hofmeyr03ab9a62017-02-03 05:00:24 +0100175 * \param[in] rand_auts RAND value sent by the SIM/MS
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100176 * \param[in] _rand Random challenge to be used to generate vector
Neels Hofmeyrc7bf8d02016-05-08 22:23:40 +0200177 * \returns 0 on success, negative error on failure
Harald Welte007a71e2012-07-18 19:47:56 +0200178 *
179 * This function performs a special variant of the core cryptographic
180 * function of the AUC: computing authentication triples/quintuples
181 * based on the permanent subscriber data, a random value as well as the
182 * AUTS and RAND values returned by the SIM/MS. This special variant is
183 * needed if the sequence numbers between MS and AUC have for some
Thorsten Alteholza81055d2017-03-02 22:13:48 +0100184 * reason become different.
Harald Welte007a71e2012-07-18 19:47:56 +0200185 */
Harald Welted82e0eb2011-12-06 21:53:42 +0100186int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec,
187 struct osmo_sub_auth_data *aud,
Neels Hofmeyr03ab9a62017-02-03 05:00:24 +0100188 const uint8_t *auts, const uint8_t *rand_auts,
Harald Welted82e0eb2011-12-06 21:53:42 +0100189 const uint8_t *_rand)
190{
Harald Welte781bd5d2011-12-06 22:23:52 +0100191 struct osmo_auth_impl *impl = selected_auths[aud->algo];
Neels Hofmeyr3b8cb392017-02-21 19:54:36 +0100192 int rc;
Harald Welted82e0eb2011-12-06 21:53:42 +0100193
194 if (!impl || !impl->gen_vec_auts)
195 return -ENOENT;
196
Neels Hofmeyr3b8cb392017-02-21 19:54:36 +0100197 rc = impl->gen_vec_auts(vec, aud, auts, rand_auts, _rand);
198 if (rc < 0)
199 return rc;
200
201 memcpy(vec->rand, _rand, sizeof(vec->rand));
202
203 return 0;
Harald Welted82e0eb2011-12-06 21:53:42 +0100204}
Harald Weltea5ab1622011-12-07 02:33:11 +0100205
Harald Welte1c72bfb2012-04-04 22:05:24 +0200206static const struct value_string auth_alg_vals[] = {
Harald Weltea5ab1622011-12-07 02:33:11 +0100207 { OSMO_AUTH_ALG_NONE, "None" },
208 { OSMO_AUTH_ALG_COMP128v1, "COMP128v1" },
209 { OSMO_AUTH_ALG_COMP128v2, "COMP128v2" },
210 { OSMO_AUTH_ALG_COMP128v3, "COMP128v3" },
211 { OSMO_AUTH_ALG_XOR, "XOR" },
212 { OSMO_AUTH_ALG_MILENAGE, "MILENAGE" },
Harald Weltee93c5e92023-02-21 22:18:11 +0100213 { OSMO_AUTH_ALG_XOR_2G, "XOR-2G" },
Harald Weltea5ab1622011-12-07 02:33:11 +0100214 { 0, NULL }
215};
216
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200217/*! Get human-readable name of authentication algorithm */
Harald Weltea5ab1622011-12-07 02:33:11 +0100218const char *osmo_auth_alg_name(enum osmo_auth_algo alg)
219{
220 return get_value_string(auth_alg_vals, alg);
221}
222
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200223/*! Parse human-readable name of authentication algorithm */
Harald Weltea5ab1622011-12-07 02:33:11 +0100224enum osmo_auth_algo osmo_auth_alg_parse(const char *name)
225{
226 return get_string_value(auth_alg_vals, name);
227}
Harald Welte007a71e2012-07-18 19:47:56 +0200228
Neels Hofmeyr26e30b12017-10-07 04:41:22 +0200229const struct value_string osmo_sub_auth_type_names[] = {
230 { OSMO_AUTH_TYPE_NONE, "None" },
231 { OSMO_AUTH_TYPE_GSM, "GSM" },
232 { OSMO_AUTH_TYPE_UMTS, "UMTS" },
233 { 0, NULL }
234};
235
Neels Hofmeyraa84b712017-12-18 03:12:01 +0100236/* Derive GSM AKA ciphering key Kc from UMTS AKA CK and IK (auth function c3 from 3GPP TS 33.103 §
237 * 4.6.1).
238 * \param[out] kc GSM AKA Kc, 8 byte target buffer.
239 * \param[in] ck UMTS AKA CK, 16 byte input buffer.
240 * \param[in] ik UMTS AKA IK, 16 byte input buffer.
241 */
242void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[])
243{
244 int i;
245 for (i = 0; i < 8; i++)
246 kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
247}
248
Harald Welte007a71e2012-07-18 19:47:56 +0200249/*! @} */