]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cksum: fix --check with untagged base64 format with tag matches
authorPádraig Brady <P@draigBrady.com>
Mon, 6 Oct 2025 18:41:24 +0000 (19:41 +0100)
committerPádraig Brady <P@draigBrady.com>
Tue, 7 Oct 2025 14:58:36 +0000 (15:58 +0100)
* src/digest.c (split_3): Fallback to untagged matching in the
case where -a is specified and we have matched a TAG in
the possibly base64 data.  This might happen in 1 in every 64K files.
Note we remove the modification of string S (and redundant streq) in
the tag matching, as that was not needed since v8.32-223-g217cd278e.
* tests/cksum/cksum-c.sh: Add a test case.
* NEWS: Mention the bug fix.

NEWS
src/digest.c
tests/cksum/cksum-c.sh

diff --git a/NEWS b/NEWS
index b49c2ea80f33dc9bc40f14485c7de7cc7c855d1f..aa7c13f97c5ccb8a96f5c199e972ed5e08423588 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,8 +7,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   `basenc --base58` would not operate correctly with input > 15561475 bytes.
   [bug introduced with --base58 in coreutils-9.8]
 
-  'cksum --check' now supports base64 encoded input in untagged format,
-  for all length adjustable algorithms (blake2b, sha2, sha3).
+  'cksum --check' now supports base64 encoded input in untagged format:
+    - for all length adjustable algorithms (blake2b, sha2, sha3),
+    - if that base64 input starts with a tag like "SHA1" etc.
+  Previously an error was given, about invalid input format.
   [bug introduced in coreutils-9.2]
 
   'cksum --check -a sha2' has better support for tagged format.  Previously
index 45c13e33c66794bea4d60ad4e4f7fa6b1144753d..d2e6e212aa1a6014b0bba86c8d968fa3d4d8ab67 100644 (file)
@@ -847,43 +847,42 @@ split_3 (char *s, size_t s_len,
   if (! algorithm_specified || cksum_algorithm == sha2)
     {
       ptrdiff_t algo_tag = algorithm_from_tag (s + i);
-      if (algo_tag >= 0)
+      if (! algorithm_specified)
         {
-          if (algo_tag <= crc32b)
-            return false;  /* We don't support checking these older formats.  */
-          if (cksum_algorithm == sha2 && algo_tag != sha2
-              && algo_tag != sha224 && algo_tag != sha256
-              && algo_tag != sha384 && algo_tag != sha512)
-            return false;  /* Wrong tag for -a sha2.  */
-          cksum_algorithm = algo_tag;
+          if (algo_tag >= 0)
+            {
+              if (algo_tag <= crc32b)
+                return false;  /* We don't support checking these formats.  */
+              cksum_algorithm = algo_tag;
+            }
+          else
+            return false;      /* We only support tagged format without -a.  */
+        }
+      else
+        {
+          if (cksum_algorithm == sha2 && (algo_tag == sha2
+              || algo_tag == sha224 || algo_tag == sha256
+              || algo_tag == sha384 || algo_tag == sha512))
+            cksum_algorithm = algo_tag;
         }
-      else if (! algorithm_specified)
-        return false;  /* We only support tagged format without -a.  */
     }
 #endif
 
+  size_t parse_offset = i;
   algo_name_len = strlen (DIGEST_TYPE_STRING);
   if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
     {
       i += algo_name_len;
 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
-      /* Terminate and match algorithm name.  */
-      char const *algo_name = &s[i - algo_name_len];
-      bool length_specified = s[i] == '-';
-      bool openssl_format = s[i] == '('; /* and no length_specified */
-      s[i++] = '\0';
-      if (!streq (algo_name, DIGEST_TYPE_STRING))
-        return false;
-      if (openssl_format)
-        s[--i] = '(';
 
 # if HASH_ALGO_BLAKE2
       digest_length = DIGEST_MAX_LEN * 8;
 # else
       digest_length = algorithm_bits[cksum_algorithm];
 # endif
-      if (length_specified)
+      if (s[i] == '-')  /* length specified. Not base64 */
         {
+          ++i;
           uintmax_t length;
           char *siend;
           if (xstrtoumax (s + i, &siend, 0, &length, nullptr) != LONGINT_OK)
@@ -908,14 +907,18 @@ split_3 (char *s, size_t s_len,
 #endif
       if (s[i] == ' ')
         ++i;
-      if (s[i] == '(')
+      if (s[i] == '(')  /* not base64 */
         {
           ++i;
           *binary = 0;
           return bsd_split_3 (s + i, s_len - i,
                               digest, d_len, file_name, escaped_filename);
         }
-      return false;
+
+      /* Note with --base64 --untagged format, we may have matched a "tag".
+         Even very short digests with: cksum -a blake2b -l24 --untagged --base64
+         So fallback to checking untagged format if issues detecting tags.  */
+      i = parse_offset;
     }
 
   /* Ignore this line if it is too short.
index 452f93368d98d7d60abfd81e6eb0d77eebc8c20e..79986d577850f675a5e9b96059303fc7990b9017 100755 (executable)
@@ -45,6 +45,14 @@ echo 'cksum: sha2-bad-length.sum: no properly formatted checksum lines found' \
   > experr || framework_failure_
 compare experr err || fail=1
 
+# Ensure base64 in untagged format that matches tags is supported
+# From coreutils 9.2 - 9.8 inclusive this was not supported
+echo 'SHA1+++++++++++++++++++++++=  /dev/null' > tag-prefix.sum \
+  || framework_failure_
+returns_ 1 cksum --check -a sha1 tag-prefix.sum 2>err || fail=1
+echo 'cksum: WARNING: 1 computed checksum did NOT match' \
+  > experr || framework_failure_
+compare experr err || fail=1
 
 # Ensure leading whitespace and \ ignored
 sed 's/^/ \\/' CHECKSUMS | cksum --strict -c || fail=1