blob: 50419a43bcc22a6787643a92ecd1c28908995262 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file osmo-auc-gen.c
2 * GSM/GPRS/3G authentication testing tool. */
3/*
Harald Welte0ea9b912023-05-30 12:05:56 +02004 * (C) 2010-2023 by Harald Welte <laforge@gnumonks.org>
Harald Welte915e0ef2011-12-07 02:38:42 +01005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
Harald Welte915e0ef2011-12-07 02:38:42 +010018 */
19
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <errno.h>
24#include <string.h>
Jan Engelhardta6d83932013-06-03 01:38:57 +020025#include <time.h>
Harald Welte915e0ef2011-12-07 02:38:42 +010026#include <getopt.h>
Harald Welteb53717f2012-08-02 08:42:59 +020027#include <unistd.h>
Holger Hans Peter Freythera652abc2013-07-14 09:11:47 +020028#include <inttypes.h>
29#include <time.h>
Harald Welte915e0ef2011-12-07 02:38:42 +010030
31#include <osmocom/crypt/auth.h>
32#include <osmocom/core/utils.h>
Harald Welte53b4bbb2021-09-16 21:36:16 +020033#include <osmocom/core/base64.h>
Max4b2b0cc2017-07-10 14:32:48 +020034#include <osmocom/gsm/gsm_utils.h>
Harald Welte915e0ef2011-12-07 02:38:42 +010035
Harald Welte53b4bbb2021-09-16 21:36:16 +020036static void print_base64(const char *fmt, const uint8_t *data, unsigned int len)
37{
38 uint8_t outbuf[256];
39 size_t olen;
40
41 OSMO_ASSERT(osmo_base64_encode(outbuf, sizeof(outbuf), &olen, data, len) == 0);
42 OSMO_ASSERT(sizeof(outbuf) > olen);
43 outbuf[olen] = '\0';
44 printf(fmt, outbuf);
45}
46
Harald Welte57799ed2012-06-27 15:06:19 +020047static void dump_triplets_dat(struct osmo_auth_vector *vec)
48{
49 if (vec->auth_types & OSMO_AUTH_TYPE_UMTS) {
50 fprintf(stderr, "triplets.dat doesn't support UMTS!\n");
51 return;
52 }
53 printf("imsi,");
54 printf("%s,", osmo_hexdump_nospc(vec->rand, sizeof(vec->rand)));
55 printf("%s,", osmo_hexdump_nospc(vec->sres, sizeof(vec->sres)));
56 printf("%s\n", osmo_hexdump_nospc(vec->kc, sizeof(vec->kc)));
57}
58
Harald Welte915e0ef2011-12-07 02:38:42 +010059static void dump_auth_vec(struct osmo_auth_vector *vec)
60{
Harald Welte4f511b62016-05-18 19:36:42 +020061 printf("RAND:\t%s\n", osmo_hexdump_nospc(vec->rand, sizeof(vec->rand)));
Harald Welte915e0ef2011-12-07 02:38:42 +010062
63 if (vec->auth_types & OSMO_AUTH_TYPE_UMTS) {
Harald Welte53b4bbb2021-09-16 21:36:16 +020064 uint8_t inbuf[sizeof(vec->rand) + sizeof(vec->autn)];
65
Harald Welte4f511b62016-05-18 19:36:42 +020066 printf("AUTN:\t%s\n", osmo_hexdump_nospc(vec->autn, sizeof(vec->autn)));
67 printf("IK:\t%s\n", osmo_hexdump_nospc(vec->ik, sizeof(vec->ik)));
68 printf("CK:\t%s\n", osmo_hexdump_nospc(vec->ck, sizeof(vec->ck)));
69 printf("RES:\t%s\n", osmo_hexdump_nospc(vec->res, vec->res_len));
Harald Welte53b4bbb2021-09-16 21:36:16 +020070
71 memcpy(inbuf, vec->rand, sizeof(vec->rand));
72 memcpy(inbuf + sizeof(vec->rand), vec->autn, sizeof(vec->autn));
73 print_base64("IMS nonce:\t%s\n", inbuf, sizeof(inbuf));
74 print_base64("IMS res:\t%s\n", vec->res, vec->res_len);
Harald Welte915e0ef2011-12-07 02:38:42 +010075 }
76
77 if (vec->auth_types & OSMO_AUTH_TYPE_GSM) {
Harald Welte4f511b62016-05-18 19:36:42 +020078 printf("SRES:\t%s\n", osmo_hexdump_nospc(vec->sres, sizeof(vec->sres)));
79 printf("Kc:\t%s\n", osmo_hexdump_nospc(vec->kc, sizeof(vec->kc)));
Harald Welte915e0ef2011-12-07 02:38:42 +010080 }
81}
82
Harald Welte0ea9b912023-05-30 12:05:56 +020083static struct osmo_sub_auth_data2 test_aud = {
Harald Welte915e0ef2011-12-07 02:38:42 +010084 .type = OSMO_AUTH_TYPE_NONE,
85 .algo = OSMO_AUTH_ALG_NONE,
86};
87
Harald Weltee61d4592022-11-03 11:05:58 +010088static void help(void)
Harald Welte5fb795e2012-03-21 08:51:48 +010089{
Neels Hofmeyr18d65be2017-02-03 18:36:32 +010090 int alg;
Harald Welte5fb795e2012-03-21 08:51:48 +010091 printf( "-2 --2g\tUse 2G (GSM) authentication\n"
92 "-3 --3g\tUse 3G (UMTS) authentication\n"
93 "-a --algorithm\tSpecify name of the algorithm\n"
94 "-k --key\tSpecify Ki / K\n"
95 "-o --opc\tSpecify OPC (only for 3G)\n"
Harald Weltea72e47b2012-03-21 09:03:16 +010096 "-O --op\tSpecify OP (only for 3G)\n"
Holger Hans Peter Freyther91ff17c2015-05-26 00:11:37 +080097 "-f --amf\tSpecify AMF (only for 3G)\n"
Harald Welte5fb795e2012-03-21 08:51:48 +010098 "-s --sqn\tSpecify SQN (only for 3G)\n"
Neels Hofmeyr3cb08272017-08-26 21:45:33 +020099 "-i --ind\tSpecify IND slot for new SQN after AUTS (only for 3G)\n"
Neels Hofmeyrb1af6ef2017-08-26 21:38:51 +0200100 "-l --ind-len\tSpecify IND bit length (default=5) (only for 3G)\n"
Harald Welted8e53092023-05-30 15:01:38 +0200101 "-L --res-len\tSpecify RES byte length (default=8) (only for 3G)\n"
Harald Weltecebf3f02012-03-22 16:45:23 +0100102 "-A --auts\tSpecify AUTS (only for 3G)\n"
Harald Welte57799ed2012-06-27 15:06:19 +0200103 "-r --rand\tSpecify random value\n"
104 "-I --ipsec\tOutput in triplets.dat format for strongswan\n");
Neels Hofmeyr18d65be2017-02-03 18:36:32 +0100105
106 fprintf(stderr, "\nAvailable algorithms for option -a:\n");
107 for (alg = 1; alg < _OSMO_AUTH_ALG_NUM; alg++)
108 fprintf(stderr, " %s\n",
109 osmo_auth_alg_name(alg));
Harald Welte5fb795e2012-03-21 08:51:48 +0100110}
111
Harald Welte915e0ef2011-12-07 02:38:42 +0100112int main(int argc, char **argv)
113{
114 struct osmo_auth_vector _vec;
115 struct osmo_auth_vector *vec = &_vec;
Neels Hofmeyr8352d312017-02-02 20:05:14 +0100116 uint8_t _rand[16], _auts[14];
Pau Espin Pedrolc30a76b2017-11-16 16:37:55 +0100117 uint64_t sqn = 0;
Neels Hofmeyrb2e41cc2017-09-12 03:25:43 +0200118 unsigned int ind = 0;
Harald Welte915e0ef2011-12-07 02:38:42 +0100119 int rc, option_index;
120 int rand_is_set = 0;
Harald Weltecebf3f02012-03-22 16:45:23 +0100121 int auts_is_set = 0;
Neels Hofmeyrd157bbb2017-08-26 22:08:36 +0200122 int sqn_is_set = 0;
Neels Hofmeyr3cb08272017-08-26 21:45:33 +0200123 int ind_is_set = 0;
Harald Welte57799ed2012-06-27 15:06:19 +0200124 int fmt_triplets_dat = 0;
Neels Hofmeyrb2e41cc2017-09-12 03:25:43 +0200125 uint64_t ind_mask = 0;
Harald Welte915e0ef2011-12-07 02:38:42 +0100126
Harald Welted8e53092023-05-30 15:01:38 +0200127 printf("osmo-auc-gen (C) 2011-2023 by Harald Welte\n");
Harald Welte915e0ef2011-12-07 02:38:42 +0100128 printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
129
Harald Weltecebf3f02012-03-22 16:45:23 +0100130 memset(_auts, 0, sizeof(_auts));
Harald Welted8e53092023-05-30 15:01:38 +0200131 memset(vec, 0, sizeof(*vec));
132 vec->res_len = 8; /* default */
Harald Weltecebf3f02012-03-22 16:45:23 +0100133
Harald Welte915e0ef2011-12-07 02:38:42 +0100134 while (1) {
135 int c;
Harald Welte915e0ef2011-12-07 02:38:42 +0100136 static struct option long_options[] = {
137 { "2g", 0, 0, '2' },
138 { "3g", 0, 0, '3' },
139 { "algorithm", 1, 0, 'a' },
140 { "key", 1, 0, 'k' },
141 { "opc", 1, 0, 'o' },
Harald Weltea72e47b2012-03-21 09:03:16 +0100142 { "op", 1, 0, 'O' },
Harald Welte915e0ef2011-12-07 02:38:42 +0100143 { "amf", 1, 0, 'f' },
144 { "sqn", 1, 0, 's' },
Neels Hofmeyr3cb08272017-08-26 21:45:33 +0200145 { "ind", 1, 0, 'i' },
Neels Hofmeyrb1af6ef2017-08-26 21:38:51 +0200146 { "ind-len", 1, 0, 'l' },
Harald Welted8e53092023-05-30 15:01:38 +0200147 { "res-len", 1, 0, 'L' },
Harald Welte915e0ef2011-12-07 02:38:42 +0100148 { "rand", 1, 0, 'r' },
Harald Weltecebf3f02012-03-22 16:45:23 +0100149 { "auts", 1, 0, 'A' },
Harald Welte5fb795e2012-03-21 08:51:48 +0100150 { "help", 0, 0, 'h' },
Harald Welte915e0ef2011-12-07 02:38:42 +0100151 { 0, 0, 0, 0 }
152 };
153
154 rc = 0;
155
Harald Welted8e53092023-05-30 15:01:38 +0200156 c = getopt_long(argc, argv, "23a:k:o:f:s:i:l:L:r:hO:A:I", long_options,
Harald Welte915e0ef2011-12-07 02:38:42 +0100157 &option_index);
158
159 if (c == -1)
160 break;
161
162 switch (c) {
163 case '2':
164 test_aud.type = OSMO_AUTH_TYPE_GSM;
165 break;
166 case '3':
167 test_aud.type = OSMO_AUTH_TYPE_UMTS;
Neels Hofmeyr4315e012017-08-26 21:40:11 +0200168 test_aud.u.umts.ind_bitlen = 5;
Harald Welte915e0ef2011-12-07 02:38:42 +0100169 break;
170 case 'a':
171 rc = osmo_auth_alg_parse(optarg);
172 if (rc < 0)
173 break;
174 test_aud.algo = rc;
175 break;
176 case 'k':
177 switch (test_aud.type) {
178 case OSMO_AUTH_TYPE_GSM:
Harald Welteaae23622011-12-07 11:35:02 +0100179 rc = osmo_hexparse(optarg, test_aud.u.gsm.ki,
180 sizeof(test_aud.u.gsm.ki));
Harald Welte0ea9b912023-05-30 12:05:56 +0200181 if (rc != sizeof(test_aud.u.gsm.ki)) {
182 fprintf(stderr, "Invalid Ki length %d\n", rc);
183 exit(2);
184 }
Harald Welte915e0ef2011-12-07 02:38:42 +0100185 break;
186 case OSMO_AUTH_TYPE_UMTS:
Harald Welteaae23622011-12-07 11:35:02 +0100187 rc = osmo_hexparse(optarg, test_aud.u.umts.k,
188 sizeof(test_aud.u.umts.k));
Harald Welte0ea9b912023-05-30 12:05:56 +0200189 /* 3GPP TS 33.102 6.3.7: "The authentication key (K) shall have a length of
190 * 128 bits or 256 bits." */
191 if (rc != 16 && rc != 32) {
192 fprintf(stderr, "Invalid K length %d\n", rc);
193 exit(2);
194 }
195 test_aud.u.umts.k_len = rc;
Harald Welte915e0ef2011-12-07 02:38:42 +0100196 break;
197 default:
198 fprintf(stderr, "please specify 2g/3g first!\n");
199 }
200 break;
201 case 'o':
202 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
203 fprintf(stderr, "Only UMTS has OPC\n");
204 exit(2);
205 }
Harald Welteaae23622011-12-07 11:35:02 +0100206 rc = osmo_hexparse(optarg, test_aud.u.umts.opc,
207 sizeof(test_aud.u.umts.opc));
Harald Welte0ea9b912023-05-30 12:05:56 +0200208 if (rc != 16 && rc != 32) {
209 fprintf(stderr, "Invalid OPC length %d\n", rc);
210 exit(2);
211 }
212 test_aud.u.umts.opc_len = rc;
Harald Weltea72e47b2012-03-21 09:03:16 +0100213 test_aud.u.umts.opc_is_op = 0;
214 break;
215 case 'O':
216 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
217 fprintf(stderr, "Only UMTS has OP\n");
218 exit(2);
219 }
220 rc = osmo_hexparse(optarg, test_aud.u.umts.opc,
221 sizeof(test_aud.u.umts.opc));
Harald Welte0ea9b912023-05-30 12:05:56 +0200222 if (rc != 16 && rc != 32) {
223 fprintf(stderr, "Invalid OP length %d\n", rc);
224 exit(2);
225 }
226 test_aud.u.umts.opc_len = rc;
Harald Weltea72e47b2012-03-21 09:03:16 +0100227 test_aud.u.umts.opc_is_op = 1;
Harald Welte915e0ef2011-12-07 02:38:42 +0100228 break;
Harald Weltecebf3f02012-03-22 16:45:23 +0100229 case 'A':
230 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
231 fprintf(stderr, "Only UMTS has AUTS\n");
232 exit(2);
233 }
234 rc = osmo_hexparse(optarg, _auts, sizeof(_auts));
235 auts_is_set = 1;
236 break;
Harald Welte915e0ef2011-12-07 02:38:42 +0100237 case 'f':
238 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
239 fprintf(stderr, "Only UMTS has AMF\n");
240 exit(2);
241 }
Harald Welteaae23622011-12-07 11:35:02 +0100242 rc = osmo_hexparse(optarg, test_aud.u.umts.amf,
243 sizeof(test_aud.u.umts.amf));
Harald Welte0ea9b912023-05-30 12:05:56 +0200244 if (rc != 2) {
245 fprintf(stderr, "Invalid AMF length %d\n", rc);
246 exit(2);
247 }
Harald Welte915e0ef2011-12-07 02:38:42 +0100248 break;
249 case 's':
250 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
251 fprintf(stderr, "Only UMTS has SQN\n");
252 exit(2);
253 }
Harald Welteb48f4382021-09-17 07:56:09 +0200254 sqn = strtoull(optarg, 0, 0);
Neels Hofmeyrd157bbb2017-08-26 22:08:36 +0200255 sqn_is_set = 1;
Harald Welte915e0ef2011-12-07 02:38:42 +0100256 break;
Neels Hofmeyr3cb08272017-08-26 21:45:33 +0200257 case 'i':
258 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
259 fprintf(stderr, "Only UMTS has IND\n");
260 exit(2);
261 }
262 ind = atoi(optarg);
263 ind_is_set = 1;
264 break;
Neels Hofmeyrb1af6ef2017-08-26 21:38:51 +0200265 case 'l':
266 if (test_aud.type != OSMO_AUTH_TYPE_UMTS) {
267 fprintf(stderr, "Only UMTS has IND bitlen\n");
268 exit(2);
269 }
270 test_aud.u.umts.ind_bitlen = atoi(optarg);
271 break;
Harald Welted8e53092023-05-30 15:01:38 +0200272 case 'L':
273 rc = atoi(optarg);
274 if (rc != 4 && rc != 8 && rc != 16) {
275 fprintf(stderr, "Invalid RES length %u\n", rc);
276 exit(2);
277 }
278 vec->res_len = rc;
279 break;
Harald Welte915e0ef2011-12-07 02:38:42 +0100280 case 'r':
281 rc = osmo_hexparse(optarg, _rand, sizeof(_rand));
Harald Welte0ea9b912023-05-30 12:05:56 +0200282 if (rc != sizeof(_rand)) {
283 fprintf(stderr, "Invalid RAND length %d\n", rc);
284 exit(2);
285 }
Harald Welte915e0ef2011-12-07 02:38:42 +0100286 rand_is_set = 1;
287 break;
Harald Welte57799ed2012-06-27 15:06:19 +0200288 case 'I':
289 fmt_triplets_dat = 1;
290 break;
Harald Welte5fb795e2012-03-21 08:51:48 +0100291 case 'h':
292 help();
293 exit(0);
294 default:
295 help();
296 exit(1);
Harald Welte915e0ef2011-12-07 02:38:42 +0100297 }
298
299 if (rc < 0) {
Neels Hofmeyr18d65be2017-02-03 18:36:32 +0100300 help();
301 fprintf(stderr, "\nError parsing argument of option `%c'\n", c);
Harald Welte915e0ef2011-12-07 02:38:42 +0100302 exit(2);
303 }
304 }
305
Harald Welte278a6c82019-12-03 21:35:12 +0100306 if (argc > optind) {
307 fprintf(stderr, "Unsupported positional arguments in command line\n");
308 exit(2);
309 }
310
Harald Welte915e0ef2011-12-07 02:38:42 +0100311 if (!rand_is_set) {
Max4b2b0cc2017-07-10 14:32:48 +0200312 rc = osmo_get_rand_id(_rand, 16);
313 if (rc < 0) {
314 fprintf(stderr, "\nError: unable to obtain secure random numbers: %s!\n",
315 strerror(-rc));
316 exit(3);
Holger Hans Peter Freyther17aa6b22014-06-22 16:53:55 +0200317 }
Harald Welte915e0ef2011-12-07 02:38:42 +0100318 }
319
Harald Welte5fb795e2012-03-21 08:51:48 +0100320 if (test_aud.type == OSMO_AUTH_TYPE_NONE ||
321 test_aud.algo == OSMO_AUTH_ALG_NONE) {
322 help();
Neels Hofmeyr18d65be2017-02-03 18:36:32 +0100323 fprintf(stderr, "\nError: you need to pass at least"
324 " -2 or -3, as well as an algorithm to use.\n");
Harald Welte5fb795e2012-03-21 08:51:48 +0100325 exit(2);
326 }
327
Neels Hofmeyrd157bbb2017-08-26 22:08:36 +0200328 if (test_aud.type == OSMO_AUTH_TYPE_UMTS) {
Neels Hofmeyrb2e41cc2017-09-12 03:25:43 +0200329 uint64_t seq_1 = 1LL << test_aud.u.umts.ind_bitlen;
Neels Hofmeyre6e64462017-08-26 22:29:51 +0200330 ind_mask = seq_1 - 1;
Neels Hofmeyrd157bbb2017-08-26 22:08:36 +0200331
332 if (sqn_is_set) {
333 /* Before calculating the UMTS auth vector, osmo_auth_gen_vec() increments SEQ.
334 * To end up with the SQN passed in by the user, we need to pass in SEQ-1, and
335 * indicate which IND slot to target. */
336 test_aud.u.umts.sqn = sqn - seq_1;
337 test_aud.u.umts.ind = sqn & ind_mask;
338 }
Neels Hofmeyr3cb08272017-08-26 21:45:33 +0200339
340 if (sqn_is_set && ind_is_set) {
341 fprintf(stderr, "Requesting --sqn %"PRIu64" implies IND=%u,"
342 " so no further --ind argument is allowed.\n",
343 sqn, test_aud.u.umts.ind);
344 exit(2);
345 }
346
347 if (ind_is_set) {
348 if (ind >= (1 << test_aud.u.umts.ind_bitlen)) {
349 fprintf(stderr, "Requested --ind %u is too large for IND bitlen of %u\n",
350 ind, test_aud.u.umts.ind_bitlen);
351 exit(2);
352 }
353 test_aud.u.umts.ind = ind;
354 }
Neels Hofmeyrd157bbb2017-08-26 22:08:36 +0200355 }
356
Harald Weltecebf3f02012-03-22 16:45:23 +0100357 if (!auts_is_set)
Harald Welte0ea9b912023-05-30 12:05:56 +0200358 rc = osmo_auth_gen_vec2(vec, &test_aud, _rand);
Harald Weltecebf3f02012-03-22 16:45:23 +0100359 else
Harald Welte0ea9b912023-05-30 12:05:56 +0200360 rc = osmo_auth_gen_vec_auts2(vec, &test_aud, _auts, _rand, _rand);
Harald Welte915e0ef2011-12-07 02:38:42 +0100361 if (rc < 0) {
Harald Weltecebf3f02012-03-22 16:45:23 +0100362 if (!auts_is_set)
363 fprintf(stderr, "error generating auth vector\n");
364 else
365 fprintf(stderr, "AUTS from MS seems incorrect\n");
Harald Welte915e0ef2011-12-07 02:38:42 +0100366 exit(1);
367 }
368
Harald Welte57799ed2012-06-27 15:06:19 +0200369 if (fmt_triplets_dat)
370 dump_triplets_dat(vec);
Neels Hofmeyr5fe3d1b2017-03-15 01:16:43 +0100371 else {
Harald Welte57799ed2012-06-27 15:06:19 +0200372 dump_auth_vec(vec);
Neels Hofmeyre6e64462017-08-26 22:29:51 +0200373 if (test_aud.type == OSMO_AUTH_TYPE_UMTS) {
Neels Hofmeyr82c9a0e2017-03-13 17:36:17 +0100374 printf("SQN:\t%" PRIu64 "\n", test_aud.u.umts.sqn);
Neels Hofmeyre6e64462017-08-26 22:29:51 +0200375 printf("IND:\t%u\n", (unsigned int)(test_aud.u.umts.sqn & ind_mask));
Neels Hofmeyr2066a422017-08-26 22:43:50 +0200376 if (auts_is_set)
377 printf("SQN.MS:\t%" PRIu64 "\n", test_aud.u.umts.sqn_ms);
Neels Hofmeyre6e64462017-08-26 22:29:51 +0200378 }
Neels Hofmeyr5fe3d1b2017-03-15 01:16:43 +0100379 }
Harald Welte915e0ef2011-12-07 02:38:42 +0100380
Harald Weltecebf3f02012-03-22 16:45:23 +0100381 exit(0);
Harald Welte915e0ef2011-12-07 02:38:42 +0100382}