]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nts: add support for NTP authenticator field using AES-GCM-SIV
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 10 Oct 2022 13:09:01 +0000 (15:09 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 19 Oct 2022 13:50:39 +0000 (15:50 +0200)
Add support for SIV algorithms which have maximum nonce length shorter
than 16 bytes.

nts_ntp_auth.c
nts_ntp_auth.h
test/unit/nts_ntp_auth.c

index 78e54c293cf1efb0bc8f936a0f890625773d5272..2f502bb5327548aadf2e2a76e74ba72313a0960c 100644 (file)
@@ -61,23 +61,25 @@ get_padded_length(int length)
 
 int
 NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
-                   const unsigned char *nonce, int nonce_length,
+                   const unsigned char *nonce, int max_nonce_length,
                    const unsigned char *plaintext, int plaintext_length,
                    int min_ef_length)
 {
-  int auth_length, ciphertext_length, assoc_length;
+  int auth_length, ciphertext_length, assoc_length, nonce_length, max_siv_nonce_length;
   int nonce_padding, ciphertext_padding, additional_padding;
   unsigned char *ciphertext, *body;
   struct AuthHeader *header;
 
   assert(sizeof (*header) == 4);
 
-  if (nonce_length <= 0 || plaintext_length < 0) {
+  if (max_nonce_length <= 0 || plaintext_length < 0) {
     DEBUG_LOG("Invalid nonce/plaintext length");
     return 0;
   }
 
   assoc_length = info->length;
+  max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
+  nonce_length = MIN(max_nonce_length, max_siv_nonce_length);
   ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
   nonce_padding = get_padding_length(nonce_length);
   ciphertext_padding = get_padding_length(ciphertext_length);
@@ -86,8 +88,8 @@ NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
   auth_length = sizeof (*header) + nonce_length + nonce_padding +
                 ciphertext_length + ciphertext_padding;
   additional_padding = MAX(min_ef_length - auth_length - 4, 0);
-  additional_padding = MAX(NTS_MIN_UNPADDED_NONCE_LENGTH - nonce_length - nonce_padding,
-                           additional_padding);
+  additional_padding = MAX(MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) -
+                           nonce_length - nonce_padding, additional_padding);
   auth_length += additional_padding;
 
   if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
@@ -127,7 +129,7 @@ int
 NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
                   unsigned char *plaintext, int buffer_length, int *plaintext_length)
 {
-  int siv_tag_length, nonce_length, ciphertext_length;
+  int siv_tag_length, max_siv_nonce_length, nonce_length, ciphertext_length;
   unsigned char *nonce, *ciphertext;
   int ef_type, ef_body_length;
   void *ef_body;
@@ -155,6 +157,7 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
   nonce = (unsigned char *)(header + 1);
   ciphertext = nonce + get_padded_length(nonce_length);
 
+  max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
   siv_tag_length = SIV_GetTagLength(siv);
 
   if (nonce_length < 1 ||
@@ -164,8 +167,8 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
     return 0;
   }
 
-  if (ef_body_length < sizeof (*header) +
-        NTS_MIN_UNPADDED_NONCE_LENGTH + get_padded_length(ciphertext_length)) {
+  if (sizeof (*header) + MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) +
+      get_padded_length(ciphertext_length) > ef_body_length) {
     DEBUG_LOG("Missing padding");
     return 0;
   }
index 856beb3b15d2a96d156a6232f3a9a671a4170749..19d04bf8e6ad4637905c469a4b7a231d26d1c7d3 100644 (file)
@@ -32,7 +32,7 @@
 #include "siv.h"
 
 extern int NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
-                              const unsigned char *nonce, int nonce_length,
+                              const unsigned char *nonce, int max_nonce_length,
                               const unsigned char *plaintext, int plaintext_length,
                               int min_ef_length);
 
index 307b93b81c416746f72085567a28108389668ec7..207ebeb5a0459f24f723dbbbbdd5d0059b3c6f2b 100644 (file)
@@ -34,74 +34,95 @@ test_unit(void)
   unsigned char key[SIV_MAX_KEY_LENGTH], nonce[256], plaintext[256], plaintext2[256];
   NTP_PacketInfo info;
   NTP_Packet packet;
+  SIV_Algorithm algo;
   SIV_Instance siv;
   int i, j, r, packet_length, nonce_length, key_length;
   int plaintext_length, plaintext2_length, min_ef_length;
 
