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
info available. The format is the usual ISO string are a number
with the seconds since Epoch.
*** MANUFACTORER <n> [<string>]
*** MANUFACTURER <n> [<string>]
This status returns the Manufactorer ID as the unsigned number N.
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
byte) with the status of the PIN. PWID is the PIN ID, If SIGG is
true, the application is switched into SigG mode.
Returns:
-1 = Error retrieving the data,
-2 = No such PIN,
-3 = PIN blocked,
-4 = NullPIN active,
n >= 0 = Number of verification attempts left. */
* byte) with the status of the PIN. PWID is the PIN ID, If SIGG is
* true, the application is switched into SigG mode. Returns:
* ISO7816_VERIFY_* codes or non-negative number of verification
* attempts left. */
static int
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))
return sigg? -2 : -1; /* No such PIN / General error. */
command[0] = 0x00;
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;
return iso7816_verify_status (app_get_slot (app), pwid);
}

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 card. Given the PIN name (e.g. "PIV.80" for the application
* pin, a status is returned:
*
* -1 = Error retrieving the data,
* -2 = No such PIN,
* -3 = PIN blocked,
* -5 = Verified and still valid,
* n >= 0 = Number of verification attempts left.
*/
* pin, a ISO7817_VERIFY_* code is returned or a non-negative number
* of verification attempts left. */
static int
get_chv_status (app_t app, const char *keyrefstr)
{
unsigned char apdu[4];
unsigned int sw;
int result;
int keyref;
keyref = parse_chv_keyref (keyrefstr);
if (!keyrefstr)
return -1;
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;
return ISO7816_VERIFY_ERROR;
return iso7816_verify_status (app_get_slot (app), keyref);
}
@ -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 err;
unsigned char apdu[4];
unsigned int sw;
int remaining;
char *pin = NULL;
unsigned int pinlen, unpaddedpinlen;
/* 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_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
/* First check whether a verify is at all needed. */
remaining = iso7816_verify_status (app_get_slot (app), keyref);
if (remaining == ISO7816_VERIFY_NOT_NEEDED)
{
if (!force) /* No need to verification. */
return 0; /* All fine. */
remaining = -1;
}
else if ((sw & 0xfff0) == 0x63C0)
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
else
else if (remaining < 0) /* We don't care about other errors. */
remaining = -1;
err = ask_and_prepare_chv (app, ctrl, keyref, 0, remaining, force,
pincb, pincb_arg,
&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);
}
/* 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
verification vector CHVNO. With PININFO non-NULL the pinpad of the
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_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
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,
int chvno, const char *chv, size_t chvlen);
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,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen);