Support writing of existing keys with non-matching key sizes.
authorWerner Koch <wk@gnupg.org>
Thu, 9 Jul 2009 14:54:18 +0000 (14:54 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 9 Jul 2009 14:54:18 +0000 (14:54 +0000)
NEWS
doc/DETAILS
g10/ChangeLog
g10/card-util.c
scd/ChangeLog
scd/app-openpgp.c

diff --git a/NEWS b/NEWS
index 12f6978..f0a2487 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,11 @@ Noteworthy changes in version 2.0.13
 
  * New option --re-import for GPGSM's IMPORT server command.
 
+ * Enhanced writing of existing keys to OpenPGP v2 cards.
+
+ * Add hack to the internal CCID driver to allow the use of some
+   Omnikey based card readers with 2048 bit keys.
+
  * Minor bug fixes.
 
 
index 76078c2..a74c83c 100644 (file)
@@ -503,8 +503,9 @@ more arguments in future versions.
        "char" is the character displayed with no --status-fd enabled, with
        the linefeed replaced by an 'X'.  "cur" is the current amount
        done and "total" is amount to be done; a "total" of 0 indicates that
-       the total amount is not known.  100/100 may be used to detect the
-       end of operation.
+       the total amount is not known.  The condition 
+           TOATL && CUR == TOTAL
+        may be used to detect the end of an operation.
         Well known values for WHAT:
              "pk_dsa"   - DSA key generation
              "pk_elg"   - Elgamal key generation
index 971d488..e670afd 100644 (file)
@@ -1,5 +1,8 @@
 2009-07-09  Werner Koch  <wk@g10code.com>
 
+       * card-util.c (card_store_subkey): Do not restrict to 1024 bit keys.
+       Print an error message on write errors.
+
        * gpg.c (main): Remove the SHA-1 default from the personal digest
        list.  This was used in the past as a hack to avoid preferring
        RMD-160.
index 26349d6..f825034 100644 (file)
@@ -1,5 +1,5 @@
 /* card-util.c - Utility functions for the OpenPGP card.
- *     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -1393,7 +1393,8 @@ card_store_subkey (KBNODE node, int use)
 
   show_card_key_info (&info);
 
-  if (!is_RSA (sk->pubkey_algo) || nbits_from_sk (sk) != 1024 )
+  if (!is_RSA (sk->pubkey_algo) 
+      || (!info.is_v2 && nbits_from_sk (sk) != 1024) )
     {
       tty_printf ("You may only store a 1024 bit RSA key on the card\n");
       tty_printf ("\n");
@@ -1461,7 +1462,10 @@ card_store_subkey (KBNODE node, int use)
 
   rc = save_unprotected_key_to_card (sk, keyno);
   if (rc)
-    goto leave;
+    {
+      log_error (_("error writing key to card: %s\n"), gpg_strerror (rc));
+      goto leave;
+    }
 
   /* Get back to the maybe protected original secret key.  */
   if (copied_sk)
index 7862a97..94e1ebd 100644 (file)
@@ -1,3 +1,11 @@
+2009-07-09  Werner Koch  <wk@g10code.com>
+
+       * app-openpgp.c (change_keyattr): New.
+       (do_writekey): Call it.
+       
+       * app-openpgp.c (does_key_exist): Add arg GENERATING.  Change
+       callers.
+
 2009-06-30  Werner Koch  <wk@g10code.com>
 
        * ccid-driver.c (ccid_transceive): Set RESYNCING flag.
index 3f97d28..9620d5b 100644 (file)
@@ -213,6 +213,7 @@ static gpg_error_t do_auth (app_t app, const char *keyidstr,
                             void *pincb_arg,
                             const void *indata, size_t indatalen,
                             unsigned char **outdata, size_t *outdatalen);
+static void parse_algorithm_attribute (app_t app, int keyno);
 
 
 
@@ -2144,9 +2145,10 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
 
 /* Check whether a key already exists.  KEYIDX is the index of the key
    (0..2).  If FORCE is TRUE a diagnositic will be printed but no
-   error returned if the key already exists. */
+   error returned if the key already exists.  The flag GENERATING is
+   only used to print correct messages. */
 static gpg_error_t
-does_key_exist (app_t app, int keyidx, int force)
+does_key_exist (app_t app, int keyidx, int generating, int force)
 {
   const unsigned char *fpr;
   unsigned char *buffer;
@@ -2178,8 +2180,10 @@ does_key_exist (app_t app, int keyidx, int force)
     }
   else if (i!=20)
     log_info (_("existing key will be replaced\n"));
-  else
+  else if (generating)
     log_info (_("generating new key\n"));
+  else
+    log_info (_("writing new key\n"));
   return 0;
 }
 
