summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-04-07 18:25:41 +0200
committerWerner Koch <wk@gnupg.org>2020-04-07 18:26:00 +0200
commit60d018f6a91c4c90b8ecf13f88ac4256699f4007 (patch)
tree23777ca47346da386213417757f2d56776fe3f7c /scd
parentdoc: Typo fix in code comment. (diff)
downloadgnupg2-60d018f6a91c4c90b8ecf13f88ac4256699f4007.tar.xz
gnupg2-60d018f6a91c4c90b8ecf13f88ac4256699f4007.zip
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>
Diffstat (limited to 'scd')
-rw-r--r--scd/app-nks.c46
-rw-r--r--scd/app-piv.c50
-rw-r--r--scd/iso7816.c33
-rw-r--r--scd/iso7816.h10
4 files changed, 57 insertions, 82 deletions
diff --git a/scd/app-nks.c b/scd/app-nks.c
index efc11296a..e09009784 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -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);
}
diff --git a/scd/app-piv.c b/scd/app-piv.c
index 8a3ba1e1b..e6298e575 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -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);
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 96d016a26..8f5ce5c52 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -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
diff --git a/scd/iso7816.h b/scd/iso7816.h
index a8215808b..b59103db2 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -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);