mirror of
git://git.gnupg.org/gnupg.git
synced 2024-05-28 21:50:02 +02:00
card: Support factory reset for Yubikey PIV application.
* scd/app-common.h (struct app_ctx_s): Add field cardtype. * scd/app.c (app_new_register): Set cardtype for yubikey. (app_getattr): Add CARDTYPE. (app_write_learn_status): Emit new attribute. * scd/app-piv.c (do_getattr): Add CHV-USAGE. (do_learn_status): Emit it. * tools/card-tool.h (struct card_info_s): Add field cardtype. * tools/card-call-scd.c (learn_status_cb): Parse "CARDTYPE". * tools/gpg-card-tool.c (list_piv): Print PIN usage policy. (list_card): Print card type. (cmd_factoryreset): Implement for Yubikey with PIV. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
9325c92284
commit
79bed504e5
|
@ -52,6 +52,7 @@ struct app_ctx_s {
|
||||||
|
|
||||||
unsigned char *serialno; /* Serialnumber in raw form, allocated. */
|
unsigned char *serialno; /* Serialnumber in raw form, allocated. */
|
||||||
size_t serialnolen; /* Length in octets of serialnumber. */
|
size_t serialnolen; /* Length in octets of serialnumber. */
|
||||||
|
const char *cardtype; /* NULL or string with the token's type. */
|
||||||
const char *apptype;
|
const char *apptype;
|
||||||
unsigned int card_version;
|
unsigned int card_version;
|
||||||
unsigned int card_status;
|
unsigned int card_status;
|
||||||
|
|
|
@ -469,13 +469,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||||
{ "SERIALNO", 0x0000, -1 },
|
{ "SERIALNO", 0x0000, -1 },
|
||||||
{ "$AUTHKEYID", 0x0000, -2 }, /* Default key for ssh. */
|
{ "$AUTHKEYID", 0x0000, -2 }, /* Default key for ssh. */
|
||||||
{ "$DISPSERIALNO",0x0000, -3 },
|
{ "$DISPSERIALNO",0x0000, -3 },
|
||||||
{ "CHV-STATUS", 0x0000, -4 }
|
{ "CHV-STATUS", 0x0000, -4 },
|
||||||
|
{ "CHV-USAGE", 0x007E, -5 }
|
||||||
};
|
};
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
int idx;
|
int idx;
|
||||||
void *relptr;
|
void *relptr;
|
||||||
unsigned char *value;
|
unsigned char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
|
const unsigned char *s;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
for (idx=0; (idx < DIM (table)
|
for (idx=0; (idx < DIM (table)
|
||||||
&& ascii_strcasecmp (table[idx].name, name)); idx++)
|
&& ascii_strcasecmp (table[idx].name, name)); idx++)
|
||||||
|
@ -521,6 +524,20 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||||
err = send_status_printf (ctrl, table[idx].name, "%d %d %d",
|
err = send_status_printf (ctrl, table[idx].name, "%d %d %d",
|
||||||
tmp[0], tmp[1], tmp[2]);
|
tmp[0], tmp[1], tmp[2]);
|
||||||
}
|
}
|
||||||
|
else if (table[idx].special == -5) /* CHV-USAGE (aka PIN Usage Policy) */
|
||||||
|
{
|
||||||
|
/* We return 2 hex bytes or nothing in case the discovery object
|
||||||
|
* is not supported. */
|
||||||
|
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
|
||||||
|
if (relptr)
|
||||||
|
{
|
||||||
|
s = find_tlv (value, valuelen, 0x7E, &n);
|
||||||
|
if (s && n && (s = find_tlv (s, n, 0x5F2F, &n)) && n >=2 )
|
||||||
|
err = send_status_printf (ctrl, table[idx].name, "%02X %02X",
|
||||||
|
s[0], s[1]);
|
||||||
|
xfree (relptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
|
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
|
||||||
|
@ -577,6 +594,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
|
|
||||||
(void)flags;
|
(void)flags;
|
||||||
|
|
||||||
|
do_getattr (app, ctrl, "CHV-USAGE");
|
||||||
do_getattr (app, ctrl, "CHV-STATUS");
|
do_getattr (app, ctrl, "CHV-STATUS");
|
||||||
|
|
||||||
for (i=0; data_objects[i].tag; i++)
|
for (i=0; data_objects[i].tag; i++)
|
||||||
|
|
13
scd/app.c
13
scd/app.c
|
@ -228,6 +228,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
|
||||||
&& !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0,
|
&& !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0,
|
||||||
NULL, &buf, &buflen))
|
NULL, &buf, &buflen))
|
||||||
{
|
{
|
||||||
|
app->cardtype = "yubikey";
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
{
|
{
|
||||||
log_info ("Yubico: config=");
|
log_info ("Yubico: config=");
|
||||||
|
@ -640,9 +641,12 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
if (!app->fnc.learn_status)
|
if (!app->fnc.learn_status)
|
||||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
|
|
||||||
/* We do not send APPTYPE if only keypairinfo is requested. */
|
/* We do not send CARD and APPTYPE if only keypairinfo is requested. */
|
||||||
|
if (app->cardtype && !(flags & 1))
|
||||||
|
send_status_direct (ctrl, "CARDTYPE", app->cardtype);
|
||||||
if (app->apptype && !(flags & 1))
|
if (app->apptype && !(flags & 1))
|
||||||
send_status_direct (ctrl, "APPTYPE", app->apptype);
|
send_status_direct (ctrl, "APPTYPE", app->apptype);
|
||||||
|
|
||||||
err = lock_app (app, ctrl);
|
err = lock_app (app, ctrl);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -721,6 +725,11 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||||
if (!app->ref_count)
|
if (!app->ref_count)
|
||||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||||
|
|
||||||
|
if (app->cardtype && name && !strcmp (name, "CARDTYPE"))
|
||||||
|
{
|
||||||
|
send_status_direct (ctrl, "CARDTYPE", app->cardtype);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (app->apptype && name && !strcmp (name, "APPTYPE"))
|
if (app->apptype && name && !strcmp (name, "APPTYPE"))
|
||||||
{
|
{
|
||||||
send_status_direct (ctrl, "APPTYPE", app->apptype);
|
send_status_direct (ctrl, "APPTYPE", app->apptype);
|
||||||
|
@ -744,7 +753,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||||
err = lock_app (app, ctrl);
|
err = lock_app (app, ctrl);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
err = app->fnc.getattr (app, ctrl, name);
|
err = app->fnc.getattr (app, ctrl, name);
|
||||||
unlock_app (app);
|
unlock_app (app);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ release_card_info (card_info_t info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xfree (info->reader); info->reader = NULL;
|
xfree (info->reader); info->reader = NULL;
|
||||||
|
xfree (info->cardtype); info->cardtype = NULL;
|
||||||
xfree (info->serialno); info->serialno = NULL;
|
xfree (info->serialno); info->serialno = NULL;
|
||||||
xfree (info->dispserialno); info->dispserialno = NULL;
|
xfree (info->dispserialno); info->dispserialno = NULL;
|
||||||
xfree (info->apptypestr); info->apptypestr = NULL;
|
xfree (info->apptypestr); info->apptypestr = NULL;
|
||||||
|
@ -157,7 +158,7 @@ release_card_info (card_info_t info)
|
||||||
xfree (info->kinfo);
|
xfree (info->kinfo);
|
||||||
info->kinfo = kinfo;
|
info->kinfo = kinfo;
|
||||||
}
|
}
|
||||||
|
info->chvusage[0] = info->chvusage[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -724,6 +725,11 @@ learn_status_cb (void *opaque, const char *line)
|
||||||
parm->is_v2 = (strlen (parm->serialno) >= 16
|
parm->is_v2 = (strlen (parm->serialno) >= 16
|
||||||
&& xtoi_2 (parm->serialno+12) >= 2 );
|
&& xtoi_2 (parm->serialno+12) >= 2 );
|
||||||
}
|
}
|
||||||
|
else if (!memcmp (keyword, "CARDTYPE", keywordlen))
|
||||||
|
{
|
||||||
|
xfree (parm->cardtype);
|
||||||
|
parm->cardtype = unescape_status_string (line);
|
||||||
|
}
|
||||||
else if (!memcmp (keyword, "DISP-SEX", keywordlen))
|
else if (!memcmp (keyword, "DISP-SEX", keywordlen))
|
||||||
{
|
{
|
||||||
parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
|
parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
|
||||||
|
@ -779,17 +785,26 @@ learn_status_cb (void *opaque, const char *line)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
if (!memcmp (keyword, "DISP-NAME", keywordlen))
|
if (!memcmp (keyword, "DISP-NAME", keywordlen))
|
||||||
{
|
{
|
||||||
xfree (parm->disp_name);
|
xfree (parm->disp_name);
|
||||||
parm->disp_name = unescape_status_string (line);
|
parm->disp_name = unescape_status_string (line);
|
||||||
}
|
}
|
||||||
else if (!memcmp (keyword, "DISP-LANG", keywordlen))
|
else if (!memcmp (keyword, "DISP-LANG", keywordlen))
|
||||||
{
|
{
|
||||||
xfree (parm->disp_lang);
|
xfree (parm->disp_lang);
|
||||||
parm->disp_lang = unescape_status_string (line);
|
parm->disp_lang = unescape_status_string (line);
|
||||||
}
|
}
|
||||||
break;
|
else if (!memcmp (keyword, "CHV-USAGE", keywordlen))
|
||||||
|
{
|
||||||
|
unsigned int byte1, byte2;
|
||||||
|
|
||||||
|
byte1 = byte2 = 0;
|
||||||
|
sscanf (line, "%x %x", &byte1, &byte2);
|
||||||
|
parm->chvusage[0] = byte1;
|
||||||
|
parm->chvusage[1] = byte2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
if (!memcmp (keyword, "PUBKEY-URL", keywordlen))
|
if (!memcmp (keyword, "PUBKEY-URL", keywordlen))
|
||||||
|
@ -839,7 +854,7 @@ learn_status_cb (void *opaque, const char *line)
|
||||||
}
|
}
|
||||||
else if (parm->apptype == APP_TYPE_PIV)
|
else if (parm->apptype == APP_TYPE_PIV)
|
||||||
{
|
{
|
||||||
for (i=0; *p && DIM (parm->chvinfo); i++)
|
for (i=0; *p && i < DIM (parm->chvinfo); i++)
|
||||||
{
|
{
|
||||||
parm->chvinfo[i] = atoi (p);
|
parm->chvinfo[i] = atoi (p);
|
||||||
while (*p && !spacep (p))
|
while (*p && !spacep (p))
|
||||||
|
|
|
@ -104,6 +104,7 @@ struct card_info_s
|
||||||
{
|
{
|
||||||
int error; /* private. */
|
int error; /* private. */
|
||||||
char *reader; /* Reader information. */
|
char *reader; /* Reader information. */
|
||||||
|
char *cardtype; /* NULL or type of the card. */
|
||||||
char *apptypestr; /* Malloced application type string. */
|
char *apptypestr; /* Malloced application type string. */
|
||||||
app_type_t apptype;/* Translated from APPTYPESTR. */
|
app_type_t apptype;/* Translated from APPTYPESTR. */
|
||||||
char *serialno; /* malloced hex string. */
|
char *serialno; /* malloced hex string. */
|
||||||
|
@ -128,6 +129,7 @@ struct card_info_s
|
||||||
int is_v2; /* True if this is a v2 openpgp card. */
|
int is_v2; /* True if this is a v2 openpgp card. */
|
||||||
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
|
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
|
||||||
int chvinfo[3]; /* Allowed retries for the CHV; 0 = blocked. */
|
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 key_attr key_attr[3]; /* OpenPGP card key attributes. */
|
||||||
struct {
|
struct {
|
||||||
unsigned int ki:1; /* Key import available. */
|
unsigned int ki:1; /* Key import available. */
|
||||||
|
|
|
@ -763,15 +763,37 @@ static void
|
||||||
list_piv (card_info_t info, estream_t fp)
|
list_piv (card_info_t info, estream_t fp)
|
||||||
{
|
{
|
||||||
static struct keyinfolabel_s keyinfolabels[] = {
|
static struct keyinfolabel_s keyinfolabels[] = {
|
||||||
{ "PIV Authentication:", "PIV.9A" },
|
{ "PIV authentication:", "PIV.9A" },
|
||||||
{ "Card Authenticat. :", "PIV.9E" },
|
{ "Card authenticat. :", "PIV.9E" },
|
||||||
{ "Digital Signature :", "PIV.9C" },
|
{ "Digital signature :", "PIV.9C" },
|
||||||
{ "Key Management ...:", "PIV.9D" },
|
{ "Key management ...:", "PIV.9D" },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
const char *s;
|
const char *s;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (info->chvusage[0] || info->chvusage[1])
|
||||||
|
{
|
||||||
|
tty_fprintf (fp, "PIN usage policy .:");
|
||||||
|
if ((info->chvusage[0] & 0x40))
|
||||||
|
tty_fprintf (fp, " app-pin");
|
||||||
|
if ((info->chvusage[0] & 0x20))
|
||||||
|
tty_fprintf (fp, " global-pin");
|
||||||
|
if ((info->chvusage[0] & 0x10))
|
||||||
|
tty_fprintf (fp, " occ");
|
||||||
|
if ((info->chvusage[0] & 0x08))
|
||||||
|
tty_fprintf (fp, " vci");
|
||||||
|
if ((info->chvusage[0] & 0x08) && !(info->chvusage[0] & 0x04))
|
||||||
|
tty_fprintf (fp, " pairing");
|
||||||
|
|
||||||
|
if (info->chvusage[1] == 0x10)
|
||||||
|
tty_fprintf (fp, " primary:card");
|
||||||
|
else if (info->chvusage[1] == 0x20)
|
||||||
|
tty_fprintf (fp, " primary:global");
|
||||||
|
|
||||||
|
tty_fprintf (fp, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
tty_fprintf (fp, "PIN retry counter :");
|
tty_fprintf (fp, "PIN retry counter :");
|
||||||
for (i=0; i < DIM (info->chvinfo); i++)
|
for (i=0; i < DIM (info->chvinfo); i++)
|
||||||
{
|
{
|
||||||
|
@ -790,7 +812,7 @@ list_piv (card_info_t info, estream_t fp)
|
||||||
tty_fprintf (fp, " %s", s);
|
tty_fprintf (fp, " %s", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tty_fprintf (fp, "\n", s);
|
tty_fprintf (fp, "\n");
|
||||||
list_all_kinfo (info, keyinfolabels, fp);
|
list_all_kinfo (info, keyinfolabels, fp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -804,9 +826,11 @@ list_card (card_info_t info)
|
||||||
|
|
||||||
tty_fprintf (fp, "Reader ...........: %s\n",
|
tty_fprintf (fp, "Reader ...........: %s\n",
|
||||||
info->reader? info->reader : "[none]");
|
info->reader? info->reader : "[none]");
|
||||||
|
if (info->cardtype)
|
||||||
|
tty_fprintf (fp, "Card type ........: %s\n", info->cardtype);
|
||||||
tty_fprintf (fp, "Serial number ....: %s\n",
|
tty_fprintf (fp, "Serial number ....: %s\n",
|
||||||
info->serialno? info->serialno : "[none]");
|
info->serialno? info->serialno : "[none]");
|
||||||
tty_fprintf (fp, "Application Type .: %s%s%s%s\n",
|
tty_fprintf (fp, "Application type .: %s%s%s%s\n",
|
||||||
app_type_string (info->apptype),
|
app_type_string (info->apptype),
|
||||||
info->apptype == APP_TYPE_UNKNOWN && info->apptypestr? "(":"",
|
info->apptype == APP_TYPE_UNKNOWN && info->apptypestr? "(":"",
|
||||||
info->apptype == APP_TYPE_UNKNOWN && info->apptypestr
|
info->apptype == APP_TYPE_UNKNOWN && info->apptypestr
|
||||||
|
@ -1836,26 +1860,32 @@ cmd_factoryreset (card_info_t info)
|
||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
int termstate = 0;
|
int termstate = 0;
|
||||||
int any_apdu = 0;
|
int any_apdu = 0;
|
||||||
|
int is_yubikey = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return print_help
|
return print_help
|
||||||
("FACTORY-RESET\n\n"
|
("FACTORY-RESET\n\n"
|
||||||
"Do a complete reset of an OpenPGP card. This deletes all\n"
|
"Do a complete reset of some OpenPGP and PIV cards. This\n"
|
||||||
"data and keys and resets the PINs to their default. This\n"
|
"deletes all data and keys and resets the PINs to their default.\n"
|
||||||
"mainly used by developers with scratch cards. Don't worry,\n"
|
"This is mainly used by developers with scratch cards. Don't\n"
|
||||||
"you need to confirm before the command proceeds.",
|
"worry, you need to confirm before the command proceeds.",
|
||||||
APP_TYPE_OPENPGP, 0);
|
APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
|
||||||
|
|
||||||
if (info->apptype != APP_TYPE_OPENPGP)
|
/* We support the factory reset for most OpenPGP cards and Yubikeys
|
||||||
{
|
* with the PIV application. */
|
||||||
log_info ("Note: This is an OpenPGP only command.\n");
|
if (info->apptype == APP_TYPE_OPENPGP)
|
||||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
;
|
||||||
}
|
else if (info->apptype == APP_TYPE_PIV
|
||||||
|
&& info->cardtype && !strcmp (info->cardtype, "yubikey"))
|
||||||
|
is_yubikey = 1;
|
||||||
|
else
|
||||||
|
|
||||||
/* The code below basically does the same what this
|
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
* gpg-connect-agent script does:
|
|
||||||
|
/* For an OpenPGP card the code below basically does the same what
|
||||||
|
* this gpg-connect-agent script does:
|
||||||
*
|
*
|
||||||
* scd reset
|
* scd reset
|
||||||
* scd serialno undefined
|
* scd serialno undefined
|
||||||
|
@ -1873,7 +1903,8 @@ cmd_factoryreset (card_info_t info)
|
||||||
* scd reset
|
* scd reset
|
||||||
* /echo Card has been reset to factory defaults
|
* /echo Card has been reset to factory defaults
|
||||||
*
|
*
|
||||||
* but tries to find out something about the card first.
|
* For a PIV application on a Yubikey it merely issues the Yubikey
|
||||||
|
* specific resset command.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
err = scd_learn (info);
|
err = scd_learn (info);
|
||||||
|
@ -1886,17 +1917,24 @@ cmd_factoryreset (card_info_t info)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!termstate)
|
if (!termstate || is_yubikey)
|
||||||
{
|
{
|
||||||
log_info (_("OpenPGP card no. %s detected\n"),
|
if (is_yubikey)
|
||||||
info->dispserialno? info->dispserialno : info->serialno);
|
log_info (_("Yubikey no. %s with PIV application detected\n"),
|
||||||
if (!(info->status_indicator == 3 || info->status_indicator == 5))
|
info->dispserialno? info->dispserialno : info->serialno);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* Note: We won't see status-indicator 3 here because it is not
|
log_info (_("OpenPGP card no. %s detected\n"),
|
||||||
* possible to select a card application in termination state. */
|
info->dispserialno? info->dispserialno : info->serialno);
|
||||||
log_error (_("This command is not supported by this card\n"));
|
if (!(info->status_indicator == 3 || info->status_indicator == 5))
|
||||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
{
|
||||||
goto leave;
|
/* Note: We won't see status-indicator 3 here because it
|
||||||
|
* is not possible to select a card application in
|
||||||
|
* termination state. */
|
||||||
|
log_error (_("This command is not supported by this card\n"));
|
||||||
|
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_printf ("\n");
|
tty_printf ("\n");
|
||||||
|
@ -1924,51 +1962,73 @@ cmd_factoryreset (card_info_t info)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_yubikey)
|
||||||
|
{
|
||||||
|
/* The PIV application si already selected, we only need to
|
||||||
|
* send the special reset APDU after having blocked PIN and
|
||||||
|
* PUK. Note that blocking the PUK is done using the
|
||||||
|
* unblock PIN command. */
|
||||||
|
any_apdu = 1;
|
||||||
|
for (i=0; i < 5; i++)
|
||||||
|
send_apdu ("0020008008FFFFFFFFFFFFFFFF", "VERIFY", 0xffff);
|
||||||
|
for (i=0; i < 5; i++)
|
||||||
|
send_apdu ("002C008010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||||
|
"RESET RETRY COUNTER", 0xffff);
|
||||||
|
err = send_apdu ("00FB000001FF", "YUBIKEY RESET", 0);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else /* OpenPGP card. */
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
err = send_apdu ("undefined", "dummy select ", 0);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
/* Select the OpenPGP application. */
|
||||||
|
err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Do some dummy verifies with wrong PINs to set the retry
|
||||||
|
* counter to zero. We can't easily use the card version 2.1
|
||||||
|
* feature of presenting the admin PIN to allow the terminate
|
||||||
|
* command because there is no machinery in scdaemon to catch
|
||||||
|
* the verify command and ask for the PIN when the "APDU"
|
||||||
|
* command is used.
|
||||||
|
* Here, the length of dummy wrong PIN is 32-byte, also
|
||||||
|
* supporting authentication with KDF DO. */
|
||||||
|
for (i=0; i < 4; i++)
|
||||||
|
send_apdu ("0020008120"
|
||||||
|
"40404040404040404040404040404040"
|
||||||
|
"40404040404040404040404040404040", "VERIFY", 0xffff);
|
||||||
|
for (i=0; i < 4; i++)
|
||||||
|
send_apdu ("0020008320"
|
||||||
|
"40404040404040404040404040404040"
|
||||||
|
"40404040404040404040404040404040", "VERIFY", 0xffff);
|
||||||
|
|
||||||
|
/* Send terminate datafile command. */
|
||||||
|
err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_yubikey)
|
||||||
|
{
|
||||||
any_apdu = 1;
|
any_apdu = 1;
|
||||||
/* We need to select a card application before we can send APDUs
|
/* Send activate datafile command. This is used without
|
||||||
* to the card without scdaemon doing anything on its own. */
|
* confirmation if the card is already in termination state. */
|
||||||
err = send_apdu (NULL, "RESET", 0);
|
err = send_apdu ("00440000", "ACTIVATE DF", 0);
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
err = send_apdu ("undefined", "dummy select ", 0);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Select the OpenPGP application. */
|
|
||||||
err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Do some dummy verifies with wrong PINs to set the retry
|
|
||||||
* counter to zero. We can't easily use the card version 2.1
|
|
||||||
* feature of presenting the admin PIN to allow the terminate
|
|
||||||
* command because there is no machinery in scdaemon to catch
|
|
||||||
* the verify command and ask for the PIN when the "APDU"
|
|
||||||
* command is used.
|
|
||||||
* Here, the length of dummy wrong PIN is 32-byte, also
|
|
||||||
* supporting authentication with KDF DO. */
|
|
||||||
for (i=0; i < 4; i++)
|
|
||||||
send_apdu ("0020008120"
|
|
||||||
"40404040404040404040404040404040"
|
|
||||||
"40404040404040404040404040404040", "VERIFY", 0xffff);
|
|
||||||
for (i=0; i < 4; i++)
|
|
||||||
send_apdu ("0020008320"
|
|
||||||
"40404040404040404040404040404040"
|
|
||||||
"40404040404040404040404040404040", "VERIFY", 0xffff);
|
|
||||||
|
|
||||||
/* Send terminate datafile command. */
|
|
||||||
err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Finally we reset the card reader once more. */
|
/* Finally we reset the card reader once more. */
|
||||||
err = send_apdu (NULL, "RESET", 0);
|
err = send_apdu (NULL, "RESET", 0);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1979,7 +2039,7 @@ cmd_factoryreset (card_info_t info)
|
||||||
err = scd_serialno (&answer, NULL);
|
err = scd_serialno (&answer, NULL);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (err && any_apdu)
|
if (err && any_apdu && !is_yubikey)
|
||||||
{
|
{
|
||||||
log_info ("Due to an error the card might be in an inconsistent state\n"
|
log_info ("Due to an error the card might be in an inconsistent state\n"
|
||||||
"You should run the LIST command to check this.\n");
|
"You should run the LIST command to check this.\n");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user