diff options
Diffstat (limited to 'tools/gpg-card.c')
-rw-r--r-- | tools/gpg-card.c | 299 |
1 files changed, 184 insertions, 115 deletions
diff --git a/tools/gpg-card.c b/tools/gpg-card.c index e2d728dab..ddc4d12bf 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -429,6 +429,24 @@ put_data_to_file (const char *fname, const void *buffer, size_t length) } +/* Return a malloced string with the number opf the menu PROMPT. + * Control-D is mapped to "Q". */ +static char * +get_selection (const char *prompt) +{ + char *answer; + + tty_printf ("\n"); + tty_printf ("%s", prompt); + tty_printf ("\n"); + answer = tty_get (_("Your selection? ")); + tty_kill_prompt (); + if (*answer == CONTROL_D) + strcpy (answer, "q"); + return answer; +} + + /* Simply prints TEXT to the output. Returns 0 as a convenience. * This is a separate fucntion so that it can be extended to run @@ -655,7 +673,7 @@ list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo, if (!scd_readkey (kinfo->keyref, &s_pkey)) { - char *tmp = pubkey_algo_string (s_pkey); + char *tmp = pubkey_algo_string (s_pkey, NULL); tty_fprintf (fp, " algorithm ..: %s\n", tmp); xfree (tmp); gcry_sexp_release (s_pkey); @@ -982,6 +1000,81 @@ list_card (card_info_t info) +/* The LIST command. This also updates INFO. */ +static gpg_error_t +cmd_list (card_info_t info, char *argstr) +{ + gpg_error_t err; + int opt_cards; + strlist_t cards = NULL; + strlist_t sl; + estream_t fp = opt.interactive? NULL : es_stdout; + int cardno, count; + + + if (!info) + return print_help + ("LIST [--cards] [N]\n\n" + "Show the content of the current card or with N given the N-th card.\n" + "Option --cards lists available cards.", + 0); + + opt_cards = has_leading_option (argstr, "--cards"); + argstr = skip_options (argstr); + + + if (digitp (argstr)) + { + cardno = atoi (argstr); + while (digitp (argstr)) + argstr++; + while (spacep (argstr)) + argstr++; + } + else + cardno = -1; + + + if (opt_cards) + { + err = scd_cardlist (&cards); + if (err) + goto leave; + for (count = 0, sl = cards; sl; sl = sl->next, count++) + tty_fprintf (fp, "%d %s\n", count, sl->d); + } + else + { + if (cardno != -1) + { + err = scd_cardlist (&cards); + if (err) + goto leave; + for (count = 0, sl = cards; sl; sl = sl->next, count++) + if (count == cardno) + break; + if (!sl) + { + err = gpg_error (GPG_ERR_INV_INDEX); + goto leave; + } + err = scd_serialno (NULL, sl->d); + if (err) + goto leave; + } + + err = scd_learn (info); + if (!err) + list_card (info); + } + + leave: + free_strlist (cards); + return err; +} + + + /* The VERIFY command. */ static gpg_error_t cmd_verify (card_info_t info, char *argstr) @@ -2097,21 +2190,23 @@ cmd_generate (card_info_t info, char *argstr) -/* Sub-menu to change a PIN. */ +/* Change a PIN. */ static gpg_error_t cmd_passwd (card_info_t info, char *argstr) { - gpg_error_t err; + gpg_error_t err = 0; char *answer = NULL; - const char *pinref; + const char *pinref = NULL; + int reset_mode = 0; + int menu_used = 0; if (!info) return print_help ("PASSWD [PINREF]\n\n" - "Menu to change or unblock the PINs. Note that the\n" - "presented menu options depend on the type of card\n" - "and whether the admin mode is enabled. For OpenPGP\n" - "and PIV cards defaults for PINREF are available.", + "Change or unblock the PINs. Note that in interactive mode\n" + "and without a PINREF a menu is presented for certain cards;\n" + "in non-interactive and without a PINREF a default value is\n" + "used for these cards.", 0); if (opt.interactive || opt.verbose) @@ -2119,92 +2214,93 @@ cmd_passwd (card_info_t info, char *argstr) app_type_string (info->apptype), info->dispserialno? info->dispserialno : info->serialno); - if (!*argstr && info->apptype == APP_TYPE_OPENPGP) + if (*argstr) + pinref = argstr; + else if (opt.interactive && info->apptype == APP_TYPE_OPENPGP) { - /* For an OpenPGP card we present the well known menu if no - * argument is given. */ - for (;;) + menu_used = 1; + while (!pinref) { - tty_printf ("\n"); - tty_printf ("1 - change PIN\n" - "2 - unblock and set new PIN\n" - "3 - change Admin PIN\n" - "4 - set the Reset Code\n" - "Q - quit\n"); - tty_printf ("\n"); - - err = 0; xfree (answer); - answer = tty_get (_("Your selection? ")); - tty_kill_prompt (); - if (*answer == CONTROL_D) - break; /* Quit. */ + answer = get_selection ("1 - change the PIN\n" + "2 - unblock and set new a PIN\n" + "3 - change the Admin PIN\n" + "4 - set the Reset Code\n" + "Q - quit\n"); if (strlen (answer) != 1) continue; - if (*answer == 'q' || *answer == 'Q') - break; /* Quit. */ - - if (*answer == '1') - { - /* Change PIN (same as the direct thing in non-admin mode). */ - err = scd_change_pin ("OPENPGP.1", 0); - if (err) - log_error ("Error changing the PIN: %s\n", gpg_strerror (err)); - else - log_info ("PIN changed.\n"); - } + else if (*answer == 'q' || *answer == 'Q') + goto leave; + else if (*answer == '1') + pinref = "OPENPGP.1"; else if (*answer == '2') - { - /* Unblock PIN by setting a new PIN. */ - err = scd_change_pin ("OPENPGP.1", 1); - if (err) - log_error ("Error unblocking the PIN: %s\n", gpg_strerror(err)); - else - log_info ("PIN unblocked and new PIN set.\n"); - } + { pinref = "OPENPGP.1"; reset_mode = 1; } else if (*answer == '3') - { - /* Change Admin PIN. */ - err = scd_change_pin ("OPENPGP.3", 0); - if (err) - log_error ("Error changing the PIN: %s\n", gpg_strerror (err)); - else - log_info ("PIN changed.\n"); - } + pinref = "OPENPGP.3"; else if (*answer == '4') - { - /* Set a new Reset Code. */ - err = scd_change_pin ("OPENPGP.2", 1); - if (err) - log_error ("Error setting the Reset Code: %s\n", - gpg_strerror (err)); - else - log_info ("Reset Code set.\n"); - } - - } /*end for loop*/ + { pinref = "OPENPGP.2"; reset_mode = 1; } + } } - else + else if (info->apptype == APP_TYPE_OPENPGP) + pinref = "OPENPGP.1"; + else if (opt.interactive && info->apptype == APP_TYPE_PIV) { - if (*argstr) - pinref = argstr; - else if (info->apptype == APP_TYPE_PIV) - pinref = "PIV.80"; - else + menu_used = 1; + while (!pinref) { - /* Note that we do not have a default value for OpenPGP - * because we want to be mostly compatible to "gpg - * --card-edit" and show a menu in that case (above). */ - err = gpg_error (GPG_ERR_MISSING_VALUE); - goto leave; + xfree (answer); + answer = get_selection ("1 - change the PIN\n" + "2 - change the PUK\n" + "3 - change the Global PIN\n" + "Q - quit\n"); + if (strlen (answer) != 1) + ; + else if (*answer == 'q' || *answer == 'Q') + goto leave; + else if (*answer == '1') + pinref = "PIV.80"; + else if (*answer == '2') + pinref = "PIV.81"; + else if (*answer == '3') + pinref = "PIV.00"; } - err = scd_change_pin (pinref, 0); - if (err) - goto leave; + } + else if (info->apptype == APP_TYPE_PIV) + pinref = "PIV.80"; + else + { + err = gpg_error (GPG_ERR_MISSING_VALUE); + goto leave; + } - if (info->apptype == APP_TYPE_PIV - && !ascii_strcasecmp (pinref, "PIV.81")) + err = scd_change_pin (pinref, reset_mode); + if (err) + { + if (!opt.interactive && !menu_used && !opt.verbose) + ; + else if (!ascii_strcasecmp (pinref, "PIV.81")) + log_error ("Error changing the PUK.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode) + log_error ("Error unblocking the PIN.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode) + log_error ("Error setting the Reset Code.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.3")) + log_error ("Error changing the Admin PIN.\n"); + else + log_error ("Error changing the PIN.\n"); + } + else + { + if (!opt.interactive && !opt.verbose) + ; + else if (!ascii_strcasecmp (pinref, "PIV.81")) log_info ("PUK changed.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode) + log_info ("PIN unblocked and new PIN set.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode) + log_info ("Reset Code set.\n"); + else if (!ascii_strcasecmp (pinref, "OPENPGP.3")) + log_info ("Admin PIN changed.\n"); else log_info ("PIN changed.\n"); } @@ -2261,7 +2357,7 @@ cmd_unblock (card_info_t info) } else { - log_info ("Unblocking not yet supported for '%s'\n", + log_info ("Unblocking not supported for '%s'.\n", app_type_string (info->apptype)); err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); } @@ -2457,9 +2553,8 @@ cmd_factoryreset (card_info_t info) if (err) goto leave; - /* Then, connect the card again (answer used as a dummy). */ - xfree (answer); answer = NULL; - err = scd_serialno (&answer, NULL); + /* Then, connect the card again. */ + err = scd_serialno (NULL, NULL); leave: if (err && any_apdu && !is_yubikey) @@ -2988,7 +3083,7 @@ cmd_yubikey (card_info_t info, char *argstr) /* Note that we always do a learn to get a chance to the card back * into a usable state. */ - err = yubikey_commands (fp, nwords, words); + err = yubikey_commands (info, fp, nwords, words); err2 = scd_learn (info); if (err2) log_error ("Error re-reading card: %s\n", gpg_strerror (err)); @@ -3137,20 +3232,6 @@ dispatch_command (card_info_t info, const char *orig_command) } break; - case cmdLIST: - if (!info) - print_help ("LIST\n\n" - "Show content of the card.", 0); - else - { - err = scd_learn (info); - if (err) - log_error ("Error reading card: %s\n", gpg_strerror (err)); - else - list_card (info); - } - break; - case cmdRESET: if (!info) print_help ("RESET\n\n" @@ -3162,6 +3243,7 @@ dispatch_command (card_info_t info, const char *orig_command) } break; + case cmdLIST: err = cmd_list (info, argstr); break; case cmdVERIFY: err = cmd_verify (info, argstr); break; case cmdAUTH: err = cmd_authenticate (info, argstr); break; case cmdNAME: err = cmd_name (info, argstr); break; @@ -3247,14 +3329,11 @@ interactive_loop (void) } else if (redisplay) { - err = scd_learn (info); + err = cmd_list (info, ""); if (err) - { - log_error ("Error reading card: %s\n", gpg_strerror (err)); - } + log_error ("Error reading card: %s\n", gpg_strerror (err)); else { - list_card (info); tty_printf("\n"); redisplay = 0; } @@ -3367,17 +3446,6 @@ interactive_loop (void) } break; - case cmdLIST: - if (!info) - print_help ("LIST\n\n" - "Show content of the card.", 0); - else - { - /* Actual work is done by the redisplay code block. */ - redisplay = 1; - } - break; - case cmdRESET: if (!info) print_help ("RESET\n\n" @@ -3389,6 +3457,7 @@ interactive_loop (void) } break; + case cmdLIST: err = cmd_list (info, argstr); break; case cmdVERIFY: err = cmd_verify (info, argstr); if (!err) |