From e57d2a86300b86799aa86f8172dfc0bae5db9bb4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 5 Aug 2009 11:24:43 +0000 Subject: [PATCH] Ask for the keysize when generating a new card key. --- common/yesno.c | 6 +- g10/ChangeLog | 13 ++++ g10/call-agent.c | 6 +- g10/card-util.c | 163 +++++++++++++++++++++++++++++++++++++++++----- g10/gpg.c | 1 + scd/ChangeLog | 5 ++ scd/app-openpgp.c | 48 ++++++++++++++ 7 files changed, 222 insertions(+), 20 deletions(-) diff --git a/common/yesno.c b/common/yesno.c index fdbf7ddd1..a7131b7d5 100644 --- a/common/yesno.c +++ b/common/yesno.c @@ -24,8 +24,12 @@ #include "i18n.h" #include "util.h" + +/* Check the string S for a YES or NO answer and take care of + localization. If no valid string is given the value of DEF_ANSWER + is returned. Returns 1 for yes and 0 for no. */ int -answer_is_yes_no_default( const char *s, int def_answer ) +answer_is_yes_no_default (const char *s, int def_answer) { /* TRANSLATORS: See doc/TRANSLATE about this string. */ const char *long_yes = _("yes"); diff --git a/g10/ChangeLog b/g10/ChangeLog index 6e672871d..781ec57ab 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,16 @@ +2009-08-05 Werner Koch + + * gpg.c: Add --key-edit alias. + + * call-agent.c (scd_genkey_cb): Forward progress status lines. + + * card-util.c (generate_card_keys): Remove special case for + GnuPG-2. Ask for the keysize and change it. + (card_generate_subkey): Ask for the keysize and change it. + (get_info_for_key_operation): Read KEY-ATTR. + (show_keysize_warning, ask_card_keysize): New. + (do_change_keysize): New. + 2009-07-31 David Shaw * gpg.c (main): --pgp6 includes --disable-mdc. diff --git a/g10/call-agent.c b/g10/call-agent.c index 1b7578175..8a0b21a7a 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -667,7 +667,7 @@ scd_genkey_cb (void *opaque, const char *line) { parm->fprvalid = unhexify_fpr (line, parm->fpr); } - if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen)) + else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen)) { gcry_mpi_t a; const char *name = line; @@ -694,6 +694,10 @@ scd_genkey_cb (void *opaque, const char *line) { parm->created_at = (u32)strtoul (line, NULL, 10); } + else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen)) + { + write_status_text (STATUS_PROGRESS, line); + } return 0; } diff --git a/g10/card-util.c b/g10/card-util.c index d03de0b46..5ba42b871 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1158,6 +1158,8 @@ get_info_for_key_operation (struct agent_card_info_s *info) rc = agent_scd_getattr ("DISP-NAME", info); if (!rc) rc = agent_scd_getattr ("EXTCAP", info); + if (!rc) + rc = agent_scd_getattr ("KEY-ATTR", info); if (rc) log_error (_("error getting current key info: %s\n"), gpg_strerror (rc)); return rc; @@ -1253,34 +1255,114 @@ replace_existing_key_p (struct agent_card_info_s *info, int keyno) } +static void +show_keysize_warning (void) +{ + static int shown; + + if (shown) + return; + shown = 1; + tty_printf + (_("NOTE: There is no guarantee that the card " + "supports the requested size.\n" + " If the key generation does not succeed, " + "please check the\n" + " documentation of your card to see what " + "sizes are allowed.\n")); +} + + +/* Ask for the size of a card key. NBITS is the current size + configured for the card. KEYNO is the number of the key used to + select the prompt. Returns 0 to use the default size (i.e. NBITS) + or the selected size. */ +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. */ + char *prompt, *answer; + unsigned int req_nbits; + + for (;;) + { + prompt = xasprintf + (keyno == 0? + _("What keysize do you want for the Signature key? (%u) "): + keyno == 1? + _("What keysize do you want for the Encryption key? (%u) "): + _("What keysize do you want for the Authentication key? (%u) "), + nbits); + answer = cpr_get ("cardedit.genkeys.size", prompt); + cpr_kill_prompt (); + req_nbits = *answer? atoi (answer): nbits; + xfree (prompt); + xfree (answer); + + if (req_nbits != nbits && (req_nbits % 32) ) + { + req_nbits = ((req_nbits + 31) / 32) * 32; + tty_printf (_("rounded up to %u bits\n"), req_nbits); + } + + if (req_nbits == nbits) + return 0; /* Use default. */ + + if (req_nbits < min_nbits || req_nbits > max_nbits) + { + tty_printf (_("%s keysizes must be in the range %u-%u\n"), + "RSA", min_nbits, max_nbits); + } + else + { + tty_printf (_("The card will now be re-configured " + "to generate a key of %u bits\n"), req_nbits); + show_keysize_warning (); + return req_nbits; + } + } +} + + +/* Change the size of key KEYNO (0..2) to NBITS and show an error + message if that fails. */ +static gpg_error_t +do_change_keysize (int keyno, unsigned int nbits) +{ + gpg_error_t err; + char args[100]; + + snprintf (args, sizeof args, "--force %d 1 %u", keyno+1, nbits); + err = agent_scd_setattr ("KEY-ATTR", args, strlen (args), NULL); + if (err) + log_error (_("error changing size of key %d to %u bits: %s\n"), + keyno+1, nbits, gpg_strerror (err)); + return err; +} + + static void generate_card_keys (void) { struct agent_card_info_s info; int forced_chv1; int want_backup; + int keyno; if (get_info_for_key_operation (&info)) return; if (info.extcap.ki) { -#if GNUPG_MAJOR_VERSION == 1 char *answer; - answer = cpr_get ("cardedit.genkeys.backup_enc", _("Make off-card backup of encryption key? (Y/n) ")); - want_backup=answer_is_yes_no_default(answer,1); - cpr_kill_prompt(); - xfree(answer); -#else - want_backup = cpr_get_answer_is_yes - ( "cardedit.genkeys.backup_enc", - _("Make off-card backup of encryption key? (Y/n) ")); - /*FIXME: we need answer_is_yes_no_default()*/ -#endif + want_backup = answer_is_yes_no_default (answer, 1/*(default to Yes)*/); + cpr_kill_prompt (); + xfree (answer); } else want_backup = 0; @@ -1290,16 +1372,19 @@ generate_card_keys (void) || (info.fpr3valid && !fpr_is_zero (info.fpr3))) { tty_printf ("\n"); - log_info ("NOTE: keys are already stored on the card!\n"); + log_info (_("NOTE: keys are already stored on the card!\n")); tty_printf ("\n"); - if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_keys", - _("Replace existing keys? (y/N) "))) + if ( !cpr_get_answer_is_yes ("cardedit.genkeys.replace_keys", + _("Replace existing keys? (y/N) "))) { agent_release_card_info (&info); return; } } - else if (!info.disp_name || !*info.disp_name) + + /* If no displayed name has been set, we assume that this is a fresh + card and print a hint about the default PINs. */ + if (!info.disp_name || !*info.disp_name) { tty_printf ("\n"); tty_printf (_("Please note that the factory settings of the PINs are\n" @@ -1311,9 +1396,31 @@ generate_card_keys (void) if (check_pin_for_key_operation (&info, &forced_chv1)) goto leave; - - generate_keypair (NULL, info.serialno, - want_backup? opt.homedir:NULL); + + /* If the cards features changeable key attributes, we ask for the + key size. */ + if (info.is_v2 && info.extcap.aac) + { + unsigned int nbits; + + for (keyno = 0; keyno < DIM (info.key_attr); keyno++) + { + nbits = ask_card_keysize (keyno, info.key_attr[keyno].nbits); + if (nbits && do_change_keysize (keyno, nbits)) + { + /* Error: Better read the default key size again. */ + agent_release_card_info (&info); + if (get_info_for_key_operation (&info)) + goto leave; + /* Ask again for this key size. */ + keyno--; + } + } + /* Note that INFO has not be synced. However we will only use + the serialnumber and thus it won't harm. */ + } + + generate_keypair (NULL, info.serialno, want_backup? opt.homedir:NULL); leave: agent_release_card_info (&info); @@ -1365,6 +1472,26 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock) if (check_pin_for_key_operation (&info, &forced_chv1)) goto leave; + /* If the cards features changeable key attributes, we ask for the + key size. */ + if (info.is_v2 && info.extcap.aac) + { + unsigned int nbits; + + ask_again: + nbits = ask_card_keysize (keyno-1, info.key_attr[keyno-1].nbits); + if (nbits && do_change_keysize (keyno-1, nbits)) + { + /* Error: Better read the default key size again. */ + agent_release_card_info (&info); + if (get_info_for_key_operation (&info)) + goto leave; + goto ask_again; + } + /* Note that INFO has not be synced. However we will only use + the serialnumber and thus it won't harm. */ + } + okay = generate_card_subkeypair (pub_keyblock, sec_keyblock, keyno, info.serialno); diff --git a/g10/gpg.c b/g10/gpg.c index 08c91106c..640490bda 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -394,6 +394,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")), ARGPARSE_c (aLSignKey, "lsign-key" ,N_("sign a key locally")), ARGPARSE_c (aEditKey, "edit-key" ,N_("sign or edit a key")), + ARGPARSE_c (aEditKey, "key-edit" ,"@"), ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")), ARGPARSE_c (aDesigRevoke, "desig-revoke","@" ), ARGPARSE_c (aExport, "export" , N_("export keys") ), diff --git a/scd/ChangeLog b/scd/ChangeLog index 62af9cf3d..e7bf65339 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2009-08-05 Werner Koch + + * app-openpgp.c (change_keyattr_from_string): New. + (do_setattr): Support KEY-ATTR. + 2009-07-29 Marcus Brinkmann * ccid-driver.c (print_pr_data): Fix 64 bit compat problem. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index d2b2bdd3f..2c10cd9bf 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -214,6 +214,11 @@ static gpg_error_t do_auth (app_t app, const char *keyidstr, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); static void parse_algorithm_attribute (app_t app, int keyno); +static gpg_error_t change_keyattr_from_string + (app_t app, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *value, size_t valuelen); @@ -1793,6 +1798,7 @@ do_setattr (app_t app, const char *name, { "CERT-3", 0x7F21, 3, 0, 1 }, { "SM-KEY-ENC", 0x00D1, 3, 0, 1 }, { "SM-KEY-MAC", 0x00D2, 3, 0, 1 }, + { "KEY-ATTR", 0, 0, 3, 1 }, { NULL, 0 } }; int exmode; @@ -1804,6 +1810,9 @@ do_setattr (app_t app, const char *name, if (table[idx].need_v2 && !app->app_local->extcap.is_v2) return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Not yet supported. */ + if (table[idx].special == 3) + return change_keyattr_from_string (app, pincb, pincb_arg, value, valuelen); + switch (table[idx].need_chv) { case 2: @@ -2404,6 +2413,45 @@ change_keyattr (app_t app, int keyno, unsigned int nbits, } +/* Helper to process an setattr command for name KEY-ATTR. It expects + a string "--force " in (VALUE,VALUELEN). */ +static gpg_error_t +change_keyattr_from_string (app_t app, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *value, size_t valuelen) +{ + gpg_error_t err; + char *string; + int keyno, algo; + unsigned int nbits; + + /* VALUE is expected to be a string but not guaranteed to be + terminated. Thus copy it to an allocated buffer first. */ + string = xtrymalloc (valuelen+1); + if (!string) + return gpg_error_from_syserror (); + memcpy (string, value, valuelen); + string[valuelen] = 0; + + /* Because this function deletes the key we require the string + "--force" in the data to make clear that something serious might + happen. */ + if (sscanf (string, " --force %d %d %u", &keyno, &algo, &nbits) != 3) + err = gpg_error (GPG_ERR_INV_DATA); + else if (keyno < 1 || keyno > 3) + err = gpg_error (GPG_ERR_INV_ID); + else if (algo != 1) + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Not RSA. */ + else if (nbits < 1024) + err = gpg_error (GPG_ERR_TOO_SHORT); + else + err = change_keyattr (app, keyno-1, nbits, pincb, pincb_arg); + + xfree (string); + return err; +} + /* Handle the WRITEKEY command for OpenPGP. This function expects a canonical encoded S-expression with the secret key in KEYDATA and