summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2017-10-10 02:25:00 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-10-10 23:43:52 +0200
commita085519047f1e140084a00954cf3b6986b7ebae0 (patch)
treed36025767c9564c91110f86397f3a13103c7279c
parent21c4b1427c17ad567ef98cccc1848193bb09b617 (diff)
add db_subscr_update_aud_by_id(), complete db_subscr_delete_by_id()
Add ability to add and remove auc_2g and auc_3g table rows with db_subscr_update_aud_by_id(). In db_subscr_delete_by_id(), make sure that when deleting a subscriber, also all auth data associated with that user ID is removed as well. A newly created subscriber must not obtain the same auth tokens just by getting the same id. Depends: libosmocore Idf75946eb0a84e145adad13fc7c78bb7a267aa0a Change-Id: Icb11b5e059fb920447a9aa414db1819a0c020529
-rw-r--r--src/db.c8
-rw-r--r--src/db.h29
-rw-r--r--src/db_hlr.c208
-rw-r--r--tests/db/db_test.c280
-rw-r--r--tests/db/db_test.err480
5 files changed, 1003 insertions, 2 deletions
diff --git a/src/db.c b/src/db.c
index c8b6a0c..50c192d 100644
--- a/src/db.c
+++ b/src/db.c
@@ -61,6 +61,14 @@ static const char *stmt_sql[] = {
[DB_STMT_SUBSCR_CREATE] = "INSERT INTO subscriber (imsi) VALUES ($imsi)",
[DB_STMT_DEL_BY_ID] = "DELETE FROM subscriber WHERE id = $subscriber_id",
[DB_STMT_SET_MSISDN_BY_IMSI] = "UPDATE subscriber SET msisdn = $msisdn WHERE imsi = $imsi",
+ [DB_STMT_AUC_2G_INSERT] =
+ "INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki)"
+ " VALUES($subscriber_id, $algo_id_2g, $ki)",
+ [DB_STMT_AUC_2G_DELETE] = "DELETE FROM auc_2g WHERE subscriber_id = $subscriber_id",
+ [DB_STMT_AUC_3G_INSERT] =
+ "INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, op, opc, ind_bitlen)"
+ " VALUES($subscriber_id, $algo_id_3g, $k, $op, $opc, $ind_bitlen)",
+ [DB_STMT_AUC_3G_DELETE] = "DELETE FROM auc_3g WHERE subscriber_id = $subscriber_id",
};
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
diff --git a/src/db.h b/src/db.h
index 2e6cc9b..f6aaa58 100644
--- a/src/db.h
+++ b/src/db.h
@@ -18,6 +18,10 @@ enum stmt_idx {
DB_STMT_SUBSCR_CREATE,
DB_STMT_DEL_BY_ID,
DB_STMT_SET_MSISDN_BY_IMSI,
+ DB_STMT_AUC_2G_INSERT,
+ DB_STMT_AUC_2G_DELETE,
+ DB_STMT_AUC_3G_INSERT,
+ DB_STMT_AUC_3G_DELETE,
_NUM_DB_STMT
};
@@ -78,11 +82,36 @@ struct hlr_subscriber {
bool ms_purged_ps;
};
+/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation.
+ * This is useful because SQLite requires them in hexdump format, and callers
+ * like the VTY and CTRL interface also have them available as hexdump to begin
+ * with. In the binary format, a VTY command would first need to hexparse,
+ * after which the db function would again hexdump, copying to separate
+ * buffers. The roundtrip can be saved by providing char* to begin with. */
+struct sub_auth_data_str {
+ enum osmo_sub_auth_type type;
+ enum osmo_auth_algo algo;
+ union {
+ struct {
+ const char *opc;
+ const char *k;
+ uint64_t sqn;
+ int opc_is_op;
+ unsigned int ind_bitlen;
+ } umts;
+ struct {
+ const char *ki;
+ } gsm;
+ } u;
+};
+
int db_subscr_create(struct db_context *dbc, const char *imsi);
int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id);
int db_subscr_update_msisdn_by_imsi(struct db_context *dbc, const char *imsi,
const char *msisdn);
+int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
+ const struct sub_auth_data_str *aud);
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
struct hlr_subscriber *subscr);
diff --git a/src/db_hlr.c b/src/db_hlr.c
index 194cd35..612de86 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -70,6 +70,7 @@ int db_subscr_create(struct db_context *dbc, const char *imsi)
int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
{
int rc;
+ struct sub_auth_data_str aud;
int ret = 0;
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_DEL_BY_ID];
@@ -98,10 +99,27 @@ int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
": SQL modified %d rows (expected 1)\n", subscr_id, rc);
ret = -EIO;
}
+ db_remove_reset(stmt);
- /* FIXME: also remove authentication data from auc_2g and auc_3g */
+ /* make sure to remove authentication data for this subscriber id, for
+ * both 2G and 3G. */
+
+ aud = (struct sub_auth_data_str){
+ .type = OSMO_AUTH_TYPE_GSM,
+ .algo = OSMO_AUTH_ALG_NONE,
+ };
+ rc = db_subscr_update_aud_by_id(dbc, subscr_id, &aud);
+ if (ret == -ENOENT && !rc)
+ ret = 0;
+
+ aud = (struct sub_auth_data_str){
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_NONE,
+ };
+ rc = db_subscr_update_aud_by_id(dbc, subscr_id, &aud);
+ if (ret == -ENOENT && !rc)
+ ret = 0;
- db_remove_reset(stmt);
return ret;
}
@@ -153,6 +171,192 @@ out:
}
+/* Insert or update 2G or 3G authentication tokens in the database.
+ * If aud->type is OSMO_AUTH_TYPE_GSM, the auc_2g table entry for the
+ * subscriber will be added or modified; if aud->algo is OSMO_AUTH_ALG_NONE,
+ * however, the auc_2g entry for the subscriber is deleted. If aud->type is
+ * OSMO_AUTH_TYPE_UMTS, the auc_3g table is updated; again, if aud->algo is
+ * OSMO_AUTH_ALG_NONE, the auc_3g entry is deleted.
+ * Returns 0 if successful, -EINVAL for unknown aud->type, -ENOENT for unknown
+ * subscr_id, -EIO for SQL errors.
+ */
+int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
+ const struct sub_auth_data_str *aud)
+{
+ sqlite3_stmt *stmt_del;
+ sqlite3_stmt *stmt_ins;
+ sqlite3_stmt *stmt;
+ const char *label;
+ int rc;
+ int ret = 0;
+
+ switch (aud->type) {
+ case OSMO_AUTH_TYPE_GSM:
+ label = "auc_2g";
+ stmt_del = dbc->stmt[DB_STMT_AUC_2G_DELETE];
+ stmt_ins = dbc->stmt[DB_STMT_AUC_2G_INSERT];
+
+ switch (aud->algo) {
+ case OSMO_AUTH_ALG_NONE:
+ case OSMO_AUTH_ALG_COMP128v1:
+ case OSMO_AUTH_ALG_COMP128v2:
+ case OSMO_AUTH_ALG_COMP128v3:
+ case OSMO_AUTH_ALG_XOR:
+ break;
+ case OSMO_AUTH_ALG_MILENAGE:
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " auth algo not suited for 2G: %s\n",
+ osmo_auth_alg_name(aud->algo));
+ return -EINVAL;
+ default:
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Unknown auth algo: %d\n", aud->algo);
+ return -EINVAL;
+ }
+
+ if (aud->algo == OSMO_AUTH_ALG_NONE)
+ break;
+ if (!osmo_is_hexstr(aud->u.gsm.ki, 32, 32, true)) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Invalid KI: '%s'\n", aud->u.gsm.ki);
+ return -EINVAL;
+ }
+ break;
+
+ case OSMO_AUTH_TYPE_UMTS:
+ label = "auc_3g";
+ stmt_del = dbc->stmt[DB_STMT_AUC_3G_DELETE];
+ stmt_ins = dbc->stmt[DB_STMT_AUC_3G_INSERT];
+ switch (aud->algo) {
+ case OSMO_AUTH_ALG_NONE:
+ case OSMO_AUTH_ALG_MILENAGE:
+ break;
+ case OSMO_AUTH_ALG_COMP128v1:
+ case OSMO_AUTH_ALG_COMP128v2:
+ case OSMO_AUTH_ALG_COMP128v3:
+ case OSMO_AUTH_ALG_XOR:
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " auth algo not suited for 3G: %s\n",
+ osmo_auth_alg_name(aud->algo));
+ return -EINVAL;
+ default:
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Unknown auth algo: %d\n", aud->algo);
+ return -EINVAL;
+ }
+
+ if (aud->algo == OSMO_AUTH_ALG_NONE)
+ break;
+ if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Invalid K: '%s'\n", aud->u.umts.k);
+ return -EINVAL;
+ }
+ if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
+ return -EINVAL;
+ }
+ if (aud->u.umts.ind_bitlen > OSMO_MILENAGE_IND_BITLEN_MAX) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " Invalid ind_bitlen: %d\n", aud->u.umts.ind_bitlen);
+ return -EINVAL;
+ }
+ break;
+ default:
+ LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
+ " unknown auth type: %d\n", aud->type);
+ return -EINVAL;
+ }
+
+ stmt = stmt_del;
+
+ if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
+ return -EIO;
+
+ /* execute the statement */
+ rc = sqlite3_step(stmt);
+ if (rc != SQLITE_DONE) {
+ LOGP(DAUC, LOGL_ERROR,
+ "Cannot delete %s row: SQL error: (%d) %s\n",
+ label, rc, sqlite3_errmsg(dbc->db));
+ ret = -EIO;
+ goto out;
+ }
+
+ /* verify execution result */
+ rc = sqlite3_changes(dbc->db);
+ if (!rc)
+ /* Leave "no such entry" logging to the caller -- during
+ * db_subscr_delete_by_id(), we call this to make sure it is
+ * empty, and no entry is not an error then.*/
+ ret = -ENOENT;
+ else if (rc != 1) {
+ LOGP(DAUC, LOGL_ERROR, "Delete subscriber ID=%"PRId64
+ " from %s: SQL modified %d rows (expected 1)\n",
+ subscr_id, label, rc);
+ ret = -EIO;
+ }
+
+ db_remove_reset(stmt);
+
+ /* Error situation? Return now. */
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ /* Just delete requested? */
+ if (aud->algo == OSMO_AUTH_ALG_NONE)
+ return ret;
+
+ /* Don't return -ENOENT if inserting new data. */
+ ret = 0;
+
+ /* Insert new row */
+ stmt = stmt_ins;
+
+ if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
+ return -EIO;
+
+ switch (aud->type) {
+ case OSMO_AUTH_TYPE_GSM:
+ if (!db_bind_int(stmt, "$algo_id_2g", aud->algo))
+ return -EIO;
+ if (!db_bind_text(stmt, "$ki", aud->u.gsm.ki))
+ return -EIO;
+ break;
+ case OSMO_AUTH_TYPE_UMTS:
+ if (!db_bind_int(stmt, "$algo_id_3g", aud->algo))
+ return -EIO;
+ if (!db_bind_text(stmt, "$k", aud->u.umts.k))
+ return -EIO;
+ if (!db_bind_text(stmt, "$op",
+ aud->u.umts.opc_is_op ? aud->u.umts.opc : NULL))
+ return -EIO;
+ if (!db_bind_text(stmt, "$opc",
+ aud->u.umts.opc_is_op ? NULL : aud->u.umts.opc))
+ return -EIO;
+ if (!db_bind_int(stmt, "$ind_bitlen", aud->u.umts.ind_bitlen))
+ return -EIO;
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+
+ /* execute the statement */
+ rc = sqlite3_step(stmt);
+ if (rc != SQLITE_DONE) {
+ LOGP(DAUC, LOGL_ERROR,
+ "Cannot insert %s row: SQL error: (%d) %s\n",
+ label, rc, sqlite3_errmsg(dbc->db));
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ db_remove_reset(stmt);
+ return ret;
+}
+
/* Common code for db_subscr_get_by_*() functions. */
static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscriber *subscr,
const char **err)
diff --git a/tests/db/db_test.c b/tests/db/db_test.c
index 20553ef..0442dbe 100644
--- a/tests/db/db_test.c
+++ b/tests/db/db_test.c
@@ -66,9 +66,32 @@
fprintf(stderr, "\n"); \
} while (0)
+/* Do db_get_auth_data() and verbosely assert that its return value is as expected.
+ * Print the subscriber struct to stderr to be validated by db_test.err.
+ * The results are then available in g_aud2g and g_aud3g. */
+#define ASSERT_SEL_AUD(imsi, expect_rc, expect_id) \
+ do { \
+ g_aud2g = (struct osmo_sub_auth_data){}; \
+ g_aud3g = (struct osmo_sub_auth_data){}; \
+ g_id = 0; \
+ ASSERT_RC(db_get_auth_data(dbc, imsi, &g_aud2g, &g_aud3g, &g_id), expect_rc); \
+ if (g_rc == 1) { \
+ dump_aud("2G", &g_aud2g); \
+ dump_aud("3G", &g_aud3g); \
+ }\
+ if (g_id != expect_id) {\
+ fprintf(stderr, "MISMATCH: got subscriber id %"PRId64 \
+ ", expected %"PRId64"\n", g_id, (int64_t)(expect_id)); \
+ OSMO_ASSERT(g_id == expect_id); \
+ } \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
static struct db_context *dbc = NULL;
static void *ctx = NULL;
static struct hlr_subscriber g_subscr;
+static struct osmo_sub_auth_data g_aud2g;
+static struct osmo_sub_auth_data g_aud3g;
static int g_rc;
static int64_t g_id;
@@ -385,6 +408,262 @@ static void test_subscr_create_update_sel_delete()
comment_end();
}
+static const struct sub_auth_data_str *mk_aud_2g(enum osmo_auth_algo algo,
+ const char *ki)
+{
+ static struct sub_auth_data_str aud;
+ aud = (struct sub_auth_data_str){
+ .type = OSMO_AUTH_TYPE_GSM,
+ .algo = algo,
+ .u.gsm.ki = ki,
+ };
+ return &aud;
+}
+
+static const struct sub_auth_data_str *mk_aud_3g(enum osmo_auth_algo algo,
+ const char *opc, bool opc_is_op,
+ const char *k, unsigned int ind_bitlen)
+{
+ static struct sub_auth_data_str aud;
+ aud = (struct sub_auth_data_str){
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = algo,
+ .u.umts.k = k,
+ .u.umts.opc = opc,
+ .u.umts.opc_is_op = opc_is_op ? 1 : 0,
+ .u.umts.ind_bitlen = ind_bitlen,
+ };
+ return &aud;
+}
+
+static void test_subscr_aud()
+{
+ int64_t id;
+
+ comment_start();
+
+ comment("Get auth data for non-existent subscriber");
+ ASSERT_SEL_AUD(unknown_imsi, 0, 0);
+
+ comment("Create subscriber");
+
+ ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
+ ASSERT_SEL(imsi, imsi0, 0);
+
+ id = g_subscr.id;
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+
+ comment("Set auth data, 2G only");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ /* same again */
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBeeAced1EbbedDefacedFacade")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBeddedBabeAcceededFadedDecaf")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ comment("Remove 2G auth data");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+ /* Removing nothing results in -ENOENT */
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)),
+ -ENOENT);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")),
+ 0);
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+
+ comment("Set auth data, 3G only");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", true,
+ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ /* same again */
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", true,
+ "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "Deaf0ff1ceD0d0DabbedD1ced1ceF00d", true,
+ "F1bbed0afD0eF0bD0ffed0ddF1fe0b0e", 0)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", false,
+ "DeafBeddedBabeAcceededFadedDecaf",
+ OSMO_MILENAGE_IND_BITLEN_MAX)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "CededEffacedAceFacedBadFadedBeef", false,
+ "BeefedCafeFaceAcedAddedDecadeFee", 5)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ comment("Remove 3G auth data");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+ /* Removing nothing results in -ENOENT */
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)),
+ -ENOENT);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "CededEffacedAceFacedBadFadedBeef", false,
+ "BeefedCafeFaceAcedAddedDecadeFee", 5)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_NONE,
+ "asdfasdfasd", false,
+ "asdfasdfasdf", 99999)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+
+ comment("Set auth data, 2G and 3G");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "CededEffacedAceFacedBadFadedBeef")),
+ 0);
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "BeefedCafeFaceAcedAddedDecadeFee", false,
+ "DeafBeddedBabeAcceededFadedDecaf", 5)),
+ 0);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+
+ comment("Set invalid auth data");
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(99999, "f000000000000f00000000000f000000")),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_2g(OSMO_AUTH_ALG_MILENAGE, "0123456789abcdef0123456789abcdef")),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "0f000000000000f00000000000f000000", false,
+ "f000000000000f00000000000f000000", 5)),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "f000000000000f00000000000f000000", false,
+ "000000000000f00000000000f000000", 5)),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "f000000000000f00000000000f000000", false,
+ "f000000000000f00000000000f000000",
+ OSMO_MILENAGE_IND_BITLEN_MAX + 1)),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "X000000000000f00000000000f000000", false,
+ "f000000000000f00000000000f000000", 5)),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
+ mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
+ "f000000000000f00000000000f000000", false,
+ "f000000000000 f00000000000 f000000", 5)),
+ -EINVAL);
+ ASSERT_SEL_AUD(imsi0, 1, id);
+
+ comment("Delete subscriber");
+
+ ASSERT_SEL(imsi, imsi0, 0);
+ ASSERT_RC(db_subscr_delete_by_id(dbc, id), 0);
+ ASSERT_SEL(imsi, imsi0, -ENOENT);
+
+ comment("Re-add subscriber and verify auth data didn't come back");
+
+ ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
+ ASSERT_SEL(imsi, imsi0, 0);
+
+ /* For this test to work, we want to get the same subscriber ID back,
+ * and make sure there are no auth data leftovers for this ID. */
+ OSMO_ASSERT(id == g_subscr.id);
+ ASSERT_SEL_AUD(imsi0, -1, id);
+
+ ASSERT_RC(db_subscr_delete_by_id(dbc, id), 0);
+ ASSERT_SEL(imsi, imsi0, -ENOENT);
+
+ comment_end();
+}
+
static struct {
bool verbose;
} cmdline_opts = {
@@ -459,6 +738,7 @@ int main(int argc, char **argv)
OSMO_ASSERT(dbc);
test_subscr_create_update_sel_delete();
+ test_subscr_aud();
printf("Done\n");
return 0;
diff --git a/tests/db/db_test.err b/tests/db/db_test.err
index 59b9ba1..5d3ab5f 100644
--- a/tests/db/db_test.err
+++ b/tests/db/db_test.err
@@ -711,3 +711,483 @@ DAUC Cannot read subscriber from db: IMSI='123456': No such subscriber
===== test_subscr_create_update_sel_delete: SUCCESS
+
+===== test_subscr_aud
+
+--- Get auth data for non-existent subscriber
+
+db_get_auth_data(dbc, unknown_imsi, &g_aud2g, &g_aud3g, &g_id) --> 0
+DAUC IMSI='999999999': No such subscriber
+
+
+
+--- Create subscriber
+
+db_subscr_create(dbc, imsi0) --> 0
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
+struct hlr_subscriber {
+ .id = 1,
+ .imsi = '123456789000000',
+}
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+
+--- Set auth data, 2G only
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v1,
+ .u.gsm.ki = '0123456789abcdef0123456789abcdef',
+}
+3G: none
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v1,
+ .u.gsm.ki = '0123456789abcdef0123456789abcdef',
+}
+3G: none
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBeeAced1EbbedDefacedFacade")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v2,
+ .u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
+}
+3G: none
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBeddedBabeAcceededFadedDecaf")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
+}
+3G: none
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = XOR,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: none
+
+
+--- Remove 2G auth data
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = XOR,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: none
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+
+--- Set auth data, 3G only
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 1,
+ .u.umts.k = 'c01ffedc1cadaeac1d1f1edacac1ab0a',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 1,
+ .u.umts.k = 'c01ffedc1cadaeac1d1f1edacac1ab0a',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "Deaf0ff1ceD0d0DabbedD1ced1ceF00d", true, "F1bbed0afD0eF0bD0ffed0ddF1fe0b0e", 0)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
+ .u.umts.opc_is_op = 1,
+ .u.umts.k = 'f1bbed0afd0ef0bd0ffed0ddf1fe0b0e',
+ .u.umts.amf = '0000',
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", false, "DeafBeddedBabeAcceededFadedDecaf", OSMO_MILENAGE_IND_BITLEN_MAX)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 28,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "CededEffacedAceFacedBadFadedBeef", false, "BeefedCafeFaceAcedAddedDecadeFee", 5)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+
+--- Remove 3G auth data
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> -ENOENT
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "CededEffacedAceFacedBadFadedBeef", false, "BeefedCafeFaceAcedAddedDecadeFee", 5)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+DAUC IMSI='123456789000000': No 2G Auth Data
+
+2G: none
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, "asdfasdfasd", false, "asdfasdfasdf", 99999)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+
+--- Set auth data, 2G and 3G
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "CededEffacedAceFacedBadFadedBeef")) --> 0
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", false, "DeafBeddedBabeAcceededFadedDecaf", 5)) --> 0
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+
+--- Set invalid auth data
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(99999, "f000000000000f00000000000f000000")) --> -EINVAL
+DAUC Cannot update auth tokens: Unknown auth algo: 99999
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid KI: 'f00'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_MILENAGE, "0123456789abcdef0123456789abcdef")) --> -EINVAL
+DAUC Cannot update auth tokens: auth algo not suited for 2G: MILENAGE
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "0f000000000000f00000000000f000000", false, "f000000000000f00000000000f000000", 5)) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid OP/OPC: '0f000000000000f00000000000f000000'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "f000000000000f00000000000f000000", false, "000000000000f00000000000f000000", 5)) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid K: '000000000000f00000000000f000000'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "f000000000000f00000000000f000000", false, "f000000000000f00000000000f000000", OSMO_MILENAGE_IND_BITLEN_MAX + 1)) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid ind_bitlen: 29
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "X000000000000f00000000000f000000", false, "f000000000000f00000000000f000000", 5)) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid OP/OPC: 'X000000000000f00000000000f000000'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "f000000000000f00000000000f000000", false, "f000000000000 f00000000000 f000000", 5)) --> -EINVAL
+DAUC Cannot update auth tokens: Invalid K: 'f000000000000 f00000000000 f000000'
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 1
+
+2G: struct osmo_sub_auth_data {
+ .type = GSM,
+ .algo = COMP128v3,
+ .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
+}
+3G: struct osmo_sub_auth_data {
+ .type = UMTS,
+ .algo = MILENAGE,
+ .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
+ .u.umts.opc_is_op = 0,
+ .u.umts.k = 'deafbeddedbabeacceededfadeddecaf',
+ .u.umts.amf = '0000',
+ .u.umts.ind_bitlen = 5,
+}
+
+
+--- Delete subscriber
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
+struct hlr_subscriber {
+ .id = 1,
+ .imsi = '123456789000000',
+}
+
+db_subscr_delete_by_id(dbc, id) --> 0
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
+DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
+
+
+--- Re-add subscriber and verify auth data didn't come back
+
+db_subscr_create(dbc, imsi0) --> 0
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
+struct hlr_subscriber {
+ .id = 1,
+ .imsi = '123456789000000',
+}
+
+db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -1
+DAUC IMSI='123456789000000': No 2G Auth Data
+DAUC IMSI='123456789000000': No 3G Auth Data
+
+
+db_subscr_delete_by_id(dbc, id) --> 0
+
+db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
+DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
+
+===== test_subscr_aud: SUCCESS
+