mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
scd: Implement PIN changing and unblocking for PIV cards.
* scd/app-piv.c: Some refactoring (do_change_chv): Implement. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
3231ecdafd
commit
e9e876cb55
269
scd/app-piv.c
269
scd/app-piv.c
@ -20,6 +20,24 @@
|
|||||||
/* Some notes:
|
/* Some notes:
|
||||||
* - Specs for PIV are at http://dx.doi.org/10.6028/NIST.SP.800-73-4
|
* - Specs for PIV are at http://dx.doi.org/10.6028/NIST.SP.800-73-4
|
||||||
*
|
*
|
||||||
|
* - Access control matrix:
|
||||||
|
* | Action | 9B | PIN | PUK | |
|
||||||
|
* |--------------+-----+-----+-----+------------------------------|
|
||||||
|
* | Generate key | yes | | | |
|
||||||
|
* | Change 9B | yes | | | |
|
||||||
|
* | Change retry | yes | yes | | Yubikey only |
|
||||||
|
* | Import key | yes | | | |
|
||||||
|
* | Import cert | yes | | | |
|
||||||
|
* | Change CHUID | yes | | | |
|
||||||
|
* | Reset card | | | | PIN and PUK in blocked state |
|
||||||
|
* | Verify PIN | | yes | | |
|
||||||
|
* | Sign data | | yes | | |
|
||||||
|
* | Decrypt data | | yes | | |
|
||||||
|
* | Change PIN | | yes | | |
|
||||||
|
* | Change PUK | | | yes | |
|
||||||
|
* | Unblock PIN | | | yes | New PIN required |
|
||||||
|
* |---------------------------------------------------------------|
|
||||||
|
* (9B indicates the 24 byte PIV Card Application Administration Key)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -389,10 +407,10 @@ dump_all_do (int slot)
|
|||||||
|
|
||||||
|
|
||||||
/* Parse the key reference KEYREFSTR which is expected to hold a key
|
/* Parse the key reference KEYREFSTR which is expected to hold a key
|
||||||
* reference for a PIN object. Return the one octet keyref or -1 for
|
* reference for a CHV object. Return the one octet keyref or -1 for
|
||||||
* an invalid reference. */
|
* an invalid reference. */
|
||||||
static int
|
static int
|
||||||
parse_pin_keyref (const char *keyrefstr)
|
parse_chv_keyref (const char *keyrefstr)
|
||||||
{
|
{
|
||||||
if (!keyrefstr)
|
if (!keyrefstr)
|
||||||
return -1;
|
return -1;
|
||||||
@ -457,7 +475,7 @@ get_chv_status (app_t app, const char *keyrefstr)
|
|||||||
int result;
|
int result;
|
||||||
int keyref;
|
int keyref;
|
||||||
|
|
||||||
keyref = parse_pin_keyref (keyrefstr);
|
keyref = parse_chv_keyref (keyrefstr);
|
||||||
if (!keyrefstr)
|
if (!keyrefstr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -467,7 +485,7 @@ get_chv_status (app_t app, const char *keyrefstr)
|
|||||||
apdu[3] = keyref;
|
apdu[3] = keyref;
|
||||||
if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
|
if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
|
||||||
result = -5; /* No need to verification. */
|
result = -5; /* No need to verification. */
|
||||||
else if (sw == 0x6a88)
|
else if (sw == 0x6a88 || sw == 0x6a80)
|
||||||
result = -2; /* No such PIN. */
|
result = -2; /* No such PIN. */
|
||||||
else if (sw == 0x6983)
|
else if (sw == 0x6983)
|
||||||
result = -3; /* PIN is blocked. */
|
result = -3; /* PIN is blocked. */
|
||||||
@ -540,7 +558,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
}
|
}
|
||||||
else if (table[idx].special == -4) /* CHV-STATUS */
|
else if (table[idx].special == -4) /* CHV-STATUS */
|
||||||
{
|
{
|
||||||
int tmp[3];
|
int tmp[4];
|
||||||
|
|
||||||
tmp[0] = get_chv_status (app, "PIV.00");
|
tmp[0] = get_chv_status (app, "PIV.00");
|
||||||
tmp[1] = get_chv_status (app, "PIV.80");
|
tmp[1] = get_chv_status (app, "PIV.80");
|
||||||
@ -1177,40 +1195,29 @@ make_prompt (app_t app, int remaining, const char *firstline)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Verify the Application PIN KEYREF. */
|
/* Helper for verify_chv to ask for the PIN and to prepare/pad it. On
|
||||||
|
* success the result is stored at (R_PIN,R_PINLEN). */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
verify_pin (app_t app, int keyref,
|
ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
||||||
gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
|
gpg_error_t (*pincb)(void*,const char *,char **),
|
||||||
|
void *pincb_arg, char **r_pin, unsigned int *r_pinlen)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char apdu[4];
|
|
||||||
unsigned int sw;
|
|
||||||
int remaining;
|
|
||||||
const char *label;
|
const char *label;
|
||||||
char *prompt;
|
char *prompt;
|
||||||
char *pinvalue = NULL;
|
char *pinvalue = NULL;
|
||||||
unsigned int pinlen;
|
unsigned int pinlen;
|
||||||
char pinbuffer[8];
|
char *pinbuffer = NULL;
|
||||||
int minlen, maxlen, padding, onlydigits;
|
int minlen, maxlen, padding, onlydigits;
|
||||||
|
|
||||||
/* First check whether a verify is at all needed. This is done with
|
*r_pin = NULL;
|
||||||
* P1 being 0 and no Lc and command data send. */
|
*r_pinlen = 0;
|
||||||
apdu[0] = 0x00;
|
|
||||||
apdu[1] = ISO7816_VERIFY;
|
if (ask_new)
|
||||||
apdu[2] = 0x00;
|
|
||||||
apdu[3] = keyref;
|
|
||||||
if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
|
|
||||||
{
|
|
||||||
/* No need to verification. */
|
|
||||||
return 0; /* All fine. */
|
|
||||||
}
|
|
||||||
if ((sw & 0xfff0) == 0x63C0)
|
|
||||||
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
|
|
||||||
else
|
|
||||||
remaining = -1;
|
remaining = -1;
|
||||||
|
|
||||||
if (remaining != -1)
|
if (remaining != -1)
|
||||||
log_debug ("piv: PIN %2X has %d attempts left\n", keyref, remaining);
|
log_debug ("piv: CHV %02X has %d attempts left\n", keyref, remaining);
|
||||||
|
|
||||||
switch (keyref)
|
switch (keyref)
|
||||||
{
|
{
|
||||||
@ -1219,21 +1226,24 @@ verify_pin (app_t app, int keyref,
|
|||||||
maxlen = 8;
|
maxlen = 8;
|
||||||
padding = 1;
|
padding = 1;
|
||||||
onlydigits = 1;
|
onlydigits = 1;
|
||||||
label = _("||Please enter the Global-PIN of your PIV card");
|
label = (ask_new? _("|N|Please enter the new Global-PIN")
|
||||||
|
/**/ : _("||Please enter the Global-PIN of your PIV card"));
|
||||||
break;
|
break;
|
||||||
case 0x80:
|
case 0x80:
|
||||||
minlen = 6;
|
minlen = 6;
|
||||||
maxlen = 8;
|
maxlen = 8;
|
||||||
padding = 1;
|
padding = 1;
|
||||||
onlydigits = 1;
|
onlydigits = 1;
|
||||||
label = _("||Please enter the PIN of your PIV card");
|
label = (ask_new? _("|N|Please enter the new PIN")
|
||||||
|
/**/ : _("||Please enter the PIN of your PIV card"));
|
||||||
break;
|
break;
|
||||||
case 0x81:
|
case 0x81:
|
||||||
minlen = 8;
|
minlen = 8;
|
||||||
maxlen = 8;
|
maxlen = 8;
|
||||||
padding = 0;
|
padding = 0;
|
||||||
onlydigits = 0;
|
onlydigits = 0;
|
||||||
label = _("||Please enter the Unblocking Key of your PIV card");
|
label = (ask_new? _("|N|Please enter the new Unblocking Key")
|
||||||
|
/**/ :_("||Please enter the Unblocking Key of your PIV card"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x96:
|
case 0x96:
|
||||||
@ -1245,8 +1255,6 @@ verify_pin (app_t app, int keyref,
|
|||||||
default:
|
default:
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
}
|
}
|
||||||
log_assert (sizeof pinbuffer >= maxlen);
|
|
||||||
|
|
||||||
|
|
||||||
/* Ask for the PIN. */
|
/* Ask for the PIN. */
|
||||||
prompt = make_prompt (app, remaining, label);
|
prompt = make_prompt (app, remaining, label);
|
||||||
@ -1282,21 +1290,72 @@ verify_pin (app_t app, int keyref,
|
|||||||
xfree (pinvalue);
|
xfree (pinvalue);
|
||||||
return gpg_error (GPG_ERR_BAD_PIN);
|
return gpg_error (GPG_ERR_BAD_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pinbuffer = xtrymalloc_secure (maxlen);
|
||||||
|
if (!pinbuffer)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
wipememory (pinvalue, pinlen);
|
||||||
|
xfree (pinvalue);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy (pinbuffer, pinvalue, pinlen);
|
memcpy (pinbuffer, pinvalue, pinlen);
|
||||||
|
wipememory (pinvalue, pinlen);
|
||||||
|
xfree (pinvalue);
|
||||||
if (padding)
|
if (padding)
|
||||||
{
|
{
|
||||||
memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
|
memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
|
||||||
wipememory (pinvalue, pinlen);
|
|
||||||
pinlen = maxlen;
|
pinlen = maxlen;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
wipememory (pinvalue, pinlen);
|
|
||||||
xfree (pinvalue);
|
|
||||||
|
|
||||||
err = iso7816_verify (app->slot, keyref, pinbuffer, pinlen);
|
*r_pin = pinbuffer;
|
||||||
wipememory (pinbuffer, pinlen);
|
*r_pinlen = pinlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Verify the card holder verification identified by KEYREF. This is
|
||||||
|
* either the Appication PIN or the Global PIN. */
|
||||||
|
static gpg_error_t
|
||||||
|
verify_chv (app_t app, int keyref,
|
||||||
|
gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned char apdu[4];
|
||||||
|
unsigned int sw;
|
||||||
|
int remaining;
|
||||||
|
char *pin = NULL;
|
||||||
|
unsigned int pinlen;
|
||||||
|
|
||||||
|
/* First check whether a verify is at all needed. This is done with
|
||||||
|
* P1 being 0 and no Lc and command data send. */
|
||||||
|
apdu[0] = 0x00;
|
||||||
|
apdu[1] = ISO7816_VERIFY;
|
||||||
|
apdu[2] = 0x00;
|
||||||
|
apdu[3] = keyref;
|
||||||
|
if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
|
||||||
|
{
|
||||||
|
/* No need to verification. */
|
||||||
|
return 0; /* All fine. */
|
||||||
|
}
|
||||||
|
if ((sw & 0xfff0) == 0x63C0)
|
||||||
|
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
|
||||||
|
else
|
||||||
|
remaining = -1;
|
||||||
|
|
||||||
|
err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
|
||||||
|
&pin, &pinlen);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("PIN %02X verification failed: %s\n", keyref,gpg_strerror (err));
|
return err;
|
||||||
|
|
||||||
|
err = iso7816_verify (app->slot, keyref, pin, pinlen);
|
||||||
|
wipememory (pin, pinlen);
|
||||||
|
xfree (pin);
|
||||||
|
if (err)
|
||||||
|
log_error ("CHV %02X verification failed: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1309,40 +1368,41 @@ verify_pin (app_t app, int keyref,
|
|||||||
* PIV.81 - The PIN Unblocking key
|
* PIV.81 - The PIN Unblocking key
|
||||||
* The supported flags are:
|
* The supported flags are:
|
||||||
* APP_CHANGE_FLAG_CLEAR Clear the PIN verification state.
|
* APP_CHANGE_FLAG_CLEAR Clear the PIN verification state.
|
||||||
|
* APP_CHANGE_FLAG_RESET Reset a PIN using the PUK. Only
|
||||||
|
* allowed with PIV.80.
|
||||||
*/
|
*/
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
int keyref;
|
int keyref, targetkeyref;
|
||||||
unsigned char apdu[4];
|
unsigned char apdu[4];
|
||||||
|
unsigned int sw;
|
||||||
char *newpin = NULL;
|
int remaining;
|
||||||
char *oldpin = NULL;
|
char *oldpin = NULL;
|
||||||
/* size_t newpinlen; */
|
unsigned int oldpinlen;
|
||||||
/* size_t oldpinlen; */
|
char *newpin = NULL;
|
||||||
/* const char *newdesc; */
|
unsigned int newpinlen;
|
||||||
/* int pwid; */
|
|
||||||
pininfo_t pininfo;
|
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
(void)pincb;
|
|
||||||
(void)pincb_arg;
|
|
||||||
|
|
||||||
/* The minimum and maximum lengths are enforced by PIV. */
|
/* Check for unknown flags. */
|
||||||
memset (&pininfo, 0, sizeof pininfo);
|
if ((flags & ~(APP_CHANGE_FLAG_CLEAR|APP_CHANGE_FLAG_RESET)))
|
||||||
pininfo.minlen = 6;
|
{
|
||||||
pininfo.maxlen = 8;
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
keyref = parse_pin_keyref (pwidstr);
|
/* Parse the keyref. */
|
||||||
|
targetkeyref = keyref = parse_chv_keyref (pwidstr);
|
||||||
if (keyref == -1)
|
if (keyref == -1)
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
{
|
||||||
|
err = gpg_error (GPG_ERR_INV_ID);
|
||||||
if ((flags & ~APP_CHANGE_FLAG_CLEAR))
|
goto leave;
|
||||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
}
|
||||||
|
|
||||||
/* First see whether the special --clear mode has been requested. */
|
/* First see whether the special --clear mode has been requested. */
|
||||||
if ((flags & APP_CHANGE_FLAG_CLEAR))
|
if ((flags & APP_CHANGE_FLAG_CLEAR))
|
||||||
@ -1355,7 +1415,82 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
/* Prepare reset mode. */
|
||||||
|
if ((flags & APP_CHANGE_FLAG_RESET))
|
||||||
|
{
|
||||||
|
if (keyref == 0x81)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_INV_ID); /* Can't reset the PUK. */
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
/* Set the keyref to the PUK and keep the TARGETKEYREF. */
|
||||||
|
keyref = 0x81;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the remaining tries count. This is done by using the check
|
||||||
|
* for verified state feature. */
|
||||||
|
apdu[0] = 0x00;
|
||||||
|
apdu[1] = ISO7816_VERIFY;
|
||||||
|
apdu[2] = 0x00;
|
||||||
|
apdu[3] = keyref;
|
||||||
|
if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
|
||||||
|
remaining = -1; /* Already verified, thus full number of tries. */
|
||||||
|
else if ((sw & 0xfff0) == 0x63C0)
|
||||||
|
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
|
||||||
|
else
|
||||||
|
remaining = -1;
|
||||||
|
|
||||||
|
/* Ask for the old pin or puk. */
|
||||||
|
err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
|
||||||
|
&oldpin, &oldpinlen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Verify the old pin so that we don't prompt for the new pin if the
|
||||||
|
* old is wrong. This is not possible for the PUK, though. */
|
||||||
|
if (keyref != 0x81)
|
||||||
|
{
|
||||||
|
err = iso7816_verify (app->slot, keyref, oldpin, oldpinlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("CHV %02X verification failed: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask for the new pin. */
|
||||||
|
err = ask_and_prepare_chv (app, targetkeyref, 1, -1, pincb, pincb_arg,
|
||||||
|
&newpin, &newpinlen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if ((flags & APP_CHANGE_FLAG_RESET))
|
||||||
|
{
|
||||||
|
char *buf = xtrymalloc_secure (oldpinlen + newpinlen);
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
memcpy (buf, oldpin, oldpinlen);
|
||||||
|
memcpy (buf+oldpinlen, newpin, newpinlen);
|
||||||
|
err = iso7816_reset_retry_counter_with_rc (app->slot, targetkeyref,
|
||||||
|
buf, oldpinlen+newpinlen);
|
||||||
|
xfree (buf);
|
||||||
|
if (err)
|
||||||
|
log_error ("resetting CHV %02X using CHV %02X failed: %s\n",
|
||||||
|
targetkeyref, keyref, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = iso7816_change_reference_data (app->slot, keyref,
|
||||||
|
oldpin, oldpinlen,
|
||||||
|
newpin, newpinlen);
|
||||||
|
if (err)
|
||||||
|
log_error ("CHV %02X changing PIN failed: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
xfree (oldpin);
|
xfree (oldpin);
|
||||||
@ -1365,19 +1500,19 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
|
|
||||||
|
|
||||||
/* Perform a simple verify operation for the PIN specified by PWIDSTR.
|
/* Perform a simple verify operation for the PIN specified by PWIDSTR.
|
||||||
* For valid values see do_change_pin. */
|
* For valid values see do_change_chv. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_check_pin (app_t app, const char *pwidstr,
|
do_check_chv (app_t app, const char *pwidstr,
|
||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
void *pincb_arg)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int keyref;
|
int keyref;
|
||||||
|
|
||||||
keyref = parse_pin_keyref (pwidstr);
|
keyref = parse_chv_keyref (pwidstr);
|
||||||
if (keyref == -1)
|
if (keyref == -1)
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
|
||||||
return verify_pin (app, keyref, pincb, pincb_arg);
|
return verify_chv (app, keyref, pincb, pincb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1492,7 +1627,7 @@ do_auth (app_t app, const char *keyidstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now verify the Application PIN. */
|
/* Now verify the Application PIN. */
|
||||||
err = verify_pin (app, 0x80, pincb, pincb_arg);
|
err = verify_chv (app, 0x80, pincb, pincb_arg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1675,8 +1810,8 @@ app_select_piv (app_t app)
|
|||||||
/* app->fnc.sign = do_sign; */
|
/* app->fnc.sign = do_sign; */
|
||||||
app->fnc.auth = do_auth;
|
app->fnc.auth = do_auth;
|
||||||
/* app->fnc.decipher = do_decipher; */
|
/* app->fnc.decipher = do_decipher; */
|
||||||
app->fnc.change_pin = do_change_pin;
|
app->fnc.change_pin = do_change_chv;
|
||||||
app->fnc.check_pin = do_check_pin;
|
app->fnc.check_pin = do_check_chv;
|
||||||
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
@ -899,7 +899,7 @@ list_piv (card_info_t info, estream_t fp)
|
|||||||
switch (info->chvinfo[i])
|
switch (info->chvinfo[i])
|
||||||
{
|
{
|
||||||
case -1: s = "[error]"; break;
|
case -1: s = "[error]"; break;
|
||||||
case -2: s = "-"; break; /* No such PIN */
|
case -2: s = "-"; break; /* No such PIN or info not available. */
|
||||||
case -3: s = "[blocked]"; break;
|
case -3: s = "[blocked]"; break;
|
||||||
case -5: s = "[verified]"; break;
|
case -5: s = "[verified]"; break;
|
||||||
default: s = "[?]"; break;
|
default: s = "[?]"; break;
|
||||||
@ -950,15 +950,21 @@ static gpg_error_t
|
|||||||
cmd_verify (card_info_t info, char *argstr)
|
cmd_verify (card_info_t info, char *argstr)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
const char *pinref;
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return print_help ("verify [chvid]", 0);
|
return print_help ("verify [chvid]", 0);
|
||||||
|
|
||||||
if (info->apptype == APP_TYPE_OPENPGP)
|
if (*argstr)
|
||||||
err = scd_checkpin (info->serialno);
|
pinref = argstr;
|
||||||
|
else if (info->apptype == APP_TYPE_OPENPGP)
|
||||||
|
pinref = info->serialno;
|
||||||
|
else if (info->apptype == APP_TYPE_PIV)
|
||||||
|
pinref = "PIV.80";
|
||||||
else
|
else
|
||||||
err = scd_checkpin (argstr);
|
return gpg_error (GPG_ERR_MISSING_VALUE);
|
||||||
|
|
||||||
|
err = scd_checkpin (pinref);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("verify failed: %s <%s>\n",
|
log_error ("verify failed: %s <%s>\n",
|
||||||
gpg_strerror (err), gpg_strsource (err));
|
gpg_strerror (err), gpg_strsource (err));
|
||||||
@ -1845,29 +1851,47 @@ cmd_generate (card_info_t info)
|
|||||||
/* Sub-menu to change a PIN. The presented options may depend on the
|
/* Sub-menu to change a PIN. The presented options may depend on the
|
||||||
* the ALLOW_ADMIN flag. */
|
* the ALLOW_ADMIN flag. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_passwd (card_info_t info, int allow_admin)
|
cmd_passwd (card_info_t info, int allow_admin, char *argstr)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
|
const char *pinref;
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return print_help
|
return print_help
|
||||||
("PASSWD\n\n"
|
("PASSWD [PINREF]\n\n"
|
||||||
"Menu to change or unblock the PINs. Note that the\n"
|
"Menu to change or unblock the PINs. Note that the\n"
|
||||||
"presented menu options depend on the type of card\n"
|
"presented menu options depend on the type of card\n"
|
||||||
"and whether the admin mode is enabled.",
|
"and whether the admin mode is enabled. For OpenPGP\n"
|
||||||
|
"and PIV cards defaults for PINREF are available.",
|
||||||
0);
|
0);
|
||||||
|
|
||||||
/* Convenience message because we did this in gpg --card-edit too. */
|
if (opt.interactive || opt.verbose)
|
||||||
if (info->apptype == APP_TYPE_OPENPGP)
|
log_info (_("%s card no. %s detected\n"),
|
||||||
log_info (_("OpenPGP card no. %s detected\n"),
|
app_type_string (info->apptype),
|
||||||
info->dispserialno? info->dispserialno : info->serialno);
|
info->dispserialno? info->dispserialno : info->serialno);
|
||||||
|
|
||||||
if (!allow_admin)
|
if (!allow_admin || info->apptype != APP_TYPE_OPENPGP)
|
||||||
{
|
{
|
||||||
err = scd_change_pin ("OPENPGP.1", 0);
|
if (*argstr)
|
||||||
|
pinref = argstr;
|
||||||
|
else if (info->apptype == APP_TYPE_OPENPGP)
|
||||||
|
pinref = "OPENPGP.1";
|
||||||
|
else if (info->apptype == APP_TYPE_PIV)
|
||||||
|
pinref = "PIV.80";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = scd_change_pin (pinref, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
if (info->apptype == APP_TYPE_PIV
|
||||||
|
&& !ascii_strcasecmp (pinref, "PIV.81"))
|
||||||
|
log_info ("PUK changed.\n");
|
||||||
|
else
|
||||||
log_info ("PIN changed.\n");
|
log_info ("PIN changed.\n");
|
||||||
}
|
}
|
||||||
else if (info->apptype == APP_TYPE_OPENPGP)
|
else if (info->apptype == APP_TYPE_OPENPGP)
|
||||||
@ -1959,23 +1983,43 @@ cmd_unblock (card_info_t info)
|
|||||||
"command can be used to set a new PIN.",
|
"command can be used to set a new PIN.",
|
||||||
0);
|
0);
|
||||||
|
|
||||||
if (info->apptype == APP_TYPE_OPENPGP)
|
if (opt.interactive || opt.verbose)
|
||||||
log_info (_("OpenPGP card no. %s detected\n"),
|
log_info (_("%s card no. %s detected\n"),
|
||||||
|
app_type_string (info->apptype),
|
||||||
info->dispserialno? info->dispserialno : info->serialno);
|
info->dispserialno? info->dispserialno : info->serialno);
|
||||||
|
|
||||||
if (info->apptype == APP_TYPE_OPENPGP && !info->is_v2)
|
if (info->apptype == APP_TYPE_OPENPGP)
|
||||||
|
{
|
||||||
|
if (!info->is_v2)
|
||||||
|
{
|
||||||
log_error (_("This command is only available for version 2 cards\n"));
|
log_error (_("This command is only available for version 2 cards\n"));
|
||||||
else if (info->apptype == APP_TYPE_OPENPGP && !info->chvinfo[1])
|
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
else if (!info->chvinfo[1])
|
||||||
|
{
|
||||||
log_error (_("Reset Code not or not anymore available\n"));
|
log_error (_("Reset Code not or not anymore available\n"));
|
||||||
else if (info->apptype == APP_TYPE_OPENPGP)
|
err = gpg_error (GPG_ERR_PIN_BLOCKED);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
err = scd_change_pin ("OPENPGP.2", 0);
|
err = scd_change_pin ("OPENPGP.2", 0);
|
||||||
if (!err)
|
if (!err)
|
||||||
log_info ("PIN changed.\n");
|
log_info ("PIN changed.\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (info->apptype == APP_TYPE_PIV)
|
||||||
|
{
|
||||||
|
/* Unblock the Application PIN. */
|
||||||
|
err = scd_change_pin ("PIV.80", 1);
|
||||||
|
if (!err)
|
||||||
|
log_info ("PIN unblocked and changed.\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
log_info ("Unblocking not yet supported for '%s'\n",
|
log_info ("Unblocking not yet supported for '%s'\n",
|
||||||
app_type_string (info->apptype));
|
app_type_string (info->apptype));
|
||||||
|
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -2079,15 +2123,15 @@ cmd_factoryreset (card_info_t info)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.interactive || opt.verbose)
|
||||||
|
log_info (_("%s card no. %s detected\n"),
|
||||||
|
app_type_string (info->apptype),
|
||||||
|
info->dispserialno? info->dispserialno : info->serialno);
|
||||||
|
|
||||||
if (!termstate || is_yubikey)
|
if (!termstate || is_yubikey)
|
||||||
{
|
{
|
||||||
if (is_yubikey)
|
if (!is_yubikey)
|
||||||
log_info (_("Yubikey no. %s with PIV application detected\n"),
|
|
||||||
info->dispserialno? info->dispserialno : info->serialno);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
log_info (_("OpenPGP card no. %s detected\n"),
|
|
||||||
info->dispserialno? info->dispserialno : info->serialno);
|
|
||||||
if (!(info->status_indicator == 3 || info->status_indicator == 5))
|
if (!(info->status_indicator == 3 || info->status_indicator == 5))
|
||||||
{
|
{
|
||||||
/* Note: We won't see status-indicator 3 here because it
|
/* Note: We won't see status-indicator 3 here because it
|
||||||
@ -2865,7 +2909,7 @@ dispatch_command (card_info_t info, const char *orig_command)
|
|||||||
case cmdREADCERT: err = cmd_readcert (info, argstr); break;
|
case cmdREADCERT: err = cmd_readcert (info, argstr); break;
|
||||||
case cmdFORCESIG: err = cmd_forcesig (info); break;
|
case cmdFORCESIG: err = cmd_forcesig (info); break;
|
||||||
case cmdGENERATE: err = cmd_generate (info); break;
|
case cmdGENERATE: err = cmd_generate (info); break;
|
||||||
case cmdPASSWD: err = cmd_passwd (info, 1); break;
|
case cmdPASSWD: err = cmd_passwd (info, 1, argstr); break;
|
||||||
case cmdUNBLOCK: err = cmd_unblock (info); break;
|
case cmdUNBLOCK: err = cmd_unblock (info); break;
|
||||||
case cmdFACTORYRESET: err = cmd_factoryreset (info); break;
|
case cmdFACTORYRESET: err = cmd_factoryreset (info); break;
|
||||||
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
|
case cmdKDFSETUP: err = cmd_kdfsetup (info, argstr); break;
|
||||||
@ -3131,7 +3175,7 @@ interactive_loop (void)
|
|||||||
case cmdREADCERT: err = cmd_readcert (info, argstr); break;
|
case cmdREADCERT: err = cmd_readcert (info, argstr); break;
|
||||||
case cmdFORCESIG: err = cmd_forcesig (info); break;
|
case cmdFORCESIG: err = cmd_forcesig (info); break;
|
||||||
case cmdGENERATE: err = cmd_generate (info); break;
|
case cmdGENERATE: err = cmd_generate (info); break;
|
||||||
case cmdPASSWD: err = cmd_passwd (info, allow_admin); break;
|
case cmdPASSWD: err = cmd_passwd (info, allow_admin, argstr); break;
|
||||||
case cmdUNBLOCK: err = cmd_unblock (info); break;
|
case cmdUNBLOCK: err = cmd_unblock (info); break;
|
||||||
case cmdFACTORYRESET:
|
case cmdFACTORYRESET:
|
||||||
err = cmd_factoryreset (info);
|
err = cmd_factoryreset (info);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user