[PATCH] Scute: remove extra nul byte in signature data

Damien Goutte-Gattat dgouttegattat at incenp.org
Wed Jan 28 17:09:57 CET 2015


* src/agent.c (scute_agent_sign): Check for extra nul byte at the
beginning of signature data.
--

GPG Agent 2.1 prepends a nul byte in the signature value if the first
byte has its most significant bit set, to prevent it from being
interpreted as a sign bit (see agent_pksign_do, in GnuPG's
agent/pksign.c).

But Scute expects the signature to be always of a fixed size (128 or
256 bytes), and it will reject a signature containing this extra nul
byte.

This patch makes Scute read the effective size of the signature from
the S-expression, and remove the prepended nul byte if present.

Signed-off-by: Damien Goutte-Gattat <dgouttegattat at incenp.org>
---
 src/agent.c | 57 ++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 25 deletions(-)

diff --git a/src/agent.c b/src/agent.c
index 9265ca2..547c587 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -981,13 +981,12 @@ pksign_cb (void *opaque, const void *buffer, size_t length)
 }
 
 
-#define SIG_PREFIX   "(7:sig-val(3:rsa(1:s128:"
-#define SIG_PREFIX_2 "(7:sig-val(3:rsa(1:s256:"
+#define SIG_PREFIX   "(7:sig-val(3:rsa(1:s"
 #define SIG_PREFIX_LEN (sizeof (SIG_PREFIX) - 1)
 #define SIG_POSTFIX ")))"
 #define SIG_POSTFIX_LEN (sizeof (SIG_POSTFIX) - 1)
-#define SIG_LEN 128
-#define SIG_LEN_2 256
+#define SIG_MIN_LEN 128
+#define SIG_MAX_LEN 256
 
 /* Call the agent to learn about a smartcard.  */
 gpg_error_t
@@ -1009,14 +1008,14 @@ scute_agent_sign (char *grip, unsigned char *data, int len,
   if (sig_result == NULL)
     {
       /* FIXME:  We return the largest supported size - is that correct?  */
-      *sig_len = SIG_LEN_2;
+      *sig_len = SIG_MAX_LEN;
       return 0;
     }
 
   if (len > MAX_DATA_LEN)
     return gpg_error (GPG_ERR_INV_ARG);
 
-  if (grip == NULL || sig_result == NULL || *sig_len < SIG_LEN)
+  if (grip == NULL || sig_result == NULL || *sig_len < SIG_MIN_LEN)
     return gpg_error (GPG_ERR_INV_ARG);
 
   snprintf (cmd, sizeof (cmd), "SIGKEY %s", grip);
@@ -1041,30 +1040,38 @@ scute_agent_sign (char *grip, unsigned char *data, int len,
     return err;
 
   /* FIXME: we need a real parser to cope with all kind of S-expressions.  */
-  if (sig.len == SIG_PREFIX_LEN + SIG_LEN_2 + SIG_POSTFIX_LEN)
+  if (!memcmp (sig.data, SIG_PREFIX, SIG_PREFIX_LEN))
     {
-      if (memcmp (sig.data, SIG_PREFIX_2, SIG_PREFIX_LEN))
-        return gpg_error (GPG_ERR_BAD_SIGNATURE);
-      if (memcmp (sig.data + sig.len - SIG_POSTFIX_LEN,
-                  SIG_POSTFIX, SIG_POSTFIX_LEN))
-        return gpg_error (GPG_ERR_BAD_SIGNATURE);
-      memcpy (sig_result, sig.data + SIG_PREFIX_LEN, SIG_LEN_2);
-      *sig_len = SIG_LEN_2;
-    }
-  else
-    {
-      if (sig.len != SIG_PREFIX_LEN + SIG_LEN + SIG_POSTFIX_LEN)
+      unsigned char *sig_val;
+      unsigned int sig_val_len;
+
+      sig_val_len = strtol (sig.data + SIG_PREFIX_LEN, (char **)&sig_val, 10);
+
+      if (*(sig_val++) != ':')
         return gpg_error (GPG_ERR_BAD_SIGNATURE);
-      if (memcmp (sig.data, SIG_PREFIX, SIG_PREFIX_LEN))
+      if (sig.len != sig_val - sig.data + sig_val_len + SIG_POSTFIX_LEN)
         return gpg_error (GPG_ERR_BAD_SIGNATURE);
-      if (memcmp (sig.data + sig.len - SIG_POSTFIX_LEN,
-                  SIG_POSTFIX, SIG_POSTFIX_LEN))
+      if (memcmp (sig.data + sig.len - SIG_POSTFIX_LEN, SIG_POSTFIX,
+                  SIG_POSTFIX_LEN))
         return gpg_error (GPG_ERR_BAD_SIGNATURE);
-      memcpy (sig_result, sig.data + SIG_PREFIX_LEN, SIG_LEN);
-      *sig_len = SIG_LEN;
+
+      if ( *sig_val == 0 && *(sig_val+1) & 0x80 )
+        {
+          /* Remove the extra nul byte that was added to prevent
+           * the signature from being interpreted as a negative value. */
+          sig_val += 1;
+          sig_val_len -= 1;
+        }
+
+      if ( sig_val_len > *sig_len )
+        return gpg_error (GPG_ERR_TOO_LARGE);
+
+      memcpy (sig_result, sig_val, sig_val_len);
+      *sig_len = sig_val_len;
     }
-  
-  
+  else
+    return gpg_error( GPG_ERR_BAD_SIGNATURE );  /* Unexpected prefix. */
+
   return 0;
 }
 
-- 
1.8.4




More information about the Gnupg-devel mailing list