Page MenuHome GnuPG

GpgAgent: trustlist.txt still requires LF on the last line
Open, LowPublic

Description

According to https://dev.gnupg.org/rG1b4ac98de7db6f6828b1b255ad3d4e5e7373666e the last line in trustlist.txt should not require a LF. This is still not the case.

With the following trustlist.txt (our test root cert, no newline at the end):

D4:EC:A6:B4:69:AB:B5:44:08:27:CB:3F:C7:D7:91:08:3C:10:27:DB S

In both gpg4win-5.0.0 @ win11 and vsd-3.3.4 @ win10 I still get a Line too long error:

2026-02-02 14:53:04 gpg-agent[6276] file 'C:\ProgramData\GNU\etc\gnupg\trustlist.txt', line 48: Line too long
2026-02-02 14:53:04 gpg-agent[6276] error reading list of trusted root certificates
2026-02-02 14:53:04 gpg-agent[6276] command 'LISTTRUSTED' failed: Line too long

Details

Version
gpg4win-5.0.0 @ win11, vsd-3.3.4 @ win10

Event Timeline

timegrid created this object with edit policy "Contributor (Project)".

Oh yeah, the mentioned patch is bogus because it assumes that fgets has already set the eof flag while reading the last line. This seems not to be the case.

I found that it's not that simple to accept the case of no newline at the end.
Because we need to handle the edge case where no newline occurs at the maximum buffer length, too.
It's something like the following.

diff --git a/agent/trustlist.c b/agent/trustlist.c
index f90075a1f..ea289e178 100644
--- a/agent/trustlist.c
+++ b/agent/trustlist.c
@@ -162,7 +162,6 @@ read_one_trustfile (const char *fname, int systrust,
   int tableidx;
   size_t tablesize;
   int lnr = 0;
-  int no_trailing_lf = 0;
 
   table = *addr_of_table;
   tablesize = *addr_of_tablesize;
@@ -181,21 +180,54 @@ read_one_trustfile (const char *fname, int systrust,
       lnr++;
 
       n = strlen (line);
-      if (!n || line[n-1] != '\n')
+
+      if (n == 0)
         {
-          if (n && es_feof (fp))
-            no_trailing_lf = 1;  /* (The next fgets will break the loop.) */
-          /* Eat until end of line. */
-          while ( (c=es_getc (fp)) != EOF && c != '\n')
-            ;
-          err = gpg_error (*line && !no_trailing_lf? GPG_ERR_LINE_TOO_LONG
-                           : GPG_ERR_INCOMPLETE_LINE);
+          /* Something goes wrong.  */
+          err = gpg_error (GPG_ERR_INCOMPLETE_LINE);
           log_error (_("file '%s', line %d: %s\n"),
                      fname, lnr, gpg_strerror (err));
-          if (no_trailing_lf)
-            err = 0;  /* Clear the error.  */
           continue;
         }
+
+      /* Firstly, check if it's too long to have a newline.  */
+      if (n == DIM(line)-1 && line[n-1] != '\n')
+        {
+          c = es_getc (fp);
+          if (c == EOF)
+            /* Accept no newline at EOF.  */
+            n++;
+          else
+            {
+              /* Eat until end of line. */
+              do
+                c = es_getc (fp);
+              while (c != EOF && c != '\n');
+              /* Then, emit an error and ignore the line.  */
+              err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+              log_error (_("file '%s', line %d: %s\n"),
+                         fname, lnr, gpg_strerror (err));
+              continue;
+            }
+        }
+      /* Secondly, check if it has no newline, but not too long.  */
+      else if (line[n-1] != '\n')
+        {
+          c = es_getc (fp);
+          if (c == EOF)
+            /* Accept no newline at EOF.  */ 
+            n++;
+          else
+            {
+              /* Emit an error and ignore the line.  */
+              es_ungetc (c, fp);
+              err = gpg_error (GPG_ERR_INCOMPLETE_LINE);
+              log_error (_("file '%s', line %d: %s\n"),
+                         fname, lnr, gpg_strerror (err));
+              continue;
+            }
+        }
+
       line[--n] = 0; /* Chop the LF. */
       if (n && line[n-1] == '\r')
         line[--n] = 0; /* Chop an optional CR. */
gniibe mentioned this in Unknown Object (Maniphest Task).Mon, Mar 2, 3:00 AM

This should also be fixed in 2.2 and 2.4 (if neccessary)

That change is too complex for just getting a proper error message. The original patch covers the most common case.

vsd 3.3 does not have the fix at all.