mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-21 14:47:03 +01:00
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:
parent
fb6ff7ead7
commit
438b7881ba
@ -817,25 +817,54 @@ learn_status_cb (void *opaque, const char *line)
|
||||
}
|
||||
else if (!memcmp (keyword, "KEY-ATTR", keywordlen))
|
||||
{
|
||||
int keyno = 0;
|
||||
int algo = GCRY_PK_RSA;
|
||||
int n = 0;
|
||||
char keyrefbuf[20];
|
||||
int keyno, algo, n;
|
||||
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);
|
||||
keyno--;
|
||||
if (keyno < 0 || keyno >= DIM (parm->key_attr))
|
||||
algo = map_openpgp_pk_to_gcry (algo);
|
||||
if (keyno < 1 || keyno > 3)
|
||||
; /* Out of range - ignore. */
|
||||
else
|
||||
{
|
||||
parm->key_attr[keyno].algo = algo;
|
||||
if (algo == PUBKEY_ALGO_RSA)
|
||||
parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
|
||||
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA)
|
||||
snprintf (keyrefbuf, sizeof keyrefbuf, "OPENPGP.%d", keyno);
|
||||
keyref = keyrefbuf;
|
||||
|
||||
kinfo = find_kinfo (parm, keyref);
|
||||
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 =
|
||||
openpgp_is_curve_supported (line + n, NULL, NULL);
|
||||
curve = 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;
|
||||
@ -1267,11 +1296,11 @@ scd_genkey_cb (void *opaque, const char *line)
|
||||
return 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 key is created with this. Otherwise, timestamp was generated by
|
||||
* SCDEAMON. On success, creation time is stored back to
|
||||
* CREATETIME. */
|
||||
* SCDAEMON. On success, creation time is stored back to CREATETIME. */
|
||||
gpg_error_t
|
||||
scd_genkey (const char *keyref, int force, const char *algo, u32 *createtime)
|
||||
{
|
||||
|
528
tools/gpg-card.c
528
tools/gpg-card.c
@ -127,6 +127,7 @@ typedef struct keyinfolabel_s *keyinfolabel_t;
|
||||
|
||||
|
||||
/* Local prototypes. */
|
||||
static void show_keysize_warning (void);
|
||||
static gpg_error_t dispatch_command (card_info_t info, const char *command);
|
||||
static void interactive_loop (void);
|
||||
#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, " keyref .....: %s\n", kinfo->keyref);
|
||||
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -681,6 +683,10 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo,
|
||||
gcry_sexp_release (s_pkey);
|
||||
s_pkey = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
|
||||
}
|
||||
|
||||
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");
|
||||
if (label_keyref)
|
||||
tty_fprintf (fp, " keyref .....: %s\n", label_keyref);
|
||||
if (kinfo)
|
||||
tty_fprintf (fp, " algorithm ..: %s\n", kinfo->keyalgo);
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -798,7 +806,6 @@ list_openpgp (card_info_t info, estream_t fp)
|
||||
{ "Authentication key:", "OPENPGP.3" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int i;
|
||||
|
||||
if (!info->serialno
|
||||
|| 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",
|
||||
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",
|
||||
info->chvmaxlen[0], info->chvmaxlen[1], info->chvmaxlen[2]);
|
||||
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. */
|
||||
static gpg_error_t
|
||||
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
|
||||
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;
|
||||
int forced_chv1 = -1;
|
||||
@ -2089,22 +2109,9 @@ generate_openpgp (card_info_t info)
|
||||
|| (kinfo3 && kinfo3->fprlen && !mem_is_zero (kinfo3->fpr,kinfo3->fprlen))
|
||||
)
|
||||
{
|
||||
tty_printf ("\n");
|
||||
log_info (_("Note: keys are already stored on the card!\n"));
|
||||
tty_printf ("\n");
|
||||
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;
|
||||
}
|
||||
err = ask_replace_keys (NULL);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
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
|
||||
* gpg. We might also first create the keys on the card and then
|
||||
* 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
|
||||
generate_generic (card_info_t info, const char *keyref, int force,
|
||||
const char *algo)
|
||||
generate_key (card_info_t info, const char *keyref, int force,
|
||||
const char *algo)
|
||||
{
|
||||
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);
|
||||
|
||||
leave:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2165,17 +2207,21 @@ cmd_generate (card_info_t info, char *argstr)
|
||||
};
|
||||
gpg_error_t err;
|
||||
int opt_force;
|
||||
char *opt_algo = NULL; /* Malloced. */
|
||||
char *p;
|
||||
char **opt_algo = NULL; /* Malloced. */
|
||||
char *keyref_buffer = NULL; /* Malloced. */
|
||||
char *keyref; /* Points into argstr or keyref_buffer. */
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
if (!info)
|
||||
return print_help
|
||||
("GENERATE [--force] [--algo=ALGO] KEYREF\n\n"
|
||||
"Create a new key on a card. For OpenPGP cards a menu is used\n"
|
||||
"and KEYREF is ignored. Use --force to overwrite an existing key.\n"
|
||||
"Using \"help\" for ALGO gives a list of known algorithms.\n",
|
||||
("GENERATE [--force] [--algo=ALGO{+ALGO2}] KEYREF\n\n"
|
||||
"Create a new key on a card.\n"
|
||||
"Use --force to overwrite an existing key.\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);
|
||||
|
||||
if (opt.interactive || opt.verbose)
|
||||
@ -2184,9 +2230,21 @@ cmd_generate (card_info_t info, char *argstr)
|
||||
info->dispserialno? info->dispserialno : info->serialno);
|
||||
|
||||
opt_force = has_leading_option (argstr, "--force");
|
||||
err = get_option_value (argstr, "--algo", &opt_algo);
|
||||
err = get_option_value (argstr, "--algo", &p);
|
||||
if (err)
|
||||
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);
|
||||
|
||||
keyref = argstr;
|
||||
@ -2211,33 +2269,40 @@ cmd_generate (card_info_t info, char *argstr)
|
||||
|
||||
if (opt_algo)
|
||||
{
|
||||
for (i=0; valid_algos[i]; i++)
|
||||
if (*valid_algos[i] && !strcmp (valid_algos[i], opt_algo))
|
||||
break;
|
||||
if (!valid_algos[i])
|
||||
/* opt_algo is an array of algos. */
|
||||
for (i=0; opt_algo[i]; i++)
|
||||
{
|
||||
int lf = 1;
|
||||
if (!ascii_strcasecmp (opt_algo, "help"))
|
||||
log_info ("Known algorithms:\n");
|
||||
else
|
||||
for (j=0; valid_algos[j]; j++)
|
||||
if (*valid_algos[j] && !strcmp (valid_algos[j], opt_algo[i]))
|
||||
break;
|
||||
if (!valid_algos[j])
|
||||
{
|
||||
log_info ("Invalid algorithm '%s' given. Use one:\n", opt_algo);
|
||||
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]?",":".");
|
||||
}
|
||||
int lf = 1;
|
||||
if (!ascii_strcasecmp (opt_algo[i], "help"))
|
||||
log_info ("Known algorithms:\n");
|
||||
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. */
|
||||
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)
|
||||
log_info ("Note: Options are ignored for OpenPGP cards.\n");
|
||||
err = generate_openpgp (info);
|
||||
/* With no algo requested or more than one algo requested and no
|
||||
* keyref given we create all keys. */
|
||||
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)
|
||||
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
|
||||
err = generate_generic (info, keyref, opt_force, opt_algo);
|
||||
err = generate_key (info, keyref, opt_force, opt_algo? opt_algo[0]:NULL);
|
||||
|
||||
leave:
|
||||
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
|
||||
cmd_uif (card_info_t info, char *argstr)
|
||||
{
|
||||
@ -3196,7 +2981,7 @@ enum cmdids
|
||||
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
|
||||
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
|
||||
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
|
||||
cmdKEYATTR, cmdUIF, cmdAUTH, cmdYUBIKEY,
|
||||
cmdUIF, cmdAUTH, cmdYUBIKEY,
|
||||
cmdINVCMD
|
||||
};
|
||||
|
||||
@ -3230,7 +3015,6 @@ static struct
|
||||
{ "reset" , cmdRESET, N_("send a reset to the card daemon")},
|
||||
{ "factory-reset",cmdFACTRST, N_("destroy all keys and data")},
|
||||
{ "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")},
|
||||
{ "privatedo", cmdPRIVATEDO, N_("change a private 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 cmdFACTRST: err = cmd_factoryreset (info); 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 cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;
|
||||
|
||||
@ -3578,7 +3361,6 @@ interactive_loop (void)
|
||||
redisplay = 1;
|
||||
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 cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;
|
||||
|
||||
|
@ -102,16 +102,6 @@ typedef enum
|
||||
} 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
|
||||
* on a card. This is commonly used as a linked list with all keys
|
||||
* known for the current card. */
|
||||
@ -123,6 +113,11 @@ struct key_info_s
|
||||
|
||||
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. */
|
||||
unsigned char fprlen; /* Use length of the next item. */
|
||||
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 chvinfo[3]; /* Allowed retries for the CHV; 0 = blocked. */
|
||||
unsigned char chvusage[2]; /* Data object 5F2F */
|
||||
struct key_attr key_attr[3]; /* OpenPGP card key attributes. */
|
||||
struct {
|
||||
unsigned int ki:1; /* Key import available. */
|
||||
unsigned int aac:1; /* Algorithm attributes are changeable. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user