card: Remove command "key-attr" and hack on "generate".

* tools/gpg-card.h (struct key_attr): Remove.
(struct key_info_s): Remove key_attr.  Add keyalgo and keyalgo_id.
* tools/card-call-scd.c (learn_status_cb): Rework the key-attr info.
* tools/gpg-card.c (list_one_kinfo): Always show the algorithm; if
there is no key show the key attributes instead.
(list_openpgp): Do not print the "Key attributes".
(generate_key): Factor the repalce key pormpt out to ...
(ask_replace_keys): new.
(generate_openpgp): Rename to generate_all_openpgp_card_keys and add
an algo parameter.
(generate_generic): Rename to generate_key.  Prepare generation of a
single OpenPGP key.
(cmd_generate): Revamp.
(ask_card_rsa_keysize): Remove.
(ask_card_keyattr): Remove.
(do_change_keyattr): Remove.
(cmd_keyattr): Remove.
(enum cmdids): Remove cmdKEYATTR.
(cmds): Ditto.
(dispatch_command): Ditto.
(interactive_loop): Ditto.
--

This change shows the key attributes of an OpenPGP card instead of the
key's algorithm if no key exists.  It also remove the key-attr command
because for uniformity it is better to do this directly in
scd/app-openpgp.c At least for this new gpg-card tool.

There a couple of other changes but to the generate command but they
are not yet ready.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-02-10 14:12:36 +01:00
parent fb6ff7ead7
commit 438b7881ba
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 203 additions and 398 deletions

View File

