Check-in [93bc06dab6]
Overview
Comment:Fixed retry on NOT_TRANSACTED to retry at a higher level

Consolidated all SCardReconnect calls into a wrapper that takes care of T=0 or T=1 selection

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:93bc06dab6eec10a99dacf3af520ba4edd5c0521
User & Date: rkeene on 2010-07-23 17:24:42
Other Links: manifest | tags
Context
2010-07-23
21:23
Added timing information to debug output

Fixed issue where readers that were removed and readded weren't connected to properly check-in: e4fd58cbb9 user: rkeene tags: trunk

17:24
Fixed retry on NOT_TRANSACTED to retry at a higher level

Consolidated all SCardReconnect calls into a wrapper that takes care of T=0 or T=1 selection check-in: 93bc06dab6 user: rkeene tags: trunk

09:08
Fixed bug with selecting between T=0 and T=1 protocol and card going to sleep

Fixed bug with soft-transactions

Updated soft-transactions to re-lock hardware card if possible check-in: 9b04a062cc user: rkeene tags: trunk

Changes

Modified cackey.c from [4c31fc86bf] to [5f33c366a8].

   571    571   typedef enum {
   572    572   	CACKEY_PCSC_S_TOKENPRESENT    = 1,
   573    573   	CACKEY_PCSC_S_OK              = 0,
   574    574   	CACKEY_PCSC_E_GENERIC         = -1,
   575    575   	CACKEY_PCSC_E_BADPIN          = -2,
   576    576   	CACKEY_PCSC_E_LOCKED          = -3,
   577    577   	CACKEY_PCSC_E_NEEDLOGIN       = -4,
   578         -	CACKEY_PCSC_E_TOKENABSENT     = -6
          578  +	CACKEY_PCSC_E_TOKENABSENT     = -6,
          579  +	CACKEY_PCSC_E_RETRY           = -7
   579    580   } cackey_ret;
   580    581   
   581    582   struct cackey_tlv_cardurl {
   582    583   	unsigned char        rid[5];
   583    584   	cackey_tlv_apptype   apptype;
   584    585   	cackey_tlv_objectid  objectid;
   585    586   	cackey_tlv_objectid  appid;
................................................................................
   806    807   
   807    808   	if (scard_rel_context_ret != SCARD_S_SUCCESS) {
   808    809   		return(CACKEY_PCSC_E_GENERIC);
   809    810   	}
   810    811   
   811    812   	return(CACKEY_PCSC_S_OK);
   812    813   }
          814  +
          815  +/*
          816  + * SYNPOSIS
          817  + *     LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol);
          818  + *
          819  + * ARGUMENTS
          820  + *     cackey_slot *slot
          821  + *         Slot to send commands to
          822  + *
          823  + *     DWORD default_protocol
          824  + *         Protocol to attempt first
          825  + *
          826  + *     LPDWORD selected_protocol
          827  + *         [OUT] Protocol selected
          828  + *
          829  + * RETURN VALUE
          830  + *     The return value from SCardReconnect()
          831  + *
          832  + * NOTES
          833  + *     This function is a wrapper around SCardReconnect()
          834  + *
          835  + *     The SCardReconnect() function call will be called first with the
          836  + *     dwPreferredProtocols of "default_protocol".  If that call returns
          837  + *     SCARD_E_PROTO_MISMATCH try again with a protocol of T=0, and failing
          838  + *     that T=1.
          839  + *
          840  + */
          841  +static LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol) {
          842  +	LONG scard_conn_ret;
          843  +
          844  +	scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, default_protocol, SCARD_RESET_CARD, selected_protocol);
          845  +
          846  +	if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
          847  +		CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0")
          848  +		scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, selected_protocol);
          849  +
          850  +		if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
          851  +			CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1")
          852  +			scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, selected_protocol);
          853  +		}
          854  +	}
          855  +
          856  +	return(scard_conn_ret);
          857  +}
   813    858   
   814    859   /*
   815    860    * SYNPOSIS
   816    861    *     cackey_ret cackey_connect_card(struct cackey_slot *slot);
   817    862    *
   818    863    * ARGUMENTS
   819    864    *     cackey_slot *slot
................................................................................
   875    920   
   876    921   				if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
   877    922   					CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1")
   878    923   					scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol);
   879    924   				}
   880    925   			}
   881    926   
   882         -			scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, protocol, SCARD_RESET_CARD, &protocol);
   883         -
   884         -			if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
   885         -				CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0")
   886         -				scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &protocol);
   887         -
   888         -				if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
   889         -					CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1")
   890         -					scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &protocol);
   891         -				}
   892         -			}
   893         -
          927  +			scard_conn_ret = cackey_reconnect_card(slot, protocol, &protocol);
   894    928   		}
   895    929   
   896    930   		if (scard_conn_ret != SCARD_S_SUCCESS) {
   897    931   			CACKEY_DEBUG_PRINTF("Connection to card failed, returning in failure (SCardConnect() = %s/%li)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_conn_ret), (long) scard_conn_ret);
   898    932   
   899    933   			return(CACKEY_PCSC_E_GENERIC);
   900    934   		}
................................................................................
  1096   1130   	size_t bytes_to_copy, tmp_respdata_len;
  1097   1131   	LPCSCARD_IO_REQUEST pioSendPci;
  1098   1132   	DWORD protocol;
  1099   1133   	DWORD xmit_len, recv_len;
  1100   1134   	LONG scard_xmit_ret, scard_reconn_ret;
  1101   1135   	BYTE xmit_buf[1024], recv_buf[1024];
  1102   1136   	int pcsc_connect_ret, pcsc_getresp_ret;
  1103         -	int idx, retry;
         1137  +	int idx;
  1104   1138   
  1105   1139   	CACKEY_DEBUG_PRINTF("Called.");
  1106   1140   
  1107   1141   	if (!slot) {
  1108   1142   		CACKEY_DEBUG_PRINTF("Invalid slot specified.");
  1109   1143   
  1110   1144   		return(CACKEY_PCSC_E_GENERIC);
................................................................................
  1156   1190   	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00 && p2 == 0x00) {
  1157   1191   		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
  1158   1192   	} else {
  1159   1193   		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
  1160   1194   	}
  1161   1195   
  1162   1196   	recv_len = sizeof(recv_buf);
  1163         -	for (retry = 0; retry < 10; retry++) {
  1164         -		CACKEY_DEBUG_PRINTF("Calling SCardTransmit()");
  1165   1197   		scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
  1166   1198   
  1167   1199   		if (scard_xmit_ret == SCARD_E_NOT_TRANSACTED) {
  1168         -			CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx), will retry...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);
  1169         -		} else {
  1170         -			break;
  1171         -		}
         1200  +		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx), will ask calling function to retry...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);
         1201  +
         1202  +		/* Begin Smartcard Transaction */
         1203  +		cackey_end_transaction(slot);
         1204  +
         1205  +		return(CACKEY_PCSC_E_RETRY);
  1172   1206   	}
  1173   1207   
  1174   1208   	if (scard_xmit_ret != SCARD_S_SUCCESS) {
  1175   1209   		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);
  1176   1210   
  1177   1211   		CACKEY_DEBUG_PRINTF("Marking slot as having been reset");
  1178   1212   		slot->slot_reset = 1;
  1179   1213   
  1180   1214   		if (scard_xmit_ret == SCARD_W_RESET_CARD) {
  1181   1215   			CACKEY_DEBUG_PRINTF("Reset required, please hold...");
  1182   1216   
  1183         -			scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &protocol);
         1217  +			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol);
         1218  +
  1184   1219   			if (scard_reconn_ret == SCARD_S_SUCCESS) {
  1185   1220   				/* Update protocol */
  1186   1221   				slot->protocol = protocol;
  1187   1222   				switch (slot->protocol) {
  1188   1223   					case SCARD_PROTOCOL_T0:
  1189   1224   						pioSendPci = SCARD_PCI_T0;
  1190   1225   
................................................................................
  1302   1337   		CACKEY_DEBUG_PRINTF("Buffer read required");
  1303   1338   
  1304   1339   		if (minor_rc == 0x00) {
  1305   1340   			minor_rc = CACKEY_APDU_MTU;
  1306   1341   		}
  1307   1342   
  1308   1343   		pcsc_getresp_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_GET_RESPONSE, 0x00, 0x00, 0, NULL, minor_rc, respcode, respdata, &tmp_respdata_len);
         1344  +
  1309   1345   		if (pcsc_getresp_ret != CACKEY_PCSC_S_OK) {
  1310   1346   			CACKEY_DEBUG_PRINTF("Buffer read failed!  Returning in failure");
  1311   1347   
  1312   1348   			/* End Smartcard Transaction */
  1313   1349   			cackey_end_transaction(slot);
         1350  +
         1351  +			if (pcsc_getresp_ret == CACKEY_PCSC_E_RETRY) {
         1352  +				return(CACKEY_PCSC_E_RETRY);
         1353  +			}
  1314   1354   
  1315   1355   			return(CACKEY_PCSC_E_GENERIC);
  1316   1356   		}
  1317   1357   
  1318   1358   		if (respdata_len) {
  1319   1359   			*respdata_len += tmp_respdata_len;
  1320   1360   		}
................................................................................
  1367   1407    *     This function returns the number of bytes actually read, or -1 on error.
  1368   1408    *
  1369   1409    * NOTES
  1370   1410    *     None
  1371   1411    *
  1372   1412    */
  1373   1413   static ssize_t cackey_read_buffer(struct cackey_slot *slot, unsigned char *buffer, size_t count, unsigned char t_or_v, size_t initial_offset) {
         1414  +	unsigned char *init_buffer;
         1415  +	size_t init_count;
         1416  +	size_t init_initial_offset;
         1417  +
  1374   1418   	size_t offset = 0, max_offset, max_count;
  1375   1419   	unsigned char cmd[2];
  1376   1420   	uint16_t respcode;
  1377   1421   	int send_ret;
  1378   1422   
  1379   1423   	CACKEY_DEBUG_PRINTF("Called.");
  1380   1424   
         1425  +	init_buffer = buffer;
         1426  +	init_count = count;
         1427  +	init_initial_offset = initial_offset;
         1428  +
  1381   1429   	max_offset = count;
  1382   1430   	max_count = CACKEY_APDU_MTU;
  1383   1431   
  1384   1432   	if (t_or_v != 1 && t_or_v != 2) {
  1385   1433   		CACKEY_DEBUG_PRINTF("Invalid T or V parameter specified, returning in failure");
  1386   1434   
  1387   1435   		return(-1);
................................................................................
  1400   1448   		if (count > max_count) {
  1401   1449   			count = max_count;
  1402   1450   		}
  1403   1451   
  1404   1452   		cmd[1] = count;
  1405   1453   
  1406   1454   		send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_READ_BUFFER, ((initial_offset + offset) >> 8) & 0xff, (initial_offset + offset) & 0xff, sizeof(cmd), cmd, 0x00, &respcode, buffer + offset, &count);
         1455  +
         1456  +		if (send_ret == CACKEY_PCSC_E_RETRY) {
         1457  +			CACKEY_DEBUG_PRINTF("ADPU Sending failed, retrying read buffer");
         1458  +
         1459  +			return(cackey_read_buffer(slot, init_buffer, init_count, t_or_v, init_initial_offset));
         1460  +		}
         1461  +
  1407   1462   		if (send_ret != CACKEY_PCSC_S_OK) {
  1408   1463   			if (respcode == 0x6A86) {
  1409   1464   				if (max_count == 1) {
  1410   1465   					break;
  1411   1466   				}
  1412   1467   
  1413   1468   				max_count = max_count / 2;
................................................................................
  1470   1525   	int send_ret;
  1471   1526   
  1472   1527   	CACKEY_DEBUG_PRINTF("Called.");
  1473   1528   
  1474   1529   	CACKEY_DEBUG_PRINTBUF("Selecting applet:", aid, aid_len);
  1475   1530   
  1476   1531   	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_SELECT, GSCIS_PARAM_SELECT_APPLET, 0x00, aid_len, aid, 0x00, NULL, NULL, NULL);
         1532  +
         1533  +	if (send_ret == CACKEY_PCSC_E_RETRY) {
         1534  +		CACKEY_DEBUG_PRINTF("ADPU Sending failed, retrying select applet");
         1535  +
         1536  +		return(cackey_select_applet(slot, aid, aid_len));
         1537  +	}
         1538  +
  1477   1539   	if (send_ret != CACKEY_PCSC_S_OK) {
  1478   1540   		CACKEY_DEBUG_PRINTF("Failed to open applet, returning in failure");
  1479   1541   
  1480   1542   		return(CACKEY_PCSC_E_GENERIC);
  1481   1543   	}
  1482   1544   
  1483   1545   	CACKEY_DEBUG_PRINTF("Successfully selected file");
................................................................................
  2331   2393   	if (status_ret != SCARD_S_SUCCESS) {
  2332   2394   		slot->slot_reset = 1;
  2333   2395   		slot->token_flags = CKF_LOGIN_REQUIRED;
  2334   2396   
  2335   2397   		if (status_ret == SCARD_W_RESET_CARD) {
  2336   2398   			CACKEY_DEBUG_PRINTF("Reset required, please hold...");
  2337   2399   
  2338         -			scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &protocol);
         2400  +			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol);
  2339   2401   			if (scard_reconn_ret == SCARD_S_SUCCESS) {
  2340   2402   				/* Update protocol */
  2341   2403   				slot->protocol = protocol;
  2342   2404   
  2343   2405   				/* Re-establish transaction, if it was present */
  2344   2406   				if (slot->transaction_depth > 0) {
  2345   2407   					slot->transaction_depth--;