From 1fe1d40e3812e564ddc1667b312053354e721eb7 Mon Sep 17 00:00:00 2001 From: Doug Engert Date: Sat, 8 Dec 2018 18:16:40 -0600 Subject: [PATCH] PIV - Improved error handling of get_challenge Random data from PIV card is obtained using GENERAL AUTHENTICATE command for a request of a Challenge from the card. "00 87 00 9B 04 7C 02 81 00" Usually 8 bytes are returned. NIST 800-73-3_PART2, "A.1 Authentication of the PIV Card Application Administrator" "Table 11. Authentication of PIV Card Application Administrator" shows an example of how to do this. Some cards (one I have: 3b:7d:96:00:00:80:31:80:65:b0:83:11:17:d6:83:00:90:00) will not allow 2 of these commands in a row. (Maybe assuming command is only used as in Table 11 and is expecting the second command.) Code was added to card-piv.c so if "6A 80" is returned, try the command one more time. For any other GENERAL AUTHENTICATE failure, SC_ERROR_NOT_SUPPORTED is returned. piv_get_challenge may be called within a loop from sc_get_challenge if more random data is needed thus causing the the 2 commands to sent in a row. On branch piv-improved-matching Changes to be committed: modified: card-piv.c --- src/libopensc/card-piv.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 6d37ea15..79447213 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -2277,6 +2277,22 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) /* NIST 800-73-3 says use 9B, previous verisons used 00 */ r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); + /* + * piv_get_challenge is called in a loop. + * some cards may allow 1 challenge expecting it to be part of + * NIST 800-73-3 part 2 "Authentication of PIV Card Application Administrator" + * and return "6A 80" if last command was a get_challenge. + * Now that the card returned error, we can try one more time. + */ + if (r == SC_ERROR_INCORRECT_PARAMETERS) { + if (rbuf) + free(rbuf); + rbuf_len = 0; + r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); + if (r == SC_ERROR_INCORRECT_PARAMETERS) { + r = SC_ERROR_NOT_SUPPORTED; + } + } LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed"); p = rbuf;