[MERGED] osmo-hlr[master]: add db_subscr_update_aud_by_id(), complete db_subscr_delete_...

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Wed Oct 11 22:02:34 UTC 2017


Neels Hofmeyr has submitted this change and it was merged.

Change subject: add db_subscr_update_aud_by_id(), complete db_subscr_delete_by_id()
......................................................................


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
---
M src/db.c
M src/db.h
M src/db_hlr.c
M tests/db/db_test.c
M tests/db/db_test.err
5 files changed, 1,004 insertions(+), 3 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/src/db.c b/src/db.c
index 2b2c2c4..4136e39 100644
--- a/src/db.c
+++ b/src/db.c
@@ -61,6 +61,14 @@
 	[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 @@
 	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 @@
 	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 b6d224b..71f682d 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -71,6 +71,7 @@
 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];
@@ -99,10 +100,27 @@
 		     ": SQL modified %d rows (expected 1)\n", subscr_id, rc);
 		ret = -EIO;
 	}
-
-	/* FIXME: also remove authentication data from auc_2g and auc_3g */
-
 	db_remove_reset(stmt);
+
+	/* 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;
+
 	return ret;
 }
 
@@ -154,6 +172,192 @@
 
 }
 
+/* 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 @@
 	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 @@
 	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 @@
 
 ===== 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
+

-- 
To view, visit https://gerrit.osmocom.org/4185
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Icb11b5e059fb920447a9aa414db1819a0c020529
Gerrit-PatchSet: 4
Gerrit-Project: osmo-hlr
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list