scd: Factor common PIN status check out.

* scd/iso7816.h (ISO7816_VERIFY_ERROR): New.
(ISO7816_VERIFY_NO_PIN): New.
(ISO7816_VERIFY_BLOCKED): New.
(ISO7816_VERIFY_NULLPIN): New.
(ISO7816_VERIFY_NOT_NEEDED): New.
* scd/iso7816.c (iso7816_verify_status): New.
* scd/app-nks.c (get_chv_status): Use new function.
* scd/app-piv.c (get_chv_status): Ditto.
(verify_chv): Ditto.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-04-07 18:25:41 +02:00
parent 5ec1f66793
commit 60d018f6a9
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 58 additions and 83 deletions

View File

@ -1171,7 +1171,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
by OpenPGP cards for the stored key creation time. A '-' means no by OpenPGP cards for the stored key creation time. A '-' means no
info available. The format is the usual ISO string are a number info available. The format is the usual ISO string are a number
with the seconds since Epoch. with the seconds since Epoch.
*** MANUFACTORER <n> [<string>] *** MANUFACTURER <n> [<string>]
This status returns the Manufactorer ID as the unsigned number N. This status returns the Manufactorer ID as the unsigned number N.
For OpenPGP this is weel defined; for other cards this is 0. The For OpenPGP this is weel defined; for other cards this is 0. The

View File

@ -249,53 +249,17 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
/* TCOS responds to a verify with empty data (i.e. without the Lc /* TCOS responds to a verify with empty data (i.e. without the Lc
byte) with the status of the PIN. PWID is the PIN ID, If SIGG is * byte) with the status of the PIN. PWID is the PIN ID, If SIGG is
true, the application is switched into SigG mode. * true, the application is switched into SigG mode. Returns:
Returns: * ISO7816_VERIFY_* codes or non-negative number of verification
-1 = Error retrieving the data, * attempts left. */
-2 = No such PIN,
-3 = PIN blocked,
-4 = NullPIN active,
n >= 0 = Number of verification attempts left. */
static int static int
get_chv_status (app_t app, int sigg, int pwid) get_chv_status (app_t app, int sigg, int pwid)
{ {
unsigned char *result = NULL;
size_t resultlen;
char command[4];
int rc;
if (switch_application (app, sigg)) if (switch_application (app, sigg))
return sigg? -2 : -1; /* No such PIN / General error. */ return sigg? -2 : -1; /* No such PIN / General error. */
command[0] = 0x00; return iso7816_verify_status (app_get_slot (app), pwid);
command[1] = 0x20;
command[2] = 0x00;
command[3] = pwid;
if (apdu_send_direct (app_get_slot (app), 0, (unsigned char *)command,
4, 0, NULL, &result, &resultlen))
rc = -1; /* Error. */
else if (resultlen < 2)
rc = -1; /* Error. */
else
{
unsigned int sw = buf16_to_uint (result+resultlen-2);
if (sw == 0x6a88)
rc = -2; /* No such PIN. */
else if (sw == 0x6983)
rc = -3; /* PIN is blocked. */
else if (sw == 0x6985)
rc = -4; /* NullPIN is active. */
else if ((sw & 0xfff0) == 0x63C0)
rc = (sw & 0x000f); /* PIN has N tries left. */
else
rc = -1; /* Other error. */
}
xfree (result);
return rc;
} }

View File

