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
This commit is contained in:
parent
7dba11fe32
commit
7921ab1593
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue