blob: b8777a8c5d92d287ef0a9aabee6e05c155fbedac [file] [log] [blame]
Neels Hofmeyr37984bd2016-03-30 11:22:24 +02001#include <stdbool.h>
2
3#include <osmocom/core/application.h>
4#include <osmocom/core/logging.h>
5
6#include <openbsc/debug.h>
7#include <openbsc/gsm_data.h>
8#include <openbsc/gsm_subscriber.h>
9#include <openbsc/auth.h>
10
Neels Hofmeyr4554a622016-03-30 11:22:25 +020011#define min(A,B) ((A)>(B)? (B) : (A))
12
13static char *auth_tuple_str(struct gsm_auth_tuple *atuple)
14{
15 static char buf[256];
16 char *pos = buf;
17 int len = sizeof(buf);
18 int l;
19
20#define print2buf(FMT, args...) do {\
21 l = snprintf(pos, len, FMT, ## args); \
22 pos += l;\
23 len -= l;\
24 } while (0)
25
26 print2buf("gsm_auth_tuple {\n");
27 print2buf(" .use_count = %d\n", atuple->use_count);
28 print2buf(" .key_seq = %d\n", atuple->key_seq);
Harald Welte121e9a42016-04-20 13:13:19 +020029 print2buf(" .rand = %s\n", osmo_hexdump(atuple->vec.rand, sizeof(atuple->vec.rand)));
30 print2buf(" .sres = %s\n", osmo_hexdump(atuple->vec.sres, sizeof(atuple->vec.sres)));
31 print2buf(" .kc = %s\n", osmo_hexdump(atuple->vec.kc, sizeof(atuple->vec.kc)));
Neels Hofmeyr4554a622016-03-30 11:22:25 +020032 print2buf("}\n");
33#undef print2buf
34
35 return buf;
36}
37
38static bool auth_tuple_is(struct gsm_auth_tuple *atuple,
39 const char *expect_str)
40{
41 int l, l1, l2;
42 int i;
43 char *tuple_str = auth_tuple_str(atuple);
44 bool same = (strcmp(expect_str, tuple_str) == 0);
45 if (!same) {
46 l1 = strlen(expect_str);
47 l2 = strlen(tuple_str);
48 printf("Expected %d:\n%s\nGot %d:\n%s\n",
49 l1, expect_str, l2, tuple_str);
50 l = min(l1, l2);
51 for (i = 0; i < l; i++) {
52 if (expect_str[i] != tuple_str[i]) {
53 printf("Difference at pos %d"
54 " (%c 0x%0x != %c 0x%0x)\n",
55 i, expect_str[i], expect_str[i],
56 tuple_str[i], tuple_str[i]);
57 break;
58 }
59 }
60 }
61 return same;
62}
63
Neels Hofmeyr37984bd2016-03-30 11:22:24 +020064/* override, requires '-Wl,--wrap=db_get_authinfo_for_subscr' */
65int __real_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
66 struct gsm_subscriber *subscr);
67
68int test_get_authinfo_rc = 0;
69struct gsm_auth_info test_auth_info = {0};
70struct gsm_auth_info default_auth_info = {
71 .auth_algo = AUTH_ALGO_COMP128v1,
72 .a3a8_ki_len = 16,
73 .a3a8_ki = { 0 }
74};
75
76int __wrap_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
77 struct gsm_subscriber *subscr)
78{
79 *ainfo = test_auth_info;
80 printf("wrapped: db_get_authinfo_for_subscr(): rc = %d\n", test_get_authinfo_rc);
81 return test_get_authinfo_rc;
82}
83
84/* override, requires '-Wl,--wrap=db_get_lastauthtuple_for_subscr' */
85int __real_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
86 struct gsm_subscriber *subscr);
87
88int test_get_lastauthtuple_rc = 0;
89struct gsm_auth_tuple test_last_auth_tuple = { 0 };
90struct gsm_auth_tuple default_auth_tuple = { 0 };
91
92int __wrap_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
93 struct gsm_subscriber *subscr)
94{
95 *atuple = test_last_auth_tuple;
96 printf("wrapped: db_get_lastauthtuple_for_subscr(): rc = %d\n", test_get_lastauthtuple_rc);
97 return test_get_lastauthtuple_rc;
98}
99
100/* override, requires '-Wl,--wrap=db_sync_lastauthtuple_for_subscr' */
101int __real_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
102 struct gsm_subscriber *subscr);
103int test_sync_lastauthtuple_rc = 0;
104int __wrap_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
105 struct gsm_subscriber *subscr)
106{
107 test_last_auth_tuple = *atuple;
108 printf("wrapped: db_sync_lastauthtuple_for_subscr(): rc = %d\n", test_sync_lastauthtuple_rc);
109 return test_sync_lastauthtuple_rc;
110}
111
112int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple,
113 struct gsm_subscriber *subscr,
114 int key_seq)
115{
116 int auth_action;
117 auth_action = auth_get_tuple_for_subscr(atuple, subscr, key_seq);
118 printf("auth_get_tuple_for_subscr(key_seq=%d) --> auth_action == %s\n",
119 key_seq, auth_action_str(auth_action));
120 return auth_action;
121}
122
123/* override libssl RAND_bytes() to get testable crypto results */
124int RAND_bytes(uint8_t *rand, int len)
125{
126 memset(rand, 23, len);
127 return 1;
128}
129
130static void test_error()
131{
132 int auth_action;
133
134 struct gsm_auth_tuple atuple = {0};
135 struct gsm_subscriber subscr = {0};
136 int key_seq = 0;
137
138 printf("\n* test_error()\n");
139
140 /* any error (except -ENOENT) */
141 test_get_authinfo_rc = -EIO;
142 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
143 key_seq);
Neels Hofmeyrf9b212f2016-03-30 11:22:27 +0200144 OSMO_ASSERT(auth_action == AUTH_ERROR);
Neels Hofmeyr37984bd2016-03-30 11:22:24 +0200145}
146
147static void test_auth_not_avail()
148{
149 int auth_action;
150
151 struct gsm_auth_tuple atuple = {0};
152 struct gsm_subscriber subscr = {0};
153 int key_seq = 0;
154
155 printf("\n* test_auth_not_avail()\n");
156
157 /* no entry */
158 test_get_authinfo_rc = -ENOENT;
159 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
160 key_seq);
161 OSMO_ASSERT(auth_action == AUTH_NOT_AVAIL);
162}
163
Neels Hofmeyr4554a622016-03-30 11:22:25 +0200164static void test_auth_then_ciph1()
165{
166 int auth_action;
167
168 struct gsm_auth_tuple atuple = {0};
169 struct gsm_subscriber subscr = {0};
170 int key_seq;
171
172 printf("\n* test_auth_then_ciph1()\n");
173
174 /* Ki entry, but no auth tuple negotiated yet */
175 test_auth_info = default_auth_info;
176 test_last_auth_tuple = default_auth_tuple;
177 test_get_authinfo_rc = 0;
178 test_get_lastauthtuple_rc = -ENOENT;
179 key_seq = 0;
180 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
181 key_seq);
182 OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
183 OSMO_ASSERT(auth_tuple_is(&atuple,
184 "gsm_auth_tuple {\n"
185 " .use_count = 1\n"
Neels Hofmeyrcf1302e2016-03-30 11:22:30 +0200186 " .key_seq = 0\n"
187 " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
188 " .sres = a1 ab c6 90 \n"
189 " .kc = 0f 27 ed f3 ac 97 ac 00 \n"
190 "}\n"
191 ));
192
193 /* With a different last saved key_seq stored in the out-arg of
194 * db_get_lastauthtuple_for_subscr() by coincidence, expect absolutely
195 * the same as above. */
196 test_auth_info = default_auth_info;
197 test_last_auth_tuple = default_auth_tuple;
198 test_last_auth_tuple.key_seq = 3;
199 test_get_authinfo_rc = 0;
200 test_get_lastauthtuple_rc = -ENOENT;
201 key_seq = 0;
202 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
203 key_seq);
204 OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
205 OSMO_ASSERT(auth_tuple_is(&atuple,
206 "gsm_auth_tuple {\n"
207 " .use_count = 1\n"
208 " .key_seq = 0\n"
Neels Hofmeyr4554a622016-03-30 11:22:25 +0200209 " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
210 " .sres = a1 ab c6 90 \n"
211 " .kc = 0f 27 ed f3 ac 97 ac 00 \n"
212 "}\n"
213 ));
214}
215
216static void test_auth_then_ciph2()
217{
218 int auth_action;
219
220 struct gsm_auth_tuple atuple = {0};
221 struct gsm_subscriber subscr = {0};
222 int key_seq;
223
224 printf("\n* test_auth_then_ciph2()\n");
225
226 /* Ki entry, auth tuple negotiated, but invalid incoming key_seq */
227 test_auth_info = default_auth_info;
228 test_last_auth_tuple = default_auth_tuple;
229 test_last_auth_tuple.key_seq = 2;
230 test_get_authinfo_rc = 0;
231 test_get_lastauthtuple_rc = 0;
232 key_seq = GSM_KEY_SEQ_INVAL;
233 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
234 key_seq);
235 OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
236 OSMO_ASSERT(auth_tuple_is(&atuple,
237 "gsm_auth_tuple {\n"
238 " .use_count = 1\n"
239 " .key_seq = 3\n"
240 " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
241 " .sres = a1 ab c6 90 \n"
242 " .kc = 0f 27 ed f3 ac 97 ac 00 \n"
243 "}\n"
244 ));
245
246 /* Change the last saved key_seq, expect last_auth_tuple.key_seq + 1 */
247 test_auth_info = default_auth_info;
248 test_last_auth_tuple = default_auth_tuple;
249 test_last_auth_tuple.key_seq = 3;
250 test_get_authinfo_rc = 0;
251 test_get_lastauthtuple_rc = 0;
252 key_seq = GSM_KEY_SEQ_INVAL;
253 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
254 key_seq);
255 OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
256 OSMO_ASSERT(auth_tuple_is(&atuple,
257 "gsm_auth_tuple {\n"
258 " .use_count = 1\n"
259 " .key_seq = 4\n"
260 " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
261 " .sres = a1 ab c6 90 \n"
262 " .kc = 0f 27 ed f3 ac 97 ac 00 \n"
263 "}\n"
264 ));
265}
266
Neels Hofmeyrd617c5d2016-03-30 11:22:26 +0200267static void test_auth_reuse()
268{
269 int auth_action;
270 struct gsm_auth_tuple atuple = {0};
271 struct gsm_subscriber subscr = {0};
272 int key_seq;
273
274 printf("\n* test_auth_reuse()\n");
275
276 /* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */
277 test_auth_info = default_auth_info;
278 test_last_auth_tuple = default_auth_tuple;
279 test_last_auth_tuple.key_seq = key_seq = 3;
280 test_last_auth_tuple.use_count = 1;
281 test_get_authinfo_rc = 0;
282 test_get_lastauthtuple_rc = 0;
283 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
284 key_seq);
285 OSMO_ASSERT(auth_action == AUTH_DO_CIPH);
286 OSMO_ASSERT(auth_tuple_is(&atuple,
287 "gsm_auth_tuple {\n"
288 " .use_count = 2\n"
289 " .key_seq = 3\n"
290 " .rand = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \n"
291 " .sres = 00 00 00 00 \n"
292 " .kc = 00 00 00 00 00 00 00 00 \n"
293 "}\n"
294 ));
295}
296
Neels Hofmeyr0d929be2016-03-30 11:22:29 +0200297static void test_auth_reuse_key_seq_mismatch()
298{
299 int auth_action;
300 struct gsm_auth_tuple atuple = {0};
301 struct gsm_subscriber subscr = {0};
302 int key_seq;
303
304 printf("\n* test_auth_reuse_key_seq_mismatch()\n");
305
306 /* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */
307 test_auth_info = default_auth_info;
308 test_last_auth_tuple = default_auth_tuple;
309 test_last_auth_tuple.key_seq = 3;
310 key_seq = 4;
311 test_last_auth_tuple.use_count = 1;
312 test_get_authinfo_rc = 0;
313 test_get_lastauthtuple_rc = 0;
314 auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
315 key_seq);
316 OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
317 OSMO_ASSERT(auth_tuple_is(&atuple,
318 "gsm_auth_tuple {\n"
319 " .use_count = 1\n"
320 " .key_seq = 4\n"
321 " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
322 " .sres = a1 ab c6 90 \n"
323 " .kc = 0f 27 ed f3 ac 97 ac 00 \n"
324 "}\n"
325 ));
326}
327
Neels Hofmeyr37984bd2016-03-30 11:22:24 +0200328int main(void)
329{
330 osmo_init_logging(&log_info);
331 log_set_log_level(osmo_stderr_target, LOGL_INFO);
332
333 test_error();
334 test_auth_not_avail();
Neels Hofmeyr4554a622016-03-30 11:22:25 +0200335 test_auth_then_ciph1();
336 test_auth_then_ciph2();
Neels Hofmeyrd617c5d2016-03-30 11:22:26 +0200337 test_auth_reuse();
Neels Hofmeyr0d929be2016-03-30 11:22:29 +0200338 test_auth_reuse_key_seq_mismatch();
Neels Hofmeyr37984bd2016-03-30 11:22:24 +0200339 return 0;
340}