aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm/auth_core.c
blob: 415669599abc78b0955b403940964183df08338a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org>
 *
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include <errno.h>
#include <stdint.h>
#include <string.h>

#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/plugin.h>

#include <osmocom/crypt/auth.h>

/*! \addtogroup auth
 *  @{
 *  GSM/GPRS/3G authentication core infrastructure
 *
 * \file auth_core.c */

static LLIST_HEAD(osmo_auths);

static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM];

/*! Register an authentication algorithm implementation with the core
 *  \param[in] impl Structure describing implementation and it's callbacks
 *  \returns 0 on success, or a negative error code on failure
 *
 * This function is called by an authentication implementation plugin to
 * register itself with the authentication core.
 */
int osmo_auth_register(struct osmo_auth_impl *impl)
{
	if (impl->algo >= ARRAY_SIZE(selected_auths))
		return -ERANGE;

	llist_add_tail(&impl->list, &osmo_auths);

	/* check if we want to select this implementation over others */
	if (!selected_auths[impl->algo] ||
	    (selected_auths[impl->algo]->priority > impl->priority))
		selected_auths[impl->algo] = impl;

	return 0;
}

/*! Load all available authentication plugins from the given path
 *  \param[in] path Path name of the directory containing the plugins
 *  \returns number of plugins loaded in case of success, negative in case of error
 *
 * This function will load all plugins contained in the specified path.
 */
int osmo_auth_load(const char *path)
{
	/* load all plugins available from path */
	return osmo_plugin_load_all(path);
}

/*! Determine if a given authentication algorithm is supported
 *  \param[in] algo Algorithm which should be checked
 *  \returns 1 if algo is supported, 0 if not, negative error on failure
 *
 * This function is used by an application to determine at runtime if a
 * given authentication algorithm is supported or not.
 */
int osmo_auth_supported(enum osmo_auth_algo algo)
{
	if (algo >= ARRAY_SIZE(selected_auths))
		return -ERANGE;

	if (selected_auths[algo])
		return 1;

	return 0;
}

/* C5 function to derive UMTS IK from GSM Kc */
static inline void c5_function(uint8_t *ik, const uint8_t *kc)
{
	unsigned int i;

	for (i = 0; i < 4; i++)
		ik[i] = kc[i] ^ kc[i+4];
	memcpy(ik+4, kc, 8);
	for (i = 12; i < 16; i++)
		ik[i] = ik[i-12];
}

/* C4 function to derive UMTS CK from GSM Kc */
void osmo_c4(uint8_t *ck, const uint8_t *kc)
{
	memcpy(ck, kc, 8);
	memcpy(ck+8, kc, 8);
}

/*! Generate 3G CK + IK from 2G authentication vector
 *  \param vec Authentication Vector to be modified
 *  \returns 1 if the vector was changed, 0 otherwise
 *
 * This function performs the C5 and C4 functions to derive the UMTS key
 * material from the GSM key material in the supplied vector, _if_ the input
 * vector doesn't yet have UMTS authentication capability.
 */
int osmo_auth_3g_from_2g(struct osmo_auth_vector *vec)
{
	if ((vec->auth_types & OSMO_AUTH_TYPE_GSM) &&
	    !(vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
		c5_function(vec->ik, vec->kc);
		osmo_c4(vec->ck, vec->kc);
		/* We cannot actually set OSMO_AUTH_TYPE_UMTS as we have no
		 * AUTN and no RES, and thus can only perform GSM
		 * authentication with this tuple.
		 */
		return 1;
	}

	return 0;
}

/*! Generate authentication vector
 *  \param[out] vec Generated authentication vector
 *  \param[in] aud Subscriber-specific key material
 *  \param[in] _rand Random challenge to be used
 *  \returns 0 on success, negative error on failure
 *
 * This function performs the core cryptographic function of the AUC,
 * computing authentication triples/quintuples based on the permanent
 * subscriber data and a random value.  The result is what is forwarded
 * by the AUC via HLR and VLR to the MSC which will then be able to
 * invoke authentication with the MS
 */
int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
		      struct osmo_sub_auth_data *aud,
		      const uint8_t *_rand)
{
	struct osmo_auth_impl *impl = selected_auths[aud->algo];
	int rc;

	if (!impl)
		return -ENOENT;

	rc = impl->gen_vec(vec, aud, _rand);
	if (rc < 0)
		return rc;

	memcpy(vec->rand, _rand, sizeof(vec->rand));

	return 0;
}

/*! Generate authentication vector and re-sync sequence
 *  \param[out] vec Generated authentication vector
 *  \param[in] aud Subscriber-specific key material
 *  \param[in] auts AUTS value sent by the SIM/MS
 *  \param[in] rand_auts RAND value sent by the SIM/MS
 *  \param[in] _rand Random challenge to be used to generate vector
 *  \returns 0 on success, negative error on failure
 *
 * This function performs a special variant of the  core cryptographic
 * function of the AUC: computing authentication triples/quintuples
 * based on the permanent subscriber data, a random value as well as the
 * AUTS and RAND values returned by the SIM/MS.  This special variant is
 * needed if the sequence numbers between MS and AUC have for some
 * reason become different.
 */
int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec,
			   struct osmo_sub_auth_data *aud,
			   const uint8_t *auts, const uint8_t *rand_auts,
			   const uint8_t *_rand)
{
	struct osmo_auth_impl *impl = selected_auths[aud->algo];
	int rc;

	if (!impl || !impl->gen_vec_auts)
		return -ENOENT;

	rc = impl->gen_vec_auts(vec, aud, auts, rand_auts, _rand);
	if (rc < 0)
		return rc;

	memcpy(vec->rand, _rand, sizeof(vec->rand));

	return 0;
}

static const struct value_string auth_alg_vals[] = {
	{ OSMO_AUTH_ALG_NONE, "None" },
	{ OSMO_AUTH_ALG_COMP128v1, "COMP128v1" },
	{ OSMO_AUTH_ALG_COMP128v2, "COMP128v2" },
	{ OSMO_AUTH_ALG_COMP128v3, "COMP128v3" },
	{ OSMO_AUTH_ALG_XOR, "XOR" },
	{ OSMO_AUTH_ALG_MILENAGE, "MILENAGE" },
	{ 0, NULL }
};

/*! Get human-readable name of authentication algorithm */
const char *osmo_auth_alg_name(enum osmo_auth_algo alg)
{
	return get_value_string(auth_alg_vals, alg);
}

/*! Parse human-readable name of authentication algorithm */
enum osmo_auth_algo osmo_auth_alg_parse(const char *name)
{
	return get_string_value(auth_alg_vals, name);
}

/*! @} */