@ -817,25 +817,54 @@ learn_status_cb (void *opaque, const char *line)
} }
else if (!memcmp (keyword, "KEY-ATTR", keywordlen)) else if (!memcmp (keyword, "KEY-ATTR", keywordlen))
{ {
int keyno = 0; char keyrefbuf[20];
int algo = GCRY_PK_RSA; int keyno, algo, n;
int n = 0; const char *curve;
unsigned int nbits;
/* To prepare for future changes we allow for a full OpenPGP
* keyref here. */
if (!ascii_strncasecmp (line, "OPENPGP.", 8))
line += 8;
/* Note that KEY-ATTR returns OpenPGP algorithm numbers but
* we want to use the Gcrypt numbers here. A compatible
* change would be to add another paramater along with a
* magic algo number to indicate that. */
algo = PUBKEY_ALGO_RSA;
keyno = n = 0;
sscanf (line, "%d %d %n", &keyno, &algo, &n); sscanf (line, "%d %d %n", &keyno, &algo, &n);
keyno--; algo = map_openpgp_pk_to_gcry (algo);
if (keyno < 0 || keyno >= DIM (parm->key_attr)) if (keyno < 1 || keyno > 3)
; /* Out of range - ignore. */ ; /* Out of range - ignore. */
else else
{ {
parm->key_attr[keyno].algo = algo; snprintf (keyrefbuf, sizeof keyrefbuf, "OPENPGP.%d", keyno);
if (algo == PUBKEY_ALGO_RSA) keyref = keyrefbuf;
parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA kinfo = find_kinfo (parm, keyref);
|| algo == PUBKEY_ALGO_EDDSA) if (!kinfo) /* No: new entry. */
kinfo = create_kinfo (parm, keyref);
/* Although we could use the the value at %n directly as
* keyalgo string, we want to use the standard
* keyalgo_string function and thus we reconstruct it
* here to make sure the displayed form of the curve
* names is used. */
nbits = 0;
curve = NULL;
if (algo == GCRY_PK_ECDH || algo == GCRY_PK_ECDSA
|| algo == GCRY_PK_EDDSA || algo == GCRY_PK_ECC)
{ {
parm->key_attr[keyno].curve = curve = openpgp_is_curve_supported (line + n, NULL, NULL);
openpgp_is_curve_supported (line + n, NULL, NULL);
} }
else /* For rsa we see here for example "rsa2048". */
{
if (line[n] && line[n+1] && line[n+2])
nbits = strtoul (line+n+3, NULL, 10);
}
kinfo->keyalgo = get_keyalgo_string (algo, nbits, curve);
kinfo->keyalgo_id = algo;
} }
} }
break; break;
@ -1267,11 +1296,11 @@ scd_genkey_cb (void *opaque, const char *line)
return 0; return 0;
} }
/* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0, /* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0,
* the value will be passed to SCDAEMON with --timestamp option so that * the value will be passed to SCDAEMON with --timestamp option so that
* the key is created with this. Otherwise, timestamp was generated by * the key is created with this. Otherwise, timestamp was generated by
* SCDEAMON. On success, creation time is stored back to * SCDAEMON. On success, creation time is stored back to CREATETIME. */
* CREATETIME. */
gpg_error_t gpg_error_t
scd_genkey (const char *keyref, int force, const char *algo, u32 *createtime) scd_genkey (const char *keyref, int force, const char *algo, u32 *createtime)
{ {

View File

@ -127,6 +127,7 @@ typedef struct keyinfolabel_s *keyinfolabel_t;
/* Local prototypes. */ /* Local prototypes. */
static void show_keysize_warning (void);
static gpg_error_t dispatch_command (card_info_t info, const char *command); static gpg_error_t dispatch_command (card_info_t info, const char *command);
static void interactive_loop (void); static void interactive_loop (void);
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
@ -652,6 +653,7 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
{ {
tty_fprintf (fp, "[none]\n"); tty_fprintf (fp, "[none]\n");
tty_fprintf (fp, " keyref .....: %s\n", kinfo->keyref); tty_fprintf (fp, " keyref .....: %s\n", kinfo->keyref);
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
goto leave; goto leave;
} }
@ -681,6 +683,10 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
s_pkey = NULL; s_pkey = NULL;
} }
else
{
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
}
if (kinfo->fprlen && kinfo->created) if (kinfo->fprlen && kinfo->created)
{ {
@ -746,6 +752,8 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
tty_fprintf (fp, " [none]\n"); tty_fprintf (fp, " [none]\n");
if (label_keyref) if (label_keyref)
tty_fprintf (fp, " keyref .....: %s\n", label_keyref); tty_fprintf (fp, " keyref .....: %s\n", label_keyref);
if (kinfo)
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
} }
leave: leave:
@ -798,7 +806,6 @@ list_openpgp (card_info_t info, estream_t fp)
{ "Authentication key:", "OPENPGP.3" }, { "Authentication key:", "OPENPGP.3" },
{ NULL, NULL } { NULL, NULL }
}; };
int i;
if (!info->serialno if (!info->serialno
|| strncmp (info->serialno, "D27600012401", 12) || strncmp (info->serialno, "D27600012401", 12)
@ -845,26 +852,6 @@ list_openpgp (card_info_t info, estream_t fp)
} }
tty_fprintf (fp, "Signature PIN ....: %s\n", tty_fprintf (fp, "Signature PIN ....: %s\n",
info->chv1_cached? _("not forced"): _("forced")); info->chv1_cached? _("not forced"): _("forced"));
if (info->key_attr[0].algo)
{
tty_fprintf (fp, "Key attributes ...:");
for (i=0; i < DIM (info->key_attr); i++)
if (info->key_attr[i].algo == PUBKEY_ALGO_RSA)
tty_fprintf (fp, " rsa%u", info->key_attr[i].nbits);
else if (info->key_attr[i].algo == PUBKEY_ALGO_ECDH
|| info->key_attr[i].algo == PUBKEY_ALGO_ECDSA
|| info->key_attr[i].algo == PUBKEY_ALGO_EDDSA)
{
const char *curve_for_print = "?";
const char *oid;
if (info->key_attr[i].curve
&& (oid = openpgp_curve_to_oid (info->key_attr[i].curve, NULL)))
curve_for_print = openpgp_oid_to_curve (oid, 0);
tty_fprintf (fp, " %s", curve_for_print);
}
tty_fprintf (fp, "\n");
}
tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n", tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n",
info->chvmaxlen[0], info->chvmaxlen[1], info->chvmaxlen[2]); info->chvmaxlen[0], info->chvmaxlen[1], info->chvmaxlen[2]);
tty_fprintf (fp, "PIN retry counter : %d %d %d\n", tty_fprintf (fp, "PIN retry counter : %d %d %d\n",
@ -2002,7 +1989,7 @@ cmd_forcesig (card_info_t info)
/* Helper for cmd_generate_openpgp. Noe that either 0 or 1 is stored at /* Helper for cmd_generate_openpgp. Nore that either 0 or 1 is stored at
* FORCED_CHV1. */ * FORCED_CHV1. */
static gpg_error_t static gpg_error_t
check_pin_for_key_operation (card_info_t info, int *forced_chv1) check_pin_for_key_operation (card_info_t info, int *forced_chv1)
@ -2055,9 +2042,42 @@ restore_forced_chv1 (int *forced_chv1)
} }
/* Implementation of cmd_generate for OpenPGP cards. */ /* Ask whether existing keys shall be overwritten. With NULL used for
* KINFO it will ask for all keys, other wise for the given key. */
static gpg_error_t static gpg_error_t
generate_openpgp (card_info_t info) ask_replace_keys (key_info_t kinfo)
{
gpg_error_t err;
char *answer;
tty_printf ("\n");
if (kinfo)
log_info (_("Note: key %s is already stored on the card!\n"),
kinfo->keyref);
else
log_info (_("Note: Keys are already stored on the card!\n"));
tty_printf ("\n");
if (kinfo)
answer = tty_getf (_("Replace existing key %s ? (y/N) "), kinfo->keyref);
else
answer = tty_get (_("Replace existing keys? (y/N) "));
tty_kill_prompt ();
if (*answer == CONTROL_D)
err = gpg_error (GPG_ERR_CANCELED);
else if (!answer_is_yes_no_default (answer, 0/*(default to No)*/))
err = gpg_error (GPG_ERR_CANCELED);
else
err = 0;
xfree (answer);
return err;
}
/* Implementation of cmd_generate for OpenPGP cards to generate all
* standard keys at once. */
static gpg_error_t
generate_all_openpgp_card_keys (card_info_t info, char **algos)
{ {
gpg_error_t err; gpg_error_t err;
int forced_chv1 = -1; int forced_chv1 = -1;
@ -2089,22 +2109,9 @@ generate_openpgp (card_info_t info)
|| (kinfo3 && kinfo3->fprlen && !mem_is_zero (kinfo3->fpr,kinfo3->fprlen)) || (kinfo3 && kinfo3->fprlen && !mem_is_zero (kinfo3->fpr,kinfo3->fprlen))
) )
{ {
tty_printf ("\n"); err = ask_replace_keys (NULL);
log_info (_("Note: keys are already stored on the card!\n")); if (err)
tty_printf ("\n"); goto leave;
answer = tty_get (_("Replace existing keys? (y/N) "));
tty_kill_prompt ();
if (*answer == CONTROL_D)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
if (!answer_is_yes_no_default (answer, 0/*(default to No)*/))
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
} }
/* If no displayed name has been set, we assume that this is a fresh /* If no displayed name has been set, we assume that this is a fresh
@ -2123,7 +2130,9 @@ generate_openpgp (card_info_t info)
if (err) if (err)
goto leave; goto leave;
/* FIXME: We need to divert to a function which spwans gpg which (void)algos; /* FIXME: If we have ALGOS, we need to change the key attr. */
/* FIXME: We need to divert to a function which spawns gpg which
* will then create the key. This also requires new features in * will then create the key. This also requires new features in
* gpg. We might also first create the keys on the card and then * gpg. We might also first create the keys on the card and then
* tell gpg to use them to create the OpenPGP keyblock. */ * tell gpg to use them to create the OpenPGP keyblock. */
@ -2138,17 +2147,50 @@ generate_openpgp (card_info_t info)
} }
/* Generic implementation of cmd_generate. */ /* Create a single key. This is a helper for cmd_generate. */
static gpg_error_t static gpg_error_t
generate_generic (card_info_t info, const char *keyref, int force, generate_key (card_info_t info, const char *keyref, int force,
const char *algo) const char *algo)
{ {
gpg_error_t err; gpg_error_t err;
key_info_t kinfo;
(void)info; if (info->apptype == APP_TYPE_OPENPGP)
{
kinfo = find_kinfo (info, keyref);
if (!kinfo)
{
err = gpg_error (GPG_ERR_INV_ID);
goto leave;
}
if (!force
&& kinfo->fprlen && !mem_is_zero (kinfo->fpr, kinfo->fprlen))
{
err = ask_replace_keys (NULL);
if (err)
goto leave;
}
log_debug ("current algo is: %s\n", kinfo->keyalgo);
if (algo)
{
log_debug ("setting algo to: %s\n", algo);
/* OpenPGP cards require us to set the key attributes prior
* to generation because the generate command does not take
* key attributes. Actually this should be hidden by
* scd/app-openpgp but that is not the case. */
}
goto leave;
/* err = generate_openpgp (info); */
}
err = scd_genkey (keyref, force, algo, NULL); err = scd_genkey (keyref, force, algo, NULL);
leave:
return err; return err;
} }
@ -2165,17 +2207,21 @@ cmd_generate (card_info_t info, char *argstr)
}; };
gpg_error_t err; gpg_error_t err;
int opt_force; int opt_force;
char *opt_algo = NULL; /* Malloced. */ char *p;
char **opt_algo = NULL; /* Malloced. */
char *keyref_buffer = NULL; /* Malloced. */ char *keyref_buffer = NULL; /* Malloced. */
char *keyref; /* Points into argstr or keyref_buffer. */ char *keyref; /* Points into argstr or keyref_buffer. */
int i; int i, j;
if (!info) if (!info)
return print_help return print_help
("GENERATE [--force] [--algo=ALGO] KEYREF\n\n" ("GENERATE [--force] [--algo=ALGO{+ALGO2}] KEYREF\n\n"
"Create a new key on a card. For OpenPGP cards a menu is used\n" "Create a new key on a card.\n"
"and KEYREF is ignored. Use --force to overwrite an existing key.\n" "Use --force to overwrite an existing key.\n"
"Using \"help\" for ALGO gives a list of known algorithms.\n", "Use \"help\" for ALGO to get a list of known algorithms.\n"
"For OpenPGP cards several algos may be given.\n"
"Note that the OpenPGP key generation is done interactively\n"
"unless a single ALGO or KEYREF are given.",
APP_TYPE_OPENPGP, APP_TYPE_PIV, 0); APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
if (opt.interactive || opt.verbose) if (opt.interactive || opt.verbose)
@ -2184,9 +2230,21 @@ cmd_generate (card_info_t info, char *argstr)
info->dispserialno? info->dispserialno : info->serialno); info->dispserialno? info->dispserialno : info->serialno);
opt_force = has_leading_option (argstr, "--force"); opt_force = has_leading_option (argstr, "--force");
err = get_option_value (argstr, "--algo", &opt_algo); err = get_option_value (argstr, "--algo", &p);
if (err) if (err)
goto leave; goto leave;
if (p)
{
opt_algo = strtokenize (p, "+");
if (!opt_algo)
{
err = gpg_error_from_syserror ();
xfree (p);
goto leave;
}
xfree (p);
}
argstr = skip_options (argstr); argstr = skip_options (argstr);
keyref = argstr; keyref = argstr;
@ -2211,33 +2269,40 @@ cmd_generate (card_info_t info, char *argstr)
if (opt_algo) if (opt_algo)
{ {
for (i=0; valid_algos[i]; i++) /* opt_algo is an array of algos. */
if (*valid_algos[i] && !strcmp (valid_algos[i], opt_algo)) for (i=0; opt_algo[i]; i++)
break;
if (!valid_algos[i])
{ {
int lf = 1; for (j=0; valid_algos[j]; j++)
if (!ascii_strcasecmp (opt_algo, "help")) if (*valid_algos[j] && !strcmp (valid_algos[j], opt_algo[i]))
log_info ("Known algorithms:\n"); break;
else if (!valid_algos[j])
{ {
log_info ("Invalid algorithm '%s' given. Use one:\n", opt_algo); int lf = 1;
err = gpg_error (GPG_ERR_PUBKEY_ALGO); if (!ascii_strcasecmp (opt_algo[i], "help"))
} log_info ("Known algorithms:\n");
for (i=0; valid_algos[i]; i++)
{
if (!*valid_algos[i])
lf = 1;
else if (lf)
{
lf = 0;
log_info (" %s%s", valid_algos[i], valid_algos[i+1]?",":".");
}
else else
log_printf (" %s%s", valid_algos[i], valid_algos[i+1]?",":"."); {
log_info ("Invalid algorithm '%s' given. Use one of:\n",
opt_algo[i]);
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
}
for (i=0; valid_algos[i]; i++)
{
if (!*valid_algos[i])
lf = 1;
else if (lf)
{
lf = 0;
log_info (" %s%s",
valid_algos[i], valid_algos[i+1]?",":".");
}
else
log_printf (" %s%s",
valid_algos[i], valid_algos[i+1]?",":".");
}
show_keysize_warning ();
goto leave;
} }
log_info ("Note that the card may not support all of them.\n");
goto leave;
} }
} }
@ -2264,16 +2329,25 @@ cmd_generate (card_info_t info, char *argstr)
} }
/* Divert to dedicated functions. */ /* Divert to dedicated functions. */
if (info->apptype == APP_TYPE_OPENPGP) if (info->apptype == APP_TYPE_OPENPGP
&& !keyref
&& (!opt_algo || (opt_algo[0] && opt_algo[1])))
{ {
if (opt_force || opt_algo || keyref) /* With no algo requested or more than one algo requested and no
log_info ("Note: Options are ignored for OpenPGP cards.\n"); * keyref given we create all keys. */
err = generate_openpgp (info); if (opt_force || keyref)
log_info ("Note: OpenPGP key generation is interactive.\n");
err = generate_all_openpgp_card_keys (info, opt_algo);
} }
else if (!keyref) else if (!keyref)
err = gpg_error (GPG_ERR_INV_ID); err = gpg_error (GPG_ERR_INV_ID);
else if (opt_algo && opt_algo[0] && opt_algo[1])
{
log_error ("only one algorithm expected as value for --algo.\n");
err = gpg_error (GPG_ERR_INV_ARG);
}
else else
err = generate_generic (info, keyref, opt_force, opt_algo); err = generate_key (info, keyref, opt_force, opt_algo? opt_algo[0]:NULL);
leave: leave:
xfree (opt_algo); xfree (opt_algo);
@ -2805,295 +2879,6 @@ show_keysize_warning (void)
} }
/* Ask for the size of a card key. NBITS is the current size
* configured for the card. Returns 0 on success and stored the
* chosen key size at R_KEYSIZE; 0 is stored to indicate that the
* default size shall be used. */
static gpg_error_t
ask_card_rsa_keysize (unsigned int nbits, unsigned int *r_keysize)
{
unsigned int min_nbits = 1024;
unsigned int max_nbits = 4096;
char*answer;
unsigned int req_nbits;
for (;;)
{
answer = tty_getf (_("What keysize do you want? (%u) "), nbits);
trim_spaces (answer);
tty_kill_prompt ();
if (*answer == CONTROL_D)
{
xfree (answer);
return gpg_error (GPG_ERR_CANCELED);
}
req_nbits = *answer? atoi (answer): nbits;
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)
{
/* Use default. */
*r_keysize = 0;
return 0;
}
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
{
*r_keysize = req_nbits;
return 0;
}
}
}
/* Ask for the key attribute of a card key. CURRENT is the current
* attribute configured for the card. KEYNO is the number of the key
* used to select the prompt. Stores NULL at result to use the
* default attribute or stores the selected attribute structure at
* RESULT. On error an error code is returned. */
static gpg_error_t
ask_card_keyattr (int keyno, const struct key_attr *current,
struct key_attr **result)
{
gpg_error_t err;
struct key_attr *key_attr = NULL;
char *answer = NULL;
int selection;
*result = NULL;
key_attr = xcalloc (1, sizeof *key_attr);
tty_printf (_("Changing card key attribute for: "));
if (keyno == 0)
tty_printf (_("Signature key\n"));
else if (keyno == 1)
tty_printf (_("Encryption key\n"));
else
tty_printf (_("Authentication key\n"));
tty_printf (_("Please select what kind of key you want:\n"));
tty_printf (_(" (%d) RSA\n"), 1 );
tty_printf (_(" (%d) ECC\n"), 2 );
for (;;)
{
xfree (answer);
answer = tty_get (_("Your selection? "));
trim_spaces (answer);
tty_kill_prompt ();
if (!*answer || *answer == CONTROL_D)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
selection = *answer? atoi (answer) : 0;
if (selection == 1 || selection == 2)
break;
else
tty_printf (_("Invalid selection.\n"));
}
if (selection == 1)
{
unsigned int nbits, result_nbits;
if (current->algo == PUBKEY_ALGO_RSA)
nbits = current->nbits;
else
nbits = 2048;
err = ask_card_rsa_keysize (nbits, &result_nbits);
if (err)
goto leave;
if (result_nbits == 0)
{
if (current->algo == PUBKEY_ALGO_RSA)
{
xfree (key_attr);
key_attr = NULL;
}
else
result_nbits = nbits;
}
if (key_attr)
{
key_attr->algo = PUBKEY_ALGO_RSA;
key_attr->nbits = result_nbits;
}
}
else if (selection == 2)
{
const char *curve;
/* const char *oid_str; */
int algo;
if (current->algo == PUBKEY_ALGO_RSA)
{
if (keyno == 1) /* Encryption key */
algo = PUBKEY_ALGO_ECDH;
else /* Signature key or Authentication key */
algo = PUBKEY_ALGO_ECDSA;
curve = NULL;
}
else
{
algo = current->algo;
curve = current->curve;
}
(void)curve;
(void)algo;
err = GPG_ERR_NOT_IMPLEMENTED;
goto leave;
/* FIXME: We need to move the ask_cure code out to common or
* provide another sultion. */
/* curve = ask_curve (&algo, NULL, curve); */
/* if (curve) */
/* { */
/* key_attr->algo = algo; */
/* oid_str = openpgp_curve_to_oid (curve, NULL); */
/* key_attr->curve = openpgp_oid_to_curve (oid_str, 0); */
/* } */
/* else */
/* { */
/* xfree (key_attr); */
/* key_attr = NULL; */
/* } */
}
else
{
err = gpg_error (GPG_ERR_BUG);
goto leave;
}
/* Tell the user what we are going to do. */
if (key_attr->algo == PUBKEY_ALGO_RSA)
{
tty_printf (_("The card will now be re-configured"
" to generate a key of %u bits\n"), key_attr->nbits);
}
else if (key_attr->algo == PUBKEY_ALGO_ECDH
|| key_attr->algo == PUBKEY_ALGO_ECDSA
|| key_attr->algo == PUBKEY_ALGO_EDDSA)
{
tty_printf (_("The card will now be re-configured"
" to generate a key of type: %s\n"), key_attr->curve);
}
show_keysize_warning ();
*result = key_attr;
key_attr = NULL;
leave:
xfree (key_attr);
xfree (answer);
return err;
}
/* Change the key attribute of key KEYNO (0..2) and show an error
* message if that fails. */
static gpg_error_t
do_change_keyattr (int keyno, const struct key_attr *key_attr)
{
gpg_error_t err = 0;
char args[100];
if (key_attr->algo == PUBKEY_ALGO_RSA)
snprintf (args, sizeof args, "--force %d 1 rsa%u", keyno+1,
key_attr->nbits);
else if (key_attr->algo == PUBKEY_ALGO_ECDH
|| key_attr->algo == PUBKEY_ALGO_ECDSA
|| key_attr->algo == PUBKEY_ALGO_EDDSA)
snprintf (args, sizeof args, "--force %d %d %s",
keyno+1, key_attr->algo, key_attr->curve);
else
{
/* FIXME: Above we use openpgp algo names but in the error
* message we use the gcrypt names. We should settle for a
* consistent solution. */
log_error (_("public key algorithm %d (%s) is not supported\n"),
key_attr->algo, gcry_pk_algo_name (key_attr->algo));
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
goto leave;
}
err = scd_setattr ("KEY-ATTR", args, strlen (args));
if (err)
log_error (_("error changing key attribute for key %d: %s\n"),
keyno+1, gpg_strerror (err));
leave:
return err;
}
static gpg_error_t
cmd_keyattr (card_info_t info, char *argstr)
{
gpg_error_t err = 0;
int keyno;
struct key_attr *key_attr = NULL;
(void)argstr;
if (!info)
return print_help
("KEY-ATTR\n\n"
"Menu to change the key attributes of an OpenPGP card.",
APP_TYPE_OPENPGP, 0);
if (info->apptype != APP_TYPE_OPENPGP)
{
log_info ("Note: This is an OpenPGP only command.\n");
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
if (!(info->is_v2 && info->extcap.aac))
{
log_error (_("This command is not supported by this card\n"));
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave;
}
for (keyno = 0; keyno < DIM (info->key_attr); keyno++)
{
xfree (key_attr);
key_attr = NULL;
err = ask_card_keyattr (keyno, &info->key_attr[keyno], &key_attr);
if (err)
goto leave;
err = do_change_keyattr (keyno, key_attr);
if (err)
{
/* Error: Better read the default key attribute again. */
log_debug ("FIXME\n");
/* Ask again for this key. */
keyno--;
}
}
leave:
xfree (key_attr);
return err;
}
static gpg_error_t static gpg_error_t
cmd_uif (card_info_t info, char *argstr) cmd_uif (card_info_t info, char *argstr)
{ {
@ -3196,7 +2981,7 @@ enum cmdids
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR, cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP, cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
cmdKEYATTR, cmdUIF, cmdAUTH, cmdYUBIKEY, cmdUIF, cmdAUTH, cmdYUBIKEY,
cmdINVCMD cmdINVCMD
}; };
@ -3230,7 +3015,6 @@ static struct
{ "reset" , cmdRESET, N_("send a reset to the card daemon")}, { "reset" , cmdRESET, N_("send a reset to the card daemon")},
{ "factory-reset",cmdFACTRST, N_("destroy all keys and data")}, { "factory-reset",cmdFACTRST, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, N_("setup KDF for PIN authentication")}, { "kdf-setup", cmdKDFSETUP, N_("setup KDF for PIN authentication")},
{ "key-attr", cmdKEYATTR, N_("change the key attribute")},
{ "uif", cmdUIF, N_("change the User Interaction Flag")}, { "uif", cmdUIF, N_("change the User Interaction Flag")},
{ "privatedo", cmdPRIVATEDO, N_("change a private data object")}, { "privatedo", cmdPRIVATEDO, N_("change a private data object")},
{ "readcert", cmdREADCERT, N_("read a certificate from a data object")}, { "readcert", cmdREADCERT, N_("read a certificate from a data object")},
@ -3356,7 +3140,6 @@ dispatch_command (card_info_t info, const char *orig_command)
case cmdUNBLOCK: err = cmd_unblock (info); break; case cmdUNBLOCK: err = cmd_unblock (info); break;
case cmdFACTRST: err = cmd_factoryreset (info); break; case cmdFACTRST: err = cmd_factoryreset (info); break;
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break; case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
case cmdKEYATTR: err = cmd_keyattr (info, argstr); break;
case cmdUIF: err = cmd_uif (info, argstr); break; case cmdUIF: err = cmd_uif (info, argstr); break;
case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break; case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;
@ -3578,7 +3361,6 @@ interactive_loop (void)
redisplay = 1; redisplay = 1;
break; break;
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break; case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
case cmdKEYATTR: err = cmd_keyattr (info, argstr); break;
case cmdUIF: err = cmd_uif (info, argstr); break; case cmdUIF: err = cmd_uif (info, argstr); break;
case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break; case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;

View File

@ -102,16 +102,6 @@ typedef enum
} app_type_t; } app_type_t;
/* OpenPGP card key attributes. */
struct key_attr
{
int algo; /* Algorithm identifier. */
union {
unsigned int nbits; /* Supported keysize. */
const char *curve; /* Name of curve. */
};
};
/* An object to store information pertaining to a key pair as stored /* An object to store information pertaining to a key pair as stored
* on a card. This is commonly used as a linked list with all keys * on a card. This is commonly used as a linked list with all keys
* known for the current card. */ * known for the current card. */
@ -123,6 +113,11 @@ struct key_info_s
unsigned char xflag; /* Temporary flag to help processing a list. */ unsigned char xflag; /* Temporary flag to help processing a list. */
/* OpenPGP card and possible other cards keyalgo string (an atom)
* and the id of the algorithm. */
const char *keyalgo;
enum gcry_pk_algos keyalgo_id;
/* The three next items are mostly useful for OpenPGP cards. */ /* The three next items are mostly useful for OpenPGP cards. */
unsigned char fprlen; /* Use length of the next item. */ unsigned char fprlen; /* Use length of the next item. */
unsigned char fpr[32]; /* The binary fingerprint of length FPRLEN. */ unsigned char fpr[32]; /* The binary fingerprint of length FPRLEN. */
@ -169,7 +164,6 @@ struct card_info_s
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */ int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
int chvinfo[3]; /* Allowed retries for the CHV; 0 = blocked. */ int chvinfo[3]; /* Allowed retries for the CHV; 0 = blocked. */
unsigned char chvusage[2]; /* Data object 5F2F */ unsigned char chvusage[2]; /* Data object 5F2F */
struct key_attr key_attr[3]; /* OpenPGP card key attributes. */
struct { struct {
unsigned int ki:1; /* Key import available. */ unsigned int ki:1; /* Key import available. */
unsigned int aac:1; /* Algorithm attributes are changeable. */ unsigned int aac:1; /* Algorithm attributes are changeable. */