Allow generation of card keys up to 4096 bit.
authorWerner Koch <wk@gnupg.org>
Thu, 7 Jul 2011 09:20:53 +0000 (11:20 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 7 Jul 2011 09:20:53 +0000 (11:20 +0200)
This patch implementes a chunk mode to pass the key parameters from
scdaemon to gpg.  This allows to pass arbitrary long key paremeters;
it is used for keys larger than 3072 bit.

NEWS
configure.ac
g10/call-agent.c
g10/card-util.c
scd/app-openpgp.c
scd/command.c

diff --git a/NEWS b/NEWS
index 492fe41..b3ce8e0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,10 @@
 Noteworthy changes in version 2.0.18 (unreleased)
 -------------------------------------------------
 
+ * Allow generation of card keys up to 4096 bit.
+
+ * Bug fix for newer versions of Libgcrypt.
+
 
 Noteworthy changes in version 2.0.17 (2011-01-13)
 -------------------------------------------------
index 3527c43..36c8901 100644 (file)
@@ -1,19 +1,19 @@
 # configure.ac - for GnuPG 2.0
 # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
 #               2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
-# 
+#
 # This file is part of GnuPG.
-# 
+#
 # GnuPG is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
-# 
+#
 # GnuPG is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
@@ -31,7 +31,7 @@ m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \
           | sed -n '/^Revision:/ s/[^0-9]//gp'|head -1)]))
 m4_define([git_revision], m4_esyscmd([git branch -v 2>/dev/null \
           | awk '/^\* / {printf "%s",$3}']))
-AC_INIT([gnupg], 
+AC_INIT([gnupg],
         [my_version[]m4_if(my_issvn,[yes],
         [m4_if(git_revision,[],[-svn[]svn_revision],[-git[]git_revision])])],
         [http://bugs.gnupg.org])
@@ -67,7 +67,7 @@ AC_GNU_SOURCE
 
 # Some status variables.
 have_gpg_error=no
-have_libgcrypt=no 
+have_libgcrypt=no
 have_libassuan=no
 have_ksba=no
 have_pth=no
@@ -369,10 +369,10 @@ AH_BOTTOM([
 #ifdef HAVE_DRIVE_LETTERS
 #define GNUPG_DEFAULT_HOMEDIR "c:/gnupg"
 #elif defined(__VMS)
-#define GNUPG_DEFAULT_HOMEDIR "/SYS\$LOGIN/gnupg" 
+#define GNUPG_DEFAULT_HOMEDIR "/SYS\$LOGIN/gnupg"
 #else
 #define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
-#endif 
+#endif
 #define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
 
 /* For some systems (DOS currently), we hardcode the path here.  For
@@ -380,7 +380,7 @@ AH_BOTTOM([
    the values may be overridden by the make invocations; this is to
    comply with the GNU coding standards. */
 #ifdef HAVE_DRIVE_LETTERS
- /* FIXME: We need to use a function to determine these values depending 
+ /* FIXME: We need to use a function to determine these values depending
     on the actual installation directory. */
 #define GNUPG_BINDIR      "c:\\gnupg"
 #define GNUPG_LIBEXECDIR  "c:\\gnupg"
@@ -574,7 +574,7 @@ esac
 
 if test "$have_dosish_system" = yes; then
    AC_DEFINE(HAVE_DOSISH_SYSTEM,1,
-             [Defined if we run on some of the PCDOS like systems 
+             [Defined if we run on some of the PCDOS like systems
               (DOS, Windoze. OS/2) with special properties like
               no file modes])
 fi
@@ -726,7 +726,7 @@ else
 *** To support concurrent access to the gpg-agent and the SCdaemon
 *** we need the support of the GNU Portable Threads Library.
 *** Download it from ftp://ftp.gnu.org/gnu/pth/
-*** On a Debian GNU/Linux system you might want to try 
+*** On a Debian GNU/Linux system you might want to try
 ***   apt-get install libpth-dev
 ***]])
 fi
@@ -766,7 +766,7 @@ if test "$with_adns" != "no"; then
                 [CPPFLAGS=${_cppflags} LDFLAGS=${_ldflags}])
 fi
 if test "$have_adns" = "yes"; then
-  ADNSLIBS="-ladns" 
+  ADNSLIBS="-ladns"
 fi
 AC_SUBST(ADNSLIBS)
 # Newer adns versions feature a free function to be used under W32.
@@ -820,7 +820,7 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \
 #include <resolv.h>],
 [[unsigned char answer[PACKETSZ];
   res_query("foo.bar",C_IN,T_A,answer,PACKETSZ);
-  dn_skipname(0,0); 
+  dn_skipname(0,0);
   dn_expand(0,0,0,0,0);
 ]])],have_resolver=yes,have_resolver=no)
     AC_MSG_RESULT($have_resolver)
