Overview
Comment: | Merged in changes from PIV |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: | 8ba93699b446465b1b1ce456b037b964eccedcc0 |
User & Date: | rkeene on 2014-03-14 14:30:03 |
Other Links: | manifest | tags |
Context
2014-03-18
| ||
04:33 | Updated to work with pclose() failures check-in: 42891ae8ca user: rkeene tags: trunk | |
2014-03-14
| ||
14:30 | Merged in changes from PIV check-in: 8ba93699b4 user: rkeene tags: trunk | |
14:25 | Updated to reset the card if a retry is required check-in: ad6536ceb0 user: rkeene tags: protected-auth-path | |
2014-01-17
| ||
13:35 | Work towards fixing listing of slots to not list redundant slots check-in: afd6df445d user: rkeene tags: trunk | |
Changes
Modified cackey.c from [6eb21adaf8] to [3de1a30e4b].
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 .... 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 .... 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 .... 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 .... 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 .... 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 .... 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 .... 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 .... 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 .... 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 .... 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 .... 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 .... 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 .... 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 .... 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 .... 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 |
if (slot->pcsc_card_connected) { SCardDisconnect(slot->pcsc_card, SCARD_LEAVE_CARD); } slot->slot_reset = 1; slot->pcsc_card_connected = 0; slot->token_flags = CKF_LOGIN_REQUIRED; CACKEY_DEBUG_PRINTF("Returning."); return; } /* * SYNPOSIS * LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol); * * ARGUMENTS * cackey_slot *slot * Slot to send commands to * * DWORD default_protocol * Protocol to attempt first * * LPDWORD selected_protocol * [OUT] Protocol selected * * RETURN VALUE * The return value from SCardReconnect() * * NOTES * This function is a wrapper around SCardReconnect() * * The SCardReconnect() function call will be called first with the * dwPreferredProtocols of "default_protocol". If that call returns * SCARD_E_PROTO_MISMATCH try again with a protocol of T=0, and failing * that T=1. * */ static LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol) { LONG scard_conn_ret; scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, default_protocol, SCARD_RESET_CARD, selected_protocol); if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0") scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, selected_protocol); if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1") scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, selected_protocol); } } return(scard_conn_ret); } /* * SYNPOSIS * cackey_ret cackey_connect_card(struct cackey_slot *slot); ................................................................................ if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1") scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol); } } scard_conn_ret = cackey_reconnect_card(slot, protocol, &protocol); } if (scard_conn_ret != SCARD_S_SUCCESS) { 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); return(CACKEY_PCSC_E_GENERIC); } ................................................................................ * goes away. * */ static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) { uint8_t major_rc, minor_rc; size_t bytes_to_copy, tmp_respdata_len; LPCSCARD_IO_REQUEST pioSendPci; DWORD protocol; DWORD xmit_len, recv_len; LONG scard_xmit_ret, scard_reconn_ret; BYTE xmit_buf[1024], recv_buf[1024]; int pcsc_connect_ret, pcsc_getresp_ret; int idx; CACKEY_DEBUG_PRINTF("Called."); ................................................................................ if (scard_xmit_ret == SCARD_E_NOT_TRANSACTED) { CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx), will ask calling function to retry (not resetting card)...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret); /* Begin Smartcard Transaction */ cackey_end_transaction(slot); return(CACKEY_PCSC_E_RETRY); } if (scard_xmit_ret != SCARD_S_SUCCESS) { 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); CACKEY_DEBUG_PRINTF("Marking slot as having been reset"); cackey_mark_slot_reset(slot); if (scard_xmit_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol); if (scard_reconn_ret == SCARD_S_SUCCESS) { /* Update protocol */ slot->protocol = protocol; switch (slot->protocol) { case SCARD_PROTOCOL_T0: pioSendPci = SCARD_PCI_T0; break; case SCARD_PROTOCOL_T1: pioSendPci = SCARD_PCI_T1; ................................................................................ send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->card.piv.key_id, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen); break; case CACKEY_ID_TYPE_CERT_ONLY: break; } if (send_ret != CACKEY_PCSC_S_OK) { CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error."); if (free_tmpbuf) { if (tmpbuf_s) { free(tmpbuf_s); } } /* End transaction */ cackey_end_transaction(slot); if (respcode == 0x6982 || respcode == 0x6e00) { CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x). Returning NEEDLOGIN", (int) respcode); cackey_mark_slot_reset(slot); return(CACKEY_PCSC_E_NEEDLOGIN); } if (respcode == 0x6E00) { CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting"); ................................................................................ if (status_ret != SCARD_S_SUCCESS) { cackey_mark_slot_reset(slot); if (status_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol); if (scard_reconn_ret == SCARD_S_SUCCESS) { /* Update protocol */ slot->protocol = protocol; /* Re-establish transaction, if it was present */ if (slot->transaction_depth > 0) { slot->transaction_depth--; slot->transaction_need_hw_lock = 1; cackey_begin_transaction(slot); } ................................................................................ if (slot_reset) { cackey_slots[currslot].active = 1; cackey_slots[currslot].internal = 0; cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers); cackey_slots[currslot].pcsc_card_connected = 0; cackey_slots[currslot].transaction_depth = 0; cackey_slots[currslot].transaction_need_hw_lock = 0; cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED; cackey_slots[currslot].label = NULL; cackey_mark_slot_reset(&cackey_slots[currslot]); } } else { if (!cackey_slots[currslot].active) { /* Artificially increase the number of active slots by what will become active */ ................................................................................ } CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); return(CKR_FUNCTION_NOT_SUPPORTED); } CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_SLOT_ID slotID; FILE *pinfd; char *pincmd, pinbuf[64], *fgets_ret; int mutex_retval; int tries_remaining; int login_ret; int pclose_ret; ................................................................................ if (userType != CKU_USER) { CACKEY_DEBUG_PRINTF("Error. We only support USER mode, asked for %lu mode.", (unsigned long) userType) return(CKR_USER_TYPE_INVALID); } mutex_retval = cackey_mutex_lock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Locking failed."); return(CKR_GENERAL_ERROR); } if (!cackey_sessions[hSession].active) { cackey_mutex_unlock(cackey_biglock); CACKEY_DEBUG_PRINTF("Error. Session not active."); return(CKR_SESSION_HANDLE_INVALID); } slotID = cackey_sessions[hSession].slotID; if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) { CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID); return(CKR_GENERAL_ERROR); } if (cackey_slots[slotID].active == 0) { CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); cackey_mutex_unlock(cackey_biglock); return(CKR_GENERAL_ERROR); } pincmd = cackey_pin_command; if (pincmd != NULL) { CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd); ................................................................................ CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?"); } pinfd = popen(pincmd, "r"); if (pinfd == NULL) { CACKEY_DEBUG_PRINTF("Error. %s: Unable to run", pincmd); cackey_mutex_unlock(cackey_biglock); CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd); ................................................................................ pinbuf[0] = '\0'; } pclose_ret = pclose(pinfd); if (pclose_ret != 0) { CACKEY_DEBUG_PRINTF("Error. %s: exited with non-zero status of %i", pincmd, pclose_ret); cackey_mutex_unlock(cackey_biglock); CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } if (strlen(pinbuf) < 1) { CACKEY_DEBUG_PRINTF("Error. %s: returned no data", pincmd); cackey_mutex_unlock(cackey_biglock); CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } if (pinbuf[strlen(pinbuf) - 1] == '\n') { ................................................................................ pPin = (CK_UTF8CHAR_PTR) pinbuf; ulPinLen = strlen(pinbuf); } login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining); if (login_ret != CACKEY_PCSC_S_OK) { cackey_mutex_unlock(cackey_biglock); if (login_ret == CACKEY_PCSC_E_LOCKED) { CACKEY_DEBUG_PRINTF("Error. Token is locked."); cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED; CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED); ................................................................................ return(CKR_GENERAL_ERROR); } cackey_slots[slotID].token_flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_COUNT_LOW | CKF_LOGIN_REQUIRED | CKF_USER_PIN_FINAL_TRY); cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS; mutex_retval = cackey_mutex_unlock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); return(CKR_GENERAL_ERROR); } CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); } CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) { CK_SLOT_ID slotID; int mutex_retval; CACKEY_DEBUG_PRINTF("Called."); ................................................................................ cackey_mutex_unlock(cackey_biglock); return(CKR_GENERAL_ERROR); } cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION; cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED; mutex_retval = cackey_mutex_unlock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); return(CKR_GENERAL_ERROR); } ................................................................................ return(CKR_GENERAL_ERROR); } switch (cackey_sessions[hSession].decrypt_mechanism) { case CKM_RSA_PKCS: /* Ask card to decrypt */ buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1); if (buflen < 0) { /* Decryption failed. */ if (buflen == CACKEY_PCSC_E_NEEDLOGIN) { retval = CKR_USER_NOT_LOGGED_IN; } else if (buflen == CACKEY_PCSC_E_TOKENABSENT) { retval = CKR_DEVICE_REMOVED; } else { retval = CKR_GENERAL_ERROR; } } else if (((unsigned long) buflen) > *pulPartLen && pPart) { /* Decrypted data too large */ retval = CKR_BUFFER_TOO_SMALL; } else { if (pPart) { ................................................................................ } switch (cackey_sessions[hSession].sign_mechanism) { case CKM_RSA_PKCS: /* Ask card to sign */ CACKEY_DEBUG_PRINTF("Asking to sign from identity %p in session %lu", (void *) cackey_sessions[hSession].sign_identity, (unsigned long) hSession); sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0); if (sigbuflen < 0) { /* Signing failed. */ if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN) { retval = CKR_USER_NOT_LOGGED_IN; } else if (sigbuflen == CACKEY_PCSC_E_TOKENABSENT) { retval = CKR_DEVICE_REMOVED; |
> | > > > | < < < | > > > | | | > > > > | < > > | < < < < > > > > > > > > > > > | | > > > | < < < > | > > > | > | | | | > > | > > > > > > | > > | > > | > > | > > | > > | | | | > > > > > > > | > > > > > > > > > > > > > > > > > |
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 .... 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 .... 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 .... 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 .... 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 .... 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 .... 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 .... 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 .... 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 .... 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 .... 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 .... 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 .... 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 .... 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 .... 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 .... 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 |
if (slot->pcsc_card_connected) { SCardDisconnect(slot->pcsc_card, SCARD_LEAVE_CARD); } slot->slot_reset = 1; slot->pcsc_card_connected = 0; if (cackey_pin_command == NULL) { slot->token_flags = CKF_LOGIN_REQUIRED; } else { slot->token_flags = 0; } CACKEY_DEBUG_PRINTF("Returning."); return; } /* * SYNPOSIS * LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol); * * ARGUMENTS * cackey_slot *slot * Slot to send commands to * * DWORD default_protocol * Protocol to attempt first * * RETURN VALUE * The return value from SCardReconnect() * * NOTES * This function is a wrapper around SCardReconnect() * * The SCardReconnect() function call will be called first with the * dwPreferredProtocols of "default_protocol". If that call returns * SCARD_E_PROTO_MISMATCH try again with a protocol of T=0, and failing * that T=1. * */ static LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol) { DWORD selected_protocol; LONG scard_conn_ret; selected_protocol = 0; scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, default_protocol, SCARD_RESET_CARD, &selected_protocol); if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0") scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &selected_protocol); if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1") scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &selected_protocol); } } if (scard_conn_ret == SCARD_S_SUCCESS) { slot->protocol = selected_protocol; } return(scard_conn_ret); } /* * SYNPOSIS * cackey_ret cackey_connect_card(struct cackey_slot *slot); ................................................................................ if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) { CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1") scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol); } } scard_conn_ret = cackey_reconnect_card(slot, protocol); } if (scard_conn_ret != SCARD_S_SUCCESS) { 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); return(CACKEY_PCSC_E_GENERIC); } ................................................................................ * goes away. * */ static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) { uint8_t major_rc, minor_rc; size_t bytes_to_copy, tmp_respdata_len; LPCSCARD_IO_REQUEST pioSendPci; DWORD xmit_len, recv_len; LONG scard_xmit_ret, scard_reconn_ret; BYTE xmit_buf[1024], recv_buf[1024]; int pcsc_connect_ret, pcsc_getresp_ret; int idx; CACKEY_DEBUG_PRINTF("Called."); ................................................................................ if (scard_xmit_ret == SCARD_E_NOT_TRANSACTED) { CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx), will ask calling function to retry (not resetting card)...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret); /* Begin Smartcard Transaction */ cackey_end_transaction(slot); cackey_reconnect_card(slot, slot->protocol); return(CACKEY_PCSC_E_RETRY); } if (scard_xmit_ret != SCARD_S_SUCCESS) { 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); CACKEY_DEBUG_PRINTF("Marking slot as having been reset"); cackey_mark_slot_reset(slot); if (scard_xmit_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1); if (scard_reconn_ret == SCARD_S_SUCCESS) { switch (slot->protocol) { case SCARD_PROTOCOL_T0: pioSendPci = SCARD_PCI_T0; break; case SCARD_PROTOCOL_T1: pioSendPci = SCARD_PCI_T1; ................................................................................ send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->card.piv.key_id, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen); break; case CACKEY_ID_TYPE_CERT_ONLY: break; } if (send_ret != CACKEY_PCSC_S_OK) { if (free_tmpbuf) { if (tmpbuf_s) { free(tmpbuf_s); } } /* End transaction */ cackey_end_transaction(slot); if (send_ret == CACKEY_PCSC_E_RETRY) { CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- retrying."); return(cackey_signdecrypt(slot, identity, buf, buflen, outbuf, outbuflen, padInput, unpadOutput)); } CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error."); if (respcode == 0x6982 || respcode == 0x6e00) { if (respcode == 0x6E00) { CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting"); } else { CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x). Returning NEEDLOGIN", (int) respcode); } cackey_mark_slot_reset(slot); slot->token_flags = CKF_LOGIN_REQUIRED; return(CACKEY_PCSC_E_NEEDLOGIN); } if (respcode == 0x6E00) { CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting"); ................................................................................ if (status_ret != SCARD_S_SUCCESS) { cackey_mark_slot_reset(slot); if (status_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1); if (scard_reconn_ret == SCARD_S_SUCCESS) { /* Re-establish transaction, if it was present */ if (slot->transaction_depth > 0) { slot->transaction_depth--; slot->transaction_need_hw_lock = 1; cackey_begin_transaction(slot); } ................................................................................ if (slot_reset) { cackey_slots[currslot].active = 1; cackey_slots[currslot].internal = 0; cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers); cackey_slots[currslot].pcsc_card_connected = 0; cackey_slots[currslot].transaction_depth = 0; cackey_slots[currslot].transaction_need_hw_lock = 0; if (cackey_pin_command == NULL) { cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED; } else { cackey_slots[currslot].token_flags = 0; } cackey_slots[currslot].label = NULL; cackey_mark_slot_reset(&cackey_slots[currslot]); } } else { if (!cackey_slots[currslot].active) { /* Artificially increase the number of active slots by what will become active */ ................................................................................ } CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED); return(CKR_FUNCTION_NOT_SUPPORTED); } CK_DEFINE_FUNCTION(CK_RV, _C_LoginMutexArg)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, int lock_mutex) { CK_SLOT_ID slotID; FILE *pinfd; char *pincmd, pinbuf[64], *fgets_ret; int mutex_retval; int tries_remaining; int login_ret; int pclose_ret; ................................................................................ if (userType != CKU_USER) { CACKEY_DEBUG_PRINTF("Error. We only support USER mode, asked for %lu mode.", (unsigned long) userType) return(CKR_USER_TYPE_INVALID); } if (lock_mutex) { mutex_retval = cackey_mutex_lock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Locking failed."); return(CKR_GENERAL_ERROR); } } if (!cackey_sessions[hSession].active) { if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } CACKEY_DEBUG_PRINTF("Error. Session not active."); return(CKR_SESSION_HANDLE_INVALID); } slotID = cackey_sessions[hSession].slotID; if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) { CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID); if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } return(CKR_GENERAL_ERROR); } if (cackey_slots[slotID].active == 0) { CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } return(CKR_GENERAL_ERROR); } pincmd = cackey_pin_command; if (pincmd != NULL) { CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd); ................................................................................ CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?"); } pinfd = popen(pincmd, "r"); if (pinfd == NULL) { CACKEY_DEBUG_PRINTF("Error. %s: Unable to run", pincmd); if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd); ................................................................................ pinbuf[0] = '\0'; } pclose_ret = pclose(pinfd); if (pclose_ret != 0) { CACKEY_DEBUG_PRINTF("Error. %s: exited with non-zero status of %i", pincmd, pclose_ret); if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } if (strlen(pinbuf) < 1) { CACKEY_DEBUG_PRINTF("Error. %s: returned no data", pincmd); if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } if (pinbuf[strlen(pinbuf) - 1] == '\n') { ................................................................................ pPin = (CK_UTF8CHAR_PTR) pinbuf; ulPinLen = strlen(pinbuf); } login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining); if (login_ret != CACKEY_PCSC_S_OK) { if (lock_mutex) { cackey_mutex_unlock(cackey_biglock); } if (login_ret == CACKEY_PCSC_E_LOCKED) { CACKEY_DEBUG_PRINTF("Error. Token is locked."); cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED; CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED); ................................................................................ return(CKR_GENERAL_ERROR); } cackey_slots[slotID].token_flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_COUNT_LOW | CKF_LOGIN_REQUIRED | CKF_USER_PIN_FINAL_TRY); cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS; if (lock_mutex) { mutex_retval = cackey_mutex_unlock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); return(CKR_GENERAL_ERROR); } } CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); } CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { return(_C_LoginMutexArg(hSession, userType, pPin, ulPinLen, 1)); } CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) { CK_SLOT_ID slotID; int mutex_retval; CACKEY_DEBUG_PRINTF("Called."); ................................................................................ cackey_mutex_unlock(cackey_biglock); return(CKR_GENERAL_ERROR); } cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION; if (cackey_pin_command == NULL) { cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED; } else { cackey_slots[slotID].token_flags = 0; } mutex_retval = cackey_mutex_unlock(cackey_biglock); if (mutex_retval != 0) { CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); return(CKR_GENERAL_ERROR); } ................................................................................ return(CKR_GENERAL_ERROR); } switch (cackey_sessions[hSession].decrypt_mechanism) { case CKM_RSA_PKCS: /* Ask card to decrypt */ buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1); if (buflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) { if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) { buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1); } } if (buflen < 0) { /* Decryption failed. */ if (buflen == CACKEY_PCSC_E_NEEDLOGIN) { retval = CKR_USER_NOT_LOGGED_IN; } else if (buflen == CACKEY_PCSC_E_TOKENABSENT) { retval = CKR_DEVICE_REMOVED; } else { CACKEY_DEBUG_PRINTF("Failed to send APDU, error = %li", (long int) buflen); retval = CKR_GENERAL_ERROR; } } else if (((unsigned long) buflen) > *pulPartLen && pPart) { /* Decrypted data too large */ retval = CKR_BUFFER_TOO_SMALL; } else { if (pPart) { ................................................................................ } switch (cackey_sessions[hSession].sign_mechanism) { case CKM_RSA_PKCS: /* Ask card to sign */ CACKEY_DEBUG_PRINTF("Asking to sign from identity %p in session %lu", (void *) cackey_sessions[hSession].sign_identity, (unsigned long) hSession); sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0); if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) { if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) { sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0); } } if (sigbuflen < 0) { /* Signing failed. */ if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN) { retval = CKR_USER_NOT_LOGGED_IN; } else if (sigbuflen == CACKEY_PCSC_E_TOKENABSENT) { retval = CKR_DEVICE_REMOVED; |