diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-12-08 15:52:00 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-12-24 16:50:16 +0100 |
commit | 7921ab1593f45f12588e074ad1280472416ae930 (patch) | |
tree | 4eaed783c52f5a24d07c1521886469b3282d08bf | |
parent | 7dba11fe32615fb5e49fae0a3bbd787ce4abc9b7 (diff) |
sgsn: Add support for authentication triplets
This commit add data structures, functions, initialization, and VTY
commands for per subscriber authentication triplets.
The following VTY command is added:
- update-subscriber imsi IMSI \
insert auth-triplet <1-5> sres SRES rand RAND kc KC
Note that the triplets are not really used by the SGSN yet.
Sponsored-by: On-Waves ehf
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 4 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 4 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_auth.c | 37 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 79 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 65 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.ok | 1 |
6 files changed, 189 insertions, 1 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index d3cd8bb2f..411462b07 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -273,6 +273,8 @@ struct imsi_acl_entry { struct sgsn_subscriber_data { struct sgsn_mm_ctx *mm; + struct gsm_auth_tuple auth_triplets[5]; + int auth_triplets_updated; int authenticate; }; @@ -288,6 +290,8 @@ int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg); int sgsn_auth_request(struct sgsn_mm_ctx *mm); enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm); void sgsn_auth_update(struct sgsn_mm_ctx *mm); +struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, + unsigned key_seq); /* * GPRS subscriber data diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c index cf0af9083..16753315c 100644 --- a/openbsc/src/gprs/gprs_subscriber.c +++ b/openbsc/src/gprs/gprs_subscriber.c @@ -36,9 +36,13 @@ void gprs_subscr_init(struct sgsn_instance *sgi) static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx) { struct sgsn_subscriber_data *sdata; + int idx; sdata = talloc_zero(ctx, struct sgsn_subscriber_data); + for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++) + sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL; + return sdata; } diff --git a/openbsc/src/gprs/sgsn_auth.c b/openbsc/src/gprs/sgsn_auth.c index 5f90f5cbd..b065c061a 100644 --- a/openbsc/src/gprs/sgsn_auth.c +++ b/openbsc/src/gprs/sgsn_auth.c @@ -203,3 +203,40 @@ void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) break; } } + +struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, + unsigned key_seq) +{ + unsigned count; + unsigned idx; + struct gsm_auth_tuple *at = NULL; + + struct sgsn_subscriber_data *sdata; + + if (!mmctx->subscr) + return NULL; + + if (key_seq == GSM_KEY_SEQ_INVAL) + /* Start with 0 after increment module array size */ + idx = ARRAY_SIZE(sdata->auth_triplets) - 1; + else + idx = key_seq; + + sdata = mmctx->subscr->sgsn_data; + + /* Find next tuple */ + for (count = ARRAY_SIZE(sdata->auth_triplets); count > 0; count--) { + idx = (idx + 1) % ARRAY_SIZE(sdata->auth_triplets); + + if (sdata->auth_triplets[idx].key_seq == GSM_KEY_SEQ_INVAL) + continue; + + if (sdata->auth_triplets[idx].use_count == 0) { + at = &sdata->auth_triplets[idx]; + at->use_count = 1; + return at; + } + } + + return NULL; +} diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 4bb6a86a4..99c59853b 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -380,6 +380,8 @@ DEFUN(cfg_auth_policy, cfg_auth_policy_cmd, static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, int pending) { char expire_time[200]; + struct gsm_auth_tuple *at; + int at_idx; vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, subscr->authorized, VTY_NEWLINE); @@ -398,6 +400,25 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, if (strlen(subscr->equipment.imei) > 0) vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE); + for (at_idx = 0; at_idx < ARRAY_SIZE(subscr->sgsn_data->auth_triplets); + at_idx++) { + at = &subscr->sgsn_data->auth_triplets[at_idx]; + if (at->key_seq == GSM_KEY_SEQ_INVAL) + continue; + + vty_out(vty, " A3A8 tuple (used %d times): ", + at->use_count); + vty_out(vty, " seq # : %d, ", + at->key_seq); + vty_out(vty, " RAND : %s, ", + osmo_hexdump(at->rand, sizeof(at->rand))); + vty_out(vty, " SRES : %s, ", + osmo_hexdump(at->sres, sizeof(at->sres))); + vty_out(vty, " Kc : %s%s", + osmo_hexdump(at->kc, sizeof(at->kc)), + VTY_NEWLINE); + } + /* print the expiration time of a subscriber */ if (subscr->expire_lu) { strftime(expire_time, sizeof(expire_time), @@ -440,10 +461,12 @@ DEFUN(show_subscr_cache, "Use the IMSI to select the subscriber\n" \ "The IMSI\n" +#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n" + DEFUN(update_subscr_insert, update_subscr_insert_cmd, UPDATE_SUBSCR_STR "insert (authorized|authenticate) (0|1)", UPDATE_SUBSCR_HELP - "Insert data into the subscriber record\n" + UPDATE_SUBSCR_INSERT_HELP "Authorize the subscriber to attach\n" "New option value\n") { @@ -469,6 +492,59 @@ DEFUN(update_subscr_insert, update_subscr_insert_cmd, return CMD_SUCCESS; } +DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd, + UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC", + UPDATE_SUBSCR_HELP + UPDATE_SUBSCR_INSERT_HELP + "Update authentication triplet\n" + "Triplet index\n" + "Set SRES value\nSRES value (4 byte) in hex\n" + "Set RAND value\nRAND value (16 byte) in hex\n" + "Set Kc value\nKc value (8 byte) in hex\n") +{ + const char *imsi = argv[0]; + const int cksn = atoi(argv[1]) - 1; + const char *sres_str = argv[2]; + const char *rand_str = argv[3]; + const char *kc_str = argv[4]; + struct gsm_auth_tuple at = {0,}; + + struct gsm_subscriber *subscr; + + subscr = gprs_subscr_get_or_create(imsi); + if (!subscr) { + vty_out(vty, "%% unable get subscriber record for %s\n", imsi); + return CMD_WARNING; + } + + OSMO_ASSERT(subscr->sgsn_data); + + if (!osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) { + vty_out(vty, "%% invalid SRES value '%s'\n", sres_str); + goto failed; + } + if (!osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) { + vty_out(vty, "%% invalid RAND value '%s'\n", rand_str); + goto failed; + } + if (!osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) { + vty_out(vty, "%% invalid Kc value '%s'\n", kc_str); + goto failed; + } + at.key_seq = cksn; + + subscr->sgsn_data->auth_triplets[cksn] = at; + subscr->sgsn_data->auth_triplets_updated = 1; + + subscr_put(subscr); + + return CMD_SUCCESS; + +failed: + subscr_put(subscr); + return CMD_SUCCESS; +} + DEFUN(update_subscr_cancel, update_subscr_cancel_cmd, UPDATE_SUBSCR_STR "cancel", UPDATE_SUBSCR_HELP @@ -521,6 +597,7 @@ int sgsn_vty_init(void) install_element_ve(&show_subscr_cache_cmd); install_element(ENABLE_NODE, &update_subscr_insert_cmd); + install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd); install_element(ENABLE_NODE, &update_subscr_cancel_cmd); install_element(ENABLE_NODE, &update_subscr_commit_cmd); diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index f5f68206b..b4f6fdb74 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -249,6 +249,70 @@ static void test_subscriber(void) update_subscriber_data_cb = __real_sgsn_update_subscriber_data; } +static void test_auth_triplets(void) +{ + struct gsm_subscriber *s1, *s1found; + const char *imsi1 = "1234567890"; + struct gsm_auth_tuple *at; + struct sgsn_mm_ctx *ctx; + struct gprs_ra_id raid = { 0, }; + uint32_t local_tlli = 0xffeeddcc; + struct gprs_llc_llme *llme; + + printf("Testing authentication triplet handling\n"); + + /* Check for emptiness */ + OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); + + /* Allocate entry 1 */ + s1 = gprs_subscr_get_or_create(imsi1); + s1->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; + s1found = gprs_subscr_get_by_imsi(imsi1); + OSMO_ASSERT(s1found == s1); + subscr_put(s1found); + + /* Create a context */ + OSMO_ASSERT(count(gprs_llme_list()) == 0); + ctx = alloc_mm_ctx(local_tlli, &raid); + + /* Attach s1 to ctx */ + ctx->subscr = subscr_get(s1); + ctx->subscr->sgsn_data->mm = ctx; + + /* Try to get auth tuple */ + at = sgsn_auth_get_tuple(ctx, GSM_KEY_SEQ_INVAL); + OSMO_ASSERT(at == NULL); + + /* Add triplets */ + s1->sgsn_data->auth_triplets[0].key_seq = 0; + s1->sgsn_data->auth_triplets[1].key_seq = 1; + s1->sgsn_data->auth_triplets[2].key_seq = 2; + + /* Try to get auth tuple */ + at = sgsn_auth_get_tuple(ctx, GSM_KEY_SEQ_INVAL); + OSMO_ASSERT(at != NULL); + OSMO_ASSERT(at->key_seq == 0); + OSMO_ASSERT(at->use_count == 1); + at = sgsn_auth_get_tuple(ctx, at->key_seq); + OSMO_ASSERT(at != NULL); + OSMO_ASSERT(at->key_seq == 1); + OSMO_ASSERT(at->use_count == 1); + at = sgsn_auth_get_tuple(ctx, at->key_seq); + OSMO_ASSERT(at != NULL); + OSMO_ASSERT(at->key_seq == 2); + OSMO_ASSERT(at->use_count == 1); + at = sgsn_auth_get_tuple(ctx, at->key_seq); + OSMO_ASSERT(at == NULL); + + /* Free MM context and subscriber */ + subscr_put(s1); + llme = ctx->llme; + sgsn_mm_ctx_free(ctx); + s1found = gprs_subscr_get_by_imsi(imsi1); + OSMO_ASSERT(s1found == NULL); + gprs_llgmm_assign(llme, local_tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL); +} + /* * Test that a GMM Detach will remove the MMCTX and the * associated LLME. @@ -1159,6 +1223,7 @@ int main(int argc, char **argv) test_llme(); test_subscriber(); + test_auth_triplets(); test_gmm_detach(); test_gmm_detach_power_off(); test_gmm_detach_no_mmctx(); diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index 7d739add4..eff47c423 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -1,5 +1,6 @@ Testing LLME allocations Testing core subscriber data API +Testing authentication triplet handling Testing GMM detach Testing GMM detach (power off) Testing GMM detach (no MMCTX) |