Overview
Comment: | Reset the card and rescan for certificates if we get the ISO 7816 error 6D 00 (Wrong instruction) error from the card when trying to verify. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | piv-reset-on-wronginstruction |
Files: | files | file ages | folders |
SHA1: | 52569c3e74727533fa081ffc00a7cc827b1226fa |
User & Date: | rkeene on 2015-07-16 16:06:35 |
Other Links: | manifest | tags |
Context
2015-07-16
| ||
16:18 | Updated to retry login if it fails with a 6D 00 (wrong instruction) check-in: 4e30511f94 user: rkeene tags: trunk | |
16:06 | Reset the card and rescan for certificates if we get the ISO 7816 error 6D 00 (Wrong instruction) error from the card when trying to verify. Closed-Leaf check-in: 52569c3e74 user: rkeene tags: piv-reset-on-wronginstruction | |
2015-07-15
| ||
20:05 | Added support for updating the PIN check-in: b5ecb7c2d6 user: rkeene tags: trunk | |
Changes
Modified cackey.c from [3a0d4abad4] to [06b013b460].
3138 3138 * 3139 3139 * RETURN VALUE 3140 3140 * ... 3141 3141 * 3142 3142 * NOTES 3143 3143 * ... 3144 3144 * 3145 + */ 3146 +static cackey_ret cackey_token_present(struct cackey_slot *slot) { 3147 + cackey_ret pcsc_connect_ret; 3148 + DWORD reader_len = 0, state = 0, protocol = 0, atr_len; 3149 + BYTE atr[MAX_ATR_SIZE]; 3150 + LONG status_ret, scard_reconn_ret; 3151 + 3152 + CACKEY_DEBUG_PRINTF("Called."); 3153 + 3154 + if (slot->internal) { 3155 + CACKEY_DEBUG_PRINTF("Returning token present (internal token)"); 3156 + 3157 + return(CACKEY_PCSC_S_TOKENPRESENT); 3158 + } 3159 + 3160 + pcsc_connect_ret = cackey_connect_card(slot); 3161 + if (pcsc_connect_ret != CACKEY_PCSC_S_OK) { 3162 + CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent"); 3163 + 3164 + return(CACKEY_PCSC_E_TOKENABSENT); 3165 + } 3166 + 3167 + CACKEY_DEBUG_PRINTF("Calling SCardStatus() to determine card status"); 3168 + 3169 + atr_len = sizeof(atr); 3170 + status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3171 + 3172 + if (status_ret == SCARD_E_INVALID_HANDLE) { 3173 + CACKEY_DEBUG_PRINTF("SCardStatus() returned SCARD_E_INVALID_HANDLE, marking is not already connected and trying again"); 3174 + cackey_mark_slot_reset(slot); 3175 + 3176 + pcsc_connect_ret = cackey_connect_card(slot); 3177 + if (pcsc_connect_ret != CACKEY_PCSC_S_OK) { 3178 + CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent"); 3179 + 3180 + return(CACKEY_PCSC_E_TOKENABSENT); 3181 + } 3182 + 3183 + CACKEY_DEBUG_PRINTF("Calling SCardStatus() again"); 3184 + 3185 + atr_len = sizeof(atr); 3186 + status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3187 + } 3188 + 3189 + if (status_ret != SCARD_S_SUCCESS) { 3190 + cackey_mark_slot_reset(slot); 3191 + 3192 + if (status_ret == SCARD_W_RESET_CARD) { 3193 + CACKEY_DEBUG_PRINTF("Reset required, please hold..."); 3194 + 3195 + scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1); 3196 + if (scard_reconn_ret == SCARD_S_SUCCESS) { 3197 + /* Re-establish transaction, if it was present */ 3198 + if (slot->transaction_depth > 0) { 3199 + slot->transaction_depth--; 3200 + slot->transaction_need_hw_lock = 1; 3201 + cackey_begin_transaction(slot); 3202 + } 3203 + 3204 + CACKEY_DEBUG_PRINTF("Reset successful, requerying"); 3205 + status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3206 + if (status_ret != SCARD_S_SUCCESS) { 3207 + CACKEY_DEBUG_PRINTF("Still unable to query card status, returning token absent. SCardStatus() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(status_ret)); 3208 + 3209 + return(CACKEY_PCSC_E_TOKENABSENT); 3210 + } 3211 + } else { 3212 + CACKEY_DEBUG_PRINTF("Unable to reconnect to card, returning token absent. SCardReconnect() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_reconn_ret)); 3213 + 3214 + return(CACKEY_PCSC_E_TOKENABSENT); 3215 + } 3216 + } else { 3217 + CACKEY_DEBUG_PRINTF("Unable to query card status, returning token absent. SCardStatus() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(status_ret)); 3218 + 3219 + return(CACKEY_PCSC_E_TOKENABSENT); 3220 + } 3221 + } 3222 + 3223 + if ((state & SCARD_ABSENT) == SCARD_ABSENT) { 3224 + CACKEY_DEBUG_PRINTF("Card is absent, returning token absent"); 3225 + 3226 + return(CACKEY_PCSC_E_TOKENABSENT); 3227 + } 3228 + 3229 + CACKEY_DEBUG_PRINTF("Returning token present."); 3230 + 3231 + return(CACKEY_PCSC_S_TOKENPRESENT); 3232 +} 3233 + 3234 +/* 3235 + * SYNPOSIS 3236 + * ... 3237 + * 3238 + * ARGUMENTS 3239 + * ... 3240 + * 3241 + * RETURN VALUE 3242 + * ... 3243 + * 3244 + * NOTES 3245 + * ... 3246 + * 3145 3247 */ 3146 3248 static cackey_ret cackey_set_pin(struct cackey_slot *slot, unsigned char *old_pin, unsigned long old_pin_len, unsigned char *pin, unsigned long pin_len) { 3147 3249 struct cackey_pcsc_identity *pcsc_identities; 3148 3250 unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 3149 3251 unsigned char old_cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 3150 3252 unsigned char pin_update[sizeof(cac_pin) + sizeof(old_cac_pin)]; 3151 3253 unsigned long num_certs; ................................................................................ 3236 3338 * RETURN VALUE 3237 3339 * ... 3238 3340 * 3239 3341 * NOTES 3240 3342 * ... 3241 3343 * 3242 3344 */ 3243 -static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) { 3345 +static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p, int retries) { 3244 3346 struct cackey_pcsc_identity *pcsc_identities; 3245 3347 unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 3246 3348 unsigned long num_certs; 3247 3349 uint16_t response_code; 3248 3350 int tries_remaining; 3249 3351 int send_ret; 3250 - int key_reference = 0x00; 3352 + int key_reference = 0x00, have_piv = 0; 3353 + cackey_ret connect_ret, token_ret; 3251 3354 3252 3355 /* Indicate that we do not know about how many tries are remaining */ 3253 3356 if (tries_remaining_p) { 3254 3357 *tries_remaining_p = -1; 3255 3358 } 3256 3359 3257 3360 /* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */ ................................................................................ 3271 3374 /* PIV authentication uses a "key_reference" of 0x80 */ 3272 3375 pcsc_identities = cackey_read_certs(slot, NULL, &num_certs); 3273 3376 if (num_certs > 0 && pcsc_identities != NULL) { 3274 3377 switch (pcsc_identities[0].id_type) { 3275 3378 case CACKEY_ID_TYPE_PIV: 3276 3379 CACKEY_DEBUG_PRINTF("We have PIV card, so we will attempt to authenticate using the PIV Application key reference"); 3277 3380 3278 - key_reference = 0x80; 3381 + have_piv = 1; 3279 3382 break; 3280 3383 default: 3281 3384 break; 3282 3385 } 3283 3386 3284 3387 cackey_free_certs(pcsc_identities, num_certs, 1); 3285 3388 } 3389 + 3390 + if (have_piv == 1) { 3391 + key_reference = 0x80; 3392 + } 3286 3393 3287 3394 /* Issue PIN Verify */ 3288 3395 send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_VERIFY, 0x00, key_reference, sizeof(cac_pin), cac_pin, 0x00, &response_code, NULL, NULL); 3289 3396 3290 3397 if (send_ret != CACKEY_PCSC_S_OK) { 3291 3398 if ((response_code & 0x63C0) == 0x63C0) { 3292 3399 tries_remaining = (response_code & 0xF); ................................................................................ 3301 3408 } 3302 3409 3303 3410 if (response_code == 0x6983) { 3304 3411 CACKEY_DEBUG_PRINTF("PIN Verification failed, device is locked"); 3305 3412 3306 3413 return(CACKEY_PCSC_E_LOCKED); 3307 3414 } 3415 + 3416 + if (response_code == 0x6d00) { 3417 + if (have_piv == 1 && retries > 0) { 3418 + CACKEY_DEBUG_PRINTF("Got ISO 7816 Response \"6D 00\" in response to a VERIFY request."); 3419 + CACKEY_DEBUG_PRINTF("We did not expect this because it is not mentioned in NIST SP 800-73-3 Part 2 Section 3.2.1"); 3420 + CACKEY_DEBUG_PRINTF("We are going to try to reset the card and select the applet again."); 3421 + 3422 + cackey_mark_slot_reset(slot); 3423 + 3424 + connect_ret = cackey_connect_card(slot); 3425 + if (connect_ret != CACKEY_PCSC_S_OK) { 3426 + CACKEY_DEBUG_PRINTF("Unable to reconnect after resetting the card, returning in error."); 3427 + 3428 + return(connect_ret); 3429 + } 3430 + 3431 + CACKEY_DEBUG_PRINTF("Verifying we still have a token."); 3432 + token_ret = cackey_token_present(slot); 3433 + if (token_ret != CACKEY_PCSC_S_TOKENPRESENT) { 3434 + CACKEY_DEBUG_PRINTF("Token not present, returning in error."); 3435 + 3436 + return(token_ret); 3437 + } 3438 + 3439 + 3440 + CACKEY_DEBUG_PRINTF("Trying to login again"); 3441 + return(cackey_login(slot, pin, pin_len, tries_remaining_p, retries - 1)); 3442 + } 3443 + } 3308 3444 3309 3445 return(CACKEY_PCSC_E_GENERIC); 3310 3446 } 3311 3447 3312 3448 CACKEY_DEBUG_PRINTF("PIN Verification succeeded"); 3313 3449 3314 3450 return(CACKEY_PCSC_S_OK); 3315 3451 } 3316 3452 3317 -/* 3318 - * SYNPOSIS 3319 - * ... 3320 - * 3321 - * ARGUMENTS 3322 - * ... 3323 - * 3324 - * RETURN VALUE 3325 - * ... 3326 - * 3327 - * NOTES 3328 - * ... 3329 - * 3330 - */ 3331 -static cackey_ret cackey_token_present(struct cackey_slot *slot) { 3332 - cackey_ret pcsc_connect_ret; 3333 - DWORD reader_len = 0, state = 0, protocol = 0, atr_len; 3334 - BYTE atr[MAX_ATR_SIZE]; 3335 - LONG status_ret, scard_reconn_ret; 3336 - 3337 - CACKEY_DEBUG_PRINTF("Called."); 3338 - 3339 - if (slot->internal) { 3340 - CACKEY_DEBUG_PRINTF("Returning token present (internal token)"); 3341 - 3342 - return(CACKEY_PCSC_S_TOKENPRESENT); 3343 - } 3344 - 3345 - pcsc_connect_ret = cackey_connect_card(slot); 3346 - if (pcsc_connect_ret != CACKEY_PCSC_S_OK) { 3347 - CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent"); 3348 - 3349 - return(CACKEY_PCSC_E_TOKENABSENT); 3350 - } 3351 - 3352 - CACKEY_DEBUG_PRINTF("Calling SCardStatus() to determine card status"); 3353 - 3354 - atr_len = sizeof(atr); 3355 - status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3356 - 3357 - if (status_ret == SCARD_E_INVALID_HANDLE) { 3358 - CACKEY_DEBUG_PRINTF("SCardStatus() returned SCARD_E_INVALID_HANDLE, marking is not already connected and trying again"); 3359 - cackey_mark_slot_reset(slot); 3360 - 3361 - pcsc_connect_ret = cackey_connect_card(slot); 3362 - if (pcsc_connect_ret != CACKEY_PCSC_S_OK) { 3363 - CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent"); 3364 - 3365 - return(CACKEY_PCSC_E_TOKENABSENT); 3366 - } 3367 - 3368 - CACKEY_DEBUG_PRINTF("Calling SCardStatus() again"); 3369 - 3370 - atr_len = sizeof(atr); 3371 - status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3372 - } 3373 - 3374 - if (status_ret != SCARD_S_SUCCESS) { 3375 - cackey_mark_slot_reset(slot); 3376 - 3377 - if (status_ret == SCARD_W_RESET_CARD) { 3378 - CACKEY_DEBUG_PRINTF("Reset required, please hold..."); 3379 - 3380 - scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1); 3381 - if (scard_reconn_ret == SCARD_S_SUCCESS) { 3382 - /* Re-establish transaction, if it was present */ 3383 - if (slot->transaction_depth > 0) { 3384 - slot->transaction_depth--; 3385 - slot->transaction_need_hw_lock = 1; 3386 - cackey_begin_transaction(slot); 3387 - } 3388 - 3389 - CACKEY_DEBUG_PRINTF("Reset successful, requerying"); 3390 - status_ret = SCardStatus(slot->pcsc_card, NULL, &reader_len, &state, &protocol, atr, &atr_len); 3391 - if (status_ret != SCARD_S_SUCCESS) { 3392 - CACKEY_DEBUG_PRINTF("Still unable to query card status, returning token absent. SCardStatus() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(status_ret)); 3393 - 3394 - return(CACKEY_PCSC_E_TOKENABSENT); 3395 - } 3396 - } else { 3397 - CACKEY_DEBUG_PRINTF("Unable to reconnect to card, returning token absent. SCardReconnect() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_reconn_ret)); 3398 - 3399 - return(CACKEY_PCSC_E_TOKENABSENT); 3400 - } 3401 - } else { 3402 - CACKEY_DEBUG_PRINTF("Unable to query card status, returning token absent. SCardStatus() = %s", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(status_ret)); 3403 - 3404 - return(CACKEY_PCSC_E_TOKENABSENT); 3405 - } 3406 - } 3407 - 3408 - if ((state & SCARD_ABSENT) == SCARD_ABSENT) { 3409 - CACKEY_DEBUG_PRINTF("Card is absent, returning token absent"); 3410 - 3411 - return(CACKEY_PCSC_E_TOKENABSENT); 3412 - } 3413 - 3414 - CACKEY_DEBUG_PRINTF("Returning token present."); 3415 - 3416 - return(CACKEY_PCSC_S_TOKENPRESENT); 3417 -} 3418 - 3419 3453 /* 3420 3454 * SYNPOSIS 3421 3455 * ... 3422 3456 * 3423 3457 * ARGUMENTS 3424 3458 * ... 3425 3459 * ................................................................................ 5661 5695 return(CKR_PIN_INCORRECT); 5662 5696 } 5663 5697 5664 5698 pPin = (CK_UTF8CHAR_PTR) pinbuf; 5665 5699 ulPinLen = strlen(pinbuf); 5666 5700 } 5667 5701 5668 - login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining); 5702 + login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining, 3); 5669 5703 if (login_ret != CACKEY_PCSC_S_OK) { 5670 5704 if (lock_mutex) { 5671 5705 cackey_mutex_unlock(cackey_biglock); 5672 5706 } 5673 5707 5674 5708 if (login_ret == CACKEY_PCSC_E_LOCKED) { 5675 5709 CACKEY_DEBUG_PRINTF("Error. Token is locked.");