@@ -1155,7 +1155,7 @@ if test "$use_regex" = yes ; then
         CPPFLAGS="${CPPFLAGS} -I$withval/include"
         LDFLAGS="${LDFLAGS} -L$withval/lib"
       fi
-      ],withval="")     
+      ],withval="")
 
   # Does the system have regex functions at all?
   AC_SEARCH_LIBS([regcomp], [regex])
@@ -1215,7 +1215,7 @@ AC_CHECK_HEADER(zlib.h,
 
 #
 # Check whether we can support bzip2
-# 
+#
 if test "$use_bzip2" = yes ; then
   _cppflags="${CPPFLAGS}"
   _ldflags="${LDFLAGS}"
@@ -1229,7 +1229,7 @@ if test "$use_bzip2" = yes ; then
       ],withval="")
 
   # Checking alongside stdio.h as an early version of bzip2 (1.0)
-  # required stdio.h to be included before bzlib.h, and Solaris 9 is 
+  # required stdio.h to be included before bzlib.h, and Solaris 9 is
   # woefully out of date.
   if test "$withval" != no ; then
      AC_CHECK_HEADER(bzlib.h,
@@ -1254,7 +1254,7 @@ GNUPG_CHECK_READLINE
 #
 # Allow users to append something to the version string without
 # flagging it as development version.  The user version parts is
-# considered everything after a dash. 
+# considered everything after a dash.
 #
 if test "$development_version" != yes; then
   changequote(,)dnl
@@ -1428,7 +1428,7 @@ die=no
 if test "$have_gpg_error" = "no"; then
    die=yes
    AC_MSG_NOTICE([[
-***  
+***
 *** You need libgpg-error to build this program.
 **  This library is for example available at
 ***   ftp://ftp.gnupg.org/gcrypt/libgpg-error
@@ -1438,7 +1438,7 @@ fi
 if test "$have_libgcrypt" = "no"; then
    die=yes
    AC_MSG_NOTICE([[
-***  
+***
 *** You need libgcrypt to build this program.
 **  This library is for example available at
 ***   ftp://ftp.gnupg.org/gcrypt/libgcrypt/
@@ -1471,7 +1471,7 @@ if test "$missing_pth" = "yes"; then
 *** GNU Portable Threads Library (Pth). Please install this
 *** library first.  The library is for example available at
 ***   ftp://ftp.gnu.org/gnu/pth/
-*** On a Debian GNU/Linux system you can install it using 
+*** On a Debian GNU/Linux system you can install it using
 ***   apt-get install libpth-dev
 *** To build GnuPG for Windows you need to use the W32PTH
 *** package; available at:
@@ -1490,7 +1490,7 @@ fi
 
 
 
-AC_CONFIG_FILES([ m4/Makefile 
+AC_CONFIG_FILES([ m4/Makefile
 Makefile
 po/Makefile.in
 gl/Makefile
@@ -1517,7 +1517,7 @@ AC_OUTPUT
 
 echo "
         GnuPG v${VERSION} has been configured as follows:
-        
+
         Platform:  $PRINTABLE_OS_NAME ($host)
 
         OpenPGP:   $build_gpg
index 8906082..cded773 100644 (file)
@@ -1,5 +1,5 @@
 /* call-agent.c - Divert GPG operations to the agent.
- * Copyright (C) 2001, 2002, 2003, 2006, 2007, 
+ * Copyright (C) 2001, 2002, 2003, 2006, 2007,
  *               2008, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
+#include <unistd.h>
 #include <time.h>
 #include <assert.h>
 #ifdef HAVE_LOCALE_H
@@ -48,7 +48,7 @@
 static assuan_context_t agent_ctx = NULL;
 static int did_early_card_test;
 
-struct cipher_parm_s 
+struct cipher_parm_s
 {
   assuan_context_t ctx;
   const char *ciphertext;
@@ -69,13 +69,19 @@ struct writekey_parm_s
   size_t keydatalen;
 };
 
-struct genkey_parm_s 
+struct genkey_parm_s
 {
   assuan_context_t ctx;
   const char *sexp;
   size_t sexplen;
 };
 
+struct scd_genkey_parm_s
+{
+  struct agent_card_genkey_s *cgk;
+  char *savedbytes;     /* Malloced space to save key parameter chunks.  */
+};
+
 
 static gpg_error_t learn_status_cb (void *opaque, const char *line);
 
@@ -99,7 +105,7 @@ status_sc_op_failure (int rc)
       write_status (STATUS_SC_OP_FAILURE);
       break;
     }
-}  
+}
 
 
 
@@ -162,7 +168,7 @@ start_agent (int for_card)
       if (!rc && is_status_enabled () && info.serialno)
         {
           char *buf;
-          
+
           buf = xasprintf ("3 %s", info.serialno);
           write_status_text (STATUS_CARDCTRL, buf);
           xfree (buf);
@@ -174,7 +180,7 @@ start_agent (int for_card)
         did_early_card_test = 1;
     }
 
-  
+
   return rc;
 }
 
@@ -267,7 +273,7 @@ get_serialno_cb (void *opaque, const char *line)
       memcpy (*serialno, line, n);
       (*serialno)[n] = 0;
     }
-  
+
   return 0;
 }
 
@@ -329,7 +335,7 @@ learn_status_cb (void *opaque, const char *line)
     {
       xfree (parm->serialno);
       parm->serialno = store_serialno (line);
-      parm->is_v2 = (strlen (parm->serialno) >= 16 
+      parm->is_v2 = (strlen (parm->serialno) >= 16
                      && xtoi_2 (parm->serialno+12) >= 2 );
     }
   else if (keywordlen == 7 && !memcmp (keyword, "APPTYPE", keywordlen))
@@ -510,7 +516,7 @@ agent_learn (struct agent_card_info_s *info)
   /* Also try to get the key attributes.  */
   if (!rc)
     agent_scd_getattr ("KEY-ATTR", info);
-  
+
   return rc;
 }
 
@@ -529,7 +535,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
   /* We assume that NAME does not need escaping. */
   if (12 + strlen (name) > DIM(line)-1)
     return gpg_error (GPG_ERR_TOO_LARGE);
-  stpcpy (stpcpy (line, "SCD GETATTR "), name); 
+  stpcpy (stpcpy (line, "SCD GETATTR "), name);
 
   rc = start_agent (1);
   if (rc)
@@ -537,7 +543,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL,
                         learn_status_cb, info);
-  
+
   return rc;
 }
 
@@ -562,8 +568,8 @@ agent_scd_setattr (const char *name,
   /* We assume that NAME does not need escaping. */
   if (12 + strlen (name) > DIM(line)-1)
     return gpg_error (GPG_ERR_TOO_LARGE);
-      
-  p = stpcpy (stpcpy (line, "SCD SETATTR "), name); 
+
+  p = stpcpy (stpcpy (line, "SCD SETATTR "), name);
   *p++ = ' ';
   for (; valuelen; value++, valuelen--)
     {
@@ -584,7 +590,7 @@ agent_scd_setattr (const char *name,
   rc = start_agent (1);
   if (!rc)
     {
-      rc = assuan_transact (agent_ctx, line, NULL, NULL, 
+      rc = assuan_transact (agent_ctx, line, NULL, NULL,
                             default_inq_cb, NULL, NULL, NULL);
     }
 
@@ -601,7 +607,7 @@ static gpg_error_t
 inq_writecert_parms (void *opaque, const char *line)
 {
   int rc;
-  struct writecert_parm_s *parm = opaque; 
+  struct writecert_parm_s *parm = opaque;
 
   if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8]))
     {
@@ -615,7 +621,7 @@ inq_writecert_parms (void *opaque, const char *line)
 
 
 /* Send a WRITECERT command to the SCdaemon. */
-int 
+int
 agent_scd_writecert (const char *certidstr,
                      const unsigned char *certdata, size_t certdatalen)
 {
@@ -634,7 +640,7 @@ agent_scd_writecert (const char *certidstr,
   parms.ctx = agent_ctx;
   parms.certdata = certdata;
   parms.certdatalen = certdatalen;
-  
+
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
                         inq_writecert_parms, &parms, NULL, NULL);
 
@@ -649,7 +655,7 @@ static gpg_error_t
 inq_writekey_parms (void *opaque, const char *line)
 {
   int rc;
-  struct writekey_parm_s *parm = opaque; 
+  struct writekey_parm_s *parm = opaque;
 
   if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
     {
@@ -663,7 +669,7 @@ inq_writekey_parms (void *opaque, const char *line)
 
 
 /* Send a WRITEKEY command to the SCdaemon. */
-int 
+int
 agent_scd_writekey (int keyno, const char *serialno,
                     const unsigned char *keydata, size_t keydatalen)
 {
@@ -684,7 +690,7 @@ agent_scd_writekey (int keyno, const char *serialno,
   parms.ctx = agent_ctx;
   parms.keydata = keydata;
   parms.keydatalen = keydatalen;
-  
+
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
                         inq_writekey_parms, &parms, NULL, NULL);
 
@@ -694,14 +700,44 @@ agent_scd_writekey (int keyno, const char *serialno,
 
 
 \f
+static gpg_error_t
+scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm,
+                                 const char *line)
+{
+  gpg_error_t err = 0;
+  char *p;
+
+  if (!parm->savedbytes)
+    {
+      parm->savedbytes = xtrystrdup (line);
+      if (!parm->savedbytes)
+        err = gpg_error_from_syserror ();
+    }
+  else
+    {
+      p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1);
+      if (!p)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          strcpy (stpcpy (p, parm->savedbytes), line);
+          xfree (parm->savedbytes);
+          parm->savedbytes = p;
+        }
+    }
+
+  return err;
+}
+
+
 /* Status callback for the SCD GENKEY command. */
 static gpg_error_t
 scd_genkey_cb (void *opaque, const char *line)
 {
-  struct agent_card_genkey_s *parm = opaque;
+  struct scd_genkey_parm_s *parm = opaque;
   const char *keyword = line;
   int keywordlen;
-  gpg_error_t rc;
+  gpg_error_t rc = 0;
 
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
@@ -710,7 +746,7 @@ scd_genkey_cb (void *opaque, const char *line)
 
   if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
     {
-      parm->fprvalid = unhexify_fpr (line, parm->fpr);
+      parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
     {
@@ -722,29 +758,47 @@ scd_genkey_cb (void *opaque, const char *line)
       while (spacep (line))
         line++;
 
-      rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
-      if (rc)
-        log_error ("error parsing received key data: %s\n", gpg_strerror (rc));
-      else if (*name == 'n' && spacep (name+1))
-        parm->n = a;
-      else if (*name == 'e' && spacep (name+1))
-        parm->e = a;
+      if (*name == '-' && spacep (name+1))
+        rc = scd_genkey_cb_append_savedbytes (parm, line);
       else
         {
-          log_info ("unknown parameter name in received key data\n");
-          gcry_mpi_release (a);
+          if (parm->savedbytes)
+            {
+              rc = scd_genkey_cb_append_savedbytes (parm, line);
+              if (!rc)
+                rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX,
+                                    parm->savedbytes, 0, NULL);
+            }
+          else
+            rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
+          if (rc)
+            log_error ("error parsing received key data: %s\n",
+                       gpg_strerror (rc));
+          else if (*name == 'n' && spacep (name+1))
+            parm->cgk->n = a;
+          else if (*name == 'e' && spacep (name+1))
+            parm->cgk->e = a;
+          else
+            {
+              log_info ("unknown parameter name in received key data\n");
+              gcry_mpi_release (a);
+              rc = gpg_error (GPG_ERR_INV_PARAMETER);
+            }
+
+          xfree (parm->savedbytes);
+          parm->savedbytes = NULL;
         }
     }
   else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
     {
-      parm->created_at = (u32)strtoul (line, NULL, 10);
+      parm->cgk->created_at = (u32)strtoul (line, NULL, 10);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
     {
       write_status_text (STATUS_PROGRESS, line);
     }
 
-  return 0;
+  return rc;
 }
 
 /* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
@@ -759,9 +813,13 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
   int rc;
   char line[ASSUAN_LINELENGTH];
   gnupg_isotime_t tbuf;
+  struct scd_genkey_parm_s parms;
 
   (void)serialno;
 
+  memset (&parms, 0, sizeof parms);
+  parms.cgk = info;
+
   rc = start_agent (1);
   if (rc)
     return rc;
@@ -774,15 +832,17 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
   memset (info, 0, sizeof *info);
   snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
             *tbuf? "--timestamp=":"", tbuf,
-            force? "--force":"", 
+            force? "--force":"",
             keyno);
   line[DIM(line)-1] = 0;
 
   memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL, default_inq_cb, NULL,
-                        scd_genkey_cb, info);
-  
+                        scd_genkey_cb, &parms);
+
+  xfree (parms.savedbytes);
+
   status_sc_op_failure (rc);
   return rc;
 }
@@ -800,7 +860,7 @@ select_openpgp (const char *serialno)
   /* Send the serialno command to initialize the connection.  Without
      a given S/N we don't care about the data returned.  If the card
      has already been initialized, this is a very fast command.  We
-     request the openpgp card because that is what we expect. 
+     request the openpgp card because that is what we expect.
 
      Note that an opt.limit_card_insert_tries of 1 means: No tries at
      all whereas 0 means do not limit the number of tries.  Due to the
@@ -816,7 +876,7 @@ select_openpgp (const char *serialno)
       int ask;
       char *want_sn;
       char *p;
-      
+
       want_sn = xtrystrdup (serialno);
       if (!want_sn)
         return gpg_error_from_syserror ();
@@ -824,14 +884,14 @@ select_openpgp (const char *serialno)
       if (p)
         *p = 0;
 
-      do 
+      do
         {
           ask = 0;
           err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                                 NULL, NULL, NULL, NULL, 
+                                 NULL, NULL, NULL, NULL,
                                  get_serialno_cb, &this_sn);
           if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
-            ask = 1; 
+            ask = 1;
           else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
             ask = 2;
           else if (err)
@@ -844,19 +904,19 @@ select_openpgp (const char *serialno)
 
           xfree (this_sn);
           this_sn = NULL;
-                  
+
           if (ask)
             {
               char *formatted = NULL;
               char *ocodeset = i18n_switchto_utf8 ();
 
-              if (!strncmp (want_sn, "D27600012401", 12) 
+              if (!strncmp (want_sn, "D27600012401", 12)
                   && strlen (want_sn) == 32 )
                 formatted = xtryasprintf ("(%.4s) %.8s",
                                           want_sn + 16, want_sn + 20);
-              
+
               err = 0;
-              desc = xtryasprintf 
+              desc = xtryasprintf
                 ("%s:\n\n"
                  "  \"%s\"",
                  ask == 1
@@ -891,7 +951,7 @@ membuf_data_cb (void *opaque, const void *buffer, size_t length)
     put_membuf (data, buffer, length);
   return 0;
 }
-  
+
 
 /* Helper returning a command option to describe the used hash
    algorithm.  See scd/command.c:cmd_pksign.  */
@@ -1004,7 +1064,7 @@ agent_scd_pkdecrypt (const char *serialno,
   rc = select_openpgp (serialno);
   if (rc)
     return rc;
-  
+
   sprintf (line, "SCD SETDATA ");
   p = line + strlen (line);
   for (i=0; i < indatalen ; i++, p += 2 )
@@ -1037,7 +1097,7 @@ agent_scd_pkdecrypt (const char *serialno,
 
 \f
 /* Send a READCERT command to the SCdaemon. */
-int 
+int
 agent_scd_readcert (const char *certidstr,
                     void **r_buf, size_t *r_buflen)
 {
@@ -1157,8 +1217,8 @@ agent_get_passphrase (const char *cache_id,
   int rc;
   char line[ASSUAN_LINELENGTH];
   char *arg1 = NULL;
-  char *arg2 = NULL;  
-  char *arg3 = NULL; 
+  char *arg2 = NULL;
+  char *arg3 = NULL;
   char *arg4 = NULL;
   membuf_t data;
 
@@ -1169,7 +1229,7 @@ agent_get_passphrase (const char *cache_id,
     return rc;
 
   /* Check that the gpg-agent understands the repeat option.  */
-  if (assuan_transact (agent_ctx, 
+  if (assuan_transact (agent_ctx,
                        "GETINFO cmd_has_option GET_PASSPHRASE repeat",
                        NULL, NULL, NULL, NULL, NULL, NULL))
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -1187,9 +1247,9 @@ agent_get_passphrase (const char *cache_id,
     if (!(arg4 = percent_plus_escape (desc_msg)))
       goto no_mem;
 
-  snprintf (line, DIM(line)-1, 
-            "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s", 
-            repeat, 
+  snprintf (line, DIM(line)-1,
+            "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
+            repeat,
             check? " --check --qualitybar":"",
             arg1? arg1:"X",
             arg2? arg2:"X",
@@ -1202,13 +1262,13 @@ agent_get_passphrase (const char *cache_id,
   xfree (arg4);
 
   init_membuf_secure (&data, 64);
-  rc = assuan_transact (agent_ctx, line, 
+  rc = assuan_transact (agent_ctx, line,
                         membuf_data_cb, &data,
                         default_inq_cb, NULL, NULL, NULL);
 
   if (rc)
     xfree (get_membuf (&data, NULL));
-  else 
+  else
     {
       put_membuf (&data, "", 1);
       *r_passphrase = get_membuf (&data, NULL);
@@ -1287,12 +1347,12 @@ agent_get_s2k_count (unsigned long *r_count)
     return err;
 
   init_membuf (&data, 32);
-  err = assuan_transact (agent_ctx, "GETINFO s2k_count", 
+  err = assuan_transact (agent_ctx, "GETINFO s2k_count",
                         membuf_data_cb, &data,
                         NULL, NULL, NULL, NULL);
   if (err)
     xfree (get_membuf (&data, NULL));
-  else 
+  else
     {
       put_membuf (&data, "", 1);
       buf = get_membuf (&data, NULL);
index caf934d..801de57 100644 (file)
@@ -1284,7 +1284,7 @@ static unsigned int
 ask_card_keysize (int keyno, unsigned int nbits)
 {
   unsigned int min_nbits = 1024;
-  unsigned int max_nbits = 3072; /* GnuPG limit due to Assuan.  */
+  unsigned int max_nbits = 4096;
   char *prompt, *answer;
   unsigned int req_nbits;
 
index d468591..8a71caf 100644 (file)
@@ -756,20 +756,29 @@ static void
 send_key_data (ctrl_t ctrl, const char *name, 
                const unsigned char *a, size_t alen)
 {
-  char *buf;
-  
-  buf = bin2hex (a, alen, NULL);
-  if (!buf)
+  char *buffer, *buf;
+  size_t buflen;
+
+  buffer = buf = bin2hex (a, alen, NULL);
+  if (!buffer)
     {
       log_error ("memory allocation error in send_key_data\n");
       return;
     }
+  buflen = strlen (buffer);
 
+  /* 768 is the hexified size for the modulus of an 3072 bit key.  We
+     use extra chunks to transmit larger data (i.e for 4096 bit).  */
+  for ( ;buflen > 768; buflen -= 768, buf += 768)
+    send_status_info (ctrl, "KEY-DATA",
+                      "-", 1,
+                      buf, 768,
+                      NULL, 0);
   send_status_info (ctrl, "KEY-DATA",
-                    name, (size_t)strlen(name), 
-                    buf, (size_t)strlen (buf),
+                    name, (size_t)strlen(name),
+                    buf, buflen,
                     NULL, 0);
-  xfree (buf);
+  xfree (buffer);
 }
 
 
@@ -2365,7 +2374,7 @@ change_keyattr (app_t app, int keyno, unsigned int nbits,
 
   assert (keyno >=0 && keyno <= 2);
 
-  if (nbits > 3072)
+  if (nbits > 4096)
     return gpg_error (GPG_ERR_TOO_LARGE);
 
   /* Read the current attributes into a buffer.  */
@@ -2823,7 +2832,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
      already lead to a 527 byte long status line and thus a 4096 bit
      key would exceed the Assuan line length limit.  */ 
   keybits = app->app_local->keyattr[keyno].n_bits;
-  if (keybits > 3072)
+  if (keybits > 4096)
     return gpg_error (GPG_ERR_TOO_LARGE);
 
   /* Prepare for key generation by verifying the Admin PIN.  */
@@ -3377,6 +3386,8 @@ do_decipher (app_t app, const char *keyidstr,
         fixuplen = 256 - indatalen;
       else if (indatalen >= (384-16) && indatalen < 384) /* 3072 bit key.  */
         fixuplen = 384 - indatalen;
+      else if (indatalen >= (512-16) && indatalen < 512) /* 4096 bit key.  */
+        fixuplen = 512 - indatalen;
       else
         fixuplen = 0;
 
index 28bc4df..52b22c6 100644 (file)
@@ -1287,11 +1287,15 @@ static const char hlp_genkey[] =
   "\n"
   "Generate a key on-card identified by NO, which is application\n"
   "specific.  Return values are application specific.  For OpenPGP\n"
-  "cards 2 status lines are returned:\n"
+  "cards 3 status lines are returned:\n"
   "\n"
   "  S KEY-FPR  <hexstring>\n"
   "  S KEY-CREATED-AT <seconds_since_epoch>\n"
-  "  S KEY-DATA [p|n] <hexdata>\n"
+  "  S KEY-DATA [-|p|n] <hexdata>\n"
+  "\n"
+  "  'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
+  "  indicate that HEXDATA is the first chunk of a parameter given\n"
+  "  by the next KEY-DATA.\n"
   "\n"
   "--force is required to overwrite an already existing key.  The\n"
   "KEY-CREATED-AT is required for further processing because it is\n"