* passphrase.c (ask_passphrase): Add optional promptid arg.

Changed all callers.
* cardglue.c (pin_cb): Use it here, so the machine interface can
tell whether the Admin PIN is requested.

* cardglue.c (agent_scd_checkpin): New.

* misc.c (openpgp_pk_algo_usage): Added AUTH usage.

* app-openpgp.c (check_against_given_fingerprint): New. Factored
out that code elsewhere.
(do_check_pin): New.
* card-util.c (card_edit): New command "passwd".  Add logic to
check the PIN in advance.
(card_status): Add new args to return the serial number.  Changed
all callers.
This commit is contained in:
Werner Koch 2003-10-21 18:22:21 +00:00
parent b194ed0e0a
commit 441aeb85f2
14 changed files with 252 additions and 120 deletions

View File

@ -1,3 +1,9 @@
2003-10-21 Werner Koch <wk@gnupg.org>
* configure.ac (PRINTABLE_OS_NAME): Remove special case for The
Hurd; Robert Millan reported that the uname test is now
sufficient.
2003-10-16 David Shaw <dshaw@jabberwocky.com>
* configure.ac: Include -ldl when card support is used.

View File

@ -584,10 +584,6 @@ case "${target}" in
*-linux*)
PRINTABLE_OS_NAME="GNU/Linux"
;;
dnl let that after linux to avoid gnu-linux problems
*-gnu*)
PRINTABLE_OS_NAME="GNU/Hurd"
;;
*)
PRINTABLE_OS_NAME=`uname -s || echo "Unknown"`
;;

View File

@ -1,3 +1,22 @@
2003-10-21 Werner Koch <wk@gnupg.org>
* passphrase.c (ask_passphrase): Add optional promptid arg.
Changed all callers.
* cardglue.c (pin_cb): Use it here, so the machine interface can
tell whether the Admin PIN is requested.
* cardglue.c (agent_scd_checkpin): New.
* misc.c (openpgp_pk_algo_usage): Added AUTH usage.
* app-openpgp.c (check_against_given_fingerprint): New. Factored
out that code elsewhere.
(do_check_pin): New.
* card-util.c (card_edit): New command "passwd". Add logic to
check the PIN in advance.
(card_status): Add new args to return the serial number. Changed
all callers.
2003-10-14 David Shaw <dshaw@jabberwocky.com>
* import.c (import_one): Show the keyid when giving the Elgamal

View File

@ -51,6 +51,13 @@
insertion of the card (1 = don't wait). */
#ifdef _WIN32
#define DLSTDCALL __stdcall
#else
#define DLSTDCALL
#endif
/* A structure to collect information pertaining to one reader
slot. */
struct reader_table_s {
@ -84,12 +91,12 @@ static struct reader_table_s reader_table[MAX_READER];
/* ct API function pointer. */
static char (*CT_init) (unsigned short ctn, unsigned short Pn);
static char (*CT_data) (unsigned short ctn, unsigned char *dad,
unsigned char *sad, unsigned short lc,
unsigned char *cmd, unsigned short *lr,
unsigned char *rsp);
static char (*CT_close) (unsigned short ctn);
static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
unsigned char *sad, unsigned short lc,
unsigned char *cmd, unsigned short *lr,
unsigned char *rsp);
static char (* DLSTDCALL CT_close) (unsigned short ctn);
/* PC/SC constants and function pointer. */
#define PCSC_SCOPE_USER 0
@ -117,34 +124,38 @@ struct pcsc_io_request_s {
typedef struct pcsc_io_request_s *pcsc_io_request_t;
long (*pcsc_establish_context) (unsigned long scope,
const void *reserved1,
const void *reserved2,
unsigned long *r_context);
long (*pcsc_release_context) (unsigned long context);
long (*pcsc_list_readers) (unsigned long context, const char *groups,
char *readers, unsigned long *readerslen);
long (*pcsc_connect) (unsigned long context,
const char *reader,
unsigned long share_mode,
unsigned long preferred_protocols,
unsigned long *r_card,
unsigned long *r_active_protocol);
long (*pcsc_disconnect) (unsigned long card, unsigned long disposition);
long (*pcsc_status) (unsigned long card,
char *reader, unsigned long *readerlen,
unsigned long *r_state, unsigned long *r_protocol,
unsigned char *atr, unsigned long *atrlen);
long (*pcsc_begin_transaction) (unsigned long card);
long (*pcsc_end_transaction) (unsigned long card);
long (*pcsc_transmit) (unsigned long card,
const pcsc_io_request_t send_pci,
const unsigned char *send_buffer,
unsigned long send_len,
pcsc_io_request_t recv_pci,
unsigned char *recv_buffer,
unsigned long *recv_len);
long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout);
long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
const void *reserved1,
const void *reserved2,
unsigned long *r_context);
long (* DLSTDCALL pcsc_release_context) (unsigned long context);
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
const char *groups,
char *readers, unsigned long*readerslen);
long (* DLSTDCALL pcsc_connect) (unsigned long context,
const char *reader,
unsigned long share_mode,
unsigned long preferred_protocols,
unsigned long *r_card,
unsigned long *r_active_protocol);
long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
unsigned long disposition);
long (* DLSTDCALL pcsc_status) (unsigned long card,
char *reader, unsigned long *readerlen,
unsigned long *r_state,
unsigned long *r_protocol,
unsigned char *atr, unsigned long *atrlen);
long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
long (* DLSTDCALL pcsc_transmit) (unsigned long card,
const pcsc_io_request_t send_pci,
const unsigned char *send_buffer,
unsigned long send_len,
pcsc_io_request_t recv_pci,
unsigned char *recv_buffer,
unsigned long *recv_len);
long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
unsigned long timeout);

