Check-in [4e30511f94]
Overview
Comment:Updated to retry login if it fails with a 6D 00 (wrong instruction)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:4e30511f9408a58c2a5f592a670071454039a183
User & Date: rkeene on 2015-07-16 16:18:58
Other Links: manifest | tags
Context
2015-07-16
16:20
CACKey 0.7.4 check-in: 1adc8b9d33 user: rkeene tags: trunk, 0.7.4
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.");