]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nts: add client support for authentication with AES-128-GCM-SIV
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 10 Oct 2022 14:35:20 +0000 (16:35 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 19 Oct 2022 13:50:39 +0000 (15:50 +0200)
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.

doc/chronyc.adoc
nts_ke_client.c
test/unit/nts_ke_client.c
test/unit/nts_ntp_client.c

index 9f4e804e46f438ed58f92e39154f85c28f9d5caa..57300eeca8e38e8e64cc932cbcef39d74dbf056f 100644 (file)
@@ -610,6 +610,7 @@ be reported:
 * 13: AES128
 * 14: AES256
 * 15: AEAD-AES-SIV-CMAC-256
+* 30: AEAD-AES-128-GCM-SIV
 *KLen*:::
 This column shows the length of the key in bits.
 *Last*:::
index 2ad810672b9117084c9f13a76e304fccc83139a7..3891f71293467620a3211c6b05d0fb6fb161f515 100644 (file)
@@ -102,16 +102,22 @@ static int
 prepare_request(NKC_Instance inst)
 {
   NKSN_Instance session = inst->session;
-  uint16_t datum;
+  uint16_t data[2];
+  int length;
 
   NKSN_BeginMessage(session);
 
-  datum = htons(NKE_NEXT_PROTOCOL_NTPV4);
-  if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, &datum, sizeof (datum)))
+  data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
+  if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
     return 0;
 
-  datum = htons(AEAD_AES_SIV_CMAC_256);
-  if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, &datum, sizeof (datum)))
+  length = 0;
+  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;
 
   if (!NKSN_EndMessage(session))
@@ -159,12 +165,14 @@ process_response(NKC_Instance inst)
         next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
         break;
       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");
           error = 1;
           break;
         }
-        aead_algorithm = AEAD_AES_SIV_CMAC_256;
+        aead_algorithm = ntohs(data[0]);
         inst->context.algorithm = aead_algorithm;
         break;
       case NKE_RECORD_ERROR:
@@ -236,7 +244,7 @@ process_response(NKC_Instance inst)
 
   if (error || inst->num_cookies == 0 ||
       next_protocol != NKE_NEXT_PROTOCOL_NTPV4 ||
-      aead_algorithm != AEAD_AES_SIV_CMAC_256)
+      aead_algorithm < 0)
     return 0;
 
   return 1;
index 72690bf1f3bba7c61b3c31f4a576ec9547c160b9..3100d1dcf9f403376eccc89636486525c67a729c 100644 (file)
@@ -64,9 +64,12 @@ prepare_response(NKSN_Instance session, int valid)
 
   if (index != 5) {
     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
-      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)
       length = 3 + random() % 10;
     TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data, length));
index c14fd41b7c092aac62cc589ce1b99fc43fd55bf9..7953413d01e3bbabaa183f781e41dbf10d37247a 100644 (file)
@@ -50,7 +50,10 @@ get_nts_data(NKC_Instance inst, NKE_Context *context,
   if (random() % 2)
     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);
   UTI_GetRandomBytes(context->c2s.key, context->c2s.length);
@@ -75,9 +78,9 @@ static int
 get_request(NNC_Instance inst)
 {
   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_Packet packet;
-  int expected_length, req_cookies;
 
   memset(&packet, 0, sizeof (packet));
   memset(&info, 0, sizeof (info));
@@ -100,6 +103,17 @@ get_request(NNC_Instance inst)
   TEST_CHECK(inst->num_cookies > 0);
   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(uniq_id, inst->uniq_id, sizeof (uniq_id));
   TEST_CHECK(NNC_PrepareForAuth(inst));
@@ -111,9 +125,10 @@ get_request(NNC_Instance inst)
                       (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);
-  DEBUG_LOG("length=%d cookie_length=%d expected_length=%d",
-            info.length, inst->cookies[inst->cookie_index].length, expected_length);
+                    4 + 4 + nonce_length + SIV_GetTagLength(inst->siv);
+  DEBUG_LOG("algo=%d length=%d cookie_length=%d expected_length=%d",
+            (int)inst->context.algorithm, info.length,
+            inst->cookies[inst->cookie_index].length, expected_length);
 
   if (info.length % 4 == 0 && info.length >= NTP_HEADER_LENGTH &&
       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;
   }
 
-  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 {
     cookie_length = random() % (sizeof (cookie) + 1);