diff options
Diffstat (limited to 'openbsc/tests/mm_auth')
-rw-r--r-- | openbsc/tests/mm_auth/Makefile.am | 21 | ||||
-rw-r--r-- | openbsc/tests/mm_auth/mm_auth_test.c | 340 | ||||
-rw-r--r-- | openbsc/tests/mm_auth/mm_auth_test.ok | 40 |
3 files changed, 401 insertions, 0 deletions
diff --git a/openbsc/tests/mm_auth/Makefile.am b/openbsc/tests/mm_auth/Makefile.am new file mode 100644 index 000000000..516df0007 --- /dev/null +++ b/openbsc/tests/mm_auth/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall \ + $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) \ + $(LIBCRYPTO_CFLAGS) + +noinst_PROGRAMS = mm_auth_test + +EXTRA_DIST = mm_auth_test.ok + +mm_auth_test_SOURCES = mm_auth_test.c + +mm_auth_test_LDFLAGS = \ + -Wl,--wrap=db_get_authinfo_for_subscr \ + -Wl,--wrap=db_get_lastauthtuple_for_subscr \ + -Wl,--wrap=db_sync_lastauthtuple_for_subscr + +mm_auth_test_LDADD = $(top_builddir)/src/libmsc/libmsc.a \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) diff --git a/openbsc/tests/mm_auth/mm_auth_test.c b/openbsc/tests/mm_auth/mm_auth_test.c new file mode 100644 index 000000000..34d96f187 --- /dev/null +++ b/openbsc/tests/mm_auth/mm_auth_test.c @@ -0,0 +1,340 @@ +#include <stdbool.h> + +#include <osmocom/core/application.h> +#include <osmocom/core/logging.h> + +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/auth.h> + +#define min(A,B) ((A)>(B)? (B) : (A)) + +static char *auth_tuple_str(struct gsm_auth_tuple *atuple) +{ + static char buf[256]; + char *pos = buf; + int len = sizeof(buf); + int l; + +#define print2buf(FMT, args...) do {\ + l = snprintf(pos, len, FMT, ## args); \ + pos += l;\ + len -= l;\ + } while (0) + + print2buf("gsm_auth_tuple {\n"); + print2buf(" .use_count = %d\n", atuple->use_count); + print2buf(" .key_seq = %d\n", atuple->key_seq); + print2buf(" .rand = %s\n", osmo_hexdump(atuple->rand, sizeof(atuple->rand))); + print2buf(" .sres = %s\n", osmo_hexdump(atuple->sres, sizeof(atuple->sres))); + print2buf(" .kc = %s\n", osmo_hexdump(atuple->kc, sizeof(atuple->kc))); + print2buf("}\n"); +#undef print2buf + + return buf; +} + +static bool auth_tuple_is(struct gsm_auth_tuple *atuple, + const char *expect_str) +{ + int l, l1, l2; + int i; + char *tuple_str = auth_tuple_str(atuple); + bool same = (strcmp(expect_str, tuple_str) == 0); + if (!same) { + l1 = strlen(expect_str); + l2 = strlen(tuple_str); + printf("Expected %d:\n%s\nGot %d:\n%s\n", + l1, expect_str, l2, tuple_str); + l = min(l1, l2); + for (i = 0; i < l; i++) { + if (expect_str[i] != tuple_str[i]) { + printf("Difference at pos %d" + " (%c 0x%0x != %c 0x%0x)\n", + i, expect_str[i], expect_str[i], + tuple_str[i], tuple_str[i]); + break; + } + } + } + return same; +} + +/* override, requires '-Wl,--wrap=db_get_authinfo_for_subscr' */ +int __real_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr); + +int test_get_authinfo_rc = 0; +struct gsm_auth_info test_auth_info = {0}; +struct gsm_auth_info default_auth_info = { + .auth_algo = AUTH_ALGO_COMP128v1, + .a3a8_ki_len = 16, + .a3a8_ki = { 0 } +}; + +int __wrap_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo, + struct gsm_subscriber *subscr) +{ + *ainfo = test_auth_info; + printf("wrapped: db_get_authinfo_for_subscr(): rc = %d\n", test_get_authinfo_rc); + return test_get_authinfo_rc; +} + +/* override, requires '-Wl,--wrap=db_get_lastauthtuple_for_subscr' */ +int __real_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr); + +int test_get_lastauthtuple_rc = 0; +struct gsm_auth_tuple test_last_auth_tuple = { 0 }; +struct gsm_auth_tuple default_auth_tuple = { 0 }; + +int __wrap_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr) +{ + *atuple = test_last_auth_tuple; + printf("wrapped: db_get_lastauthtuple_for_subscr(): rc = %d\n", test_get_lastauthtuple_rc); + return test_get_lastauthtuple_rc; +} + +/* override, requires '-Wl,--wrap=db_sync_lastauthtuple_for_subscr' */ +int __real_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr); +int test_sync_lastauthtuple_rc = 0; +int __wrap_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr) +{ + test_last_auth_tuple = *atuple; + printf("wrapped: db_sync_lastauthtuple_for_subscr(): rc = %d\n", test_sync_lastauthtuple_rc); + return test_sync_lastauthtuple_rc; +} + +int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple, + struct gsm_subscriber *subscr, + int key_seq) +{ + int auth_action; + auth_action = auth_get_tuple_for_subscr(atuple, subscr, key_seq); + printf("auth_get_tuple_for_subscr(key_seq=%d) --> auth_action == %s\n", + key_seq, auth_action_str(auth_action)); + return auth_action; +} + +/* override libssl RAND_bytes() to get testable crypto results */ +int RAND_bytes(uint8_t *rand, int len) +{ + memset(rand, 23, len); + return 1; +} + +static void test_error() +{ + int auth_action; + + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq = 0; + + printf("\n* test_error()\n"); + + /* any error (except -ENOENT) */ + test_get_authinfo_rc = -EIO; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_ERROR); +} + +static void test_auth_not_avail() +{ + int auth_action; + + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq = 0; + + printf("\n* test_auth_not_avail()\n"); + + /* no entry */ + test_get_authinfo_rc = -ENOENT; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_NOT_AVAIL); +} + +static void test_auth_then_ciph1() +{ + int auth_action; + + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq; + + printf("\n* test_auth_then_ciph1()\n"); + + /* Ki entry, but no auth tuple negotiated yet */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = -ENOENT; + key_seq = 0; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 1\n" + " .key_seq = 0\n" + " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n" + " .sres = a1 ab c6 90 \n" + " .kc = 0f 27 ed f3 ac 97 ac 00 \n" + "}\n" + )); + + /* With a different last saved key_seq stored in the out-arg of + * db_get_lastauthtuple_for_subscr() by coincidence, expect absolutely + * the same as above. */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_last_auth_tuple.key_seq = 3; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = -ENOENT; + key_seq = 0; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 1\n" + " .key_seq = 0\n" + " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n" + " .sres = a1 ab c6 90 \n" + " .kc = 0f 27 ed f3 ac 97 ac 00 \n" + "}\n" + )); +} + +static void test_auth_then_ciph2() +{ + int auth_action; + + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq; + + printf("\n* test_auth_then_ciph2()\n"); + + /* Ki entry, auth tuple negotiated, but invalid incoming key_seq */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_last_auth_tuple.key_seq = 2; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = 0; + key_seq = GSM_KEY_SEQ_INVAL; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 1\n" + " .key_seq = 3\n" + " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n" + " .sres = a1 ab c6 90 \n" + " .kc = 0f 27 ed f3 ac 97 ac 00 \n" + "}\n" + )); + + /* Change the last saved key_seq, expect last_auth_tuple.key_seq + 1 */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_last_auth_tuple.key_seq = 3; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = 0; + key_seq = GSM_KEY_SEQ_INVAL; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 1\n" + " .key_seq = 4\n" + " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n" + " .sres = a1 ab c6 90 \n" + " .kc = 0f 27 ed f3 ac 97 ac 00 \n" + "}\n" + )); +} + +static void test_auth_reuse() +{ + int auth_action; + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq; + + printf("\n* test_auth_reuse()\n"); + + /* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_last_auth_tuple.key_seq = key_seq = 3; + test_last_auth_tuple.use_count = 1; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = 0; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 2\n" + " .key_seq = 3\n" + " .rand = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \n" + " .sres = 00 00 00 00 \n" + " .kc = 00 00 00 00 00 00 00 00 \n" + "}\n" + )); +} + +static void test_auth_reuse_key_seq_mismatch() +{ + int auth_action; + struct gsm_auth_tuple atuple = {0}; + struct gsm_subscriber subscr = {0}; + int key_seq; + + printf("\n* test_auth_reuse_key_seq_mismatch()\n"); + + /* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */ + test_auth_info = default_auth_info; + test_last_auth_tuple = default_auth_tuple; + test_last_auth_tuple.key_seq = 3; + key_seq = 4; + test_last_auth_tuple.use_count = 1; + test_get_authinfo_rc = 0; + test_get_lastauthtuple_rc = 0; + auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr, + key_seq); + OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH); + OSMO_ASSERT(auth_tuple_is(&atuple, + "gsm_auth_tuple {\n" + " .use_count = 1\n" + " .key_seq = 4\n" + " .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n" + " .sres = a1 ab c6 90 \n" + " .kc = 0f 27 ed f3 ac 97 ac 00 \n" + "}\n" + )); +} + +int main(void) +{ + osmo_init_logging(&log_info); + log_set_log_level(osmo_stderr_target, LOGL_INFO); + + test_error(); + test_auth_not_avail(); + test_auth_then_ciph1(); + test_auth_then_ciph2(); + test_auth_reuse(); + test_auth_reuse_key_seq_mismatch(); + return 0; +} diff --git a/openbsc/tests/mm_auth/mm_auth_test.ok b/openbsc/tests/mm_auth/mm_auth_test.ok new file mode 100644 index 000000000..6c49f97b7 --- /dev/null +++ b/openbsc/tests/mm_auth/mm_auth_test.ok @@ -0,0 +1,40 @@ + +* test_error() +wrapped: db_get_authinfo_for_subscr(): rc = -5 +auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_ERROR + +* test_auth_not_avail() +wrapped: db_get_authinfo_for_subscr(): rc = -2 +auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_NOT_AVAIL + +* test_auth_then_ciph1() +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = -2 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_DO_AUTH_THEN_CIPH +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = -2 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_DO_AUTH_THEN_CIPH + +* test_auth_then_ciph2() +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = 0 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=7) --> auth_action == AUTH_DO_AUTH_THEN_CIPH +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = 0 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=7) --> auth_action == AUTH_DO_AUTH_THEN_CIPH + +* test_auth_reuse() +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = 0 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=3) --> auth_action == AUTH_DO_CIPH + +* test_auth_reuse_key_seq_mismatch() +wrapped: db_get_authinfo_for_subscr(): rc = 0 +wrapped: db_get_lastauthtuple_for_subscr(): rc = 0 +wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0 +auth_get_tuple_for_subscr(key_seq=4) --> auth_action == AUTH_DO_AUTH_THEN_CIPH |