Index: asn1-x509.c ================================================================== --- asn1-x509.c +++ asn1-x509.c @@ -41,11 +41,15 @@ struct asn1_object serial_number; struct asn1_object signature_algo; struct asn1_object issuer; struct asn1_object validity; struct asn1_object subject; - struct asn1_object signature; + struct asn1_object pubkeyinfo; + struct asn1_object pubkey_algoid; + struct asn1_object pubkey_algo; + struct asn1_object pubkey_algoparm; + struct asn1_object pubkey; }; static int _asn1_x509_read_asn1_object(unsigned char *buf, size_t buflen, va_list *args) { unsigned char small_object_size; unsigned char *buf_p; @@ -67,10 +71,15 @@ buf_p++; buflen--; if (buflen == 0) { return(-1); } + + /* NULL Tag -- no size is required */ + if (outbuf->tag == 0x00) { + return(_asn1_x509_read_asn1_object(buf_p, buflen, args)); + } small_object_size = *buf_p; buf_p++; buflen--; if (buflen == 0) { @@ -132,11 +141,16 @@ read_ret = asn1_x509_read_asn1_object(outbuf->wholething.contents, outbuf->wholething.size, &outbuf->certificate, NULL); if (read_ret != 0) { return(-1); } - read_ret = asn1_x509_read_asn1_object(outbuf->certificate.contents, outbuf->certificate.size, &outbuf->version, &outbuf->serial_number, &outbuf->signature_algo, &outbuf->issuer, &outbuf->validity, &outbuf->subject, NULL); + read_ret = asn1_x509_read_asn1_object(outbuf->certificate.contents, outbuf->certificate.size, &outbuf->version, &outbuf->serial_number, &outbuf->signature_algo, &outbuf->issuer, &outbuf->validity, &outbuf->subject, &outbuf->pubkeyinfo, NULL); + if (read_ret != 0) { + return(-1); + } + + read_ret = asn1_x509_read_asn1_object(outbuf->pubkeyinfo.contents, outbuf->pubkeyinfo.size, &outbuf->pubkey_algoid, &outbuf->pubkey, NULL); if (read_ret != 0) { return(-1); } return(0); @@ -187,10 +201,34 @@ *outbuf = x509.serial_number.asn1rep; } return(x509.serial_number.asn1rep_len); } + +ssize_t x509_to_keysize(void *x509_der_buf, size_t x509_der_buf_len) { + struct asn1_object null, pubkey, modulus, exponent; + struct x509_object x509; + int read_ret; + + read_ret = asn1_x509_read_object(x509_der_buf, x509_der_buf_len, &x509); + if (read_ret != 0) { + return(-1); + } + + /* The structure of "pubkey" is specified in PKCS #1 */ + read_ret = asn1_x509_read_asn1_object(x509.pubkey.contents, x509.pubkey.size, &null, &pubkey, NULL); + if (read_ret != 0) { + return(-1); + } + + read_ret = asn1_x509_read_asn1_object(pubkey.contents, pubkey.size, &modulus, &exponent, NULL); + if (read_ret != 0) { + return(-1); + } + + return(modulus.size - 1); +} /* * http://www.blackberry.com/developers/docs/4.6.0api/javax/microedition/pki/Certificate.html */ static const char *_x509_objectid_to_label_string(void *buf, size_t buflen) { Index: asn1-x509.h ================================================================== --- asn1-x509.h +++ asn1-x509.h @@ -13,9 +13,11 @@ ssize_t x509_to_subject(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf); ssize_t x509_to_issuer(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf); ssize_t x509_to_serial(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf); + +ssize_t x509_to_keysize(void *x509_der_buf, size_t x509_der_buf_len); ssize_t x509_dn_to_string(void *asn1_der_buf, size_t asn1_der_buf_len, char *outbuf, size_t outbuf_len, char *matchlabel); #endif Index: cackey.c ================================================================== --- cackey.c +++ cackey.c @@ -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; }