nts: add server support for authentication with AES-128-GCM-SIV
Keep a server SIV instance for each available algorithm. Select AES-128-GCM-SIV if requested by NTS-KE client as the first supported algorithm. Instead of encoding the AEAD ID in the cookie, select the algorithm according to the length of decrypted keys. (This can work as a long as all supported algorithms use keys with different lengths.)
This commit is contained in:
parent
cc706b50b9
commit
790a336eb2
4 changed files with 63 additions and 21 deletions
|
@ -427,8 +427,9 @@ process_request(NKSN_Instance session)
|
|||
|
||||
for (i = 0; i < MIN(length, sizeof (data)) / 2; i++) {
|
||||
aead_algorithm_values++;
|
||||
if (ntohs(data[i]) == AEAD_AES_SIV_CMAC_256)
|
||||
aead_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
/* Use the first supported algorithm */
|
||||
if (aead_algorithm < 0 && SIV_GetKeyLength(ntohs(data[i])) > 0)
|
||||
aead_algorithm = ntohs(data[i]);;
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_ERROR:
|
||||
|
@ -862,11 +863,9 @@ NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The algorithm is hardcoded for now */
|
||||
if (context->algorithm != AEAD_AES_SIV_CMAC_256) {
|
||||
DEBUG_LOG("Unexpected SIV algorithm");
|
||||
return 0;
|
||||
}
|
||||
/* The AEAD ID is not encoded in the cookie. It is implied from the key
|
||||
length (as long as only algorithms with different key lengths are
|
||||
supported). */
|
||||
|
||||
if (context->c2s.length < 0 || context->c2s.length > NKE_MAX_KEY_LENGTH ||
|
||||
context->s2c.length != context->c2s.length) {
|
||||
|
@ -954,7 +953,19 @@ NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context)
|
|||
return 0;
|
||||
}
|
||||
|
||||
context->algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
/* Select a supported algorithm corresponding to the key length, avoiding
|
||||
potentially slow SIV_GetKeyLength() */
|
||||
switch (plaintext_length / 2) {
|
||||
case 16:
|
||||
context->algorithm = AEAD_AES_128_GCM_SIV;
|
||||
break;
|
||||
case 32:
|
||||
context->algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("Unknown key length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
context->c2s.length = plaintext_length / 2;
|
||||
context->s2c.length = plaintext_length / 2;
|
||||
|
|
|
@ -41,13 +41,15 @@
|
|||
#include "siv.h"
|
||||
#include "util.h"
|
||||
|
||||
#define SERVER_SIV AEAD_AES_SIV_CMAC_256
|
||||
#define MAX_SERVER_SIVS 2
|
||||
|
||||
struct NtsServer {
|
||||
SIV_Instance siv;
|
||||
SIV_Instance sivs[MAX_SERVER_SIVS];
|
||||
SIV_Algorithm siv_algorithms[MAX_SERVER_SIVS];
|
||||
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
|
||||
NKE_Cookie cookies[NTS_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
int siv_index;
|
||||
NTP_int64 req_tx;
|
||||
};
|
||||
|
||||
|
@ -60,6 +62,7 @@ void
|
|||
NNS_Initialise(void)
|
||||
{
|
||||
const char **certs, **keys;
|
||||
int i;
|
||||
|
||||
/* Create an NTS-NTP server instance only if NTS-KE server is enabled */
|
||||
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0) {
|
||||
|
@ -68,9 +71,17 @@ NNS_Initialise(void)
|
|||
}
|
||||
|
||||
server = Malloc(sizeof (struct NtsServer));
|
||||
server->siv = SIV_CreateInstance(SERVER_SIV);
|
||||
if (!server->siv)
|
||||
LOG_FATAL("Could not initialise SIV cipher");
|
||||
|
||||
server->siv_algorithms[0] = AEAD_AES_SIV_CMAC_256;
|
||||
server->siv_algorithms[1] = AEAD_AES_128_GCM_SIV;
|
||||
assert(MAX_SERVER_SIVS == 2);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
server->sivs[i] = SIV_CreateInstance(server->siv_algorithms[i]);
|
||||
|
||||
/* AES-SIV-CMAC-256 is required on servers */
|
||||
if (!server->sivs[0])
|
||||
LOG_FATAL("Missing AES-SIV-CMAC-256");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -78,10 +89,15 @@ NNS_Initialise(void)
|
|||
void
|
||||
NNS_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
SIV_DestroyInstance(server->siv);
|
||||
for (i = 0; i < MAX_SERVER_SIVS; i++) {
|
||||
if (server->sivs[i])
|
||||
SIV_DestroyInstance(server->sivs[i]);
|
||||
}
|
||||
Free(server);
|
||||
server = NULL;
|
||||
}
|
||||
|
@ -96,6 +112,7 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
|||
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookie;
|
||||
SIV_Instance siv;
|
||||
void *ef_body;
|
||||
|
||||
*kod = 0;
|
||||
|
@ -104,6 +121,7 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
|||
return 0;
|
||||
|
||||
server->num_cookies = 0;
|
||||
server->siv_index = -1;
|
||||
server->req_tx = packet->transmit_ts;
|
||||
|
||||
if (info->ext_fields == 0 || info->mode != MODE_CLIENT)
|
||||
|
@ -163,17 +181,22 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (context.algorithm != SERVER_SIV) {
|
||||
/* Find the SIV instance needed for authentication */
|
||||
for (i = 0; i < MAX_SERVER_SIVS && context.algorithm != server->siv_algorithms[i]; i++)
|
||||
;
|
||||
if (i == MAX_SERVER_SIVS || !server->sivs[i]) {
|
||||
DEBUG_LOG("Unexpected SIV");
|
||||
return 0;
|
||||
}
|
||||
server->siv_index = i;
|
||||
siv = server->sivs[i];
|
||||
|
||||
if (!SIV_SetKey(server->siv, context.c2s.key, context.c2s.length)) {
|
||||
if (!SIV_SetKey(siv, context.c2s.key, context.c2s.length)) {
|
||||
DEBUG_LOG("Could not set C2S key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NNA_DecryptAuthEF(packet, info, server->siv, auth_start,
|
||||
if (!NNA_DecryptAuthEF(packet, info, siv, auth_start,
|
||||
plaintext, sizeof (plaintext), &plaintext_length)) {
|
||||
*kod = NTP_KOD_NTS_NAK;
|
||||
return 0;
|
||||
|
@ -199,7 +222,7 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
|||
}
|
||||
}
|
||||
|
||||
if (!SIV_SetKey(server->siv, context.s2c.key, context.s2c.length)) {
|
||||
if (!SIV_SetKey(siv, context.s2c.key, context.s2c.length)) {
|
||||
DEBUG_LOG("Could not set S2C key");
|
||||
return 0;
|
||||
}
|
||||
|
@ -271,9 +294,12 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
|
|||
|
||||
server->num_cookies = 0;
|
||||
|
||||
if (server->siv_index < 0)
|
||||
return 0;
|
||||
|
||||
/* Generate an authenticator field which will make the length
|
||||
of the response equal to the length of the request */
|
||||
if (!NNA_GenerateAuthEF(response, res_info, server->siv,
|
||||
if (!NNA_GenerateAuthEF(response, res_info, server->sivs[server->siv_index],
|
||||
server->nonce, sizeof (server->nonce),
|
||||
plaintext, plaintext_length,
|
||||
req_info->length - res_info->length))
|
||||
|
|
|
@ -75,7 +75,8 @@ prepare_request(NKSN_Instance session, int valid)
|
|||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, length));
|
||||
|
||||
if (index != 4) {
|
||||
data[0] = htons(AEAD_AES_SIV_CMAC_256);
|
||||
data[0] = htons(random() % 2 && SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0 ?
|
||||
AEAD_AES_128_GCM_SIV : AEAD_AES_SIV_CMAC_256);
|
||||
if (index == 5)
|
||||
length = 0;
|
||||
else if (index == 6)
|
||||
|
|
|
@ -37,10 +37,13 @@ prepare_request(NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
|
|||
NKE_Cookie cookie;
|
||||
int i, index, cookie_start, auth_start;
|
||||
|
||||
context.algorithm = SERVER_SIV;
|
||||
context.algorithm = random() % 2 && SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0 ?
|
||||
AEAD_AES_128_GCM_SIV : AEAD_AES_SIV_CMAC_256;
|
||||
context.c2s.length = SIV_GetKeyLength(context.algorithm);
|
||||
assert(context.c2s.length <= sizeof (context.c2s.key));
|
||||
UTI_GetRandomBytes(&context.c2s.key, context.c2s.length);
|
||||
context.s2c.length = SIV_GetKeyLength(context.algorithm);
|
||||
assert(context.s2c.length <= sizeof (context.s2c.key));
|
||||
UTI_GetRandomBytes(&context.s2c.key, context.s2c.length);
|
||||
|
||||
TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
|
||||
|
@ -80,6 +83,7 @@ prepare_request(NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
|
|||
|
||||
if (index != 2) {
|
||||
siv = SIV_CreateInstance(context.algorithm);
|
||||
TEST_CHECK(siv);
|
||||
TEST_CHECK(SIV_SetKey(siv, context.c2s.key, context.c2s.length));
|
||||
TEST_CHECK(NNA_GenerateAuthEF(packet, info, siv, nonce, sizeof (nonce),
|
||||
(const unsigned char *)"", 0, 0));
|
||||
|
|
Loading…
Reference in a new issue