From 30342b06efcc779b9222513d8dbfb85436ab624c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 8 Oct 2003 10:46:58 +0000 Subject: [PATCH] * call-agent.c (agent_scd_getattr): Don't clear the passed info structure, so that it can indeed be updated. * card-util.c (fpr_is_zero): New. (generate_card_keys): New. (card_edit): New command "generate". * keygen.c (generate_keypair): New arg CARD_SERIALNO, removed call to check_smartcard. (check_smartcard,show_smartcard): Removed. (show_sha1_fpr,fpr_is_zero): Removed. * app-openpgp.c (do_getattr): Support SERIALNO and AID. --- NEWS | 5 ++ README | 4 + TODO | 1 + g10/ChangeLog | 13 ++++ g10/call-agent.c | 1 - g10/card-util.c | 88 ++++++++++++++++++++- g10/g10.c | 4 +- g10/keygen.c | 194 ++++------------------------------------------ g10/main.h | 2 +- scd/ChangeLog | 4 + scd/app-openpgp.c | 25 ++++++ 11 files changed, 159 insertions(+), 182 deletions(-) diff --git a/NEWS b/NEWS index 558a5e8ac..b708d44cf 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,11 @@ Noteworthy changes in version 1.9.2 (unreleased) ------------------------------------------------ + * On card key generation is no longer done using the --gen-key + command but from the menu provided by the new --card-edit command. + + * PINs are now properly cached and there are only 2 PINs visible. + The 3rd PIN (CHV2) is internally syncronized with the regular PIN. Noteworthy changes in version 1.9.1 (2003-09-06) diff --git a/README b/README index 8dea9dbb9..60b613362 100644 --- a/README +++ b/README @@ -47,6 +47,10 @@ gpg2: Offers a menu to change the PIN of OpenPGP smartcards and to reset the retry counters. +--card-edit + + Offers a menu to change any data object on the card and to generate + the keys. OPTIONS diff --git a/TODO b/TODO index 11b887b9e..e8aa872a1 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,7 @@ might want to have an agent context for each service request * sm/gpgsm.c ** Support --output ** mark all unimplemented commands and options. +** Print a hint when of MD2 is the cause for a problem. * sm/keydb.c ** Check file permissions diff --git a/g10/ChangeLog b/g10/ChangeLog index 563c71eee..cb5a8ad64 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,16 @@ +2003-10-08 Werner Koch + + * call-agent.c (agent_scd_getattr): Don't clear the passed info + structure, so that it can indeed be updated. + + * card-util.c (fpr_is_zero): New. + (generate_card_keys): New. + (card_edit): New command "generate". + * keygen.c (generate_keypair): New arg CARD_SERIALNO, removed call + to check_smartcard. + (check_smartcard,show_smartcard): Removed. + (show_sha1_fpr,fpr_is_zero): Removed. + 2003-10-01 Werner Koch * card-util.c: Tweaked to use this source also under 1.3. diff --git a/g10/call-agent.c b/g10/call-agent.c index f07c01f2a..c6c8faaec 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -600,7 +600,6 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) if (rc) return rc; - memset (info, 0, sizeof *info); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, learn_status_cb, info); diff --git a/g10/card-util.c b/g10/card-util.c index 70518e9ce..669927707 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -241,6 +241,17 @@ print_isoname (FILE *fp, const char *text, const char *tag, const char *name) tty_fprintf (fp, "\n"); } +/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */ +static int +fpr_is_zero (const char *fpr) +{ + int i; + + for (i=0; i < 20 && !fpr[i]; i++) + ; + return (i == 20); +} + /* Print all available information about the current card. */ void @@ -569,6 +580,76 @@ toggle_forcesig (void) } +static void +generate_card_keys (void) +{ + struct agent_card_info_s info; + int rc; + int forced_chv1; + + memset (&info, 0, sizeof info); + rc = agent_scd_getattr ("KEY-FPR", &info); + if (!rc) + rc = agent_scd_getattr ("SERIALNO", &info); + if (!rc) + rc = agent_scd_getattr ("CHV-STATUS", &info); + if (!rc) + rc = agent_scd_getattr ("DISP-NAME", &info); + if (rc) + { + log_error ("error getting current key info: %s\n", gpg_strerror (rc)); + return; + } + if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) + || (info.fpr2valid && !fpr_is_zero (info.fpr2)) + || (info.fpr3valid && !fpr_is_zero (info.fpr3))) + { + tty_printf ("\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? "))) + { + agent_release_card_info (&info); + return; + } + } + else if (!info.disp_name || !*info.disp_name) + { + tty_printf ("\n"); + tty_printf (_("Please note that the factory settings of the PINs are\n" + " PIN = \"%s\" Admin PIN = \"%s\"\n" + "You should change them using the command --change-pin\n"), + "123456", "12345678"); + tty_printf ("\n"); + } + + forced_chv1 = !info.chv1_cached; + if (forced_chv1) + { /* Switch of the forced mode so that during key generation we + don't get bothered with PIN queries for each + self-signature. */ + rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1); + if (rc) + { + log_error ("error clearing forced signature PIN flag: %s\n", + gpg_strerror (rc)); + return; + } + } + generate_keypair (NULL, info.serialno); + agent_release_card_info (&info); + if (forced_chv1) + { /* Switch back to forced state. */ + rc = agent_scd_setattr ("CHV-STATUS-1", "", 1); + if (rc) + { + log_error ("error setting forced signature PIN flag: %s\n", + gpg_strerror (rc)); + return; + } + } +} /* Menu to edit all user changeable values on an OpenPGP card. Only Key creation is not handled here. */ @@ -579,7 +660,7 @@ card_edit (STRLIST commands) cmdNOP = 0, cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG, cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX, - cmdFORCESIG, + cmdFORCESIG, cmdGENERATE, cmdINVCMD }; @@ -601,6 +682,7 @@ card_edit (STRLIST commands) { N_("lang") , cmdLANG , N_("change the language preferences") }, { N_("sex") , cmdSEX , N_("change card holder's sex") }, { N_("forcesig"), cmdFORCESIG, N_("toggle the signature force PIN flag") }, + { N_("generate"), cmdGENERATE, N_("generate new keys") }, { NULL, cmdINVCMD } }; @@ -725,6 +807,10 @@ card_edit (STRLIST commands) toggle_forcesig (); break; + case cmdGENERATE: + generate_card_keys (); + break; + case cmdQUIT: goto leave; diff --git a/g10/g10.c b/g10/g10.c index cdd10d845..984e50d9c 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -2555,12 +2555,12 @@ main( int argc, char **argv ) if( opt.batch ) { if( argc > 1 ) wrong_args("--gen-key [parameterfile]"); - generate_keypair( argc? *argv : NULL ); + generate_keypair( argc? *argv : NULL, NULL ); } else { if( argc ) wrong_args("--gen-key"); - generate_keypair(NULL); + generate_keypair(NULL, NULL); } break; diff --git a/g10/keygen.c b/g10/keygen.c index 38e9115b3..935cff330 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -117,7 +117,6 @@ static int mdc_available,ks_modify; static void do_generate_keypair( struct para_data_s *para, struct output_control_s *outctrl, int card); static int write_keyblock( iobuf_t out, KBNODE node ); -static int check_smartcard (char **); static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root, u32 expireval, struct para_data_s *para); @@ -2219,11 +2218,12 @@ read_parameter_file( const char *fname ) /**************** - * Generate a keypair - * (fname is only used in batch mode) + * Generate a keypair (fname is only used in batch mode) If + * CARD_SERIALNO is not NULL the fucntion will create the keys on an + * OpenPGP Card. */ void -generate_keypair( const char *fname ) +generate_keypair( const char *fname, const char *card_serialno ) { unsigned int nbits; char *uid = NULL; @@ -2232,42 +2232,34 @@ generate_keypair( const char *fname ) int algo; unsigned int use; int both = 0; - int card = 0; u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; - char *serialno = NULL; memset (&outctrl, 0, sizeof (outctrl)); + if (opt.batch && card_serialno) + { + /* We don't yet support unattended key generation. */ + log_error (_("sorry, can't do this in batch mode\n")); + return; + } + if (opt.batch) { read_parameter_file( fname ); return; } - do + if (card_serialno) { - xfree (serialno); serialno = NULL; - card = check_smartcard (&serialno); - if (card < 0) - return; - } - while (card > 1); - - if (serialno) - { - r = xcalloc (1, sizeof *r + strlen (serialno) ); + r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; - strcpy( r->u.value, serialno); + strcpy( r->u.value, card_serialno); r->next = para; para = r; - xfree (serialno); serialno = NULL; - } - if (card) - { algo = PUBKEY_ALGO_RSA; r = xcalloc (1, sizeof *r + 20 ); @@ -2388,7 +2380,7 @@ generate_keypair( const char *fname ) r->next = para; para = r; - dek = card? NULL : ask_passphrase( &s2k ); + dek = card_serialno? NULL : ask_passphrase( &s2k ); if (dek) { r = xcalloc (1, sizeof *r ); @@ -2403,7 +2395,7 @@ generate_keypair( const char *fname ) para = r; } - proc_parameter_file (para, "[internal]", &outctrl, card); + proc_parameter_file (para, "[internal]", &outctrl, !!card_serialno); release_parameter_list (para); } @@ -2719,7 +2711,7 @@ do_generate_keypair (struct para_data_s *para, release_kbnode (pub_root); release_kbnode (sec_root); if (sk && !card) /* The unprotected secret key unless we have */ - free_secret_key (sk); /* shallow copy in card mode. */ + free_secret_key (sk); /* a shallow copy in card mode. */ } @@ -2848,158 +2840,6 @@ write_keyblock( iobuf_t out, KBNODE node ) } -static void -show_sha1_fpr (const unsigned char *fpr) -{ - int i; - - if (fpr) - { - for (i=0; i < 20 ; i+=2, fpr += 2 ) - { - if (i == 10 ) - tty_printf (" "); - tty_printf (" %02X%02X", *fpr, fpr[1]); - } - } - else - tty_printf (" [none]"); - tty_printf ("\n"); -} - -static void -show_smartcard (struct agent_card_info_s *info) -{ - PKT_public_key *pk = xcalloc (1, sizeof *pk); - - /* FIXME: Sanitize what we show. */ - tty_printf ("Name of cardholder: %s\n", - info->disp_name && *info->disp_name? info->disp_name - : "[not set]"); - tty_printf ("URL of public key : %s\n", - info->pubkey_url && *info->pubkey_url? info->pubkey_url - : "[not set]"); - tty_printf ("Signature key ....:"); - show_sha1_fpr (info->fpr1valid? info->fpr1:NULL); - tty_printf ("Encryption key....:"); - show_sha1_fpr (info->fpr2valid? info->fpr2:NULL); - tty_printf ("Authentication key:"); - show_sha1_fpr (info->fpr3valid? info->fpr3:NULL); - - if (info->fpr1valid && !get_pubkey_byfprint (pk, info->fpr1, 20)) - print_pubkey_info (NULL, pk); - - free_public_key( pk ); -} - -/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */ -static int -fpr_is_zero (const char *fpr) -{ - int i; - - for (i=0; i < 20 && !fpr[i]; i++) - ; - return (i == 20); -} - -/* Check whether a smartcatrd is available and alow to select it as - the target for key generation. - - Return values: -1 = Quit generation - 0 = No smartcard - 1 = Generate keypair -*/ -static int -check_smartcard (char **r_serialno) -{ - struct agent_card_info_s info; - int rc; - - rc = agent_learn (&info); - if (rc) - { - tty_printf (_("OpenPGP card not available: %s\n"), - gpg_strerror (rc)); - return 0; - } - - tty_printf (_("OpenPGP card no. %s detected\n"), - info.serialno? info.serialno : "[none]"); - - - for (;;) - { - char *answer; - int reread = 0; - - tty_printf ("\n"); - show_smartcard (&info); - - tty_printf ("\n" - "K - generate all keys\n" - "Q - quit\n" - "\n"); - - answer = cpr_get("keygen.smartcard.menu",_("Your selection? ")); - cpr_kill_prompt(); - if (strlen (answer) != 1) - continue; - - rc = 0; - if ( *answer == 'K' || *answer == 'k') - { - if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) - || (info.fpr2valid && !fpr_is_zero (info.fpr2)) - || (info.fpr3valid && !fpr_is_zero (info.fpr3))) - { - tty_printf ("\n"); - log_error ("WARNING: key does already exists!\n"); - tty_printf ("\n"); - if ( cpr_get_answer_is_yes( "keygen.card.replace_key", - _("Replace existing key? "))) - { - rc = 1; - break; - } - } - else - { - rc = 1; - break; - } - } - else if ( *answer == 'q' || *answer == 'Q') - { - rc = -1; - break; - } - - if (reread) - { - agent_release_card_info (&info); - rc = agent_learn (&info); - if (rc) - { - tty_printf (_("OpenPGP card not anymore available: %s\n"), - gpg_strerror (rc)); - g10_exit (1); - } - reread = 0; - } - } - - if (r_serialno && rc > 0) - { - *r_serialno = info.serialno; - info.serialno = NULL; - } - agent_release_card_info (&info); - - return rc; -} - - static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root, diff --git a/g10/main.h b/g10/main.h index 76562fa91..d00044c9f 100644 --- a/g10/main.h +++ b/g10/main.h @@ -165,7 +165,7 @@ void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ u32 ask_expire_interval(int object); u32 ask_expiredate(void); -void generate_keypair( const char *fname ); +void generate_keypair( const char *fname, const char *card_serialno ); int keygen_set_std_prefs (const char *string,int personal); PKT_user_id *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); diff --git a/scd/ChangeLog b/scd/ChangeLog index f090e34c0..86068b245 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2003-10-08 Werner Koch + + * app-openpgp.c (do_getattr): Support SERIALNO and AID. + 2003-10-01 Werner Koch * ccid-driver.c: Detect GnuPG 1.3 and include appropriate files. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index e8fe19ea1..174d2e974 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -425,6 +425,8 @@ do_getattr (APP app, CTRL ctrl, const char *name) { "CA-FPR", 0x00C6, 3 }, { "CHV-STATUS", 0x00C4, 1 }, { "SIG-COUNTER", 0x0093, 2 }, + { "SERIALNO", 0x004F, -1 }, + { "AID", 0x004F }, { NULL, 0 } }; int idx, i; @@ -437,6 +439,29 @@ do_getattr (APP app, CTRL ctrl, const char *name) if (!table[idx].name) return gpg_error (GPG_ERR_INV_NAME); + if (table[idx].special == -1) + { + /* The serial number is very special. We could have used the + AID DO to retrieve it, but we have it already in the app + context and the stanmp argument is required anyway which we + can't by other means. The AID DO is available anyway but not + hex formatted. */ + char *serial; + time_t stamp; + char tmp[50]; + + if (!app_get_serial_and_stamp (app, &serial, &stamp)) + { + sprintf (tmp, "%lu", (unsigned long)stamp); + send_status_info (ctrl, "SERIALNO", + serial, strlen (serial), + tmp, strlen (tmp), + NULL, 0); + xfree (serial); + } + return 0; + } + relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen); if (relptr) {