diff --git a/lib/ykpiv.c b/lib/ykpiv.c index a35f515..1322a9e 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -557,3 +557,48 @@ ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len) { return YKPIV_GENERIC_ERROR; } } + +ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) { + APDU apdu; + unsigned char data[0xff]; + unsigned long recv_len = sizeof(data); + int sw; + size_t len = strlen(pin); + ykpiv_rc res; + + if(len > 8) { + return YKPIV_SIZE_ERROR; + } + + memset(apdu.raw, 0, sizeof(apdu.raw)); + apdu.st.ins = YKPIV_INS_VERIFY; + apdu.st.p1 = 0x00; + apdu.st.p2 = 0x80; + apdu.st.lc = 0x08; + memcpy(apdu.st.data, pin, len); + if(len < 8) { + memset(apdu.st.data + len, 0xff, 8 - len); + } + if((res = ykpiv_send_data(state, apdu.raw, data, &recv_len, &sw)) != YKPIV_OK) { + return res; + } else if(sw == 0x9000) { + return YKPIV_OK; + } else if((sw >> 8) == 0x63) { + if(state->verbose) { + fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", sw & 0xff); + } + *tries = (sw & 0xff); + return YKPIV_WRONG_PIN; + } else if(sw == 0x6983) { + if(state->verbose) { + fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n"); + } + *tries = 0; + return YKPIV_WRONG_PIN; + } else { + if(state->verbose) { + fprintf(stderr, "Pin code verification failed with code %x.\n", sw); + } + return YKPIV_GENERIC_ERROR; + } +} diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 1239df3..0207f13 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -53,6 +53,7 @@ extern "C" YKPIV_GENERIC_ERROR = -7, YKPIV_KEY_ERROR = -8, YKPIV_PARSE_ERROR = -9, + YKPIV_WRONG_PIN = -10, } ykpiv_rc; const char *ykpiv_strerror(ykpiv_rc err); @@ -75,6 +76,7 @@ extern "C" int in_len,unsigned char *sign_out, int *out_len, unsigned char algorithm, unsigned char key); ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len); + ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries); #define YKPIV_ALGO_3DES 0x03 #define YKPIV_ALGO_RSA1024 0x06 diff --git a/lib/ykpiv.map b/lib/ykpiv.map index 5aed2ae..1e156ac 100644 --- a/lib/ykpiv.map +++ b/lib/ykpiv.map @@ -41,6 +41,7 @@ global: ykpiv_parse_key; ykpiv_sign_data; ykpiv_get_version; + ykpiv_verify; local: *; diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 903866c..d15c672 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -797,36 +797,25 @@ selfsign_out: } static bool verify_pin(ykpiv_state *state, const char *pin) { - APDU apdu; - unsigned char data[0xff]; - unsigned long recv_len = sizeof(data); - int sw; - size_t len = strlen(pin); + int tries = -1; + ykpiv_rc res; + int len = strlen(pin); if(len > 8) { fprintf(stderr, "Maximum 8 digits of PIN supported.\n"); - return false; } - memset(apdu.raw, 0, sizeof(apdu.raw)); - apdu.st.ins = YKPIV_INS_VERIFY; - apdu.st.p1 = 0x00; - apdu.st.p2 = 0x80; - apdu.st.lc = 0x08; - memcpy(apdu.st.data, pin, len); - if(len < 8) { - memset(apdu.st.data + len, 0xff, 8 - len); - } - if(ykpiv_send_data(state, apdu.raw, data, &recv_len, &sw) != YKPIV_OK) { - return false; - } else if(sw == 0x9000) { + res = ykpiv_verify(state, pin, &tries); + if(res == YKPIV_OK) { return true; - } else if((sw >> 8) == 0x63) { - fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", sw & 0xff); - } else if(sw == 0x6983) { - fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n"); + } else if(res == YKPIV_WRONG_PIN) { + if(tries > 0) { + fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries); + } else { + fprintf(stderr, "Pin code blocked, use unblock-pin action to unblock.\n"); + } } else { - fprintf(stderr, "Pin code verification failed with code %x.\n", sw); + fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res)); } return false; }