unsigned char key[NKE_MAX_KEY_LENGTH];
} NKE_Key;
+typedef struct {
+ SIV_Algorithm algorithm;
+ NKE_Key c2s;
+ NKE_Key s2c;
+} NKE_Context;
+
typedef struct {
int length;
unsigned char cookie[NKE_MAX_COOKIE_LENGTH];
int got_response;
int resolving_name;
- SIV_Algorithm siv_algorithm;
- NKE_Key c2s, s2c;
+ NKE_Context context;
NKE_Cookie cookies[NKE_MAX_COOKIES];
int num_cookies;
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 1];
break;
}
aead_algorithm = AEAD_AES_SIV_CMAC_256;
- inst->siv_algorithm = aead_algorithm;
+ inst->context.algorithm = aead_algorithm;
break;
case NKE_RECORD_ERROR:
if (length == 2)
return 0;
}
- if (!NKSN_GetKeys(inst->session, inst->siv_algorithm, &inst->c2s, &inst->s2c))
+ if (!NKSN_GetKeys(inst->session, inst->context.algorithm,
+ &inst->context.c2s, &inst->context.s2c))
return 0;
if (inst->server_name[0] != '\0') {
/* ================================================== */
int
-NKC_GetNtsData(NKC_Instance inst,
- SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
+NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
IPSockAddr *ntp_address)
{
if (!inst->got_response || inst->resolving_name)
return 0;
- *siv_algorithm = inst->siv_algorithm;
- *c2s = inst->c2s;
- *s2c = inst->s2c;
+ *context = inst->context;
for (i = 0; i < inst->num_cookies && i < max_cookies; i++)
cookies[i] = inst->cookies[i];
extern int NKC_IsActive(NKC_Instance inst);
/* Get the NTS data if the session was successful */
-extern int NKC_GetNtsData(NKC_Instance inst,
- SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
+extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
IPSockAddr *ntp_address);
static int
prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm)
{
+ NKE_Context context;
NKE_Cookie cookie;
- NKE_Key c2s, s2c;
uint16_t datum;
int i;
return 0;
}
- if (!NKSN_GetKeys(session, aead_algorithm, &c2s, &s2c))
+ context.algorithm = aead_algorithm;
+
+ if (!NKSN_GetKeys(session, aead_algorithm, &context.c2s, &context.s2c))
return 0;
for (i = 0; i < NKE_MAX_COOKIES; i++) {
- if (!NKS_GenerateCookie(&c2s, &s2c, &cookie))
+ if (!NKS_GenerateCookie(&context, &cookie))
return 0;
if (!NKSN_AddRecord(session, 0, NKE_RECORD_COOKIE, cookie.cookie, cookie.length))
return 0;
/* A server cookie consists of key ID, nonce, and encrypted C2S+S2C keys */
int
-NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie)
+NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie)
{
unsigned char plaintext[2 * NKE_MAX_KEY_LENGTH], *ciphertext;
int plaintext_length, tag_length;
return 0;
}
- if (c2s->length < 0 || c2s->length > NKE_MAX_KEY_LENGTH ||
- s2c->length < 0 || s2c->length > NKE_MAX_KEY_LENGTH) {
+ /* The algorithm is hardcoded for now */
+ if (context->algorithm != AEAD_AES_SIV_CMAC_256) {
+ DEBUG_LOG("Unexpected SIV algorithm");
+ return 0;
+ }
+
+ if (context->c2s.length < 0 || context->c2s.length > NKE_MAX_KEY_LENGTH ||
+ context->s2c.length < 0 || context->s2c.length > NKE_MAX_KEY_LENGTH) {
DEBUG_LOG("Invalid key length");
return 0;
}
header->key_id = key->id;
UTI_GetRandomBytes(header->nonce, sizeof (header->nonce));
- plaintext_length = c2s->length + s2c->length;
+ plaintext_length = context->c2s.length + context->s2c.length;
assert(plaintext_length <= sizeof (plaintext));
- memcpy(plaintext, c2s->key, c2s->length);
- memcpy(plaintext + c2s->length, s2c->key, s2c->length);
+ memcpy(plaintext, context->c2s.key, context->c2s.length);
+ memcpy(plaintext + context->c2s.length, context->s2c.key, context->s2c.length);
tag_length = SIV_GetTagLength(key->siv);
cookie->length = sizeof (*header) + plaintext_length + tag_length;
/* ================================================== */
int
-NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c)
+NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context)
{
unsigned char plaintext[2 * NKE_MAX_KEY_LENGTH], *ciphertext;
int ciphertext_length, plaintext_length, tag_length;
return 0;
}
- c2s->length = plaintext_length / 2;
- s2c->length = plaintext_length / 2;
- assert(c2s->length <= sizeof (c2s->key));
+ context->algorithm = AEAD_AES_SIV_CMAC_256;
+
+ context->c2s.length = plaintext_length / 2;
+ context->s2c.length = plaintext_length / 2;
+ assert(context->c2s.length <= sizeof (context->c2s.key));
- memcpy(c2s->key, plaintext, c2s->length);
- memcpy(s2c->key, plaintext + c2s->length, s2c->length);
+ memcpy(context->c2s.key, plaintext, context->c2s.length);
+ memcpy(context->s2c.key, plaintext + context->c2s.length, context->s2c.length);
return 1;
}
extern void NKS_Initialise(int scfilter_level);
extern void NKS_Finalise(void);
-/* Generate a new NTS cookie containing the C2S and S2C keys */
-extern int NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie);
+/* Generate an NTS cookie with a given context */
+extern int NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie);
-/* Validate a cookie and extract the C2S and S2C keys */
-extern int NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c);
+/* Validate a cookie and decode the context */
+extern int NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context);
#endif
const IPSockAddr *ntp_address;
IPSockAddr nts_address;
char *name;
- SIV_Instance siv_c2s;
- SIV_Instance siv_s2c;
NKC_Instance nke;
+ SIV_Instance siv;
int nke_attempts;
double next_nke_attempt;
double last_nke_success;
+
+ NKE_Context context;
NKE_Cookie cookies[NTS_MAX_COOKIES];
int num_cookies;
int cookie_index;
inst->nke_attempts = 0;
inst->next_nke_attempt = 0.0;
inst->last_nke_success = 0.0;
+
+ memset(&inst->context, 0, sizeof (inst->context));
inst->num_cookies = 0;
inst->cookie_index = 0;
inst->nak_response = 0;
inst->ntp_address = ntp_address;
inst->nts_address = *nts_address;
inst->name = name ? Strdup(name) : NULL;
- inst->siv_c2s = NULL;
- inst->siv_s2c = NULL;
+ inst->siv = NULL;
inst->nke = NULL;
reset_instance(inst);
{
if (inst->nke)
NKC_DestroyInstance(inst->nke);
- if (inst->siv_c2s)
- SIV_DestroyInstance(inst->siv_c2s);
- if (inst->siv_s2c)
- SIV_DestroyInstance(inst->siv_s2c);
+ if (inst->siv)
+ SIV_DestroyInstance(inst->siv);
Free(inst->name);
Free(inst);
get_nke_data(NNC_Instance inst)
{
NTP_Remote_Address ntp_address;
- SIV_Algorithm siv;
- NKE_Key c2s, s2c;
double now;
int got_data;
if (NKC_IsActive(inst->nke))
return 0;
- got_data = NKC_GetNtsData(inst->nke, &siv, &c2s, &s2c,
+ got_data = NKC_GetNtsData(inst->nke, &inst->context,
inst->cookies, &inst->num_cookies, NTS_MAX_COOKIES,
&ntp_address);
inst->cookie_index = 0;
- if (inst->siv_c2s)
- SIV_DestroyInstance(inst->siv_c2s);
- if (inst->siv_s2c)
- SIV_DestroyInstance(inst->siv_s2c);
+ if (inst->siv)
+ SIV_DestroyInstance(inst->siv);
- inst->siv_c2s = SIV_CreateInstance(siv);
- inst->siv_s2c = SIV_CreateInstance(siv);
+ inst->siv = SIV_CreateInstance(inst->context.algorithm);
- if (!inst->siv_c2s || !inst->siv_s2c ||
- !SIV_SetKey(inst->siv_c2s, c2s.key, c2s.length) ||
- !SIV_SetKey(inst->siv_s2c, s2c.key, s2c.length)) {
+ if (!inst->siv) {
DEBUG_LOG("Could not initialise SIV");
inst->num_cookies = 0;
return 0;
return 0;
}
+ if (!SIV_SetKey(inst->siv, inst->context.c2s.key, inst->context.c2s.length)) {
+ DEBUG_LOG("Could not set SIV key");
+ return 0;
+ }
+
UTI_GetRandomBytes(&inst->uniq_id, sizeof (inst->uniq_id));
UTI_GetRandomBytes(&inst->nonce, sizeof (inst->nonce));
int i, req_cookies;
void *ef_body;
- if (inst->num_cookies == 0 || !inst->siv_c2s)
+ if (inst->num_cookies == 0 || !inst->siv)
return 0;
if (info->mode != MODE_CLIENT)
memset(ef_body, 0, cookie->length);
}
- if (!NNA_GenerateAuthEF(packet, info, inst->siv_c2s, inst->nonce, sizeof (inst->nonce),
+ if (!NNA_GenerateAuthEF(packet, info, inst->siv, inst->nonce, sizeof (inst->nonce),
(const unsigned char *)"", 0, NTP_MAX_V4_MAC_LENGTH + 4))
return 0;
if (inst->ok_response)
return 0;
- if (!inst->siv_s2c)
+ if (!inst->siv ||
+ !SIV_SetKey(inst->siv, inst->context.s2c.key, inst->context.s2c.length)) {
+ DEBUG_LOG("Could not set SIV key");
return 0;
+ }
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
if (!NEF_ParseField(packet, info->length, parsed,
return 0;
}
- if (!NNA_DecryptAuthEF(packet, info, inst->siv_s2c, parsed,
+ if (!NNA_DecryptAuthEF(packet, info, inst->siv, parsed,
plaintext, sizeof (plaintext), &plaintext_length))
return 0;
#include "siv.h"
#include "util.h"
+#define SERVER_SIV AEAD_AES_SIV_CMAC_256
+
struct NtsServer {
SIV_Instance siv;
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
}
server = Malloc(sizeof (struct NtsServer));
- server->siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
+ server->siv = SIV_CreateInstance(SERVER_SIV);
}
/* ================================================== */
int ef_type, ef_body_length, ef_length, has_uniq_id = 0, has_auth = 0, has_cookie = 0;
int i, plaintext_length, parsed, requested_cookies, cookie_length = -1, auth_start = 0;
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
+ NKE_Context context;
NKE_Cookie cookie;
- NKE_Key c2s, s2c;
void *ef_body;
if (!server)
return 0;
}
- if (!NKS_DecodeCookie(&cookie, &c2s, &s2c)) {
+ if (!NKS_DecodeCookie(&cookie, &context)) {
*kod = NTP_KOD_NTS_NAK;
return 0;
}
- if (!SIV_SetKey(server->siv, c2s.key, c2s.length)) {
+ if (context.algorithm != SERVER_SIV) {
+ DEBUG_LOG("Unexpected SIV");
+ return 0;
+ }
+
+ if (!SIV_SetKey(server->siv, context.c2s.key, context.c2s.length)) {
DEBUG_LOG("Could not set C2S key");
return 0;
}
}
}
- if (!SIV_SetKey(server->siv, s2c.key, s2c.length)) {
+ if (!SIV_SetKey(server->siv, context.s2c.key, context.s2c.length)) {
DEBUG_LOG("Could not set S2C key");
return 0;
}
server->num_cookies = MIN(NTS_MAX_COOKIES, requested_cookies);
for (i = 0; i < server->num_cookies; i++)
- if (!NKS_GenerateCookie(&c2s, &s2c, &server->cookies[i]))
+ if (!NKS_GenerateCookie(&context, &server->cookies[i]))
return 0;
return 1;
test_unit(void)
{
NKSN_Instance session;
+ NKE_Context context, context2;
NKE_Cookie cookie;
- NKE_Key c2s, s2c, c2s2, s2c2;
int i, valid, l;
uint32_t sum, sum2;
for (i = 0; i < 10000; i++) {
- get_keys(session, AEAD_AES_SIV_CMAC_256, &c2s, &s2c);
+ context.algorithm = AEAD_AES_SIV_CMAC_256;
+ get_keys(session, context.algorithm, &context.c2s, &context.s2c);
memset(&cookie, 0, sizeof (cookie));
- TEST_CHECK(NKS_GenerateCookie(&c2s, &s2c, &cookie));
- TEST_CHECK(NKS_DecodeCookie(&cookie, &c2s2, &s2c2));
- TEST_CHECK(c2s.length == c2s2.length);
- TEST_CHECK(s2c.length == s2c2.length);
- TEST_CHECK(memcmp(c2s.key, c2s2.key, c2s.length) == 0);
- TEST_CHECK(memcmp(s2c.key, s2c2.key, s2c.length) == 0);
+ TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
+ TEST_CHECK(NKS_DecodeCookie(&cookie, &context2));
+ TEST_CHECK(context.algorithm == context2.algorithm);
+ TEST_CHECK(context.c2s.length == context2.c2s.length);
+ TEST_CHECK(context.s2c.length == context2.s2c.length);
+ TEST_CHECK(memcmp(context.c2s.key, context2.c2s.key, context.c2s.length) == 0);
+ TEST_CHECK(memcmp(context.s2c.key, context2.s2c.key, context.s2c.length) == 0);
if (random() % 4) {
cookie.cookie[random() % (cookie.length)]++;
while (l == cookie.length)
cookie.length = random() % (sizeof (cookie.cookie) + 1);
}
- TEST_CHECK(!NKS_DecodeCookie(&cookie, &c2s2, &s2c2));
+ TEST_CHECK(!NKS_DecodeCookie(&cookie, &context2));
}
unlink("ntskeys");
#define NKC_Start(inst) (random() % 2)
#define NKC_IsActive(inst) (random() % 2)
-static int get_nts_data(NKC_Instance inst, SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
- NKE_Cookie *cookies, int *num_cookies, int max_cookies, IPSockAddr *ntp_address);
+static int get_nts_data(NKC_Instance inst, NKE_Context *context,
+ NKE_Cookie *cookies, int *num_cookies, int max_cookies,
+ IPSockAddr *ntp_address);
#define NKC_GetNtsData get_nts_data
#include <nts_ntp_client.c>
static int
-get_nts_data(NKC_Instance inst, SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
- NKE_Cookie *cookies, int *num_cookies, int max_cookies, IPSockAddr *ntp_address)
+get_nts_data(NKC_Instance inst, NKE_Context *context,
+ NKE_Cookie *cookies, int *num_cookies, int max_cookies,
+ IPSockAddr *ntp_address)
{
int i;
if (random() % 2)
return 0;
- *siv_algorithm = AEAD_AES_SIV_CMAC_256;
+ context->algorithm = AEAD_AES_SIV_CMAC_256;
- c2s->length = SIV_GetKeyLength(*siv_algorithm);
- UTI_GetRandomBytes(c2s->key, c2s->length);
- s2c->length = SIV_GetKeyLength(*siv_algorithm);
- UTI_GetRandomBytes(s2c->key, s2c->length);
+ context->c2s.length = SIV_GetKeyLength(context->algorithm);
+ UTI_GetRandomBytes(context->c2s.key, context->c2s.length);
+ context->s2c.length = SIV_GetKeyLength(context->algorithm);
+ UTI_GetRandomBytes(context->s2c.key, context->s2c.length);
*num_cookies = random() % max_cookies + 1;
for (i = 0; i < *num_cookies; i++) {
}
TEST_CHECK(inst->num_cookies > 0);
- TEST_CHECK(inst->siv_c2s);
- TEST_CHECK(inst->siv_s2c);
+ TEST_CHECK(inst->siv);
memcpy(nonce, inst->nonce, sizeof (nonce));
memcpy(uniq_id, inst->uniq_id, sizeof (uniq_id));
(inst->cookies[inst->cookie_index].length + 4));
expected_length = info.length + 4 + sizeof (inst->uniq_id) +
req_cookies * (4 + inst->cookies[inst->cookie_index].length) +
- 4 + 4 + sizeof (inst->nonce) + SIV_GetTagLength(inst->siv_c2s);
+ 4 + 4 + sizeof (inst->nonce) + SIV_GetTagLength(inst->siv);
DEBUG_LOG("length=%d cookie_length=%d expected_length=%d",
info.length, inst->cookies[inst->cookie_index].length, expected_length);
unsigned char cookie[508], plaintext[512], nonce[512];
int nonce_length, cookie_length, plaintext_length, min_auth_length;
int index, auth_start;
+ SIV_Instance siv;
memset(packet, 0, sizeof (*packet));
packet->lvm = NTP_LVM(0, 4, MODE_SERVER);
TEST_CHECK(NEF_SetField(plaintext, sizeof (plaintext), 0, NTP_EF_NTS_COOKIE,
cookie, cookie_length, &plaintext_length));
auth_start = info->length;
- if (index != 4)
- TEST_CHECK(NNA_GenerateAuthEF(packet, info, inst->siv_s2c,
+ if (index != 4) {
+ siv = SIV_CreateInstance(inst->context.algorithm);
+ TEST_CHECK(siv);
+ TEST_CHECK(SIV_SetKey(siv, inst->context.s2c.key, inst->context.s2c.length));
+ TEST_CHECK(NNA_GenerateAuthEF(packet, info, siv,
nonce, nonce_length, plaintext, plaintext_length,
min_auth_length));
+ SIV_DestroyInstance(siv);
+ }
if (index == 5)
((unsigned char *)packet)[auth_start + 8]++;
}
prepare_request(NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
{
unsigned char uniq_id[NTS_MIN_UNIQ_ID_LENGTH], nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
- NKE_Key c2s, s2c;
SIV_Instance siv;
+ NKE_Context context;
NKE_Cookie cookie;
int i, index, cookie_start, auth_start;
- c2s.length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
- UTI_GetRandomBytes(&c2s.key, c2s.length);
- s2c.length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
- UTI_GetRandomBytes(&s2c.key, s2c.length);
+ context.algorithm = SERVER_SIV;
+ context.c2s.length = SIV_GetKeyLength(context.algorithm);
+ UTI_GetRandomBytes(&context.c2s.key, context.c2s.length);
+ context.s2c.length = SIV_GetKeyLength(context.algorithm);
+ UTI_GetRandomBytes(&context.s2c.key, context.s2c.length);
- TEST_CHECK(NKS_GenerateCookie(&c2s, &s2c, &cookie));
+ TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
UTI_GetRandomBytes(uniq_id, sizeof (uniq_id));
UTI_GetRandomBytes(nonce, sizeof (nonce));
auth_start = info->length;
if (index != 2) {
- siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
- TEST_CHECK(SIV_SetKey(siv, c2s.key, c2s.length));
+ siv = SIV_CreateInstance(context.algorithm);
+ 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));
SIV_DestroyInstance(siv);