@@ -2340,6 +2344,63 @@ build_privkey_template (app_t app, int keyno,
 }
 
 
+/* Helper for do_writekley to change the size of a key.  Not ethat
+   this deletes the entire key without asking.  */
+static gpg_error_t
+change_keyattr (app_t app, int keyno, unsigned int nbits,
+                gpg_error_t (*pincb)(void*, const char *, char **),
+                void *pincb_arg)
+{
+  gpg_error_t err;
+  unsigned char *buffer;
+  size_t buflen;
+  void *relptr;
+
+  assert (keyno >=0 && keyno <= 2);
+
+  if (nbits > 3072)
+    return gpg_error (GPG_ERR_TOO_LARGE);
+
+  /* Read the current attributes into a buffer.  */
+  relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL);
+  if (!relptr)
+    return gpg_error (GPG_ERR_CARD);
+  if (buflen < 6 || buffer[0] != 1)
+    {
+      /* Attriutes too short or not an RSA key.  */
+      xfree (relptr);
+      return gpg_error (GPG_ERR_CARD);
+    }
+  
+  /* We only change n_bits and don't touch anything else.  Before we
+     do so, we round up NBITS to a sensible way in the same way as
+     gpg's key generation does it.  This may help to sort out problems
+     with a few bits too short keys.  */
+  nbits = ((nbits + 31) / 32) * 32;
+  buffer[1] = (nbits >> 8);
+  buffer[2] = nbits;
+
+  /* Prepare for storing the key.  */
+  err = verify_chv3 (app, pincb, pincb_arg);
+  if (err)
+    {
+      xfree (relptr);
+      return err;
+    }
+
+  /* Change the attribute.  */
+  err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buffer, buflen);
+  xfree (relptr);
+  if (err)
+    log_error ("error changing size of key %d to %u bits\n", keyno+1, nbits);
+  else
+    log_info ("size of key %d changed to %u bits\n", keyno+1, nbits);
+  flush_cache (app);
+  parse_algorithm_attribute (app, keyno);
+  return err;
+}
+
+
 
 /* Handle the WRITEKEY command for OpenPGP.  This function expects a
    canonical encoded S-expression with the secret key in KEYDATA and
@@ -2385,7 +2446,7 @@ do_writekey (app_t app, ctrl_t ctrl,
   else
     return gpg_error (GPG_ERR_INV_ID);
   
-  err = does_key_exist (app, keyno, force);
+  err = does_key_exist (app, keyno, 0, force);
   if (err)
     return err;
 
@@ -2515,6 +2576,14 @@ do_writekey (app_t app, ctrl_t ctrl,
   if (opt.verbose)
     log_info ("RSA modulus size is %u bits (%u bytes)\n", 
               nbits, (unsigned int)rsa_n_len);
+  if (nbits && nbits != maxbits
+      && app->app_local->extcap.algo_attr_change)
+    {
+      /* Try to switch the key to a new length.  */
+      err = change_keyattr (app, keyno, nbits, pincb, pincb_arg);
+      if (!err)
+        maxbits = app->app_local->keyattr[keyno].n_bits;
+    }
   if (nbits != maxbits)
     {
       log_error (_("RSA modulus missing or not of size %d bits\n"), 
@@ -2696,7 +2765,7 @@ do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
   app->app_local->pk[keyno].read_done = 0;
 
   /* Check whether a key already exists.  */
-  rc = does_key_exist (app, keyno, force);
+  rc = does_key_exist (app, keyno, 1, force);
   if (rc)
     return rc;