View File

@ -65,6 +65,9 @@ struct app_ctx_s {
const char *chvnostr, int reset_mode,
int (*pincb)(void*, const char *, char **),
void *pincb_arg);
int (*check_pin) (APP app, const char *keyidstr,
int (pincb)(void*, const char *, char **),
void *pincb_arg);
} fnc;
@ -106,6 +109,9 @@ int app_get_challenge (APP app, size_t nbytes, unsigned char *buffer);
int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
int (*pincb)(void*, const char *, char **),
void *pincb_arg);
int app_check_pin (APP app, const char *keyidstr,
int (*pincb)(void*, const char *, char **),
void *pincb_arg);
/*-- app-openpgp.c --*/

View File

@ -912,6 +912,33 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr)
}
/* If a fingerprint has been specified check it against the one on
the card. This is allows for a meaningful error message in case
the key on the card has been replaced but the shadow information
known to gpg was not updated. If there is no fingerprint we
assume that this is okay. */
static int
check_against_given_fingerprint (APP app, const char *fpr, int keyno)
{
unsigned char tmp[20];
const char *s;
int n;
for (s=fpr, n=0; hexdigitp (s); s++, n++)
;
if (n != 40)
return gpg_error (GPG_ERR_INV_ID);
else if (!*s)
; /* okay */
else
return gpg_error (GPG_ERR_INV_ID);
for (s=fpr, n=0; n < 20; s += 2, n++)
tmp[n] = xtoi_2 (s);
return compare_fingerprint (app, keyno, tmp);
}
/* Compute a digital signature on INDATA which is expected to be the
raw message digest. For this application the KEYIDSTR consists of
@ -976,23 +1003,9 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
known to gpg was not updated. If there is no fingerprint, gpg
will detect a bogus signature anyway due to the
verify-after-signing feature. */
if (fpr)
{
for (s=fpr, n=0; hexdigitp (s); s++, n++)
;
if (n != 40)
return gpg_error (GPG_ERR_INV_ID);
else if (!*s)
; /* okay */
else
return gpg_error (GPG_ERR_INV_ID);
for (s=fpr, n=0; n < 20; s += 2, n++)
tmp_sn[n] = xtoi_2 (s);
rc = compare_fingerprint (app, 1, tmp_sn);
if (rc)
return rc;
}
rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
if (rc)
return rc;
if (hashalgo == GCRY_MD_SHA1)
memcpy (data, sha1_prefix, 15);
@ -1107,23 +1120,9 @@ do_auth (APP app, const char *keyidstr,
known to gpg was not updated. If there is no fingerprint, gpg
will detect a bogus signature anyway due to the
verify-after-signing feature. */
if (fpr)
{
for (s=fpr, n=0; hexdigitp (s); s++, n++)
;
if (n != 40)
return gpg_error (GPG_ERR_INV_ID);
else if (!*s)
; /* okay */
else
return gpg_error (GPG_ERR_INV_ID);
for (s=fpr, n=0; n < 20; s += 2, n++)
tmp_sn[n] = xtoi_2 (s);
rc = compare_fingerprint (app, 3, tmp_sn);
if (rc)
return rc;
}
rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
if (rc)
return rc;
rc = verify_chv2 (app, pincb, pincb_arg);
if (!rc)
@ -1177,23 +1176,9 @@ do_decipher (APP app, const char *keyidstr,
the key on the card has been replaced but the shadow information
known to gpg was not updated. If there is no fingerprint, the
decryption will won't produce the right plaintext anyway. */
if (fpr)
{
for (s=fpr, n=0; hexdigitp (s); s++, n++)
;
if (n != 40)
return gpg_error (GPG_ERR_INV_ID);
else if (!*s)
; /* okay */
else
return gpg_error (GPG_ERR_INV_ID);
for (s=fpr, n=0; n < 20; s += 2, n++)
tmp_sn[n] = xtoi_2 (s);
rc = compare_fingerprint (app, 2, tmp_sn);
if (rc)
return rc;
}
rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
if (rc)
return rc;
rc = verify_chv2 (app, pincb, pincb_arg);
if (!rc)
@ -1202,6 +1187,55 @@ do_decipher (APP app, const char *keyidstr,
}
/* Perform a simple verify operation for CHV1 and CHV2, so that
further operations won't ask for CHV2 and it is possible to do a
cheap check on the PIN: If there is something wrong with the PIN
entry system, only the regular CHV will get blocked and not the
dangerous CHV3. KEYIDSTR is the usual card's serial number; an
optional fingerprint part will be ignored. */
static int
do_check_pin (APP app, const char *keyidstr,
int (pincb)(void*, const char *, char **),
void *pincb_arg)
{
unsigned char tmp_sn[20];
const char *s;
int n;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
/* Check whether an OpenPGP card of any version has been requested. */
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
return gpg_error (GPG_ERR_INV_ID);
for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
;
if (n != 32)
return gpg_error (GPG_ERR_INV_ID);
else if (!*s)
; /* No fingerprint given: we allow this for now. */
else if (*s == '/')
; /* We ignore a fingerprint. */
else
return gpg_error (GPG_ERR_INV_ID);
for (s=keyidstr, n=0; n < 16; s += 2, n++)
tmp_sn[n] = xtoi_2 (s);
if (app->serialnolen != 16)
return gpg_error (GPG_ERR_INV_CARD);
if (memcmp (app->serialno, tmp_sn, 16))
return gpg_error (GPG_ERR_WRONG_CARD);
/* Yes, there is a race conditions: The user might pull the card
right here and we won't notice that. However this is not a
problem and the check above is merely for a graceful failure
between operations. */
return verify_chv2 (app, pincb, pincb_arg);
}
/* Select the OpenPGP application on the card in SLOT. This function
@ -1262,6 +1296,7 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
app->fnc.auth = do_auth;
app->fnc.decipher = do_decipher;
app->fnc.change_pin = do_change_pin;
app->fnc.check_pin = do_check_pin;
}
leave:

View File

@ -255,13 +255,16 @@ fpr_is_zero (const char *fpr)
/* Print all available information about the current card. */
void
card_status (FILE *fp)
card_status (FILE *fp, char *serialno, size_t serialnobuflen)
{
struct agent_card_info_s info;
PKT_public_key *pk = xcalloc (1, sizeof *pk);
int rc;
unsigned int uval;
if (serialno && serialnobuflen)
*serialno = 0;
rc = agent_learn (&info);
if (rc)
{
@ -289,6 +292,13 @@ card_status (FILE *fp)
return;
}
if (!serialno)
;
else if (strlen (serialno)+1 > serialnobuflen)
log_error ("serial number longer than expected\n");
else
strcpy (serialno, info.serialno);
if (opt.with_colons)
fputs ("openpgp-card:\n", fp);
@ -660,29 +670,33 @@ card_edit (STRLIST commands)
cmdNOP = 0,
cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG,
cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX,
cmdFORCESIG, cmdGENERATE,
cmdFORCESIG, cmdGENERATE, cmdPASSWD,
cmdINVCMD
};
static struct {
const char *name;
enum cmdids id;
int requires_pin;
const char *desc;
} cmds[] = {
{ N_("quit") , cmdQUIT , N_("quit this menu") },
{ N_("q") , cmdQUIT , NULL },
{ N_("help") , cmdHELP , N_("show this help") },
{ "?" , cmdHELP , NULL },
{ N_("list") , cmdLIST , N_("list all available data") },
{ N_("l") , cmdLIST , NULL },
{ N_("debug") , cmdDEBUG , NULL },
{ N_("name") , cmdNAME , N_("change card holder's name") },
{ N_("url") , cmdURL , N_("change URL to retrieve key") },
{ N_("login") , cmdLOGIN , N_("change the login name") },
{ 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") },
{ N_("quit") , cmdQUIT , 0, N_("quit this menu") },
{ N_("q") , cmdQUIT , 0, NULL },
{ N_("help") , cmdHELP , 0, N_("show this help") },
{ "?" , cmdHELP , 0, NULL },
{ N_("list") , cmdLIST , 0, N_("list all available data") },
{ N_("l") , cmdLIST , 0, NULL },
{ N_("debug") , cmdDEBUG , 0, NULL },
{ N_("name") , cmdNAME , 1, N_("change card holder's name") },
{ N_("url") , cmdURL , 1, N_("change URL to retrieve key") },
{ N_("login") , cmdLOGIN , 1, N_("change the login name") },
{ N_("lang") , cmdLANG , 1, N_("change the language preferences") },
{ N_("sex") , cmdSEX , 1, N_("change card holder's sex") },
{ N_("forcesig"),
cmdFORCESIG, 1, N_("toggle the signature force PIN flag") },
{ N_("generate"),
cmdGENERATE, 1, N_("generate new keys") },
{ N_("passwd"), cmdPASSWD, 0, N_("menu to change or unblock the PIN") },
{ NULL, cmdINVCMD }
};
@ -690,6 +704,9 @@ card_edit (STRLIST commands)
int have_commands = !!commands;
int redisplay = 1;
char *answer = NULL;
int did_checkpin = 0;
char serialnobuf[50];
if (opt.command_fd != -1)
;
@ -705,18 +722,19 @@ card_edit (STRLIST commands)
const char *arg_string = "";
char *p;
int i;
int requires_pin;
tty_printf("\n");
if (redisplay )
{
if (opt.with_colons)
{
card_status (stdout);
card_status (stdout, serialnobuf, DIM (serialnobuf));
fflush (stdout);
}
else
{
card_status (NULL);
card_status (NULL, serialnobuf, DIM (serialnobuf));
tty_printf("\n");
}
redisplay = 0;
@ -750,6 +768,7 @@ card_edit (STRLIST commands)
while( *answer == '#' );
arg_number = 0; /* Yes, here is the init which egcc complains about */
requires_pin = 0;
if (!*answer)
cmd = cmdLIST; /* Default to the list command */
else if (*answer == CONTROL_D)
@ -769,7 +788,19 @@ card_edit (STRLIST commands)
break;
cmd = cmds[i].id;
requires_pin = cmds[i].requires_pin;
}
if (requires_pin && !did_checkpin)
{
int rc = agent_scd_checkpin (serialnobuf);
if (rc)
{
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
continue;
}
did_checkpin = 1;
}
switch (cmd)
{
@ -811,6 +842,11 @@ card_edit (STRLIST commands)
generate_card_keys ();
break;
case cmdPASSWD:
change_pin (0);
did_checkpin = 0; /* Need to reset it of course. */
break;
case cmdQUIT:
goto leave;

View File

@ -508,13 +508,16 @@ pin_cb (void *opaque, const char *info, char **retstr)
{
char *value;
int canceled;
int isadmin = (info && strstr (info, "dmin"));
*retstr = NULL;
log_debug ("asking for PIN '%s'\n", info);
value = ask_passphrase (info,
info && strstr (info, "dmin")?
_("Enter Admin PIN: ") : _("Enter PIN: "),
isadmin? "passphrase.adminpin.ask"
: "passphrase.pin.ask",
isadmin? _("Enter Admin PIN: ") : _("Enter PIN: "),
&canceled);
if (!value && canceled)
return -1;
@ -645,7 +648,6 @@ agent_scd_pkdecrypt (const char *serialno,
const unsigned char *indata, size_t indatalen,
unsigned char **r_buf, size_t *r_buflen)
{
APP app;
*r_buf = NULL;
@ -680,3 +682,18 @@ agent_scd_change_pin (int chvno)
pin_cb, NULL);
}
/* Perform a CHECKPIN operation. SERIALNO should be the seriial
number of the card - optioanlly followed by the fingerprint;
however the fingerprint is ignored here. */
int
agent_scd_checkpin (const char *serialnobuf)
{
APP app;
app = current_app? current_app : open_card ();
if (!app)
return gpg_error (GPG_ERR_CARD);
return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
}

View File

@ -158,6 +158,10 @@ int agent_scd_pkdecrypt (const char *serialno,
/* Change the PIN of an OpenPGP card or reset the retry counter. */
int agent_scd_change_pin (int chvno);
/* Send a CHECKPIN command. */
int agent_scd_checkpin (const char *serialnobuf);
#endif /*ENABLE_CARD_SUPPORT*/
#endif /*GNUPG_G10_CARDGLUE_H*/

View File

@ -2914,7 +2914,7 @@ main( int argc, char **argv )
case aCardStatus:
if (argc)
wrong_args ("--card-status");
card_status (stdout);
card_status (stdout, NULL, 0);
break;
case aCardEdit:

View File

@ -186,8 +186,8 @@ int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
int have_static_passphrase(void);
void read_passphrase_from_fd( int fd );
void passphrase_clear_cache ( u32 *keyid, int algo );
char *ask_passphrase (const char *description, const char *prompt,
int *canceled);
char *ask_passphrase (const char *description, const char *promptid,
const char *prompt, int *canceled);
DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
int cipher_algo, STRING2KEY *s2k, int mode,
const char *tryagain_text, int *canceled);

View File

@ -244,7 +244,7 @@ void unblock_all_signals(void);
#ifdef ENABLE_CARD_SUPPORT
/*-- card-util.c --*/
void change_pin (int no);
void card_status (FILE *fp);
void card_status (FILE *fp, char *serialno, size_t serialnobuflen);
void card_edit (STRLIST commands);
#endif

View File

@ -258,7 +258,7 @@ openpgp_pk_algo_usage ( int algo )
/* they are hardwired in gpg 1.0 */
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH;
break;
case PUBKEY_ALGO_RSA_E:
use = PUBKEY_USAGE_ENC;
@ -270,10 +270,10 @@ openpgp_pk_algo_usage ( int algo )
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_SIG;
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
case PUBKEY_ALGO_ELGAMAL:
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH;
break;
default:
break;

View File

@ -1007,7 +1007,9 @@ passphrase_clear_cache ( u32 *keyid, int algo )
* Ask for a passphrase and return that string.
*/
char *
ask_passphrase (const char *description, const char *prompt, int *canceled)
ask_passphrase (const char *description,
const char *promptid,
const char *prompt, int *canceled)
{
char *pw = NULL;
@ -1042,7 +1044,7 @@ ask_passphrase (const char *description, const char *prompt, int *canceled)
pw = NULL;
}
else {
pw = cpr_get_hidden("passphrase.ask",
pw = cpr_get_hidden(promptid? promptid : "passphrase.ask",
prompt?prompt : _("Enter passphrase: ") );
tty_kill_prompt();
}