nts: change ntskeys format to support different algorithms

Specify the AEAD ID for each key saved in the ntskeys file instead of
one ID for all keys. Keep support for loading files in the old format.

This will allow servers to save their keys after upgrading to a new
version with AES-128-GCM-SIV support before the loaded AES-SIV-CMAC-256
keys are rotated out.

If an unsupported key is found, don't load any keys. Also, change the
severity of the error message from debug to error.
This commit is contained in:
Miroslav Lichvar 2022-10-13 15:35:53 +02:00
parent b1230efac3
commit c8e57f4350

View file

@ -54,7 +54,8 @@
#define FUTURE_KEYS 1 #define FUTURE_KEYS 1
#define DUMP_FILENAME "ntskeys" #define DUMP_FILENAME "ntskeys"
#define DUMP_IDENTIFIER "NKS0\n" #define DUMP_IDENTIFIER "NKS1\n"
#define OLD_DUMP_IDENTIFIER "NKS0\n"
#define INVALID_SOCK_FD (-7) #define INVALID_SOCK_FD (-7)
@ -519,7 +520,7 @@ generate_key(int index)
update_key_siv(key, algorithm); update_key_siv(key, algorithm);
DEBUG_LOG("Generated key %"PRIX32" (%d)", key->id, (int)key->siv_algorithm); DEBUG_LOG("Generated key %08"PRIX32" (%d)", key->id, (int)key->siv_algorithm);
last_server_key_ts = SCH_GetLastEventMonoTime(); last_server_key_ts = SCH_GetLastEventMonoTime();
} }
@ -547,20 +548,19 @@ save_keys(void)
if (!f) if (!f)
return; return;
key_length = SIV_GetKeyLength(server_keys[0].siv_algorithm);
last_key_age = SCH_GetLastEventMonoTime() - last_server_key_ts; last_key_age = SCH_GetLastEventMonoTime() - last_server_key_ts;
if (fprintf(f, "%s%d %.1f\n", DUMP_IDENTIFIER, (int)server_keys[0].siv_algorithm, if (fprintf(f, "%s%.1f\n", DUMP_IDENTIFIER, last_key_age) < 0)
last_key_age) < 0)
goto error; goto error;
for (i = 0; i < MAX_SERVER_KEYS; i++) { for (i = 0; i < MAX_SERVER_KEYS; i++) {
index = (current_server_key + i + 1 + FUTURE_KEYS) % MAX_SERVER_KEYS; index = (current_server_key + i + 1 + FUTURE_KEYS) % MAX_SERVER_KEYS;
key_length = SIV_GetKeyLength(server_keys[index].siv_algorithm);
if (key_length > sizeof (server_keys[index].key) || if (key_length > sizeof (server_keys[index].key) ||
server_keys[index].siv_algorithm != server_keys[0].siv_algorithm ||
!UTI_BytesToHex(server_keys[index].key, key_length, buf, sizeof (buf)) || !UTI_BytesToHex(server_keys[index].key, key_length, buf, sizeof (buf)) ||
fprintf(f, "%08"PRIX32" %s\n", server_keys[index].id, buf) < 0) fprintf(f, "%08"PRIX32" %s %d\n", server_keys[index].id, buf,
(int)server_keys[index].siv_algorithm) < 0)
goto error; goto error;
} }
@ -575,7 +575,7 @@ save_keys(void)
return; return;
error: error:
DEBUG_LOG("Could not %s server keys", "save"); LOG(LOGS_ERR, "Could not %s server NTS keys", "save");
fclose(f); fclose(f);
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, NULL)) if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, NULL))
@ -584,17 +584,16 @@ error:
/* ================================================== */ /* ================================================== */
#define MAX_WORDS 2 #define MAX_WORDS 3
static int static int
load_keys(void) load_keys(void)
{ {
int i, index, key_length, algorithm = 0, old_ver;
char *dump_dir, line[1024], *words[MAX_WORDS]; char *dump_dir, line[1024], *words[MAX_WORDS];
unsigned char key[SIV_MAX_KEY_LENGTH]; ServerKey new_keys[MAX_SERVER_KEYS];
int i, index, key_length, algorithm;
double key_age; double key_age;
FILE *f; FILE *f;
uint32_t id;
dump_dir = CNF_GetNtsDumpDir(); dump_dir = CNF_GetNtsDumpDir();
if (!dump_dir) if (!dump_dir)
@ -604,42 +603,56 @@ load_keys(void)
if (!f) if (!f)
return 0; return 0;
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 || if (!fgets(line, sizeof (line), f) ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 || (strcmp(line, DUMP_IDENTIFIER) != 0 && strcmp(line, OLD_DUMP_IDENTIFIER) != 0))
sscanf(words[0], "%d", &algorithm) != 1 || SIV_GetKeyLength(algorithm) <= 0 ||
sscanf(words[1], "%lf", &key_age) != 1)
goto error; goto error;
key_length = SIV_GetKeyLength(algorithm); old_ver = strcmp(line, DUMP_IDENTIFIER) != 0;
last_server_key_ts = SCH_GetLastEventMonoTime() - MAX(key_age, 0.0);
if (!fgets(line, sizeof (line), f) ||
UTI_SplitString(line, words, MAX_WORDS) != (old_ver ? 2 : 1) ||
(old_ver && sscanf(words[0], "%d", &algorithm) != 1) ||
sscanf(words[old_ver ? 1 : 0], "%lf", &key_age) != 1)
goto error;
for (i = 0; i < MAX_SERVER_KEYS && fgets(line, sizeof (line), f); i++) { for (i = 0; i < MAX_SERVER_KEYS && fgets(line, sizeof (line), f); i++) {
if (UTI_SplitString(line, words, MAX_WORDS) != 2 || if (UTI_SplitString(line, words, MAX_WORDS) != (old_ver ? 2 : 3) ||
sscanf(words[0], "%"PRIX32, &id) != 1) sscanf(words[0], "%"PRIX32, &new_keys[i].id) != 1 ||
(!old_ver && sscanf(words[2], "%d", &algorithm) != 1))
goto error; goto error;
if (UTI_HexToBytes(words[1], key, sizeof (key)) != key_length) new_keys[i].siv_algorithm = algorithm;
key_length = SIV_GetKeyLength(algorithm);
if ((i > 0 && (new_keys[i].id - new_keys[i - 1].id) % MAX_SERVER_KEYS != 1) ||
key_length <= 0 ||
UTI_HexToBytes(words[1], new_keys[i].key, sizeof (new_keys[i].key)) != key_length)
goto error; goto error;
index = id % MAX_SERVER_KEYS;
server_keys[index].id = id;
assert(sizeof (server_keys[index].key) == sizeof (key));
memcpy(server_keys[index].key, key, key_length);
update_key_siv(&server_keys[index], algorithm);
DEBUG_LOG("Loaded key %"PRIX32" (%d)", id, (int)algorithm);
current_server_key = (index + MAX_SERVER_KEYS - FUTURE_KEYS) % MAX_SERVER_KEYS;
} }
if (i < MAX_SERVER_KEYS)
goto error;
for (i = 0; i < MAX_SERVER_KEYS; i++) {
index = new_keys[i].id % MAX_SERVER_KEYS;
server_keys[index].id = new_keys[i].id;
memcpy(server_keys[index].key, new_keys[i].key, sizeof (server_keys[index].key));
update_key_siv(&server_keys[index], new_keys[i].siv_algorithm);
DEBUG_LOG("Loaded key %08"PRIX32" (%d)",
server_keys[index].id, (int)server_keys[index].siv_algorithm);
}
current_server_key = (index + MAX_SERVER_KEYS - FUTURE_KEYS) % MAX_SERVER_KEYS;
last_server_key_ts = SCH_GetLastEventMonoTime() - MAX(key_age, 0.0);
fclose(f); fclose(f);
return 1; return 1;
error: error:
DEBUG_LOG("Could not %s server keys", "load"); LOG(LOGS_ERR, "Could not %s server NTS keys", "load");
fclose(f); fclose(f);
return 0; return 0;