Index: asn1-x509.c ================================================================== --- asn1-x509.c +++ asn1-x509.c @@ -201,10 +201,66 @@ *outbuf = x509.serial_number.asn1rep; } return(x509.serial_number.asn1rep_len); } + +ssize_t x509_to_modulus(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { + 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); + } + + if (outbuf) { + *outbuf = modulus.contents; + } + + return(modulus.size); +} + +ssize_t x509_to_exponent(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { + 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); + } + + if (outbuf) { + *outbuf = exponent.contents; + } + + return(exponent.size); +} 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; Index: asn1-x509.h ================================================================== --- asn1-x509.h +++ asn1-x509.h @@ -14,10 +14,14 @@ 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_modulus(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf); + +ssize_t x509_to_exponent(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 @@ -27,10 +27,13 @@ # include #endif #ifdef HAVE_LIMITS_H # include #endif +#ifdef HAVE_STDIO_H +# include +#endif #ifdef HAVE_ZLIB_H # ifdef HAVE_LIBZ # include # endif #else @@ -156,13 +159,10 @@ /** Applet IDs **/ #define GSCIS_AID_CCC 0xA0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00 #ifdef CACKEY_DEBUG -# ifdef HAVE_STDIO_H -# include -# endif # define CACKEY_DEBUG_PRINTF(x...) { fprintf(stderr, "%s():%i: ", __func__, __LINE__); fprintf(stderr, x); fprintf(stderr, "\n"); fflush(stderr); } # define CACKEY_DEBUG_PRINTBUF(f, x, y) { unsigned char *TMPBUF; unsigned long idx; TMPBUF = (unsigned char *) (x); fprintf(stderr, "%s():%i: %s (%s/%lu = {%02x", __func__, __LINE__, f, #x, (unsigned long) (y), TMPBUF[0]); for (idx = 1; idx < (y); idx++) { fprintf(stderr, ", %02x", TMPBUF[idx]); }; fprintf(stderr, "})\n"); fflush(stderr); } # define CACKEY_DEBUG_PERROR(x) { fprintf(stderr, "%s():%i: ", __func__, __LINE__); perror(x); fflush(stderr); } # define free(x) { CACKEY_DEBUG_PRINTF("FREE(%p) (%s)", x, #x); free(x); } @@ -1848,28 +1848,22 @@ * 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, int padInput, int unpadOutput) { - unsigned char *tmpbuf, *tmpbuf_s; + unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s; unsigned char bytes_to_send, p1; unsigned char blocktype; cackey_ret send_ret; uint16_t respcode; ssize_t retval = 0, unpadoffset; size_t tmpbuflen, padlen, tmpoutbuflen; - int free_tmpbuf = 0, sepByte = -1; + int free_tmpbuf = 0; int le; CACKEY_DEBUG_PRINTF("Called."); - if (buflen > 255) { - CACKEY_DEBUG_PRINTF("Error. buflen is greater than 255 (buflen = %lu)", (unsigned long) buflen); - - return(-1); - } - if (slot == NULL) { CACKEY_DEBUG_PRINTF("Error. slot is NULL"); return(-1); } @@ -1917,10 +1911,11 @@ tmpbuf = malloc(tmpbuflen); free_tmpbuf = 1; padlen = tmpbuflen - buflen - 3; + /* RSA PKCS#1 EMSA-PKCS1-v1_5 Padding */ tmpbuf[0] = 0x00; tmpbuf[1] = 0x01; memset(&tmpbuf[2], 0xFF, padlen); tmpbuf[padlen + 2]= 0x00; memcpy(&tmpbuf[padlen + 3], buf, buflen); @@ -1957,10 +1952,11 @@ /* Select correct file */ cackey_select_file(slot, identity->pcsc_identity->file); tmpbuf_s = tmpbuf; + outbuf_s = outbuf; while (tmpbuflen) { if (tmpbuflen > 245) { bytes_to_send = 245; p1 = 0x80; le = 0x00; @@ -2003,10 +1999,12 @@ if (free_tmpbuf) { if (tmpbuf_s) { free(tmpbuf_s); } } + + outbuf = outbuf_s; /* End transaction */ cackey_end_transaction(slot); #ifdef CACKEY_PARANOID @@ -2019,31 +2017,39 @@ # endif #endif /* Unpad reply */ if (unpadOutput) { - if (retval < 2) { + if (retval < 3) { CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!"); + CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval); + return(retval); + } + + if (outbuf[0] != 0x00) { + CACKEY_DEBUG_PRINTF("Unrecognized padding scheme -- passing back and hoping for the best!"); + + CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval); return(retval); } - blocktype = outbuf[0]; + blocktype = outbuf[1]; unpadoffset = 0; switch (blocktype) { case 0x00: /* Padding Scheme 1, the first non-zero byte is the start of data */ - for (unpadoffset = 1; unpadoffset < retval; unpadoffset++) { + for (unpadoffset = 2; unpadoffset < retval; unpadoffset++) { if (outbuf[unpadoffset] != 0x00) { break; } } break; case 0x01: /* Padding Scheme 2, pad bytes are 0xFF followed by 0x00 */ - for (unpadoffset = 1; unpadoffset < retval; unpadoffset++) { + for (unpadoffset = 2; unpadoffset < retval; unpadoffset++) { if (outbuf[unpadoffset] != 0xFF) { if (outbuf[unpadoffset] == 0x00) { unpadoffset++; break; @@ -2058,23 +2064,13 @@ return(-1); } } break; case 0x02: - /* Padding Scheme 3, pad bytes are non-zero first non-zero byte found is the pad byte */ - for (unpadoffset = 1; unpadoffset < retval; unpadoffset++) { + /* Padding Scheme 3, pad bytes are non-zero first zero byte found is the seperator byte */ + for (unpadoffset = 2; unpadoffset < retval; unpadoffset++) { if (outbuf[unpadoffset] == 0x00) { - continue; - } - - if (sepByte == -1) { - sepByte = outbuf[unpadoffset]; - - continue; - } - - if (outbuf[unpadoffset] == sepByte) { unpadoffset++; break; } } @@ -2088,17 +2084,17 @@ } CACKEY_DEBUG_PRINTBUF("Padded:", outbuf, retval); retval -= unpadoffset; - memmove(outbuf + unpadoffset, outbuf, retval); + memmove(outbuf, outbuf + unpadoffset, retval); CACKEY_DEBUG_PRINTBUF("Unpadded:", outbuf, retval); } - CACKEY_DEBUG_PRINTF("Returning in success, signed %li bytes", (long) retval); + CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval); return(retval); } /* @@ -2197,12 +2193,10 @@ slot->slot_reset = 1; slot->token_flags = CKF_LOGIN_REQUIRED; if (status_ret == SCARD_W_RESET_CARD) { CACKEY_DEBUG_PRINTF("Reset required, please hold..."); - - scard_reconn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &protocol); if (scard_reconn_ret == SCARD_S_SUCCESS) { /* Re-establish transaction, if it was present */ if (slot->transaction_depth > 0) { @@ -2493,15 +2487,17 @@ break; case CKA_LABEL: CACKEY_DEBUG_PRINTF("Requesting attribute CKA_LABEL (0x%08lx) ...", (unsigned long) curr_attr_type); - /* Determine name */ - x509_read_ret = cackey_pcsc_identity_to_label(identity, ucTmpBuf, sizeof(ucTmpBuf)); - if (x509_read_ret > 0) { - pValue = ucTmpBuf; - ulValueLen = x509_read_ret; + /* XXX: Determine name */ + ulValueLen = snprintf(ucTmpBuf, sizeof(ucTmpBuf), "Identity #%lu", (unsigned long) identity_num); + pValue = ucTmpBuf; + + if (ulValueLen >= sizeof(ucTmpBuf)) { + ulValueLen = 0; + pValue = NULL; } CACKEY_DEBUG_PRINTF(" ... returning (%p/%lu)", pValue, (unsigned long) ulValueLen); break; @@ -2653,10 +2649,11 @@ break; case CKA_SIGN_RECOVER: CACKEY_DEBUG_PRINTF("Requesting attribute CKA_SIGN_RECOVER (0x%08lx) ...", (unsigned long) curr_attr_type); + /* We currently only support "Sign with Appendix" */ pValue = &ck_false; ulValueLen = sizeof(ck_false); CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); @@ -2672,10 +2669,68 @@ ulValueLen = sizeof(ck_false); } CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + break; + case CKA_SENSITIVE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_SENSITIVE (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass == CKO_PRIVATE_KEY) { + pValue = &ck_true; + ulValueLen = sizeof(ck_true); + } else { + pValue = &ck_false; + ulValueLen = sizeof(ck_false); + } + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_EXTRACTABLE: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_EXTRACTABLE (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (objectclass == CKO_PRIVATE_KEY) { + pValue = &ck_false; + ulValueLen = sizeof(ck_true); + } else { + pValue = &ck_true; + ulValueLen = sizeof(ck_false); + } + + CACKEY_DEBUG_PRINTF(" ... returning %lu (%p/%lu)", (unsigned long) *((CK_BBOOL *) pValue), pValue, (unsigned long) ulValueLen); + + break; + case CKA_MODULUS: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_MODULUS (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (certificate_len >= 0) { + x509_read_ret = x509_to_modulus(certificate, certificate_len, &pValue); + if (x509_read_ret < 0) { + pValue = NULL; + } else { + ulValueLen = x509_read_ret; + } + } + + CACKEY_DEBUG_PRINTF(" ... returning (%p/%lu)", pValue, (unsigned long) ulValueLen); + + break; + case CKA_PUBLIC_EXPONENT: + CACKEY_DEBUG_PRINTF("Requesting attribute CKA_PUBLIC_EXPONENT (0x%08lx) ...", (unsigned long) curr_attr_type); + + if (certificate_len >= 0) { + x509_read_ret = x509_to_exponent(certificate, certificate_len, &pValue); + if (x509_read_ret < 0) { + pValue = NULL; + } else { + ulValueLen = x509_read_ret; + } + } + + CACKEY_DEBUG_PRINTF(" ... returning (%p/%lu)", pValue, (unsigned long) ulValueLen); + break; case CKA_TRUST_SERVER_AUTH: CACKEY_DEBUG_PRINTF("Requesting attribute CKA_TRUST_SERVER_AUTH (0x%08lx) ...", (unsigned long) curr_attr_type); pValue = &ck_true;