diff options
Diffstat (limited to 'tools/gpg-card-tool.c')
-rw-r--r-- | tools/gpg-card-tool.c | 131 |
1 files changed, 84 insertions, 47 deletions
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c index 93153b12f..2bc2e5f90 100644 --- a/tools/gpg-card-tool.c +++ b/tools/gpg-card-tool.c @@ -1596,6 +1596,16 @@ cmd_writecert (card_info_t info, char *argstr) } certref = certref_buffer = xstrdup ("OPENPGP.3"); } + else /* Upcase the certref; prepend cardtype if needed. */ + { + if (!strchr (certref, '.')) + certref_buffer = xstrconcat (app_type_string (info->apptype), ".", + certref, NULL); + else + certref_buffer = xstrdup (certref); + ascii_strupr (certref_buffer); + certref = certref_buffer; + } if (opt_clear) { @@ -2156,38 +2166,6 @@ cmd_unblock (card_info_t info) } -/* Direct sending of an hex encoded APDU with error printing. */ -static gpg_error_t -send_apdu (const char *hexapdu, const char *desc, unsigned int ignore) -{ - gpg_error_t err; - unsigned int sw; - - err = scd_apdu (hexapdu, &sw); - if (err) - log_error ("sending card command %s failed: %s\n", desc, - gpg_strerror (err)); - else if (!hexapdu || !strcmp (hexapdu, "undefined")) - ; - else if (ignore == 0xffff) - ; /* Ignore all status words. */ - else if (sw != 0x9000) - { - switch (sw) - { - case 0x6285: err = gpg_error (GPG_ERR_OBJ_TERM_STATE); break; - case 0x6982: err = gpg_error (GPG_ERR_BAD_PIN); break; - case 0x6985: err = gpg_error (GPG_ERR_USE_CONDITIONS); break; - default: err = gpg_error (GPG_ERR_CARD); - } - if (!(ignore && ignore == sw)) - log_error ("card command %s failed: %s (0x%04x)\n", desc, - gpg_strerror (err), sw); - } - return err; -} - - /* Note: On successful execution a redisplay should be scheduled. If * this function fails the card may be in an unknown state. */ static gpg_error_t @@ -2308,11 +2286,12 @@ cmd_factoryreset (card_info_t info) * unblock PIN command. */ any_apdu = 1; for (i=0; i < 5; i++) - send_apdu ("0020008008FFFFFFFFFFFFFFFF", "VERIFY", 0xffff); + send_apdu ("0020008008FFFFFFFFFFFFFFFF", "VERIFY", 0xffff, + NULL, NULL); for (i=0; i < 5; i++) send_apdu ("002C008010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "RESET RETRY COUNTER", 0xffff); - err = send_apdu ("00FB000001FF", "YUBIKEY RESET", 0); + "RESET RETRY COUNTER", 0xffff, NULL, NULL); + err = send_apdu ("00FB000001FF", "YUBIKEY RESET", 0, NULL, NULL); if (err) goto leave; } @@ -2321,14 +2300,15 @@ cmd_factoryreset (card_info_t info) any_apdu = 1; /* We need to select a card application before we can send APDUs * to the card without scdaemon doing anything on its own. */ - err = send_apdu (NULL, "RESET", 0); + err = send_apdu (NULL, "RESET", 0, NULL, NULL); if (err) goto leave; - err = send_apdu ("undefined", "dummy select ", 0); + err = send_apdu ("undefined", "dummy select ", 0, NULL, NULL); if (err) goto leave; /* Select the OpenPGP application. */ - err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0); + err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0, + NULL, NULL); if (err) goto leave; @@ -2343,14 +2323,16 @@ cmd_factoryreset (card_info_t info) for (i=0; i < 4; i++) send_apdu ("0020008120" "40404040404040404040404040404040" - "40404040404040404040404040404040", "VERIFY", 0xffff); + "40404040404040404040404040404040", "VERIFY", 0xffff, + NULL, NULL); for (i=0; i < 4; i++) send_apdu ("0020008320" "40404040404040404040404040404040" - "40404040404040404040404040404040", "VERIFY", 0xffff); + "40404040404040404040404040404040", "VERIFY", 0xffff, + NULL, NULL); /* Send terminate datafile command. */ - err = send_apdu ("00e60000", "TERMINATE DF", 0x6985); + err = send_apdu ("00e60000", "TERMINATE DF", 0x6985, NULL, NULL); if (err) goto leave; } @@ -2361,13 +2343,13 @@ cmd_factoryreset (card_info_t info) any_apdu = 1; /* Send activate datafile command. This is used without * confirmation if the card is already in termination state. */ - err = send_apdu ("00440000", "ACTIVATE DF", 0); + err = send_apdu ("00440000", "ACTIVATE DF", 0, NULL, NULL); if (err) goto leave; } /* Finally we reset the card reader once more. */ - err = send_apdu (NULL, "RESET", 0); + err = send_apdu (NULL, "RESET", 0, NULL, NULL); if (err) goto leave; @@ -2859,7 +2841,60 @@ cmd_uif (card_info_t info, char *argstr) } +static gpg_error_t +cmd_yubikey (card_info_t info, char *argstr) +{ + gpg_error_t err, err2; + estream_t fp = opt.interactive? NULL : es_stdout; + char *words[20]; + int nwords; + + if (!info) + return print_help + ("YUBIKEY <cmd> args\n\n" + "Various commands pertaining to Yubikey tokens with <cmd> being:\n" + "\n" + " LIST \n" + "\n" + "List supported and enabled applications.\n" + "\n" + " ENABLE usb|nfc|all [otp|u2f|opgp|piv|oath|fido2|all]\n" + " DISABLE usb|nfc|all [otp|u2f|opgp|piv|oath|fido2|all]\n" + "\n" + "Enable or disable the specified or all applications on the\n" + "given interface.", + 0); + + argstr = skip_options (argstr); + + if (!info->cardtype || strcmp (info->cardtype, "yubikey")) + { + log_info ("This command can only be used with Yubikeys.\n"); + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + goto leave; + } + + nwords = split_fields (argstr, words, DIM (words)); + if (nwords < 1) + { + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + + + /* 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); + err2 = scd_learn (info); + if (err2) + log_error ("Error re-reading card: %s\n", gpg_strerror (err)); + + leave: + return err; +} + + /* Data used by the command parser. This needs to be outside of the * function scope to allow readline based command completion. */ enum cmdids @@ -2869,7 +2904,7 @@ enum cmdids cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP, - cmdKEYATTR, cmdUIF, cmdAUTHENTICATE, + cmdKEYATTR, cmdUIF, cmdAUTHENTICATE, cmdYUBIKEY, cmdINVCMD }; @@ -2907,10 +2942,10 @@ static struct { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")}, { "key-attr", cmdKEYATTR, 1, N_("change the key attribute")}, { "uif", cmdUIF, 1, N_("change the User Interaction Flag")}, - /* Note, that we do not announce these command yet. */ { "privatedo", cmdPRIVATEDO, 0, N_("change a private data object")}, { "readcert", cmdREADCERT, 0, N_("read a certificate from a data object")}, { "writecert", cmdWRITECERT, 1, N_("store a certificate to a data object")}, + { "yubikey", cmdYUBIKEY, 0, N_("Yubikey management commands")}, { NULL, cmdINVCMD, 0, NULL } }; @@ -3020,7 +3055,7 @@ dispatch_command (card_info_t info, const char *orig_command) else { flush_keyblock_cache (); - err = scd_apdu (NULL, NULL); + err = scd_apdu (NULL, NULL, NULL, NULL); } break; @@ -3048,6 +3083,7 @@ dispatch_command (card_info_t info, const char *orig_command) 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; case cmdINVCMD: default: @@ -3262,7 +3298,7 @@ interactive_loop (void) else { flush_keyblock_cache (); - err = scd_apdu (NULL, NULL); + err = scd_apdu (NULL, NULL, NULL, NULL); } break; @@ -3318,6 +3354,7 @@ interactive_loop (void) 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; case cmdINVCMD: default: |