nts: extend server key file format
Include in the key dump file an identifier, the AEAD number, and the age of the last key to improve robustness and avoid generating a new key immediately on start. Also, improve the code that saves and loads the file.
This commit is contained in:
parent
2fa83b541c
commit
7be360041c
1 changed files with 57 additions and 28 deletions
|
@ -53,6 +53,9 @@
|
||||||
|
|
||||||
#define MIN_KEY_ROTATE_INTERVAL 1.0
|
#define MIN_KEY_ROTATE_INTERVAL 1.0
|
||||||
|
|
||||||
|
#define DUMP_FILENAME "ntskeys"
|
||||||
|
#define DUMP_IDENTIFIER "NKS0\n"
|
||||||
|
|
||||||
#define INVALID_SOCK_FD (-7)
|
#define INVALID_SOCK_FD (-7)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -78,6 +81,7 @@ typedef struct {
|
||||||
|
|
||||||
static ServerKey server_keys[MAX_SERVER_KEYS];
|
static ServerKey server_keys[MAX_SERVER_KEYS];
|
||||||
static int current_server_key;
|
static int current_server_key;
|
||||||
|
static double last_server_key_ts;
|
||||||
|
|
||||||
static int server_sock_fd4;
|
static int server_sock_fd4;
|
||||||
static int server_sock_fd6;
|
static int server_sock_fd6;
|
||||||
|
@ -438,6 +442,8 @@ generate_key(int index)
|
||||||
server_keys[index].id |= index;
|
server_keys[index].id |= index;
|
||||||
|
|
||||||
DEBUG_LOG("Generated server key %"PRIX32, server_keys[index].id);
|
DEBUG_LOG("Generated server key %"PRIX32, server_keys[index].id);
|
||||||
|
|
||||||
|
last_server_key_ts = SCH_GetLastEventMonoTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -445,46 +451,61 @@ generate_key(int index)
|
||||||
static void
|
static void
|
||||||
save_keys(void)
|
save_keys(void)
|
||||||
{
|
{
|
||||||
char hex_key[SIV_MAX_KEY_LENGTH * 2 + 1];
|
char buf[SIV_MAX_KEY_LENGTH * 2 + 1], *dump_dir;
|
||||||
int i, index, key_length;
|
int i, index, key_length;
|
||||||
char *dump_dir;
|
double last_key_age;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
dump_dir = CNF_GetNtsDumpDir();
|
dump_dir = CNF_GetNtsDumpDir();
|
||||||
if (!dump_dir)
|
if (!dump_dir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f = UTI_OpenFile(dump_dir, "ntskeys", ".tmp", 'w', 0600);
|
f = UTI_OpenFile(dump_dir, DUMP_FILENAME, ".tmp", 'w', 0600);
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
||||||
|
last_key_age = SCH_GetLastEventMonoTime() - last_server_key_ts;
|
||||||
|
|
||||||
|
if (fprintf(f, "%s%d %.1f\n", DUMP_IDENTIFIER, SERVER_COOKIE_SIV, last_key_age) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
||||||
index = (current_server_key + i + 1) % MAX_SERVER_KEYS;
|
index = (current_server_key + i + 1) % MAX_SERVER_KEYS;
|
||||||
|
|
||||||
if (key_length > sizeof (server_keys[index].key) ||
|
if (key_length > sizeof (server_keys[index].key) ||
|
||||||
!UTI_BytesToHex(server_keys[index].key, key_length, hex_key, sizeof (hex_key))) {
|
!UTI_BytesToHex(server_keys[index].key, key_length, buf, sizeof (buf)) ||
|
||||||
assert(0);
|
fprintf(f, "%08"PRIX32" %s\n", server_keys[index].id, buf) < 0)
|
||||||
break;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%08"PRIX32" %s\n", server_keys[index].id, hex_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if (!UTI_RenameTempFile(dump_dir, "ntskeys", ".tmp", NULL))
|
if (!UTI_RenameTempFile(dump_dir, DUMP_FILENAME, ".tmp", NULL)) {
|
||||||
|
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, ".tmp"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
DEBUG_LOG("Could not %s server keys", "save");
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, NULL))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
#define MAX_WORDS 2
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_keys(void)
|
load_keys(void)
|
||||||
{
|
{
|
||||||
int i, index, line_length, key_length, n;
|
char *dump_dir, line[1024], *words[MAX_WORDS];
|
||||||
char *dump_dir, line[1024];
|
int i, index, key_length, algorithm;
|
||||||
|
double key_age;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
||||||
|
@ -492,30 +513,29 @@ load_keys(void)
|
||||||
if (!dump_dir)
|
if (!dump_dir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f = UTI_OpenFile(dump_dir, "ntskeys", NULL, 'r', 0);
|
f = UTI_OpenFile(dump_dir, DUMP_FILENAME, NULL, 'r', 0);
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
|
||||||
|
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 ||
|
||||||
|
sscanf(words[0], "%d", &algorithm) != 1 || algorithm != SERVER_COOKIE_SIV ||
|
||||||
|
sscanf(words[1], "%lf", &key_age) != 1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
||||||
|
last_server_key_ts = SCH_GetLastEventMonoTime() - MAX(key_age, 0.0);
|
||||||
|
|
||||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
for (i = 0; i < MAX_SERVER_KEYS && fgets(line, sizeof (line), f); i++) {
|
||||||
if (!fgets(line, sizeof (line), f))
|
if (UTI_SplitString(line, words, MAX_WORDS) != 2 ||
|
||||||
break;
|
sscanf(words[0], "%"PRIX32, &id) != 1)
|
||||||
|
goto error;
|
||||||
line_length = strlen(line);
|
|
||||||
if (line_length < 10)
|
|
||||||
break;
|
|
||||||
/* Drop '\n' */
|
|
||||||
line[line_length - 1] = '\0';
|
|
||||||
|
|
||||||
if (sscanf(line, "%"PRIX32"%n", &id, &n) != 1 || line[n] != ' ')
|
|
||||||
break;
|
|
||||||
|
|
||||||
index = id % MAX_SERVER_KEYS;
|
index = id % MAX_SERVER_KEYS;
|
||||||
|
|
||||||
if (UTI_HexToBytes(line + n + 1, server_keys[index].key,
|
if (UTI_HexToBytes(words[1], server_keys[index].key,
|
||||||
sizeof (server_keys[index].key)) != key_length)
|
sizeof (server_keys[index].key)) != key_length)
|
||||||
break;
|
goto error;
|
||||||
|
|
||||||
server_keys[index].id = id;
|
server_keys[index].id = id;
|
||||||
if (!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
if (!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
||||||
|
@ -527,6 +547,12 @@ load_keys(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
DEBUG_LOG("Could not %s server keys", "load");
|
||||||
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -586,6 +612,7 @@ NKS_Initialise(int scfilter_level)
|
||||||
{
|
{
|
||||||
char *cert, *key;
|
char *cert, *key;
|
||||||
int i, processes;
|
int i, processes;
|
||||||
|
double key_delay;
|
||||||
|
|
||||||
server_sock_fd4 = INVALID_SOCK_FD;
|
server_sock_fd4 = INVALID_SOCK_FD;
|
||||||
server_sock_fd6 = INVALID_SOCK_FD;
|
server_sock_fd6 = INVALID_SOCK_FD;
|
||||||
|
@ -619,7 +646,9 @@ NKS_Initialise(int scfilter_level)
|
||||||
|
|
||||||
load_keys();
|
load_keys();
|
||||||
|
|
||||||
key_timeout(NULL);
|
key_delay = MAX(CNF_GetNtsRotate(), MIN_KEY_ROTATE_INTERVAL) -
|
||||||
|
(SCH_GetLastEventMonoTime() - last_server_key_ts);
|
||||||
|
SCH_AddTimeoutByDelay(MAX(key_delay, 0.0), key_timeout, NULL);
|
||||||
|
|
||||||
processes = CNF_GetNtsServerProcesses();
|
processes = CNF_GetNtsServerProcesses();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue