nts: add client support for authentication with AES-128-GCM-SIV
If AES-128-GCM-SIV is available on the client, add it to the requested algorithms in NTS-KE as the first (preferred) entry. If supported on the server, it will make the cookies shorter, which will get the length of NTP messages containing only one cookie below 200 octets. This should make NTS more reliable in networks where longer NTP packets are filtered as a mitigation against amplification attacks exploiting the ntpd mode 6/7 protocol.
This commit is contained in:
parent
73042494bd
commit
cc706b50b9
4 changed files with 46 additions and 16 deletions
|
@ -610,6 +610,7 @@ be reported:
|
||||||
* 13: AES128
|
* 13: AES128
|
||||||
* 14: AES256
|
* 14: AES256
|
||||||
* 15: AEAD-AES-SIV-CMAC-256
|
* 15: AEAD-AES-SIV-CMAC-256
|
||||||
|
* 30: AEAD-AES-128-GCM-SIV
|
||||||
*KLen*:::
|
*KLen*:::
|
||||||
This column shows the length of the key in bits.
|
This column shows the length of the key in bits.
|
||||||
*Last*:::
|
*Last*:::
|
||||||
|
|
|
@ -102,16 +102,22 @@ static int
|
||||||
prepare_request(NKC_Instance inst)
|
prepare_request(NKC_Instance inst)
|
||||||
{
|
{
|
||||||
NKSN_Instance session = inst->session;
|
NKSN_Instance session = inst->session;
|
||||||
uint16_t datum;
|
uint16_t data[2];
|
||||||
|
int length;
|
||||||
|
|
||||||
NKSN_BeginMessage(session);
|
NKSN_BeginMessage(session);
|
||||||
|
|
||||||
datum = htons(NKE_NEXT_PROTOCOL_NTPV4);
|
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
|
||||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, &datum, sizeof (datum)))
|
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
datum = htons(AEAD_AES_SIV_CMAC_256);
|
length = 0;
|
||||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, &datum, sizeof (datum)))
|
if (SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0)
|
||||||
|
data[length++] = htons(AEAD_AES_128_GCM_SIV);
|
||||||
|
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) > 0)
|
||||||
|
data[length++] = htons(AEAD_AES_SIV_CMAC_256);
|
||||||
|
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data,
|
||||||
|
length * sizeof (data[0])))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!NKSN_EndMessage(session))
|
if (!NKSN_EndMessage(session))
|
||||||
|
@ -159,12 +165,14 @@ process_response(NKC_Instance inst)
|
||||||
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
||||||
break;
|
break;
|
||||||
case NKE_RECORD_AEAD_ALGORITHM:
|
case NKE_RECORD_AEAD_ALGORITHM:
|
||||||
if (length != 2 || ntohs(data[0]) != AEAD_AES_SIV_CMAC_256) {
|
if (length != 2 || (ntohs(data[0]) != AEAD_AES_SIV_CMAC_256 &&
|
||||||
|
ntohs(data[0]) != AEAD_AES_128_GCM_SIV) ||
|
||||||
|
SIV_GetKeyLength(ntohs(data[0])) <= 0) {
|
||||||
DEBUG_LOG("Unexpected NTS-KE AEAD algorithm");
|
DEBUG_LOG("Unexpected NTS-KE AEAD algorithm");
|
||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
aead_algorithm = AEAD_AES_SIV_CMAC_256;
|
aead_algorithm = ntohs(data[0]);
|
||||||
inst->context.algorithm = aead_algorithm;
|
inst->context.algorithm = aead_algorithm;
|
||||||
break;
|
break;
|
||||||
case NKE_RECORD_ERROR:
|
case NKE_RECORD_ERROR:
|
||||||
|
@ -236,7 +244,7 @@ process_response(NKC_Instance inst)
|
||||||
|
|
||||||
if (error || inst->num_cookies == 0 ||
|
if (error || inst->num_cookies == 0 ||
|
||||||
next_protocol != NKE_NEXT_PROTOCOL_NTPV4 ||
|
next_protocol != NKE_NEXT_PROTOCOL_NTPV4 ||
|
||||||
aead_algorithm != AEAD_AES_SIV_CMAC_256)
|
aead_algorithm < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -64,9 +64,12 @@ prepare_response(NKSN_Instance session, int valid)
|
||||||
|
|
||||||
if (index != 5) {
|
if (index != 5) {
|
||||||
if (index == 6)
|
if (index == 6)
|
||||||
data[0] = htons(AEAD_AES_SIV_CMAC_256 + random() % 10 + 1);
|
do {
|
||||||
|
data[0] = htons(random() % 100);
|
||||||
|
} while (SIV_GetKeyLength(ntohs(data[0])) > 0);
|
||||||
else
|
else
|
||||||
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 == 7)
|
if (index == 7)
|
||||||
length = 3 + random() % 10;
|
length = 3 + random() % 10;
|
||||||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data, length));
|
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data, length));
|
||||||
|
|
|
@ -50,7 +50,10 @@ get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||||
if (random() % 2)
|
if (random() % 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
context->algorithm = AEAD_AES_SIV_CMAC_256;
|
do {
|
||||||
|
context->algorithm = AEAD_AES_SIV_CMAC_256 + random() %
|
||||||
|
(AEAD_AES_256_GCM_SIV - AEAD_AES_SIV_CMAC_256 + 10);
|
||||||
|
} while (SIV_GetKeyLength(context->algorithm) <= 0);
|
||||||
|
|
||||||
context->c2s.length = SIV_GetKeyLength(context->algorithm);
|
context->c2s.length = SIV_GetKeyLength(context->algorithm);
|
||||||
UTI_GetRandomBytes(context->c2s.key, context->c2s.length);
|
UTI_GetRandomBytes(context->c2s.key, context->c2s.length);
|
||||||
|
@ -75,9 +78,9 @@ static int
|
||||||
get_request(NNC_Instance inst)
|
get_request(NNC_Instance inst)
|
||||||
{
|
{
|
||||||
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH], uniq_id[NTS_MIN_UNIQ_ID_LENGTH];
|
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH], uniq_id[NTS_MIN_UNIQ_ID_LENGTH];
|
||||||
|
int nonce_length, expected_length, req_cookies;
|
||||||
NTP_PacketInfo info;
|
NTP_PacketInfo info;
|
||||||
NTP_Packet packet;
|
NTP_Packet packet;
|
||||||
int expected_length, req_cookies;
|
|
||||||
|
|
||||||
memset(&packet, 0, sizeof (packet));
|
memset(&packet, 0, sizeof (packet));
|
||||||
memset(&info, 0, sizeof (info));
|
memset(&info, 0, sizeof (info));
|
||||||
|
@ -100,6 +103,17 @@ get_request(NNC_Instance inst)
|
||||||
TEST_CHECK(inst->num_cookies > 0);
|
TEST_CHECK(inst->num_cookies > 0);
|
||||||
TEST_CHECK(inst->siv);
|
TEST_CHECK(inst->siv);
|
||||||
|
|
||||||
|
switch (inst->context.algorithm) {
|
||||||
|
case AEAD_AES_SIV_CMAC_256:
|
||||||
|
nonce_length = 16;
|
||||||
|
break;
|
||||||
|
case AEAD_AES_128_GCM_SIV:
|
||||||
|
nonce_length = 12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(nonce, inst->nonce, sizeof (nonce));
|
memcpy(nonce, inst->nonce, sizeof (nonce));
|
||||||
memcpy(uniq_id, inst->uniq_id, sizeof (uniq_id));
|
memcpy(uniq_id, inst->uniq_id, sizeof (uniq_id));
|
||||||
TEST_CHECK(NNC_PrepareForAuth(inst));
|
TEST_CHECK(NNC_PrepareForAuth(inst));
|
||||||
|
@ -111,9 +125,10 @@ get_request(NNC_Instance inst)
|
||||||
(inst->cookies[inst->cookie_index].length + 4));
|
(inst->cookies[inst->cookie_index].length + 4));
|
||||||
expected_length = info.length + 4 + sizeof (inst->uniq_id) +
|
expected_length = info.length + 4 + sizeof (inst->uniq_id) +
|
||||||
req_cookies * (4 + inst->cookies[inst->cookie_index].length) +
|
req_cookies * (4 + inst->cookies[inst->cookie_index].length) +
|
||||||
4 + 4 + sizeof (inst->nonce) + SIV_GetTagLength(inst->siv);
|
4 + 4 + nonce_length + SIV_GetTagLength(inst->siv);
|
||||||
DEBUG_LOG("length=%d cookie_length=%d expected_length=%d",
|
DEBUG_LOG("algo=%d length=%d cookie_length=%d expected_length=%d",
|
||||||
info.length, inst->cookies[inst->cookie_index].length, expected_length);
|
(int)inst->context.algorithm, info.length,
|
||||||
|
inst->cookies[inst->cookie_index].length, expected_length);
|
||||||
|
|
||||||
if (info.length % 4 == 0 && info.length >= NTP_HEADER_LENGTH &&
|
if (info.length % 4 == 0 && info.length >= NTP_HEADER_LENGTH &&
|
||||||
inst->cookies[inst->cookie_index].length % 4 == 0 &&
|
inst->cookies[inst->cookie_index].length % 4 == 0 &&
|
||||||
|
@ -162,7 +177,10 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce_length = random() % (sizeof (nonce)) + 1;
|
nonce_length = SIV_GetMinNonceLength(inst->siv) + random() %
|
||||||
|
(MIN(SIV_GetMaxNonceLength(inst->siv), sizeof (nonce)) -
|
||||||
|
SIV_GetMinNonceLength(inst->siv) + 1);
|
||||||
|
assert(nonce_length >= 1 && nonce_length <= sizeof (nonce));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
cookie_length = random() % (sizeof (cookie) + 1);
|
cookie_length = random() % (sizeof (cookie) + 1);
|
||||||
|
|
Loading…
Reference in a new issue