blob: 5906720adddadf4431231d4d596326dc0712f670 [file] [log] [blame]
Neels Hofmeyr00c06972017-01-31 01:19:27 +01001/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
2 * All Rights Reserved
3 *
4 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <stdio.h>
22#include <string.h>
Neels Hofmeyr6b883f72017-01-31 16:40:28 +010023#include <inttypes.h>
Neels Hofmeyr21380ae2017-02-21 21:53:38 +010024#include <getopt.h>
Neels Hofmeyr00c06972017-01-31 01:19:27 +010025
26#include <osmocom/core/application.h>
27#include <osmocom/core/utils.h>
28#include <osmocom/core/logging.h>
29
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010030#include <osmocom/crypt/auth.h>
Neels Hofmeyr00c06972017-01-31 01:19:27 +010031
Neels Hofmeyr2f758032019-11-20 00:37:07 +010032#include <osmocom/hlr/logging.h>
33#include <osmocom/hlr/auc.h>
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010034
35#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
Neels Hofmeyr00c06972017-01-31 01:19:27 +010036#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);
37
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010038#define VERBOSE_ASSERT(val, expect_op, fmt) \
39 do { \
40 fprintf(stderr, #val " == " fmt "\n", (val)); \
41 OSMO_ASSERT((val) expect_op); \
42 } while (0);
43
Neels Hofmeyr6b883f72017-01-31 16:40:28 +010044char *vec_str(const struct osmo_auth_vector *vec)
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010045{
46 static char buf[1024];
47 char *pos = buf;
48 char *end = buf + sizeof(buf);
49
50#define append(what) \
51 if (pos >= end) \
52 return buf; \
53 pos += snprintf(pos, sizeof(buf) - (pos - buf), \
54 " " #what ": %s\n", \
55 osmo_hexdump_nospc((void*)&vec->what, sizeof(vec->what)))
56
57 append(rand);
58 append(autn);
59 append(ck);
60 append(ik);
61 append(res);
62 append(res_len);
63 append(kc);
64 append(sres);
65 append(auth_types);
66#undef append
67
68 return buf;
69}
70
71#define VEC_IS(vec, expect) do { \
Neels Hofmeyr6b883f72017-01-31 16:40:28 +010072 char *_is = vec_str(vec); \
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010073 if (strcmp(_is, expect)) { \
74 fprintf(stderr, "MISMATCH! expected ==\n%s\n", \
75 expect); \
76 char *a = _is; \
77 char *b = expect; \
78 for (; *a && *b; a++, b++) { \
79 if (*a != *b) { \
Neels Hofmeyr21380ae2017-02-21 21:53:38 +010080 fprintf(stderr, "mismatch at %d:\n", \
81 (int)(a - _is)); \
82 while (a > _is && *(a-1) != '\n') { \
83 fprintf(stderr, " "); \
84 a--; \
85 } \
86 fprintf(stderr, "v\n%s", a); \
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010087 break; \
88 } \
89 } \
90 OSMO_ASSERT(false); \
Neels Hofmeyr8d97d342017-02-21 22:46:35 +010091 } else \
92 fprintf(stderr, "vector matches expectations\n"); \
Neels Hofmeyr8cde6622017-01-31 02:10:40 +010093 } while (0)
94
Neels Hofmeyr00c06972017-01-31 01:19:27 +010095uint8_t fake_rand[16] = { 0 };
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +010096bool fake_rand_fixed = true;
97
98void next_rand(const char *hexstr, bool fixed)
99{
100 osmo_hexparse(hexstr, fake_rand, sizeof(fake_rand));
101 fake_rand_fixed = fixed;
102}
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100103
104int rand_get(uint8_t *rand, unsigned int len)
105{
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100106 int i;
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100107 OSMO_ASSERT(len <= sizeof(fake_rand));
108 memcpy(rand, fake_rand, len);
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100109 if (!fake_rand_fixed) {
110 for (i = 0; i < len; i++)
111 fake_rand[i] += 0x11;
112 }
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100113 return len;
114}
115
Harald Weltebd94b412021-01-04 14:02:55 +0100116/* Subscriber with 2G-only (COMP128v1) authentication data */
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100117static void test_gen_vectors_2g_only(void)
118{
Harald Weltea854b482023-05-30 17:27:32 +0200119 struct osmo_sub_auth_data2 aud2g;
120 struct osmo_sub_auth_data2 aud3g;
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100121 struct osmo_auth_vector vec;
122 int rc;
123
124 comment_start();
125
Harald Weltea854b482023-05-30 17:27:32 +0200126 aud2g = (struct osmo_sub_auth_data2){
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100127 .type = OSMO_AUTH_TYPE_GSM,
128 .algo = OSMO_AUTH_ALG_COMP128v1,
129 };
130
131 osmo_hexparse("EB215756028D60E3275E613320AEC880",
132 aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
133
Harald Weltea854b482023-05-30 17:27:32 +0200134 aud3g = (struct osmo_sub_auth_data2){ 0 };
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100135
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100136 next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100137
138 vec = (struct osmo_auth_vector){ {0} };
Neels Hofmeyr6b883f72017-01-31 16:40:28 +0100139 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100140 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
141 VERBOSE_ASSERT(rc, == 1, "%d");
142
143 VEC_IS(&vec,
144 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
145 " autn: 00000000000000000000000000000000\n"
146 " ck: 00000000000000000000000000000000\n"
147 " ik: 00000000000000000000000000000000\n"
148 " res: 00000000000000000000000000000000\n"
149 " res_len: 00\n"
150 " kc: 241a5b16aeb8e400\n"
151 " sres: 429d5b27\n"
152 " auth_types: 01000000\n"
153 );
154
Neels Hofmeyr6b883f72017-01-31 16:40:28 +0100155 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100156
157 /* even though vec is not zero-initialized, it should produce the same
158 * result (regardless of the umts sequence nr) */
159 aud3g.u.umts.sqn = 123;
160 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
161 VERBOSE_ASSERT(rc, == 1, "%d");
162
163 VEC_IS(&vec,
164 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
165 " autn: 00000000000000000000000000000000\n"
166 " ck: 00000000000000000000000000000000\n"
167 " ik: 00000000000000000000000000000000\n"
168 " res: 00000000000000000000000000000000\n"
169 " res_len: 00\n"
170 " kc: 241a5b16aeb8e400\n"
171 " sres: 429d5b27\n"
172 " auth_types: 01000000\n"
173 );
174
175 comment_end();
176}
177
Harald Weltebd94b412021-01-04 14:02:55 +0100178/* Subscriber with separate 2G (COMP128v1) and 3G (MILENAGE) authentication data,
179 * reflects the default configuration of sysmoUSIM-SJS1 */
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100180static void test_gen_vectors_2g_plus_3g(void)
181{
Harald Weltea854b482023-05-30 17:27:32 +0200182 struct osmo_sub_auth_data2 aud2g;
183 struct osmo_sub_auth_data2 aud3g;
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100184 struct osmo_auth_vector vec;
185 int rc;
186
187 comment_start();
188
Harald Weltea854b482023-05-30 17:27:32 +0200189 aud2g = (struct osmo_sub_auth_data2){
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100190 .type = OSMO_AUTH_TYPE_GSM,
191 .algo = OSMO_AUTH_ALG_COMP128v1,
192 };
193
194 osmo_hexparse("EB215756028D60E3275E613320AEC880",
195 aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
196
Harald Weltea854b482023-05-30 17:27:32 +0200197 aud3g = (struct osmo_sub_auth_data2){
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100198 .type = OSMO_AUTH_TYPE_UMTS,
199 .algo = OSMO_AUTH_ALG_MILENAGE,
Harald Weltea854b482023-05-30 17:27:32 +0200200 .u.umts.k_len = 16,
201 .u.umts.opc_len = 16,
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100202 .u.umts.sqn = 31,
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100203 };
204
205 osmo_hexparse("EB215756028D60E3275E613320AEC880",
206 aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
207 osmo_hexparse("FB2A3D1B360F599ABAB99DB8669F8308",
208 aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100209 next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100210
211 vec = (struct osmo_auth_vector){ {0} };
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100212 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100213 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
214 VERBOSE_ASSERT(rc, == 1, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100215 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100216
217 VEC_IS(&vec,
218 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
Neels Hofmeyrd846ae82017-03-15 00:37:29 +0100219 " autn: 8704f5ba55d30000541dde77ea5b1d8c\n"
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100220 " ck: f64735036e5871319c679f4742a75ea1\n"
221 " ik: 27497388b6cb044648f396aa155b95ef\n"
222 " res: e229c19e791f2e410000000000000000\n"
223 " res_len: 08\n"
224 " kc: 241a5b16aeb8e400\n"
225 " sres: 429d5b27\n"
226 " auth_types: 03000000\n"
227 );
228
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100229 /* even though vec is not zero-initialized, it should produce the same
230 * result with the same sequence nr */
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100231 aud3g.u.umts.sqn = 31;
232 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100233 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
234 VERBOSE_ASSERT(rc, == 1, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100235 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100236
237 VEC_IS(&vec,
238 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
Neels Hofmeyrd846ae82017-03-15 00:37:29 +0100239 " autn: 8704f5ba55d30000541dde77ea5b1d8c\n"
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100240 " ck: f64735036e5871319c679f4742a75ea1\n"
241 " ik: 27497388b6cb044648f396aa155b95ef\n"
242 " res: e229c19e791f2e410000000000000000\n"
243 " res_len: 08\n"
244 " kc: 241a5b16aeb8e400\n"
245 " sres: 429d5b27\n"
246 " auth_types: 03000000\n"
247 );
248
249 comment_end();
250}
251
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100252void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
253{
254 fprintf(stderr, "[0]: ");
255 VEC_IS(&vecs[0],
256 " rand: 897210a0f7de278f0b8213098e098a3f\n"
257 " autn: c6b9790dad4b00000cf322869ea6a481\n"
258 " ck: e9922bd036718ed9e40bd1d02c3b81a5\n"
259 " ik: f19c20ca863137f8892326d959ec5e01\n"
260 " res: 9af5a557902d2db80000000000000000\n"
261 " res_len: 08\n"
262 " kc: 7526fc13c5976685\n"
263 " sres: 0ad888ef\n"
264 " auth_types: 03000000\n"
265 );
266 fprintf(stderr, "[1]: ");
267 VEC_IS(&vecs[1],
268 " rand: 9a8321b108ef38a01c93241a9f1a9b50\n"
269 " autn: 79a5113eb0910000be6020540503ffc5\n"
270 " ck: 3686f05df057d1899c66ae4eb18cf941\n"
271 " ik: 79f21ed53bcb47787de57d136ff803a5\n"
272 " res: 43023475cb29292c0000000000000000\n"
273 " res_len: 08\n"
274 " kc: aef73dd515e86c15\n"
275 " sres: 882b1d59\n"
276 " auth_types: 03000000\n"
277 );
278 fprintf(stderr, "[2]: ");
279 VEC_IS(&vecs[2],
280 " rand: ab9432c2190049b12da4352bb02bac61\n"
281 " autn: 24b018d46c3b00009c7e1b47f3a19b2b\n"
282 " ck: d86c3191a36fc0602e48202ef2080964\n"
283 " ik: 648dab72016181406243420649e63dc9\n"
284 " res: 010cab11cc63a6e40000000000000000\n"
285 " res_len: 08\n"
286 " kc: f0eaf8cb19e0758d\n"
287 " sres: cd6f0df5\n"
288 " auth_types: 03000000\n"
289 );
290}
291
Harald Weltebd94b412021-01-04 14:02:55 +0100292/* Subscriber with only 3G (MILENAGE) authentication data,
293 * reflects the default configuration of sysmoISIM-SJA2. Resulting
294 * tuples are suitable for both 2G and 3G authentication */
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100295static void test_gen_vectors_3g_only(void)
296{
Harald Weltea854b482023-05-30 17:27:32 +0200297 struct osmo_sub_auth_data2 aud2g;
298 struct osmo_sub_auth_data2 aud3g;
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100299 struct osmo_auth_vector vec;
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100300 struct osmo_auth_vector vecs[3];
Neels Hofmeyrec9036b2017-02-21 21:56:11 +0100301 uint8_t auts[14];
302 uint8_t rand_auts[16];
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100303 int rc;
304
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100305 comment_start();
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100306
Harald Weltea854b482023-05-30 17:27:32 +0200307 aud2g = (struct osmo_sub_auth_data2){ 0 };
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100308
Harald Weltea854b482023-05-30 17:27:32 +0200309 aud3g = (struct osmo_sub_auth_data2){
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100310 .type = OSMO_AUTH_TYPE_UMTS,
311 .algo = OSMO_AUTH_ALG_MILENAGE,
Harald Weltea854b482023-05-30 17:27:32 +0200312 .u.umts.k_len = 16,
313 .u.umts.opc_len = 16,
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100314 .u.umts.sqn = 31,
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100315 };
316
317 osmo_hexparse("EB215756028D60E3275E613320AEC880",
318 aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
319 osmo_hexparse("FB2A3D1B360F599ABAB99DB8669F8308",
320 aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100321 next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100322
323 vec = (struct osmo_auth_vector){ {0} };
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100324 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100325 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
326 VERBOSE_ASSERT(rc, == 1, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100327 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100328
329 VEC_IS(&vec,
330 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
Neels Hofmeyrd846ae82017-03-15 00:37:29 +0100331 " autn: 8704f5ba55d30000541dde77ea5b1d8c\n"
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100332 " ck: f64735036e5871319c679f4742a75ea1\n"
333 " ik: 27497388b6cb044648f396aa155b95ef\n"
334 " res: e229c19e791f2e410000000000000000\n"
335 " res_len: 08\n"
336 " kc: 059a4f668f6fbe39\n"
337 " sres: 9b36efdf\n"
338 " auth_types: 03000000\n"
339 );
340
341 /* Note: 3GPP TS 33.102 6.8.1.2: c3 function to get GSM auth is
342 * KC[0..7] == CK[0..7] ^ CK[8..15] ^ IK[0..7] ^ IK[8..15]
343 * In [16]: hex( 0xf64735036e587131
344 * ^ 0x9c679f4742a75ea1
345 * ^ 0x27497388b6cb0446
346 * ^ 0x48f396aa155b95ef)
347 * Out[16]: '0x59a4f668f6fbe39L'
348 * hence expecting kc: 059a4f668f6fbe39
349 */
350
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100351 /* even though vec is not zero-initialized, it should produce the same
352 * result with the same sequence nr */
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100353 aud3g.u.umts.sqn = 31;
354 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100355 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
356 VERBOSE_ASSERT(rc, == 1, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100357 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100358
359 VEC_IS(&vec,
360 " rand: 39fa2f4e3d523d8619a73b4f65c3e14d\n"
Neels Hofmeyrd846ae82017-03-15 00:37:29 +0100361 " autn: 8704f5ba55d30000541dde77ea5b1d8c\n"
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100362 " ck: f64735036e5871319c679f4742a75ea1\n"
363 " ik: 27497388b6cb044648f396aa155b95ef\n"
364 " res: e229c19e791f2e410000000000000000\n"
365 " res_len: 08\n"
366 " kc: 059a4f668f6fbe39\n"
367 " sres: 9b36efdf\n"
368 " auth_types: 03000000\n"
369 );
370
Neels Hofmeyrec9036b2017-02-21 21:56:11 +0100371
372 fprintf(stderr, "- test AUTS resync\n");
373 vec = (struct osmo_auth_vector){};
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100374 aud3g.u.umts.sqn = 31;
375 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
Neels Hofmeyrec9036b2017-02-21 21:56:11 +0100376
377 /* The AUTN sent was 8704f5ba55f30000d2ee44b22c8ea919
378 * with the first 6 bytes being SQN ^ AK.
379 * K = EB215756028D60E3275E613320AEC880
380 * OPC = FB2A3D1B360F599ABAB99DB8669F8308
381 * RAND = 39fa2f4e3d523d8619a73b4f65c3e14d
382 * --milenage-f5-->
383 * AK = 8704f5ba55f3
384 *
385 * The first six bytes are 8704f5ba55f3,
386 * and 8704f5ba55f3 ^ AK = 0.
387 * --> SQN = 0.
388 *
389 * Say the USIM doesn't like that, let's say it is at SQN 23.
390 * SQN_MS = 000000000017
391 *
392 * AUTS = Conc(SQN_MS) || MAC-S
393 * Conc(SQN_MS) = SQN_MS ⊕ f5*[K](RAND)
394 * MAC-S = f1*[K] (SQN MS || RAND || AMF)
395 *
396 * f5*--> Conc(SQN_MS) = 000000000017 ^ 979498b1f73a
397 * = 979498b1f72d
398 * AMF = 0000 (TS 33.102 v7.0.0, 6.3.3)
399 *
400 * MAC-S = f1*[K] (000000000017 || 39fa2f4e3d523d8619a73b4f65c3e14d || 0000)
401 * = 3e28c59fa2e72f9c
402 *
403 * AUTS = 979498b1f72d || 3e28c59fa2e72f9c
404 *
405 * verify valid AUTS resulting in SQN 23 with:
406 * osmo-auc-gen -3 -a milenage -k EB215756028D60E3275E613320AEC880 \
407 * -o FB2A3D1B360F599ABAB99DB8669F8308 \
408 * -r 39fa2f4e3d523d8619a73b4f65c3e14d \
409 * -A 979498b1f72d3e28c59fa2e72f9c
410 */
411
412 /* AUTS response by USIM */
413 osmo_hexparse("979498b1f72d3e28c59fa2e72f9c",
414 auts, sizeof(auts));
415 /* RAND sent to USIM, which AUTS was generated from */
416 osmo_hexparse("39fa2f4e3d523d8619a73b4f65c3e14d",
417 rand_auts, sizeof(rand_auts));
418 /* new RAND token for the next key */
Neels Hofmeyr3aa3c102017-02-21 22:48:35 +0100419 next_rand("897210a0f7de278f0b8213098e098a3f", true);
Neels Hofmeyrec9036b2017-02-21 21:56:11 +0100420 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, rand_auts, auts);
421 VERBOSE_ASSERT(rc, == 1, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100422 /* The USIM's last sqn was 23, the calculated vector was 24 */
423 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 24, "%"PRIu64);
Neels Hofmeyrec9036b2017-02-21 21:56:11 +0100424
425 VEC_IS(&vec,
426 " rand: 897210a0f7de278f0b8213098e098a3f\n"
427 " autn: c6b9790dad4b00000cf322869ea6a481\n"
428 " ck: e9922bd036718ed9e40bd1d02c3b81a5\n"
429 " ik: f19c20ca863137f8892326d959ec5e01\n"
430 " res: 9af5a557902d2db80000000000000000\n"
431 " res_len: 08\n"
432 " kc: 7526fc13c5976685\n"
433 " sres: 0ad888ef\n"
434 " auth_types: 03000000\n"
435 );
436
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100437
438 fprintf(stderr, "- verify N vectors with AUTS resync"
439 " == N vectors without AUTS\n"
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100440 "First just set rand and sqn = 23, and compute 3 vectors\n");
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100441 next_rand("897210a0f7de278f0b8213098e098a3f", false);
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100442 aud3g.u.umts.sqn = 23;
443 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 23, "%"PRIu64);
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100444
445 memset(vecs, 0, sizeof(vecs));
446 rc = auc_compute_vectors(vecs, 3, &aud2g, &aud3g, NULL, NULL);
447 VERBOSE_ASSERT(rc, == 3, "%d");
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100448 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 26, "%"PRIu64);
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100449
450 _test_gen_vectors_3g_only__expect_vecs(vecs);
451
Neels Hofmeyrea1052d2017-03-15 02:42:19 +0100452 fprintf(stderr, "Now reach sqn = 23 with AUTS and expect the same\n");
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100453 /* AUTS response by USIM */
454 osmo_hexparse("979498b1f72d3e28c59fa2e72f9c",
455 auts, sizeof(auts));
456 /* RAND sent to USIM, which AUTS was generated from */
457 osmo_hexparse("39fa2f4e3d523d8619a73b4f65c3e14d",
458 rand_auts, sizeof(rand_auts));
459 next_rand("897210a0f7de278f0b8213098e098a3f", false);
460 rc = auc_compute_vectors(vecs, 3, &aud2g, &aud3g, rand_auts, auts);
461
Neels Hofmeyrb5b11e32017-02-22 01:42:43 +0100462 _test_gen_vectors_3g_only__expect_vecs(vecs);
Neels Hofmeyr428c9472017-02-21 22:50:59 +0100463
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100464 comment_end();
465}
466
Harald Weltebd94b412021-01-04 14:02:55 +0100467/* Subscriber with only 3G (XOR) authentication data,
468 * reflects the default configuration of sysmoTSIM-SJAx as well
469 * as many "Test USIM" cards. Resulting tuples are suitable for both
470 * 2G and 3G authentication */
Harald Welte6e237d32020-12-28 01:01:31 +0100471static void test_gen_vectors_3g_xor(void)
472{
Harald Weltea854b482023-05-30 17:27:32 +0200473 struct osmo_sub_auth_data2 aud2g;
474 struct osmo_sub_auth_data2 aud3g;
Harald Welte6e237d32020-12-28 01:01:31 +0100475 struct osmo_auth_vector vec;
476 int rc;
477
478 comment_start();
479
Harald Weltea854b482023-05-30 17:27:32 +0200480 aud2g = (struct osmo_sub_auth_data2){ 0 };
Harald Welte6e237d32020-12-28 01:01:31 +0100481
Harald Weltea854b482023-05-30 17:27:32 +0200482 aud3g = (struct osmo_sub_auth_data2){
Harald Welte6e237d32020-12-28 01:01:31 +0100483 .type = OSMO_AUTH_TYPE_UMTS,
Harald Welte829713a2023-05-30 16:57:27 +0200484 .algo = OSMO_AUTH_ALG_XOR_3G,
Harald Weltea854b482023-05-30 17:27:32 +0200485 .u.umts.k_len = 16,
486 .u.umts.opc_len = 16,
Harald Welte6e237d32020-12-28 01:01:31 +0100487 .u.umts.sqn = 0,
488 };
489
490 osmo_hexparse("000102030405060708090a0b0c0d0e0f",
491 aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
492 osmo_hexparse("00000000000000000000000000000000",
493 aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
494 next_rand("b5039c57e4a75051551d1a390a71ce48", true);
495
496 vec = (struct osmo_auth_vector){ {0} };
497 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
498 rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
499 VERBOSE_ASSERT(rc, == 1, "%d");
500 VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
501
502 VEC_IS(&vec,
503 " rand: b5039c57e4a75051551d1a390a71ce48\n"
504 " autn: 54e0a256565d0000b5029e54e0a25656\n"
505 " ck: 029e54e0a256565d141032067cc047b5\n"
506 " ik: 9e54e0a256565d141032067cc047b502\n"
507 " res: b5029e54e0a256565d141032067cc047\n"
508 " res_len: 10\n"
509 " kc: 98e880384887f9fe\n"
510 " sres: 0ec81877\n"
511 " auth_types: 03000000\n"
512 );
513
514 comment_end();
515}
516
Harald Weltebd94b412021-01-04 14:02:55 +0100517/* Test a variety of invalid authentication data combinations */
Harald Welte7a476532022-11-03 11:38:41 +0100518void test_gen_vectors_bad_args(void)
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100519{
520 struct osmo_auth_vector vec;
521 uint8_t auts[14];
522 uint8_t rand_auts[16];
523 int rc;
524 int i;
525
Harald Weltea854b482023-05-30 17:27:32 +0200526 struct osmo_sub_auth_data2 aud2g = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100527 .type = OSMO_AUTH_TYPE_GSM,
528 .algo = OSMO_AUTH_ALG_COMP128v1,
529 };
530
Harald Weltea854b482023-05-30 17:27:32 +0200531 struct osmo_sub_auth_data2 aud3g = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100532 .type = OSMO_AUTH_TYPE_UMTS,
533 .algo = OSMO_AUTH_ALG_MILENAGE,
Harald Weltea854b482023-05-30 17:27:32 +0200534 .u.umts.k_len = 16,
535 .u.umts.opc_len = 16,
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100536 };
537
Harald Weltea854b482023-05-30 17:27:32 +0200538 struct osmo_sub_auth_data2 aud2g_noalg = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100539 .type = OSMO_AUTH_TYPE_GSM,
540 .algo = OSMO_AUTH_ALG_NONE,
541 };
542
Harald Weltea854b482023-05-30 17:27:32 +0200543 struct osmo_sub_auth_data2 aud3g_noalg = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100544 .type = OSMO_AUTH_TYPE_UMTS,
545 .algo = OSMO_AUTH_ALG_NONE,
Harald Weltea854b482023-05-30 17:27:32 +0200546 .u.umts.k_len = 16,
547 .u.umts.opc_len = 16,
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100548 };
549
Harald Weltea854b482023-05-30 17:27:32 +0200550 struct osmo_sub_auth_data2 aud_notype = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100551 .type = OSMO_AUTH_TYPE_NONE,
552 .algo = OSMO_AUTH_ALG_MILENAGE,
553 };
554
Harald Weltea854b482023-05-30 17:27:32 +0200555 struct osmo_sub_auth_data2 no_aud = {
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100556 .type = OSMO_AUTH_TYPE_NONE,
557 .algo = OSMO_AUTH_ALG_NONE,
558 };
559
560 struct {
Harald Weltea854b482023-05-30 17:27:32 +0200561 struct osmo_sub_auth_data2 *aud2g;
562 struct osmo_sub_auth_data2 *aud3g;
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100563 uint8_t *rand_auts;
564 uint8_t *auts;
565 const char *label;
566 } tests[] = {
567 { NULL, NULL, NULL, NULL, "no auth data (a)"},
568 { NULL, &aud3g_noalg, NULL, NULL, "no auth data (b)"},
569 { NULL, &aud_notype, NULL, NULL, "no auth data (c)"},
570 { NULL, &no_aud, NULL, NULL, "no auth data (d)"},
571 { &aud2g_noalg, NULL, NULL, NULL, "no auth data (e)"},
572 { &aud2g_noalg, &aud3g_noalg, NULL, NULL, "no auth data (f)"},
573 { &aud2g_noalg, &aud_notype, NULL, NULL, "no auth data (g)"},
574 { &aud2g_noalg, &no_aud, NULL, NULL, "no auth data (h)"},
575 { &aud_notype, NULL, NULL, NULL, "no auth data (i)"},
576 { &aud_notype, &aud3g_noalg, NULL, NULL, "no auth data (j)"},
577 { &aud_notype, &aud_notype, NULL, NULL, "no auth data (k)"},
578 { &aud_notype, &no_aud, NULL, NULL, "no auth data (l)"},
579 { &no_aud, NULL, NULL, NULL, "no auth data (m)"},
580 { &no_aud, &aud3g_noalg, NULL, NULL, "no auth data (n)"},
581 { &no_aud, &aud_notype, NULL, NULL, "no auth data (o)"},
582 { &no_aud, &no_aud, NULL, NULL, "no auth data (p)"},
583 { &aud3g, NULL, NULL, NULL, "wrong auth data type (a)"},
584 { &aud3g, &aud3g_noalg, NULL, NULL, "wrong auth data type (b)"},
585 { &aud3g, &aud_notype, NULL, NULL, "wrong auth data type (c)"},
586 { &aud3g, &no_aud, NULL, NULL, "wrong auth data type (d)"},
587 { NULL, &aud2g, NULL, NULL, "wrong auth data type (e)"},
588 { &aud3g_noalg, &aud2g, NULL, NULL, "wrong auth data type (f)"},
589 { &aud_notype, &aud2g, NULL, NULL, "wrong auth data type (g)"},
590 { &no_aud, &aud2g, NULL, NULL, "wrong auth data type (h)"},
591 { &aud3g, &aud2g, NULL, NULL, "wrong auth data type (i)"},
592 { &aud3g, &aud3g, NULL, NULL, "wrong auth data type (j)"},
593 { &aud2g, &aud2g, NULL, NULL, "wrong auth data type (k)"},
594 { &aud2g, NULL, rand_auts, auts, "AUTS for 2G-only (a)"},
595 { &aud2g, &aud3g_noalg, rand_auts, auts, "AUTS for 2G-only (b)"},
596 { &aud2g, &aud_notype, rand_auts, auts, "AUTS for 2G-only (c)"},
597 { &aud2g, &no_aud, rand_auts, auts, "AUTS for 2G-only (d)"},
598 { NULL, &aud3g, NULL, auts, "incomplete AUTS (a)"},
599 { NULL, &aud3g, rand_auts, NULL, "incomplete AUTS (b)"},
600 { &aud2g, &aud3g, NULL, auts, "incomplete AUTS (c)"},
601 { &aud2g, &aud3g, rand_auts, NULL, "incomplete AUTS (d)"},
602 };
603
604 comment_start();
605
606 for (i = 0; i < ARRAY_SIZE(tests); i++) {
607 fprintf(stderr, "\n- %s\n", tests[i].label);
608 rc = auc_compute_vectors(&vec, 1,
609 tests[i].aud2g,
610 tests[i].aud3g,
611 tests[i].rand_auts,
612 tests[i].auts);
613 VERBOSE_ASSERT(rc, < 0, "%d");
614 }
615
616 comment_end();
617}
618
Neels Hofmeyr21380ae2017-02-21 21:53:38 +0100619static struct {
620 bool verbose;
621} cmdline_opts = {
622 .verbose = false,
623};
624
625static void print_help(const char *program)
626{
627 printf("Usage:\n"
628 " %s [-v] [N [N...]]\n"
629 "Options:\n"
630 " -h --help show this text.\n"
631 " -v --verbose print source file and line numbers\n",
632 program
633 );
634}
635
636static void handle_options(int argc, char **argv)
637{
638 while (1) {
639 int option_index = 0, c;
640 static struct option long_options[] = {
641 {"help", 0, 0, 'h'},
642 {"verbose", 1, 0, 'v'},
643 {0, 0, 0, 0}
644 };
645
646 c = getopt_long(argc, argv, "hv",
647 long_options, &option_index);
648 if (c == -1)
649 break;
650
651 switch (c) {
652 case 'h':
653 print_help(argv[0]);
654 exit(0);
655 case 'v':
656 cmdline_opts.verbose = true;
657 break;
658 default:
659 /* catch unknown options *as well as* missing arguments. */
660 fprintf(stderr, "Error in command line options. Exiting.\n");
661 exit(-1);
662 break;
663 }
664 }
665
666 if (optind < argc) {
667 fprintf(stderr, "too many args\n");
668 exit(-1);
669 }
670}
671
672int main(int argc, char **argv)
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100673{
674 printf("auc_3g_test.c\n");
Neels Hofmeyr21380ae2017-02-21 21:53:38 +0100675
676 handle_options(argc, argv);
677
Pau Espin Pedrol51530312018-04-17 15:07:06 +0200678 void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
679
680 osmo_init_logging2(tall_ctx, &hlr_log_info);
Pau Espin Pedrold6993ea2021-02-19 13:20:18 +0100681 log_set_print_filename2(osmo_stderr_target,
682 cmdline_opts.verbose ?
683 LOG_FILENAME_BASENAME :
684 LOG_FILENAME_NONE);
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100685 log_set_print_timestamp(osmo_stderr_target, 0);
686 log_set_use_color(osmo_stderr_target, 0);
Pau Espin Pedrold6993ea2021-02-19 13:20:18 +0100687 log_set_print_category_hex(osmo_stderr_target, 0);
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100688 log_set_print_category(osmo_stderr_target, 1);
Neels Hofmeyr6eb231e2017-10-27 03:35:45 +0200689 log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100690
Neels Hofmeyr8cde6622017-01-31 02:10:40 +0100691 test_gen_vectors_2g_only();
692 test_gen_vectors_2g_plus_3g();
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100693 test_gen_vectors_3g_only();
Harald Welte6e237d32020-12-28 01:01:31 +0100694 test_gen_vectors_3g_xor();
Neels Hofmeyr569d3222017-02-21 22:57:11 +0100695 test_gen_vectors_bad_args();
Neels Hofmeyr00c06972017-01-31 01:19:27 +0100696
697 printf("Done\n");
698 return 0;
699}