-  siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
-  TEST_CHECK(siv);
-
-  for (i = 0; i < 10000; i++) {
-    key_length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
-    for (j = 0; j < key_length; j++)
-      key[j] = random() % 256;
-    TEST_CHECK(SIV_SetKey(siv, key, key_length));
-
-    nonce_length = random() % sizeof (nonce) + 1;
-    for (j = 0; j < nonce_length; j++)
-      nonce[j] = random() % 256;
-
-    plaintext_length = random() % (sizeof (plaintext) + 1);
-    for (j = 0; j < plaintext_length; j++)
-      plaintext[j] = random() % 256;
-
-    packet_length = NTP_HEADER_LENGTH + random() % 100 * 4;
-    min_ef_length = random() % (sizeof (packet) - packet_length);
-
-    memset(&packet, 0, sizeof (packet));
-    packet.lvm = NTP_LVM(0, 4, 0);
-    memset(&info, 0, sizeof (info));
-    info.version = 4;
-    info.length = packet_length;
-
-    DEBUG_LOG("packet_length=%d nonce_length=%d plaintext_length=%d min_ef_length=%d",
-              packet_length, nonce_length, plaintext_length, min_ef_length);
-
-    r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
-                           -1, 0);
-    TEST_CHECK(!r);
-    r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, 0, plaintext,
-                           plaintext_length, 0);
-    TEST_CHECK(!r);
-    r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
-                           plaintext_length, sizeof (packet) - info.length + 1);
-    TEST_CHECK(!r);
-
-    r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
-                           plaintext_length, min_ef_length);
-    TEST_CHECK(r);
-    TEST_CHECK(info.length - packet_length >= min_ef_length);
-
-    r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
-                          -1, &plaintext2_length);
-    TEST_CHECK(!r);
-
-    r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
-                          sizeof (plaintext2), &plaintext2_length);
-    TEST_CHECK(r);
-    TEST_CHECK(plaintext_length == plaintext2_length);
-    TEST_CHECK(memcmp(plaintext, plaintext2, plaintext_length) == 0);
-
-    j = random() % (packet_length + plaintext_length +
-                    nonce_length + SIV_GetTagLength(siv) + 8) / 4 * 4;
-    ((unsigned char *)&packet)[j]++;
-    r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
-                          sizeof (plaintext2), &plaintext2_length);
-    TEST_CHECK(!r);
-    ((unsigned char *)&packet)[j]--;
+  for (algo = 1; algo < 100; algo++) {
+    siv = SIV_CreateInstance(algo);
+    if (!siv) {
+      TEST_CHECK(algo != AEAD_AES_SIV_CMAC_256);
+      continue;
+    }
+
+    DEBUG_LOG("algo=%d", (int)algo);
+
+    for (i = 0; i < 10000; i++) {
+      key_length = SIV_GetKeyLength(algo);
+      for (j = 0; j < key_length; j++)
+        key[j] = random() % 256;
+      TEST_CHECK(SIV_SetKey(siv, key, key_length));
+
+      assert(sizeof (nonce) >= SIV_GetMinNonceLength(siv));
+      nonce_length = SIV_GetMinNonceLength(siv) +
+                     random() % (MIN(sizeof (nonce), SIV_GetMaxNonceLength(siv)) -
+                                 SIV_GetMinNonceLength(siv) + 1);
+      for (j = 0; j < nonce_length; j++)
+        nonce[j] = random() % 256;
+
+      plaintext_length = random() % (sizeof (plaintext) + 1);
+      for (j = 0; j < plaintext_length; j++)
+        plaintext[j] = random() % 256;
+
+      packet_length = NTP_HEADER_LENGTH + random() % 100 * 4;
+      min_ef_length = random() % (sizeof (packet) - packet_length);
+
+      memset(&packet, 0, sizeof (packet));
+      packet.lvm = NTP_LVM(0, 4, 0);
+      memset(&info, 0, sizeof (info));
+      info.version = 4;
+      info.length = packet_length;
+
+      DEBUG_LOG("packet_length=%d nonce_length=%d plaintext_length=%d min_ef_length=%d",
+                packet_length, nonce_length, plaintext_length, min_ef_length);
+
+      r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
+                             -1, 0);
+      TEST_CHECK(!r);
+      r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, 0, plaintext,
+                             plaintext_length, 0);
+      TEST_CHECK(!r);
+      if (SIV_GetMinNonceLength(siv) > 1) {
+        r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, SIV_GetMinNonceLength(siv) - 1,
+                               plaintext, plaintext_length, 0);
+        TEST_CHECK(!r);
+      }
+      if (SIV_GetMaxNonceLength(siv) <= sizeof (nonce)) {
+        r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, SIV_GetMaxNonceLength(siv) - 1,
+                               plaintext, plaintext_length, 0);
+        TEST_CHECK(!r);
+      }
+      r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
+                             plaintext_length, sizeof (packet) - info.length + 1);
+      TEST_CHECK(!r);
+
+      r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
+                             plaintext_length, min_ef_length);
+      TEST_CHECK(r);
+      TEST_CHECK(info.length - packet_length >= min_ef_length);
+
+      r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
+                            -1, &plaintext2_length);
+      TEST_CHECK(!r);
+
+      r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
+                            sizeof (plaintext2), &plaintext2_length);
+      TEST_CHECK(r);
+      TEST_CHECK(plaintext_length == plaintext2_length);
+      TEST_CHECK(memcmp(plaintext, plaintext2, plaintext_length) == 0);
+
+      j = random() % (packet_length + plaintext_length +
+                      nonce_length + SIV_GetTagLength(siv) + 8) / 4 * 4;
+      ((unsigned char *)&packet)[j]++;
+      r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
+                            sizeof (plaintext2), &plaintext2_length);
+      TEST_CHECK(!r);
+      ((unsigned char *)&packet)[j]--;
+    }
+
+    SIV_DestroyInstance(siv);
   }
-
-  SIV_DestroyInstance(siv);
 }
 #else
 void