Allow decryption with card keys > 3072 bit
authorWerner Koch <wk@gnupg.org>
Tue, 6 Nov 2012 13:39:22 +0000 (14:39 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 6 Nov 2012 13:39:22 +0000 (14:39 +0100)
* scd/command.c (MAXLEN_SETDATA): New.
(cmd_setdata): Add option --append.
* g10/call-agent.c (agent_scd_pkdecrypt): Use new option for long data

* scd/app-openpgp.c (struct app_local_s): Add field manufacturer.
(app_select_openpgp): Store manufacturer.
(do_decipher): Print a note for broken cards.

--

Please note that I was not able to run a full test because I only have
broken cards (S/N < 346) available.

g10/call-agent.c
scd/app-openpgp.c
scd/command.c

index cded773..373d8c9 100644 (file)
@@ -1034,7 +1034,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
 
 
 /* Decrypt INDATA of length INDATALEN using the card identified by
-   SERIALNO.  Return the plaintext in a nwly allocated buffer stored
+   SERIALNO.  Return the plaintext in a newly allocated buffer stored
    at the address of R_BUF.
 
    Note, we currently support only RSA or more exactly algorithms
@@ -1058,20 +1058,26 @@ agent_scd_pkdecrypt (const char *serialno,
     return rc;
 
   /* FIXME: use secure memory where appropriate */
-  if (indatalen*2 + 50 > DIM(line))
-    return gpg_error (GPG_ERR_GENERAL);
 
   rc = select_openpgp (serialno);
   if (rc)
     return rc;
 
-  sprintf (line, "SCD SETDATA ");
-  p = line + strlen (line);
-  for (i=0; i < indatalen ; i++, p += 2 )
-    sprintf (p, "%02X", indata[i]);
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  for (len = 0; len < indatalen;)
+    {
+      p = stpcpy (line, "SCD SETDATA ");
+      if (len)
+        p = stpcpy (p, "--append ");
+      for (i=0; len < indatalen && (i*2 < DIM(line)-50); i++, len++)
+        {
+          sprintf (p, "%02X", indata[len]);
+          p += 2;
+        }
+      rc = assuan_transact (agent_ctx, line,
+                            NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return rc;
+    }
 
   init_membuf (&data, 1024);
   snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
index ff26b36..141b2b7 100644 (file)
@@ -158,6 +158,8 @@ struct app_local_s {
 
   unsigned char status_indicator; /* The card status indicator.  */
 
+  unsigned int manufacturer:16;   /* Manufacturer ID from the s/n.  */
+
   /* Keep track of the ISO card capabilities.  */
   struct
   {
@@ -3462,6 +3464,12 @@ do_decipher (app_t app, const char *keyidstr,
                              indata, indatalen, le_value, padind,
                              outdata, outdatalen);
       xfree (fixbuf);
+
+      if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
+          && app->app_local->manufacturer == 5
+          && app->card_version == 0x0200)
+        log_info ("NOTE: Cards with manufacturer id 5 and s/n <= 346 (0x15a)"
+                  " do not work with encryption keys > 2048 bits\n");
     }
 
   return rc;
@@ -3749,6 +3757,8 @@ app_select_openpgp (app_t app)
           goto leave;
         }
 
+      app->app_local->manufacturer = manufacturer;
+
       if (app->card_version >= 0x0200)
         app->app_local->extcap.is_v2 = 1;
 
index 6053fc6..3ce4a57 100644 (file)
@@ -46,6 +46,9 @@
 /* Maximum allowed size of key data as used in inquiries. */
 #define MAXLEN_KEYDATA 4096
 
+/* Maximum allowed total data size for SETDATA.  */
+#define MAXLEN_SETDATA 4096
+
 /* Maximum allowed size of certificate data as used in inquiries. */
 #define MAXLEN_CERTDATA 16384
 
@@ -820,17 +823,24 @@ cmd_readkey (assuan_context_t ctx, char *line)
 
 \f
 static const char hlp_setdata[] =
-  "SETDATA <hexstring> \n"
+  "SETDATA [--append] <hexstring>\n"
   "\n"
-  "The client should use this command to tell us the data he want to sign.";
+  "The client should use this command to tell us the data he want to sign.\n"
+  "With the option --append, the data is appended to the data set by a\n"
+  "previous SETDATA command.";
 static gpg_error_t
 cmd_setdata (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
-  int n;
+  int append;
+  int n, i, off;
   char *p;
   unsigned char *buf;
 
+  append = (ctrl->in_data.value && has_option (line, "--append"));
+
+  line = skip_options (line);
+
   if (locked_session && locked_session != ctrl->server_local)
     return gpg_error (GPG_ERR_LOCKED);
 
@@ -844,14 +854,30 @@ cmd_setdata (assuan_context_t ctx, char *line)
   if ((n&1))
     return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
   n /= 2;
+  if (append)
+    {
+      if (ctrl->in_data.valuelen + n > MAXLEN_SETDATA)
+        return set_error (GPG_ERR_TOO_LARGE,
+                          "limit on total size of data reached");
+      buf = xtrymalloc (ctrl->in_data.valuelen + n);
+    }
+  else
   buf = xtrymalloc (n);
   if (!buf)
     return out_of_core ();
 
+  if (append)
+    {
+      memcpy (buf, ctrl->in_data.value, ctrl->in_data.valuelen);
+      off = ctrl->in_data.valuelen;
+    }
+  else
+    off = 0;
+  for (p=line, i=0; i < n; p += 2, i++)
+    buf[off+i] = xtoi_2 (p);
+
   ctrl->in_data.value = buf;
-  ctrl->in_data.valuelen = n;
-  for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
-    buf[n] = xtoi_2 (p);
+  ctrl->in_data.valuelen = off + n;
   return 0;
 }