@@ -463,10 +463,12 @@ unsigned char *label; size_t certificate_len; unsigned char *certificate; + + ssize_t keysize; }; struct cackey_identity { struct cackey_pcsc_identity *pcsc_identity; @@ -1776,10 +1778,11 @@ outidx++; memcpy(curr_id->applet, curr_aid, sizeof(curr_id->applet)); curr_id->file = ccc_curr->value_cardurl->objectid; curr_id->label = NULL; + curr_id->keysize = -1; CACKEY_DEBUG_PRINTF("Filling curr_id->applet (%p) with %lu bytes:", curr_id->applet, (unsigned long) sizeof(curr_id->applet)); CACKEY_DEBUG_PRINTBUF("VAL:", curr_id->applet, sizeof(curr_id->applet)); curr_id->certificate_len = app_curr->length; @@ -1831,11 +1834,15 @@ * NOTES * ... * */ static ssize_t cackey_signdecrypt(struct cackey_slot *slot, struct cackey_identity *identity, unsigned char *buf, size_t buflen, unsigned char *outbuf, size_t outbuflen) { + unsigned char *tmpbuf, *tmpbuf_s; + unsigned char bytes_to_send, p1; cackey_ret send_ret; + size_t tmpbuflen, padlen; + int free_tmpbuf = 0; int le; CACKEY_DEBUG_PRINTF("Called."); if (buflen > 255) { @@ -1877,10 +1884,50 @@ if (identity->pcsc_identity == NULL) { CACKEY_DEBUG_PRINTF("Error. identity->pcsc_identity is NULL"); return(-1); } + + /* Determine identity Key size */ + if (identity->pcsc_identity->keysize < 0) { + identity->pcsc_identity->keysize = x509_to_keysize(identity->pcsc_identity->certificate, identity->pcsc_identity->certificate_len); + } + + /* Pad message to key size */ + if (identity->pcsc_identity->keysize > 0) { + if (buflen != identity->pcsc_identity->keysize) { + if (buflen > (identity->pcsc_identity->keysize + 3)) { + CACKEY_DEBUG_PRINTF("Error. Message is too large to sign/decrypt"); + + return(-1); + } + + tmpbuflen = identity->pcsc_identity->keysize; + tmpbuf = malloc(tmpbuflen); + free_tmpbuf = 1; + + padlen = tmpbuflen - buflen - 3; + + tmpbuf[0] = 0x00; + tmpbuf[1] = 0x01; + memset(&tmpbuf[2], 0xFF, padlen); + tmpbuf[padlen]= 0x00; + memcpy(&tmpbuf[padlen + 1], buf, buflen); + } else { + tmpbuf = buf; + tmpbuflen = buflen; + free_tmpbuf = 0; + padlen = 0; + } + } else { + CACKEY_DEBUG_PRINTF("Unable to determine key size, hoping the message is properly padded!"); + + tmpbuf = buf; + tmpbuflen = buflen; + free_tmpbuf = 0; + padlen = 0; + } /* Begin transaction */ cackey_begin_transaction(slot); /* Select correct applet */ @@ -1888,18 +1935,44 @@ cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet)); /* Select correct file */ cackey_select_file(slot, identity->pcsc_identity->file); - send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, 0x00, 0x00, buflen, buf, le, NULL, outbuf, &outbuflen); - if (send_ret != CACKEY_PCSC_S_OK) { - CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error."); - - /* End transaction */ - cackey_end_transaction(slot); - - return(-1); + tmpbuf_s = tmpbuf; + while (tmpbuflen) { + if (tmpbuflen > 245) { + bytes_to_send = 245; + p1 = 0x80; + } else { + bytes_to_send = tmpbuflen; + p1 = 0x00; + } + + send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, NULL, outbuf, &outbuflen); + 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); + + return(-1); + } + + tmpbuf += bytes_to_send; + tmpbuflen -= bytes_to_send; + } + + if (free_tmpbuf) { + if (tmpbuf_s) { + free(tmpbuf_s); + } } /* End transaction */ cackey_end_transaction(slot); @@ -2940,11 +3013,11 @@ if (sizeof(pInfo->manufacturerID) < bytes_to_copy) { bytes_to_copy = sizeof(pInfo->manufacturerID); } memcpy(pInfo->manufacturerID, cackey_slots[slotID].pcsc_reader, bytes_to_copy); - pInfo->flags = CKF_REMOVABLE_DEVICE; + pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT; if (cackey_token_present(&cackey_slots[slotID]) == CACKEY_PCSC_S_TOKENPRESENT) { pInfo->flags |= CKF_TOKEN_PRESENT; }