* 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.
This commit is contained in:
Werner Koch 2003-10-08 10:46:58 +00:00
parent f194ebc782
commit 30342b06ef
11 changed files with 159 additions and 182 deletions

5
NEWS
View File

@ -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)

4
README
View File

@ -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

1
TODO
View File

@ -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

View File

@ -1,3 +1,16 @@
2003-10-08 Werner Koch <wk@gnupg.org>
* 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 <wk@gnupg.org>
* card-util.c: Tweaked to use this source also under 1.3.

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 );

View File

@ -1,3 +1,7 @@
2003-10-08 Werner Koch <wk@gnupg.org>
* app-openpgp.c (do_getattr): Support SERIALNO and AID.
2003-10-01 Werner Koch <wk@gnupg.org>
* ccid-driver.c: Detect GnuPG 1.3 and include appropriate files.

View File

@ -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)
{