From a1cb4a940f308ba21ecc002b044efccf0c547784 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 8 Feb 2019 11:58:27 +0100 Subject: [PATCH] card: Make "generate" work for PIV cards. * tools/card-call-scd.c (scd_genkey_cb): Make createtime optional. (scd_genkey_cb): Ditto. Add arg algo. * tools/gpg-card-tool.c (cmd_generate): Add options and factor card specific code out to ... (generate_openpgp, generate_generic): new functions. -- This patch keeps the interactive OpenPGP mode but adds a pure command line mode for other cards; in particular PIV cards. What we still need to do is: a) Add an interactive mode for PIV cards b) Add a command line mode for OpenPGP cards. Signed-off-by: Werner Koch --- tools/card-call-scd.c | 15 +++-- tools/card-tool.h | 3 +- tools/gpg-card-tool.c | 148 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 141 insertions(+), 25 deletions(-) diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c index 0d6dabf1b..97fb6d9f1 100644 --- a/tools/card-call-scd.c +++ b/tools/card-call-scd.c @@ -202,7 +202,7 @@ app_type_string (app_type_t app_type) case APP_TYPE_OPENPGP: result = "OpenPGP"; break; case APP_TYPE_NKS: result = "NetKey"; break; case APP_TYPE_DINSIG: result = "DINSIG"; break; - case APP_TYPE_P15: result = "PKCS#15"; break; + case APP_TYPE_P15: result = "P15"; break; case APP_TYPE_GELDKARTE: result = "Geldkarte"; break; case APP_TYPE_SC_HSM: result = "SC-HSM"; break; case APP_TYPE_PIV: result = "PIV"; break; @@ -1174,7 +1174,8 @@ scd_genkey_cb (void *opaque, const char *line) if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen)) { - *createtime = (u32)strtoul (line, NULL, 10); + if (createtime) + *createtime = (u32)strtoul (line, NULL, 10); } else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen)) { @@ -1190,7 +1191,7 @@ scd_genkey_cb (void *opaque, const char *line) * SCDEAMON. On success, creation time is stored back to * CREATETIME. */ gpg_error_t -scd_genkey (int keyno, int force, u32 *createtime) +scd_genkey (const char *keyref, int force, const char *algo, u32 *createtime) { gpg_error_t err; char line[ASSUAN_LINELENGTH]; @@ -1203,15 +1204,17 @@ scd_genkey (int keyno, int force, u32 *createtime) if (err) return err; - if (*createtime) + if (createtime && *createtime) epoch2isotime (tbuf, *createtime); else *tbuf = 0; - snprintf (line, sizeof line, "SCD GENKEY %s%s %s %d", + snprintf (line, sizeof line, "SCD GENKEY %s%s %s %s%s -- %s", *tbuf? "--timestamp=":"", tbuf, force? "--force":"", - keyno); + algo? "--algo=":"", + algo? algo:"", + keyref); dfltparm.ctx = agent_ctx; err = assuan_transact (agent_ctx, line, diff --git a/tools/card-tool.h b/tools/card-tool.h index c121e88ef..9daf7e498 100644 --- a/tools/card-tool.h +++ b/tools/card-tool.h @@ -208,7 +208,8 @@ gpg_error_t scd_writecert (const char *certidstr, const unsigned char *certdata, size_t certdatalen); gpg_error_t scd_writekey (int keyno, const unsigned char *keydata, size_t keydatalen); -gpg_error_t scd_genkey (int keyno, int force, u32 *createtime); +gpg_error_t scd_genkey (const char *keyref, int force, const char *algo, + u32 *createtime); gpg_error_t scd_serialno (char **r_serialno, const char *demand); gpg_error_t scd_readcert (const char *certidstr, void **r_buf, size_t *r_buflen); diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c index 71ce13f1b..93153b12f 100644 --- a/tools/gpg-card-tool.c +++ b/tools/gpg-card-tool.c @@ -1722,7 +1722,8 @@ cmd_forcesig (card_info_t info) } -/* Helper for cmd_generate. Noe that either 0 or 1 is stored at + +/* Helper for cmd_generate_openpgp. Noe 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) @@ -1754,7 +1755,7 @@ check_pin_for_key_operation (card_info_t info, int *forced_chv1) } -/* Helper for cmd_generate. */ +/* Helper for cmd_generate_openpgp. */ static void restore_forced_chv1 (int *forced_chv1) { @@ -1775,8 +1776,9 @@ restore_forced_chv1 (int *forced_chv1) } +/* Implementation of cmd_generate for OpenPGP cards. */ static gpg_error_t -cmd_generate (card_info_t info) +generate_openpgp (card_info_t info) { gpg_error_t err; int forced_chv1 = -1; @@ -1784,18 +1786,6 @@ cmd_generate (card_info_t info) char *answer = NULL; key_info_t kinfo1, kinfo2, kinfo3; - if (!info) - return print_help - ("GENERATE\n\n" - "Menu to generate a new keys.", - 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->extcap.ki) { xfree (answer); @@ -1811,7 +1801,6 @@ cmd_generate (card_info_t info) else want_backup = 0; - kinfo1 = find_kinfo (info, "OPENPGP.1"); kinfo2 = find_kinfo (info, "OPENPGP.2"); kinfo3 = find_kinfo (info, "OPENPGP.3"); @@ -1860,6 +1849,7 @@ cmd_generate (card_info_t info) * gpg. We might also first create the keys on the card and then * tell gpg to use them to create the OpenPGP keyblock. */ /* generate_keypair (ctrl, 1, NULL, info.serialno, want_backup); */ + (void)want_backup; err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); leave: @@ -1869,6 +1859,126 @@ cmd_generate (card_info_t info) } +/* Generic implementation of cmd_generate. */ +static gpg_error_t +generate_generic (card_info_t info, const char *keyref, int force, + const char *algo) +{ + gpg_error_t err; + + (void)info; + + err = scd_genkey (keyref, force, algo, NULL); + + return err; +} + + +static gpg_error_t +cmd_generate (card_info_t info, char *argstr) +{ + static char * const valid_algos[] = + { "rsa2048", "rsa3072", "rsa4096", + "nistp256", "nistp384", "nistp521", + "ed25519", "cv25519", + NULL + }; + gpg_error_t err; + int opt_force; + char *opt_algo = NULL; /* Malloced. */ + char *keyref_buffer = NULL; /* Malloced. */ + char *keyref; /* Points into argstr or keyref_buffer. */ + int i; + + if (!info) + return print_help + ("GENERATE [--force] [--algo=ALGO] KEYREF\n\n" + "Create a new key on a card. For OpenPGP cards are menu is used\n" + "and KEYREF is ignored. Use --force to overwrite an existing key.", + APP_TYPE_OPENPGP, APP_TYPE_PIV, 0); + + if (opt.interactive || opt.verbose) + log_info (_("%s card no. %s detected\n"), + app_type_string (info->apptype), + info->dispserialno? info->dispserialno : info->serialno); + + opt_force = has_leading_option (argstr, "--force"); + err = get_option_value (argstr, "--algo", &opt_algo); + if (err) + goto leave; + argstr = skip_options (argstr); + + keyref = argstr; + if ((argstr = strchr (keyref, ' '))) + { + *argstr++ = 0; + trim_spaces (keyref); + trim_spaces (argstr); + } + else /* Let argstr point to an empty string. */ + argstr = keyref + strlen (keyref); + + if (!*keyref) + keyref = NULL; + + if (*argstr) + { + /* Extra arguments found. */ + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + if (opt_algo) + { + for (i=0; valid_algos[i]; i++) + if (!strcmp (valid_algos[i], opt_algo)) + break; + if (!valid_algos[i]) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + log_info ("Invalid algorithm '%s' given. Use one:\n", opt_algo); + for (i=0; valid_algos[i]; i++) + if (!(i%5)) + log_info (" %s%s", valid_algos[i], valid_algos[i+1]?",":"."); + else + log_printf (" %s%s", valid_algos[i], valid_algos[i+1]?",":"."); + log_info ("Note that the card may not support all of them.\n"); + goto leave; + } + } + + /* Upcase the keyref; if it misses the cardtype, prepend it. */ + if (keyref) + { + if (!strchr (keyref, '.')) + keyref_buffer = xstrconcat (app_type_string (info->apptype), ".", + keyref, NULL); + else + keyref_buffer = xstrdup (keyref); + ascii_strupr (keyref_buffer); + keyref = keyref_buffer; + } + + /* Divert to dedicated functions. */ + if (info->apptype == APP_TYPE_OPENPGP) + { + if (opt_force || opt_algo || keyref) + log_info ("Note: Options are ignored for OpenPGP cards.\n"); + err = generate_openpgp (info); + } + else if (!keyref) + err = gpg_error (GPG_ERR_INV_ID); + else + err = generate_generic (info, keyref, opt_force, opt_algo); + + leave: + xfree (opt_algo); + xfree (keyref_buffer); + return err; +} + + + /* Sub-menu to change a PIN. The presented options may depend on the * the ALLOW_ADMIN flag. */ static gpg_error_t @@ -2572,6 +2682,8 @@ ask_card_keyattr (int keyno, const struct key_attr *current, curve = current->curve; } + (void)curve; + (void)algo; err = GPG_ERR_NOT_IMPLEMENTED; goto leave; /* FIXME: We need to mve the ask_cure code out to common or @@ -2929,7 +3041,7 @@ dispatch_command (card_info_t info, const char *orig_command) case cmdWRITECERT: err = cmd_writecert (info, argstr); break; case cmdREADCERT: err = cmd_readcert (info, argstr); break; case cmdFORCESIG: err = cmd_forcesig (info); break; - case cmdGENERATE: err = cmd_generate (info); break; + case cmdGENERATE: err = cmd_generate (info, argstr); break; case cmdPASSWD: err = cmd_passwd (info, 1, argstr); break; case cmdUNBLOCK: err = cmd_unblock (info); break; case cmdFACTORYRESET: err = cmd_factoryreset (info); break; @@ -3195,7 +3307,7 @@ interactive_loop (void) case cmdWRITECERT: err = cmd_writecert (info, argstr); break; case cmdREADCERT: err = cmd_readcert (info, argstr); break; case cmdFORCESIG: err = cmd_forcesig (info); break; - case cmdGENERATE: err = cmd_generate (info); break; + case cmdGENERATE: err = cmd_generate (info, argstr); break; case cmdPASSWD: err = cmd_passwd (info, allow_admin, argstr); break; case cmdUNBLOCK: err = cmd_unblock (info); break; case cmdFACTORYRESET: