mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
card: New subcommand "checkkeys".
* agent/command.c (cmd_havekey): Add new option --info. * tools/card-call-scd.c (scd_readkey): Allow using without result arg. (struct havekey_status_parm_s): New. (havekey_status_cb): New. (scd_havekey_info): New. (scd_delete_key): New. * tools/gpg-card.c (print_keygrip): Add arg with_lf. (cmd_checkkeys): New. (cmdCHECKKEYS): New. (cmds): Add command "checkkeys". (dispatch_command, interactive_loop): Call cmd_checkkeys. -- GnuPG-bug-id: 6943
This commit is contained in:
parent
c8060a8f23
commit
adeb17e375
@ -634,10 +634,12 @@ cmd_marktrusted (assuan_context_t ctx, char *line)
|
|||||||
static const char hlp_havekey[] =
|
static const char hlp_havekey[] =
|
||||||
"HAVEKEY <hexstrings_with_keygrips>\n"
|
"HAVEKEY <hexstrings_with_keygrips>\n"
|
||||||
"HAVEKEY --list[=<limit>]\n"
|
"HAVEKEY --list[=<limit>]\n"
|
||||||
|
"HAVEKEY --info <hexkeygrip>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return success if at least one of the secret keys with the given\n"
|
"Return success if at least one of the secret keys with the given\n"
|
||||||
"keygrips is available. With --list return all available keygrips\n"
|
"keygrips is available. With --list return all available keygrips\n"
|
||||||
"as binary data; with <limit> bail out at this number of keygrips";
|
"as binary data; with <limit> bail out at this number of keygrips.\n"
|
||||||
|
"In --info mode check just one keygrip.";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_havekey (assuan_context_t ctx, char *line)
|
cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
@ -645,7 +647,8 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char grip[20];
|
unsigned char grip[20];
|
||||||
char *p;
|
char *p;
|
||||||
int list_mode; /* Less than 0 for no limit. */
|
int list_mode = 0; /* Less than 0 for no limit. */
|
||||||
|
int info_mode = 0;
|
||||||
int counter;
|
int counter;
|
||||||
char *dirname;
|
char *dirname;
|
||||||
gnupg_dir_t dir;
|
gnupg_dir_t dir;
|
||||||
@ -653,15 +656,46 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
|||||||
char hexgrip[41];
|
char hexgrip[41];
|
||||||
struct card_key_info_s *keyinfo_on_cards, *l;
|
struct card_key_info_s *keyinfo_on_cards, *l;
|
||||||
|
|
||||||
if (has_option_name (line, "--list"))
|
if (has_option (line, "--info"))
|
||||||
|
info_mode = 1;
|
||||||
|
else if (has_option_name (line, "--list"))
|
||||||
{
|
{
|
||||||
if ((p = option_value (line, "--list")))
|
if ((p = option_value (line, "--list")))
|
||||||
list_mode = atoi (p);
|
list_mode = atoi (p);
|
||||||
else
|
else
|
||||||
list_mode = -1;
|
list_mode = -1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
list_mode = 0;
|
line = skip_options (line);
|
||||||
|
|
||||||
|
|
||||||
|
if (info_mode)
|
||||||
|
{
|
||||||
|
int keytype;
|
||||||
|
const char *infostring;
|
||||||
|
|
||||||
|
ctrl = assuan_get_pointer (ctx);
|
||||||
|
|
||||||
|
err = parse_keygrip (ctx, line, grip);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = agent_key_info_from_file (ctrl, grip, &keytype, NULL, NULL);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
switch (keytype)
|
||||||
|
{
|
||||||
|
case PRIVATE_KEY_CLEAR:
|
||||||
|
case PRIVATE_KEY_OPENPGP_NONE: infostring = "clear"; break;
|
||||||
|
case PRIVATE_KEY_PROTECTED: infostring = "protected"; break;
|
||||||
|
case PRIVATE_KEY_SHADOWED: infostring = "shadowed"; break;
|
||||||
|
default: infostring = "unknown"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent_write_status (ctrl, "KEYFILEINFO", infostring, NULL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!list_mode)
|
if (!list_mode)
|
||||||
|
@ -1529,6 +1529,7 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
|
|||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t len, buflen;
|
size_t len, buflen;
|
||||||
|
|
||||||
|
if (r_result)
|
||||||
*r_result = NULL;
|
*r_result = NULL;
|
||||||
err = start_agent (0);
|
err = start_agent (0);
|
||||||
if (err)
|
if (err)
|
||||||
@ -1536,7 +1537,8 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
|
|||||||
|
|
||||||
init_membuf (&data, 1024);
|
init_membuf (&data, 1024);
|
||||||
if (create_shadow)
|
if (create_shadow)
|
||||||
snprintf (line, DIM(line), "READKEY --card -- %s", keyrefstr);
|
snprintf (line, DIM(line), "READKEY %s--card -- %s",
|
||||||
|
r_result? "" : "--no-data ", keyrefstr);
|
||||||
else
|
else
|
||||||
snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
|
snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
|
||||||
err = assuan_transact (agent_ctx, line,
|
err = assuan_transact (agent_ctx, line,
|
||||||
@ -1552,7 +1554,7 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
|
|||||||
if (!buf)
|
if (!buf)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
err = gcry_sexp_new (r_result, buf, buflen, 0);
|
err = r_result ? gcry_sexp_new (r_result, buf, buflen, 0) : 0;
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -1769,6 +1771,90 @@ agent_get_s2k_count (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct havekey_status_parm_s
|
||||||
|
{
|
||||||
|
char *string;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
havekey_status_cb (void *opaque, const char *line)
|
||||||
|
{
|
||||||
|
struct havekey_status_parm_s *parm = opaque;
|
||||||
|
const char *s;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if ((s = has_leading_keyword (line, "KEYFILEINFO")))
|
||||||
|
{
|
||||||
|
xfree (parm->string);
|
||||||
|
parm->string = xtrystrdup (s);
|
||||||
|
if (!parm->string)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
p = strchr (parm->string, ' ');
|
||||||
|
if (p)
|
||||||
|
*p = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Run the HAVEKEY --info command and stores the retrieved string at
|
||||||
|
* R_RESULT. Caller must free that string. If an error is returned
|
||||||
|
* R_RESULT is set to NULL. */
|
||||||
|
gpg_error_t
|
||||||
|
scd_havekey_info (const unsigned char *grip, char **r_result)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
struct havekey_status_parm_s parm = {NULL};
|
||||||
|
|
||||||
|
*r_result = NULL;
|
||||||
|
|
||||||
|
err = start_agent (0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
snprintf (line, sizeof line, "HAVEKEY --info ");
|
||||||
|
log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10);
|
||||||
|
bin2hex (grip, KEYGRIP_LEN, line+strlen(line));
|
||||||
|
|
||||||
|
err = assuan_transact (agent_ctx, line,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
havekey_status_cb, &parm);
|
||||||
|
if (err)
|
||||||
|
xfree (parm.string);
|
||||||
|
else
|
||||||
|
*r_result = parm.string;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Run the DELETE_KEY command. If FORCE is given the user will not be
|
||||||
|
* asked for confirmation. */
|
||||||
|
gpg_error_t
|
||||||
|
scd_delete_key (const unsigned char *grip, int force)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
struct default_inq_parm_s dfltparm = {NULL};
|
||||||
|
|
||||||
|
err = start_agent (0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
dfltparm.ctx = agent_ctx;
|
||||||
|
|
||||||
|
snprintf (line, sizeof line, "DELETE_KEY%s ", force?" --force":"");
|
||||||
|
log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10);
|
||||||
|
bin2hex (grip, KEYGRIP_LEN, line+strlen(line));
|
||||||
|
|
||||||
|
err = assuan_transact (agent_ctx, line,
|
||||||
|
NULL, NULL, default_inq_cb, &dfltparm, NULL, NULL);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Return a malloced string describing the statusword SW. On error
|
/* Return a malloced string describing the statusword SW. On error
|
||||||
* NULL is returned. */
|
* NULL is returned. */
|
||||||
char *
|
char *
|
||||||
|
136
tools/gpg-card.c
136
tools/gpg-card.c
@ -582,12 +582,13 @@ print_shax_fpr (estream_t fp, const unsigned char *fpr, unsigned int fprlen)
|
|||||||
|
|
||||||
/* Print the keygrip GRP. */
|
/* Print the keygrip GRP. */
|
||||||
static void
|
static void
|
||||||
print_keygrip (estream_t fp, const unsigned char *grp)
|
print_keygrip (estream_t fp, const unsigned char *grp, int with_lf)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i < 20 ; i++, grp++)
|
for (i=0; i < 20 ; i++, grp++)
|
||||||
tty_fprintf (fp, "%02X", *grp);
|
tty_fprintf (fp, "%02X", *grp);
|
||||||
|
if (with_lf)
|
||||||
tty_fprintf (fp, "\n");
|
tty_fprintf (fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +701,7 @@ list_one_kinfo (card_info_t info, key_info_t kinfo,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_keygrip (fp, kinfo->grip);
|
print_keygrip (fp, kinfo->grip, 1);
|
||||||
tty_fprintf (fp, " keyref .....: %s", kinfo->keyref);
|
tty_fprintf (fp, " keyref .....: %s", kinfo->keyref);
|
||||||
if (kinfo->usage)
|
if (kinfo->usage)
|
||||||
{
|
{
|
||||||
@ -1376,6 +1377,133 @@ cmd_list (card_info_t info, char *argstr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* The CHECKKEYS command. */
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_checkkeys (card_info_t callerinfo, char *argstr)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
estream_t fp = opt.interactive? NULL : es_stdout;
|
||||||
|
strlist_t cards = NULL;
|
||||||
|
strlist_t sl;
|
||||||
|
int opt_ondisk;
|
||||||
|
int opt_delete_clear;
|
||||||
|
int opt_delete_protected;
|
||||||
|
int delete_count = 0;
|
||||||
|
struct card_info_s info_buffer = { 0 };
|
||||||
|
card_info_t info = &info_buffer;
|
||||||
|
key_info_t kinfo;
|
||||||
|
|
||||||
|
|
||||||
|
if (!callerinfo)
|
||||||
|
return print_help
|
||||||
|
("CHECKKEYS [--ondisk] [--delete-clear-copy]\n\n"
|
||||||
|
"Print a list of keys on all inserted cards. With --ondisk only\n"
|
||||||
|
"keys are listed which also have a copy on disk. Missing shadow\n"
|
||||||
|
"keys are created. With --delete-clear, copies of keys also stored\n"
|
||||||
|
"on disk without any protection will be deleted.\n"
|
||||||
|
, 0);
|
||||||
|
|
||||||
|
|
||||||
|
opt_ondisk = has_leading_option (argstr, "--ondisk");
|
||||||
|
opt_delete_clear = has_leading_option (argstr, "--delete-clear-copy");
|
||||||
|
opt_delete_protected = has_leading_option (argstr, "--delete-protected-copy");
|
||||||
|
argstr = skip_options (argstr);
|
||||||
|
|
||||||
|
if (*argstr)
|
||||||
|
{
|
||||||
|
/* No args expected */
|
||||||
|
err = gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callerinfo->serialno)
|
||||||
|
{
|
||||||
|
/* This is probably the first call We need to send a SERIALNO
|
||||||
|
* command to scdaemon so that our session knows all cards. */
|
||||||
|
err = scd_serialno (NULL, NULL);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the list of all cards. */
|
||||||
|
err = scd_cardlist (&cards);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Loop over all cards. We use our own info buffer here. */
|
||||||
|
for (sl = cards; sl; sl = sl->next)
|
||||||
|
{
|
||||||
|
err = scd_switchcard (sl->d);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("Error switching to card %s: %s\n",
|
||||||
|
sl->d, gpg_strerror (err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
release_card_info (info);
|
||||||
|
err = scd_learn (info, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("Error getting infos from card %s: %s\n",
|
||||||
|
sl->d, gpg_strerror (err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (kinfo = info->kinfo; kinfo; kinfo = kinfo->next)
|
||||||
|
{
|
||||||
|
char *infostr;
|
||||||
|
|
||||||
|
err = scd_havekey_info (kinfo->grip, &infostr);
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
/* Create a shadow key and try again. */
|
||||||
|
scd_readkey (kinfo->keyref, 1, NULL);
|
||||||
|
err = scd_havekey_info (kinfo->grip, &infostr);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
log_error ("Error getting infos for a key: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
|
||||||
|
if (opt_ondisk && infostr && !strcmp (infostr, "shadowed"))
|
||||||
|
; /* Don't print this one. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tty_fprintf (fp, "%s %s ",
|
||||||
|
nullnone (info->serialno),
|
||||||
|
app_type_string (info->apptype));
|
||||||
|
print_keygrip (fp, kinfo->grip, 0);
|
||||||
|
tty_fprintf (fp, " %s %s\n",
|
||||||
|
kinfo->keyref, infostr? infostr: "error");
|
||||||
|
}
|
||||||
|
if (infostr
|
||||||
|
&& ((opt_delete_clear && !strcmp (infostr, "clear"))
|
||||||
|
|| (opt_delete_protected && !strcmp (infostr, "protected"))))
|
||||||
|
{
|
||||||
|
err = scd_delete_key (kinfo->grip, 0);
|
||||||
|
if (err)
|
||||||
|
log_error ("Error deleting a key copy: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
else
|
||||||
|
delete_count++;
|
||||||
|
}
|
||||||
|
xfree (infostr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delete_count)
|
||||||
|
log_info ("Number of deleted key copies: %d\n", delete_count);
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
release_card_info (info);
|
||||||
|
free_strlist (cards);
|
||||||
|
/* Better reset to the original card. */
|
||||||
|
scd_learn (callerinfo, 0);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* The VERIFY command. */
|
/* The VERIFY command. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -3726,6 +3854,7 @@ enum cmdids
|
|||||||
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
||||||
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
|
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
|
||||||
cmdUIF, cmdAUTH, cmdYUBIKEY, cmdAPDU, cmdGPG, cmdGPGSM, cmdHISTORY,
|
cmdUIF, cmdAUTH, cmdYUBIKEY, cmdAPDU, cmdGPG, cmdGPGSM, cmdHISTORY,
|
||||||
|
cmdCHECKKEYS,
|
||||||
cmdINVCMD
|
cmdINVCMD
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3765,6 +3894,7 @@ static struct
|
|||||||
{ "readcert", cmdREADCERT, N_("read a certificate from a data object")},
|
{ "readcert", cmdREADCERT, N_("read a certificate from a data object")},
|
||||||
{ "writecert", cmdWRITECERT, N_("store a certificate to a data object")},
|
{ "writecert", cmdWRITECERT, N_("store a certificate to a data object")},
|
||||||
{ "writekey", cmdWRITEKEY, N_("store a private key to a data object")},
|
{ "writekey", cmdWRITEKEY, N_("store a private key to a data object")},
|
||||||
|
{ "checkkeys", cmdCHECKKEYS, N_("run various checks on the keys")},
|
||||||
{ "yubikey", cmdYUBIKEY, N_("Yubikey management commands")},
|
{ "yubikey", cmdYUBIKEY, N_("Yubikey management commands")},
|
||||||
{ "gpg", cmdGPG, NULL},
|
{ "gpg", cmdGPG, NULL},
|
||||||
{ "gpgsm", cmdGPGSM, NULL},
|
{ "gpgsm", cmdGPGSM, NULL},
|
||||||
@ -3901,6 +4031,7 @@ dispatch_command (card_info_t info, const char *orig_command)
|
|||||||
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
|
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
|
||||||
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
|
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
|
||||||
case cmdHISTORY: err = 0; break; /* Only used in interactive mode. */
|
case cmdHISTORY: err = 0; break; /* Only used in interactive mode. */
|
||||||
|
case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break;
|
||||||
|
|
||||||
case cmdINVCMD:
|
case cmdINVCMD:
|
||||||
default:
|
default:
|
||||||
@ -4160,6 +4291,7 @@ interactive_loop (void)
|
|||||||
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
|
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
|
||||||
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
|
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
|
||||||
case cmdHISTORY: err = cmd_history (info, argstr); break;
|
case cmdHISTORY: err = cmd_history (info, argstr); break;
|
||||||
|
case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break;
|
||||||
|
|
||||||
case cmdINVCMD:
|
case cmdINVCMD:
|
||||||
default:
|
default:
|
||||||
|
@ -246,6 +246,8 @@ gpg_error_t scd_cardlist (strlist_t *result);
|
|||||||
gpg_error_t scd_applist (strlist_t *result, int all);
|
gpg_error_t scd_applist (strlist_t *result, int all);
|
||||||
gpg_error_t scd_change_pin (const char *pinref, int reset_mode, int nullpin);
|
gpg_error_t scd_change_pin (const char *pinref, int reset_mode, int nullpin);
|
||||||
gpg_error_t scd_checkpin (const char *serialno);
|
gpg_error_t scd_checkpin (const char *serialno);
|
||||||
|
gpg_error_t scd_havekey_info (const unsigned char *grip, char **r_result);
|
||||||
|
gpg_error_t scd_delete_key (const unsigned char *grip, int force);
|
||||||
|
|
||||||
unsigned long agent_get_s2k_count (void);
|
unsigned long agent_get_s2k_count (void);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user