From 31084d6dc9287f6ab113ae0096d971c3e28c4eff Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 9 Jul 2009 14:54:18 +0000 Subject: [PATCH] Support writing of existing keys with non-matching key sizes. --- NEWS | 5 +++ doc/DETAILS | 5 +-- g10/ChangeLog | 3 ++ g10/card-util.c | 10 ++++-- scd/ChangeLog | 8 +++++ scd/app-openpgp.c | 79 ++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 100 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 12f6978af..f0a24879d 100644 --- 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. diff --git a/doc/DETAILS b/doc/DETAILS index 76078c2b4..a74c83cc0 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -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 diff --git a/g10/ChangeLog b/g10/ChangeLog index 971d4880b..e670afddf 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,5 +1,8 @@ 2009-07-09 Werner Koch + * 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. diff --git a/g10/card-util.c b/g10/card-util.c index 26349d653..f825034b6 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -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) diff --git a/scd/ChangeLog b/scd/ChangeLog index 7862a97db..94e1ebd59 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,11 @@ +2009-07-09 Werner Koch + + * 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 * ccid-driver.c (ccid_transceive): Set RESYNCING flag. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3f97d28cf..9620d5b40 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -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;