@ -780,42 +780,17 @@ get_dispserialno (app_t app, int failmode)
/* The verify command can be used to retrieve the security status of /* The verify command can be used to retrieve the security status of
* the card. Given the PIN name (e.g. "PIV.80" for the application * the card. Given the PIN name (e.g. "PIV.80" for the application
* pin, a status is returned: * pin, a ISO7817_VERIFY_* code is returned or a non-negative number
* * of verification attempts left. */
* -1 = Error retrieving the data,
* -2 = No such PIN,
* -3 = PIN blocked,
* -5 = Verified and still valid,
* n >= 0 = Number of verification attempts left.
*/
static int static int
get_chv_status (app_t app, const char *keyrefstr) get_chv_status (app_t app, const char *keyrefstr)
{ {
unsigned char apdu[4];
unsigned int sw;
int result;
int keyref; int keyref;
keyref = parse_chv_keyref (keyrefstr); keyref = parse_chv_keyref (keyrefstr);
if (!keyrefstr) if (!keyrefstr)
return -1; return ISO7816_VERIFY_ERROR;
return iso7816_verify_status (app_get_slot (app), keyref);
apdu[0] = 0x00;
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = keyref;
if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
result = -5; /* No need to verification. */
else if (sw == 0x6a88 || sw == 0x6a80)
result = -2; /* No such PIN. */
else if (sw == 0x6983)
result = -3; /* PIN is blocked. */
else if ((sw & 0xfff0) == 0x63C0)
result = (sw & 0x000f);
else
result = -1; /* Error. */
return result;
} }
@ -1999,29 +1974,22 @@ verify_chv (app_t app, ctrl_t ctrl, int keyref, int force,
gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg) gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
{ {
gpg_error_t err; gpg_error_t err;
unsigned char apdu[4];
unsigned int sw;
int remaining; int remaining;
char *pin = NULL; char *pin = NULL;
unsigned int pinlen, unpaddedpinlen; unsigned int pinlen, unpaddedpinlen;
/* First check whether a verify is at all needed. This is done with /* First check whether a verify is at all needed. */
* P1 being 0 and no Lc and command data send. */ remaining = iso7816_verify_status (app_get_slot (app), keyref);
apdu[0] = 0x00; if (remaining == ISO7816_VERIFY_NOT_NEEDED)
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = keyref;
if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
{ {
if (!force) /* No need to verification. */ if (!force) /* No need to verification. */
return 0; /* All fine. */ return 0; /* All fine. */
remaining = -1; remaining = -1;
} }
else if ((sw & 0xfff0) == 0x63C0) else if (remaining < 0) /* We don't care about other errors. */
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
else
remaining = -1; remaining = -1;
err = ask_and_prepare_chv (app, ctrl, keyref, 0, remaining, force, err = ask_and_prepare_chv (app, ctrl, keyref, 0, remaining, force,
pincb, pincb_arg, pincb, pincb_arg,
&pin, &pinlen, &unpaddedpinlen); &pin, &pinlen, &unpaddedpinlen);

View File

@ -339,6 +339,39 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
return map_sw (sw); return map_sw (sw);
} }
/* Some cards support a VERIFY command variant to check the status of
* the the CHV without a need to try a CHV. In contrast to the other
* functions this function returns the special codes ISO7816_VERIFY_*
* or a non-negative number with the left attempts. */
int
iso7816_verify_status (int slot, int chvno)
{
unsigned char apdu[4];
unsigned int sw;
int result;
apdu[0] = 0x00;
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = chvno;
if (!iso7816_apdu_direct (slot, apdu, 4, 0, &sw, NULL, NULL))
result = ISO7816_VERIFY_NOT_NEEDED; /* Not returned by all cards. */
else if (sw == 0x6a88 || sw == 0x6a80)
result = ISO7816_VERIFY_NO_PIN;
else if (sw == 0x6983)
result = ISO7816_VERIFY_BLOCKED;
else if (sw == 0x6985)
result = ISO7816_VERIFY_NULLPIN; /* TCOS card */
else if ((sw & 0xfff0) == 0x63C0)
result = (sw & 0x000f);
else
result = ISO7816_VERIFY_ERROR;
return result;
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. With PININFO non-NULL the pinpad of the verification vector CHVNO. With PININFO non-NULL the pinpad of the
reader will be used. If IS_EXCHANGE is 0, a "change reference reader will be used. If IS_EXCHANGE is 0, a "change reference

View File

@ -29,6 +29,15 @@
#define ISO7816_CHANGE_REFERENCE_DATA 0x24 #define ISO7816_CHANGE_REFERENCE_DATA 0x24
#define ISO7816_RESET_RETRY_COUNTER 0x2C #define ISO7816_RESET_RETRY_COUNTER 0x2C
/* Error codes returned by iso7816_verify_status. A non-negative
* number gives the number of left tries.
* NB: The values are also used by the CHV-STATUS lines and thus are
* part of the public interface. Do not change them. */
#define ISO7816_VERIFY_ERROR (-1)
#define ISO7816_VERIFY_NO_PIN (-2)
#define ISO7816_VERIFY_BLOCKED (-3)
#define ISO7816_VERIFY_NULLPIN (-4)
#define ISO7816_VERIFY_NOT_NEEDED (-5)
/* Information to be passed to pinpad equipped readers. See /* Information to be passed to pinpad equipped readers. See
ccid-driver.c for details. */ ccid-driver.c for details. */
@ -76,6 +85,7 @@ gpg_error_t iso7816_check_pinpad (int slot, int command,
gpg_error_t iso7816_verify (int slot, gpg_error_t iso7816_verify (int slot,
int chvno, const char *chv, size_t chvlen); int chvno, const char *chv, size_t chvlen);
gpg_error_t iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo); gpg_error_t iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo);
int iso7816_verify_status (int slot, int chvno);
gpg_error_t iso7816_change_reference_data (int slot, int chvno, gpg_error_t iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen, const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen); const char *newchv, size_t newchvlen);