aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gpg-card.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gpg-card.c')
-rw-r--r--tools/gpg-card.c102
1 files changed, 99 insertions, 3 deletions
diff --git a/tools/gpg-card.c b/tools/gpg-card.c
index 0496ea058..1facb5302 100644
--- a/tools/gpg-card.c
+++ b/tools/gpg-card.c
@@ -3137,6 +3137,99 @@ cmd_yubikey (card_info_t info, char *argstr)
return err;
}
+
+static gpg_error_t
+cmd_apdu (card_info_t info, char *argstr)
+{
+ gpg_error_t err;
+ estream_t fp = opt.interactive? NULL : es_stdout;
+ int with_atr;
+ int handle_more;
+ const char *s;
+ const char *exlenstr;
+ int exlenstrlen;
+ char *options = NULL;
+ unsigned int sw;
+ unsigned char *result = NULL;
+ size_t i, j, resultlen;
+
+ if (!info)
+ return print_help
+ ("APDU [--more] [--exlen[=N]] <hexstring>\n"
+ "\n"
+ "Send an APDU to the current card. This command bypasses the high\n"
+ "level functions and sends the data directly to the card. HEXSTRING\n"
+ "is expected to be a proper APDU.\n"
+ "\n"
+ "Using the option \"--more\" handles the card status word MORE_DATA\n"
+ "(61xx) and concatenates all responses to one block.\n"
+ "\n"
+ "Using the option \"--exlen\" the returned APDU may use extended\n"
+ "length up to N bytes. If N is not given a default value is used.\n",
+ 0);
+
+ if (has_option (argstr, "--dump-atr"))
+ with_atr = 2;
+ else
+ with_atr = has_option (argstr, "--atr");
+ handle_more = has_option (argstr, "--more");
+
+ exlenstr = has_option_name (argstr, "--exlen");
+ exlenstrlen = 0;
+ if (exlenstr)
+ {
+ for (s=exlenstr; *s && !spacep (s); s++)
+ exlenstrlen++;
+ }
+
+ argstr = skip_options (argstr);
+
+ if (with_atr || handle_more || exlenstr)
+ options = xasprintf ("%s%s%s%.*s",
+ with_atr == 2? " --dump-atr": with_atr? " --atr":"",
+ handle_more?" --more":"",
+ exlenstr?" ":"", exlenstrlen, exlenstr?exlenstr:"");
+
+ err = scd_apdu (argstr, options, &sw, &result, &resultlen);
+ if (err)
+ goto leave;
+ log_info ("Statusword: 0x%04x\n", sw);
+ for (i=0; i < resultlen; )
+ {
+ size_t save_i = i;
+
+ tty_fprintf (fp, "D[%04X] ", (unsigned int)i);
+ for (j=0; j < 16 ; j++, i++)
+ {
+ if (j == 8)
+ tty_fprintf (fp, " ");
+ if (i < resultlen)
+ tty_fprintf (fp, " %02X", result[i]);
+ else
+ tty_fprintf (fp, " ");
+ }
+ tty_fprintf (fp, " ");
+ i = save_i;
+ for (j=0; j < 16; j++, i++)
+ {
+ unsigned int c = result[i];
+ if ( i >= resultlen )
+ tty_fprintf (fp, " ");
+ else if (isascii (c) && isprint (c) && !iscntrl (c))
+ tty_fprintf (fp, "%c", c);
+ else
+ tty_fprintf (fp, ".");
+ }
+ tty_fprintf (fp, "\n");
+ }
+
+ leave:
+ xfree (result);
+ xfree (options);
+ return err;
+}
+
+
/* Data used by the command parser. This needs to be outside of the
@@ -3148,7 +3241,7 @@ enum cmdids
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
- cmdUIF, cmdAUTH, cmdYUBIKEY,
+ cmdUIF, cmdAUTH, cmdYUBIKEY, cmdAPDU,
cmdINVCMD
};
@@ -3189,6 +3282,7 @@ static struct
{ "writecert", cmdWRITECERT, N_("store a certificate to a data object")},
{ "writekey", cmdWRITEKEY, N_("store a private key to a data object")},
{ "yubikey", cmdYUBIKEY, N_("Yubikey management commands")},
+ { "apdu", cmdAPDU, NULL},
{ NULL, cmdINVCMD, NULL }
};
@@ -3284,7 +3378,7 @@ dispatch_command (card_info_t info, const char *orig_command)
else
{
flush_keyblock_cache ();
- err = scd_apdu (NULL, NULL, NULL, NULL);
+ err = scd_apdu (NULL, NULL, NULL, NULL, NULL);
if (!err)
info->need_sn_cmd = 1;
}
@@ -3312,6 +3406,7 @@ dispatch_command (card_info_t info, const char *orig_command)
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
case cmdUIF: err = cmd_uif (info, argstr); break;
case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;
+ case cmdAPDU: err = cmd_apdu (info, argstr); break;
case cmdINVCMD:
default:
@@ -3503,7 +3598,7 @@ interactive_loop (void)
else
{
flush_keyblock_cache ();
- err = scd_apdu (NULL, NULL, NULL, NULL);
+ err = scd_apdu (NULL, NULL, NULL, NULL, NULL);
if (!err)
info->need_sn_cmd = 1;
}
@@ -3539,6 +3634,7 @@ interactive_loop (void)
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
case cmdUIF: err = cmd_uif (info, argstr); break;
case cmdYUBIKEY: err = cmd_yubikey (info, argstr); break;
+ case cmdAPDU: err = cmd_apdu (info, argstr); break;
case cmdINVCMD:
default: