laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-hlr/+/33098 )
Change subject: db: extend database schema to support 256bit K and/or OP[c] values ......................................................................
db: extend database schema to support 256bit K and/or OP[c] values
Other UMTS AKA algorithms than MILENAGE (notably TUAK) support K sizes of up to 256bit, or mandate a OP/OPc size of 256 bit.
Let's extend our database schema to accommodate such larger sizes.
Change-Id: Ibbde68484c904507a15c35cbfdf88cd47d0c7039 --- M sql/hlr.sql M src/ctrl.c M src/db.c M src/db_hlr.c M src/hlr_vty_subscr.c M tests/db_upgrade/db_upgrade_test.ok M tests/test_subscriber.vty 7 files changed, 96 insertions(+), 31 deletions(-)
Approvals: laforge: Looks good to me, approved pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/sql/hlr.sql b/sql/hlr.sql index e855a6c..4c87f43 100644 --- a/sql/hlr.sql +++ b/sql/hlr.sql @@ -71,9 +71,9 @@ CREATE TABLE auc_3g ( subscriber_id INTEGER PRIMARY KEY, -- subscriber.id algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value - k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit) - op VARCHAR(32), -- hex string: operator's secret key (128bit) - opc VARCHAR(32), -- hex string: derived from OP and K (128bit) + k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit) + op VARCHAR(64), -- hex string: operator's secret key (128/256bit) + opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit) sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage -- nr of index bits at lower SQN end ind_bitlen INTEGER NOT NULL DEFAULT 5 @@ -91,4 +91,4 @@
-- Set HLR database schema version number -- Note: This constant is currently duplicated in src/db.c and must be kept in sync! -PRAGMA user_version = 6; +PRAGMA user_version = 7; diff --git a/src/ctrl.c b/src/ctrl.c index f0f2ee6..e04195d 100644 --- a/src/ctrl.c +++ b/src/ctrl.c @@ -39,7 +39,7 @@ #define SEL_BY_ID SEL_BY "id-"
extern bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo, - int *minlen, int *maxlen); + int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc);
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
@@ -550,7 +550,7 @@ } if (strcmp(tok, "none") == 0) { aud2g.algo = OSMO_AUTH_ALG_NONE; - } else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen)) { + } else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) { cmd->reply = "Unknown auth algorithm."; return CTRL_CMD_ERROR; } @@ -630,8 +630,8 @@ struct hlr *hlr = data; const char *by_selector = cmd->node; char *tmp = NULL, *tok, *saveptr; - int minlen = 0; - int maxlen = 0; + int minlen = 0, minlen_opc = 0; + int maxlen = 0, maxlen_opc = 0; struct sub_auth_data_str aud3g = { .type = OSMO_AUTH_TYPE_UMTS, .u.umts = { @@ -657,7 +657,7 @@ } if (strcmp(tok, "none") == 0) { aud3g.algo = OSMO_AUTH_ALG_NONE; - } else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen)) { + } else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) { cmd->reply = "Unknown auth algorithm."; return CTRL_CMD_ERROR; } @@ -699,7 +699,7 @@ }
aud3g.u.umts.opc = tok; - if (!osmo_is_hexstr(aud3g.u.umts.opc, MILENAGE_KEY_LEN * 2, MILENAGE_KEY_LEN * 2, true)) { + if (!osmo_is_hexstr(aud3g.u.umts.opc, minlen_opc * 2, maxlen_opc * 2, true)) { cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC."); return CTRL_CMD_ERROR; } diff --git a/src/db.c b/src/db.c index cfe34c3..7b8a415 100644 --- a/src/db.c +++ b/src/db.c @@ -1,4 +1,4 @@ -/* (C) 2015 by Harald Welte laforge@gnumonks.org +/* (C) 2015-2023 by Harald Welte laforge@gnumonks.org * * All Rights Reserved * @@ -28,7 +28,7 @@ #include "db_bootstrap.h"
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */ -#define CURRENT_SCHEMA_VERSION 6 +#define CURRENT_SCHEMA_VERSION 7
#define SEL_COLUMNS \ "id," \ @@ -513,6 +513,46 @@ return rc; }
+static int db_upgrade_v7(struct db_context *dbc) +{ + int rc; + /* SQLite doesn't allow us to change the column type in-place, so we + * first rename the old table, create a new table and then copy + * the data over before deleting the old table */ +#define CREATE_AUC_3G_V7 \ +"CREATE TABLE auc_3g (\n" \ +" subscriber_id INTEGER PRIMARY KEY, -- subscriber.id\n" \ +" algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value\n" \ +" k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)\n" \ +" op VARCHAR(64), -- hex string: operator's secret key (128/256bit)\n" \ +" opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)\n" \ +" sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage\n" \ +" -- nr of index bits at lower SQN end\n" \ +" ind_bitlen INTEGER NOT NULL DEFAULT 5\n" \ +");" + const char * const statements[] = { + "BEGIN TRANSACTION", + /* rename old table */ + "ALTER TABLE auc_3g RENAME TO old_auc_3g", + /* create new table */ + CREATE_AUC_3G_V7, + /* copy over old data */ + "INSERT INTO auc_3g SELECT subscriber_id, algo_id_3g, k, op, opc,sqn, ind_bitlen FROM old_auc_3g", + /* delete old table */ + "DROP TABLE old_auc_3g", + /* update user_version */ + "PRAGMA user_version = 7", + "COMMIT", + }; + + rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements)); + if (rc != SQLITE_DONE) { + LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n"); + return rc; + } + return rc; +} + typedef int (*db_upgrade_func_t)(struct db_context *dbc); static db_upgrade_func_t db_upgrade_path[] = { db_upgrade_v1, @@ -521,6 +561,7 @@ db_upgrade_v4, db_upgrade_v5, db_upgrade_v6, + db_upgrade_v7, };
static int db_get_user_version(struct db_context *dbc) diff --git a/src/db_hlr.c b/src/db_hlr.c index 8dfbb15..aa2e365 100644 --- a/src/db_hlr.c +++ b/src/db_hlr.c @@ -1,4 +1,4 @@ -/* (C) 2015 by Harald Welte laforge@gnumonks.org +/* (C) 2015-2023 by Harald Welte laforge@gnumonks.org * * All Rights Reserved * @@ -286,12 +286,12 @@
if (aud->algo == OSMO_AUTH_ALG_NONE) break; - if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) { + if (!osmo_is_hexstr(aud->u.umts.k, 32, 64, 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)) { + if (!osmo_is_hexstr(aud->u.umts.opc, 32, 64, true)) { LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" " Invalid OP/OPC: '%s'\n", aud->u.umts.opc); return -EINVAL; diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c index 191a87d..28cc5b3 100644 --- a/src/hlr_vty_subscr.c +++ b/src/hlr_vty_subscr.c @@ -473,8 +473,14 @@ "Use Milenage algorithm\n"
bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo, - int *minlen, int *maxlen) + int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc) { + /* Default: no OP[c]. True for all 2G algorithms, and 3G-XOR. Overridden below for real 3G AKA algorithms. */ + if (minlen_opc) + *minlen_opc = 0; + if (maxlen_opc) + *maxlen_opc = 0; + if (!strcasecmp(alg_str, "none")) { *algo = OSMO_AUTH_ALG_NONE; *minlen = *maxlen = 0; @@ -497,6 +503,10 @@ } else if (!strcasecmp(alg_str, "milenage")) { *algo = OSMO_AUTH_ALG_MILENAGE; *minlen = *maxlen = MILENAGE_KEY_LEN; + if (minlen_opc) + *minlen_opc = MILENAGE_KEY_LEN; + if (maxlen_opc) + *maxlen_opc = MILENAGE_KEY_LEN; } else return false; return true; @@ -552,7 +562,7 @@ .u.gsm.ki = ki, };
- if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen)) { + if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) { vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE); return CMD_WARNING; } @@ -611,13 +621,13 @@ SUBSCR_UPDATE_HELP "Set UMTS authentication data (3G, and 2G with UMTS AKA)\n" AUTH_ALG_TYPES_3G_HELP - "Set Encryption Key K\n" "K as 32 hexadecimal characters\n" - "Set OP key\n" "Set OPC key\n" "OP or OPC as 32 hexadecimal characters\n" + "Set Encryption Key K\n" "K as 32/64 hexadecimal characters\n" + "Set OP key\n" "Set OPC key\n" "OP or OPC as 32/64 hexadecimal characters\n" "Set IND bit length\n" "IND bit length value (default: 5)\n") { struct hlr_subscriber subscr; - int minlen = 0; - int maxlen = 0; + int minlen = 0, minlen_opc = 0; + int maxlen = 0, maxlen_opc = 0; int rc; const char *id_type = argv[0]; const char *id = argv[1]; @@ -636,7 +646,7 @@ }, };
- if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen)) { + if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) { vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE); return CMD_WARNING; } @@ -644,8 +654,7 @@ if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen)) return CMD_WARNING;
- if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, - MILENAGE_KEY_LEN, MILENAGE_KEY_LEN)) + if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, minlen_opc, maxlen_opc)) return CMD_WARNING;
if (get_subscr_by_argv(vty, id_type, id, &subscr)) @@ -689,7 +698,7 @@ }, };
- if (!auth_algo_parse("xor-3g", &aud3g.algo, &minlen, &maxlen)) { + if (!auth_algo_parse("xor-3g", &aud3g.algo, &minlen, &maxlen, NULL, NULL)) { vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor-3g", VTY_NEWLINE); return CMD_WARNING; } diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok index ce5b17c..c719498 100644 --- a/tests/db_upgrade/db_upgrade_test.ok +++ b/tests/db_upgrade/db_upgrade_test.ok @@ -86,6 +86,7 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4 DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5 DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6 +DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7 DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db: @@ -106,9 +107,9 @@ name|type|notnull|dflt_value|pk algo_id_3g|INTEGER|1||0 ind_bitlen|INTEGER|1|5|0 -k|VARCHAR(32)|1||0 -op|VARCHAR(32)|0||0 -opc|VARCHAR(32)|0||0 +k|VARCHAR(64)|1||0 +op|VARCHAR(64)|0||0 +opc|VARCHAR(64)|0||0 sqn|INTEGER|1|0|0 subscriber_id|INTEGER|0||1
@@ -179,5 +180,5 @@ rc = 0 DMAIN hlr starting DDB using database: <PATH>test.db -DDB Database <PATH>test.db' has HLR DB schema version 6 +DDB Database <PATH>test.db' has HLR DB schema version 7 DMAIN Cmdline option --db-check: Database was opened successfully, quitting. diff --git a/tests/test_subscriber.vty b/tests/test_subscriber.vty index dbe9327..9036fb8 100644 --- a/tests/test_subscriber.vty +++ b/tests/test_subscriber.vty @@ -275,14 +275,14 @@ k Set Encryption Key K
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k ? - K K as 32 hexadecimal characters + K K as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d ? op Set OP key opc Set OPC key
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc ? - OP_C OP or OPC as 32 hexadecimal characters + OP_C OP or OPC as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef ? [ind-bitlen] Set IND bit length