diff --git a/doc/DETAILS b/doc/DETAILS index bad311691..7655489a5 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -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 [] +*** MANUFACTURER [] This status returns the Manufactorer ID as the unsigned number N. For OpenPGP this is weel defined; for other cards this is 0. The 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);