Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -12,28 +12,35 @@ prefix = @prefix@ exec_prefix = @exec_prefix@ libdir = @libdir@ @SET_MAKE@ -all: cackey.@SHOBJEXT@ +all: libcackey.@SHOBJEXT@ -cackey.o: cackey.c +cackey.o: cackey.c asn1-x509.h $(CC) $(SHOBJFLAGS) $(CPPFLAGS) $(CFLAGS) -o cackey.o -c cackey.c -cackey.@SHOBJEXT@: cackey.o - $(CC) $(SHOBJFLAGS) $(CPPFLAGS) $(CFLAGS) $(SHOBJLDFLAGS) $(LDFLAGS) -o cackey.@SHOBJEXT@ cackey.o $(LIBS) +asn1-x509.o: asn1-x509.c asn1-x509.h + $(CC) $(SHOBJFLAGS) $(CPPFLAGS) $(CFLAGS) -o asn1-x509.o -c asn1-x509.c + +libcackey.@SHOBJEXT@: cackey.o asn1-x509.o + $(CC) $(SHOBJFLAGS) $(CPPFLAGS) $(CFLAGS) $(SHOBJLDFLAGS) $(LDFLAGS) -o libcackey.@SHOBJEXT@ cackey.o asn1-x509.o $(LIBS) + +test: test.c libcackey.@SHOBJEXT@ + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o test test.c -Wl,-R,. libcackey.@SHOBJEXT@ -install: cackey.@SHOBJEXT@ +install: libcackey.@SHOBJEXT@ -mkdir "$(DESTDIR)$(libdir)" - cp cackey.@SHOBJEXT@ "$(DESTDIR)$(libdir)/" + cp libcackey.@SHOBJEXT@ "$(DESTDIR)$(libdir)/" clean: - rm -f cackey.@SHOBJEXT@ + rm -f libcackey.@SHOBJEXT@ rm -f cackey.o + rm -f test distclean: clean rm -f config.log config.status config.h Makefile mrproper: distclean rm -f configure config.h.in aclocal.m4 *~ .PHONY: all clean distclean mrproper install ADDED asn1-x509.c Index: asn1-x509.c ================================================================== --- asn1-x509.c +++ asn1-x509.c @@ -0,0 +1,179 @@ +/* + * Basic implementation of ITU-T X.690 (07/2002) for parsing BER encoded + * X.509 certificates + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STDARG_H +# include +#endif + +#include "asn1-x509.h" + +struct asn1_object { + unsigned long tag; + unsigned long size; + void *contents; + + unsigned long asn1rep_len; + void *asn1rep; +}; + +struct x509_object { + struct asn1_object wholething; + struct asn1_object certificate; + struct asn1_object version; + 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; +}; + +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; + struct asn1_object *outbuf; + + outbuf = va_arg(*args, struct asn1_object *); + + if (outbuf == NULL) { + return(0); + } + + if (buflen == 0) { + return(-1); + } + + buf_p = buf; + + outbuf->tag = *buf_p; + buf_p++; + buflen--; + if (buflen == 0) { + return(-1); + } + + small_object_size = *buf_p; + buf_p++; + buflen--; + if (buflen == 0) { + return(-1); + } + + if ((small_object_size & 0x80) == 0x80) { + outbuf->size = 0; + + for (small_object_size ^= 0x80; small_object_size; small_object_size--) { + outbuf->size <<= 8; + outbuf->size += *buf_p; + + buf_p++; + buflen--; + if (buflen == 0) { + break; + } + } + } else { + outbuf->size = small_object_size; + } + + if (outbuf->size > buflen) { + return(-1); + } + + outbuf->contents = buf_p; + outbuf->asn1rep_len = outbuf->size + (buf_p - buf); + outbuf->asn1rep = buf; + + buf_p += outbuf->size; + buflen -= outbuf->size; + + return(_asn1_x509_read_asn1_object(buf_p, buflen, args)); +} + +static int asn1_x509_read_asn1_object(unsigned char *buf, size_t buflen, ...) { + va_list args; + int retval; + + va_start(args, buflen); + + retval = _asn1_x509_read_asn1_object(buf, buflen, &args); + + va_end(args); + + return(retval); +} + +static int asn1_x509_read_object(unsigned char *buf, size_t buflen, struct x509_object *outbuf) { + int read_ret; + + read_ret = asn1_x509_read_asn1_object(buf, buflen, &outbuf->wholething, NULL); + if (read_ret != 0) { + return(-1); + } + + 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); + if (read_ret != 0) { + return(-1); + } + + return(0); +} + +ssize_t x509_to_issuer(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { + 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); + } + + *outbuf = x509.issuer.asn1rep; + + return(x509.issuer.asn1rep_len); +} + +ssize_t x509_to_subject(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { + 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); + } + + *outbuf = x509.subject.asn1rep; + + return(x509.subject.asn1rep_len); +} + +ssize_t x509_to_serial(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { + 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); + } + + *outbuf = x509.serial_number.asn1rep; + + return(x509.serial_number.asn1rep_len); +} ADDED asn1-x509.h Index: asn1-x509.h ================================================================== --- asn1-x509.h +++ asn1-x509.h @@ -0,0 +1,19 @@ +#ifndef USACEIT_ASN1_X509_H +#define USACEIT_ASN1_X509_H 1 + +#ifdef HAVE_CONFIG_H +# include "config.h" +# ifdef HAVE_UNISTD_H +# include +# endif +#else +# include +#endif + +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); + +#endif Index: cackey.c ================================================================== --- cackey.c +++ cackey.c @@ -35,15 +35,112 @@ #ifndef NULL_PTR # define NULL_PTR 0 #endif #include "pkcs11.h" +#include "asn1-x509.h" #ifndef CACKEY_CRYPTOKI_VERSION_CODE # define CACKEY_CRYPTOKI_VERSION_CODE 0x021e00 #endif +#ifndef CKA_TRUST_SERVER_AUTH +# define CKA_TRUST_SERVER_AUTH 0xce536358 +#endif +#ifndef CKA_TRUST_CLIENT_AUTH +# define CKA_TRUST_CLIENT_AUTH 0xce536359 +#endif +#ifndef CKA_TRUST_CODE_SIGNING +# define CKA_TRUST_CODE_SIGNING 0xce53635a +#endif +#ifndef CKA_TRUST_EMAIL_PROTECTION +# define CKA_TRUST_EMAIL_PROTECTION 0xce53635b +#endif + +/* GSC-IS v2.1 Definitions */ +#define GSCIS_CLASS_ISO7816 0x00 +#define GSCIS_CLASS_GLOBAL_PLATFORM 0x80 + +#define GSCIS_INSTR_GET_RESPONSE 0xC0 +#define GSCIS_INSTR_READ_BINARY 0xB0 +#define GSCIS_INSTR_UPDATE_BINARY 0xD6 +#define GSCIS_INSTR_SELECT 0xA4 +#define GSCIS_INSTR_EXTERNAL_AUTH 0x82 +#define GSCIS_INSTR_GET_CHALLENGE 0x84 +#define GSCIS_INSTR_INTERNAL_AUTH 0x88 +#define GSCIS_INSTR_VERIFY 0x20 +#define GSCIS_INSTR_SIGN 0x2A +#define GSCIS_INSTR_GET_PROP 0x56 +#define GSCIS_INSTR_GET_ACR 0x4C +#define GSCIS_INSTR_READ_BUFFER 0x52 +#define GSCIS_INSTR_SIGNDECRYPT 0x42 + +#define GSCIS_PARAM_SELECT_APPLET 0x04 + +/* CCC */ +#define GSCIS_TAG_CARDID 0xF0 +#define GSCIS_TAG_CCC_VER 0xF1 +#define GSCIS_TAG_CCG_VER 0xF2 +#define GSCIS_TAG_CARDURL 0xF3 +#define GSCIS_TAG_PKCS15 0xF4 +#define GSCIS_TAG_REG_DATA_MODEL 0xF5 +#define GSCIS_TAG_ACR_TABLE 0xF6 +#define GSCIS_TAG_CARD_APDU 0xF7 +#define GSCIS_TAG_REDIRECTION 0xFA +#define GSCIS_TAG_CT 0xFB +#define GSCIS_TAG_ST 0xFC +#define GSCIS_TAG_NEXTCCC 0xFD + +/* General - EF 2200 */ +#define GSCIS_TAG_FNAME 0x01 +#define GSCIS_TAG_MNAME 0x02 +#define GSCIS_TAG_LNAME 0x03 +#define GSCIS_TAG_SUFFIX 0x04 +#define GSCIS_TAG_GOVT_AGENCY 0x05 +#define GSCIS_TAG_BUREAU 0x06 +#define GSCIS_TAG_BUREAU_CODE 0x07 +#define GSCIS_TAG_DEPT_CODE 0x08 +#define GSCIS_TAG_TITLE 0x09 +#define GSCIS_TAG_BUILDING 0x10 +#define GSCIS_TAG_OFFICE_ADDR1 0x11 +#define GSCIS_TAG_OFFICE_ADDR2 0x12 +#define GSCIS_TAG_OFFICE_CITY 0x13 +#define GSCIS_TAG_OFFICE_STATE 0x14 +#define GSCIS_TAG_OFFICE_ZIP 0x15 +#define GSCIS_TAG_OFFICE_COUNTRY 0x16 +#define GSCIS_TAG_OFFICE_PHONE 0x17 +#define GSCIS_TAG_OFFICE_PHONE_EXT 0x18 +#define GSCIS_TAG_OFFICE_FAX 0x19 +#define GSCIS_TAG_OFFICE_EMAIL 0x1A +#define GSCIS_TAG_OFFICE_ROOM 0x1B +#define GSCIS_TAG_NONGOV_AGENCY 0x1C +#define GSCIS_TAG_SSN_DESIGNATOR 0x1D + +/* PII - EF 2100 */ +#define GSCIS_TAG_SSN 0x20 +#define GSCIS_TAG_DOB 0x21 +#define GSCIS_TAG_GENDER 0x22 + +/* Login Information - EF 4000 */ +#define GSCIS_TAG_USERID 0x40 +#define GSCIS_TAG_DOMAIN 0x41 +#define GSCIS_TAG_PASSWORD 0x42 + +/* Card Information - EF 5000 */ +#define GSCIS_TAG_ISSUERID 0x50 +#define GSCIS_TAG_SERNO 0x51 +#define GSCIS_TAG_ISSUE_DATE 0x52 +#define GSCIS_TAG_EXPIRE_DATE 0x53 +#define GSCIS_TAG_CARD_TYPE 0x54 +#define GSCIS_TAG_SECURITY_CODE 0x57 +#define GSCIS_TAG_CARDID_AID 0x58 + +/* PKI Information - EF 7000 */ +#define GSCIS_TAG_CERTIFICATE 0x70 +#define GSCIS_TAG_CERT_ISSUE_DATE 0x71 +#define GSCIS_TAG_CERT_EXPIRE_DATE 0x72 + #ifdef CACKEY_DEBUG # ifdef HAVE_STDIO_H # include # endif @@ -75,30 +172,184 @@ fprintf(stderr, "\n"); } return(retval); } + +static const char *CACKEY_DEBUG_FUNC_TAG_TO_STR(unsigned char tag) { + const char *retval = NULL; + + switch (tag) { + case GSCIS_TAG_CARDID: + retval = "GSCIS_TAG_CARDID"; + break; + case GSCIS_TAG_CCC_VER: + retval = "GSCIS_TAG_CCC_VER"; + break; + case GSCIS_TAG_CCG_VER: + retval = "GSCIS_TAG_CCG_VER"; + break; + case GSCIS_TAG_CARDURL: + retval = "GSCIS_TAG_CARDURL"; + break; + case GSCIS_TAG_PKCS15: + retval = "GSCIS_TAG_PKCS15"; + break; + case GSCIS_TAG_REG_DATA_MODEL: + retval = "GSCIS_TAG_REG_DATA_MODEL"; + break; + case GSCIS_TAG_ACR_TABLE: + retval = "GSCIS_TAG_ACR_TABLE"; + break; + case GSCIS_TAG_CARD_APDU: + retval = "GSCIS_TAG_CARD_APDU"; + break; + case GSCIS_TAG_REDIRECTION: + retval = "GSCIS_TAG_REDIRECTION"; + break; + case GSCIS_TAG_CT: + retval = "GSCIS_TAG_CT"; + break; + case GSCIS_TAG_ST: + retval = "GSCIS_TAG_ST"; + break; + case GSCIS_TAG_NEXTCCC: + retval = "GSCIS_TAG_NEXTCCC"; + break; + case GSCIS_TAG_FNAME: + retval = "GSCIS_TAG_FNAME"; + break; + case GSCIS_TAG_MNAME: + retval = "GSCIS_TAG_MNAME"; + break; + case GSCIS_TAG_LNAME: + retval = "GSCIS_TAG_LNAME"; + break; + case GSCIS_TAG_SUFFIX: + retval = "GSCIS_TAG_SUFFIX"; + break; + case GSCIS_TAG_GOVT_AGENCY: + retval = "GSCIS_TAG_GOVT_AGENCY"; + break; + case GSCIS_TAG_BUREAU: + retval = "GSCIS_TAG_BUREAU"; + break; + case GSCIS_TAG_BUREAU_CODE: + retval = "GSCIS_TAG_BUREAU_CODE"; + break; + case GSCIS_TAG_DEPT_CODE: + retval = "GSCIS_TAG_DEPT_CODE"; + break; + case GSCIS_TAG_TITLE: + retval = "GSCIS_TAG_TITLE"; + break; + case GSCIS_TAG_BUILDING: + retval = "GSCIS_TAG_BUILDING"; + break; + case GSCIS_TAG_OFFICE_ADDR1: + retval = "GSCIS_TAG_OFFICE_ADDR1"; + break; + case GSCIS_TAG_OFFICE_ADDR2: + retval = "GSCIS_TAG_OFFICE_ADDR2"; + break; + case GSCIS_TAG_OFFICE_CITY: + retval = "GSCIS_TAG_OFFICE_CITY"; + break; + case GSCIS_TAG_OFFICE_STATE: + retval = "GSCIS_TAG_OFFICE_STATE"; + break; + case GSCIS_TAG_OFFICE_ZIP: + retval = "GSCIS_TAG_OFFICE_ZIP"; + break; + case GSCIS_TAG_OFFICE_COUNTRY: + retval = "GSCIS_TAG_OFFICE_COUNTRY"; + break; + case GSCIS_TAG_OFFICE_PHONE: + retval = "GSCIS_TAG_OFFICE_PHONE"; + break; + case GSCIS_TAG_OFFICE_PHONE_EXT: + retval = "GSCIS_TAG_OFFICE_PHONE_EXT"; + break; + case GSCIS_TAG_OFFICE_FAX: + retval = "GSCIS_TAG_OFFICE_FAX"; + break; + case GSCIS_TAG_OFFICE_EMAIL: + retval = "GSCIS_TAG_OFFICE_EMAIL"; + break; + case GSCIS_TAG_OFFICE_ROOM: + retval = "GSCIS_TAG_OFFICE_ROOM"; + break; + case GSCIS_TAG_NONGOV_AGENCY: + retval = "GSCIS_TAG_NONGOV_AGENCY"; + break; + case GSCIS_TAG_SSN_DESIGNATOR: + retval = "GSCIS_TAG_SSN_DESIGNATOR"; + break; + case GSCIS_TAG_SSN: + retval = "GSCIS_TAG_SSN"; + break; + case GSCIS_TAG_DOB: + retval = "GSCIS_TAG_DOB"; + break; + case GSCIS_TAG_GENDER: + retval = "GSCIS_TAG_GENDER"; + break; + case GSCIS_TAG_USERID: + retval = "GSCIS_TAG_USERID"; + break; + case GSCIS_TAG_DOMAIN: + retval = "GSCIS_TAG_DOMAIN"; + break; + case GSCIS_TAG_PASSWORD: + retval = "GSCIS_TAG_PASSWORD"; + break; + case GSCIS_TAG_ISSUERID: + retval = "GSCIS_TAG_ISSUERID"; + break; + case GSCIS_TAG_SERNO: + retval = "GSCIS_TAG_SERNO"; + break; + case GSCIS_TAG_ISSUE_DATE: + retval = "GSCIS_TAG_ISSUE_DATE"; + break; + case GSCIS_TAG_EXPIRE_DATE: + retval = "GSCIS_TAG_EXPIRE_DATE"; + break; + case GSCIS_TAG_CARD_TYPE: + retval = "GSCIS_TAG_CARD_TYPE"; + break; + case GSCIS_TAG_SECURITY_CODE: + retval = "GSCIS_TAG_SECURITY_CODE"; + break; + case GSCIS_TAG_CARDID_AID: + retval = "GSCIS_TAG_CARDID_AID"; + break; + case GSCIS_TAG_CERTIFICATE: + retval = "GSCIS_TAG_CERTIFICATE"; + break; + case GSCIS_TAG_CERT_ISSUE_DATE: + retval = "GSCIS_TAG_CERT_ISSUE_DATE"; + break; + case GSCIS_TAG_CERT_EXPIRE_DATE: + retval = "GSCIS_TAG_CERT_EXPIRE_DATE"; + break; + } + + if (retval == NULL) { + retval = "UNKNOWN"; + } + + return(retval); +} # define malloc(x) CACKEY_DEBUG_FUNC_MALLOC(x, __func__) # define realloc(x, y) CACKEY_DEBUG_FUNC_REALLOC(x, y, __func__) #else # define CACKEY_DEBUG_PRINTF(x...) /**/ # define CACKEY_DEBUG_PRINTBUF(f, x, y) /**/ # define CACKEY_DEBUG_PERROR(x) /**/ -#endif - -#ifndef CKA_TRUST_SERVER_AUTH -# define CKA_TRUST_SERVER_AUTH 0xce536358 -#endif -#ifndef CKA_TRUST_CLIENT_AUTH -# define CKA_TRUST_CLIENT_AUTH 0xce536359 -#endif -#ifndef CKA_TRUST_CODE_SIGNING -# define CKA_TRUST_CODE_SIGNING 0xce53635a -#endif -#ifndef CKA_TRUST_EMAIL_PROTECTION -# define CKA_TRUST_EMAIL_PROTECTION 0xce53635b +# define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED" #endif struct cackey_identity { CK_ATTRIBUTE *attributes; CK_ULONG attributes_count; @@ -106,10 +357,11 @@ struct cackey_session { int active; CK_SLOT_ID slotID; + CK_STATE state; CK_FLAGS flags; CK_ULONG ulDeviceError; CK_VOID_PTR pApplication; CK_NOTIFY Notify; @@ -130,15 +382,32 @@ int decrypt_active; CK_MECHANISM_TYPE decrypt_mechanism; CK_VOID_PTR decrypt_mech_parm; CK_ULONG decrypt_mech_parmlen; + +}; + +struct cackey_slot { + int active; + + char *pcsc_reader; + + int pcsc_card_connected; + SCARDHANDLE pcsc_card; +}; + +struct cackey_tlv_entity { + uint8_t tag; + size_t length; + unsigned char *value_buf; /* Raw buffer */ }; /* CACKEY Global Handles */ static void *cackey_biglock = NULL; static struct cackey_session cackey_sessions[128]; +static struct cackey_slot cackey_slots[128]; static int cackey_initialized = 0; static int cackey_biglock_init = 0; CK_C_INITIALIZE_ARGS cackey_args; /* PCSC Global Handles */ @@ -177,12 +446,32 @@ CACKEY_DEBUG_PRINTF("Returning 0x%lx", retval); return(retval); } -/* APDU Related Functions */ -static int cackey_send_apdu(unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned char lc, unsigned char *data, unsigned char *resp, unsigned char resplen) { +/* PC/SC Related Functions */ +static void cackey_slots_disconnect_all(void) { + uint32_t idx; + + CACKEY_DEBUG_PRINTF("Called."); + + for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) { + if (cackey_slots[idx].pcsc_card_connected) { + CACKEY_DEBUG_PRINTF("SCardDisconnect(%lu) called", (unsigned long) idx); + + SCardDisconnect(cackey_slots[idx].pcsc_card, SCARD_LEAVE_CARD); + } + + cackey_slots[idx].pcsc_card_connected = 0; + } + + CACKEY_DEBUG_PRINTF("Returning"); + + return; +} + +static int cackey_pcsc_connect(void) { LONG scard_est_context_ret; #ifdef HAVE_SCARDISVALIDCONTEXT LONG scard_isvalid_ret; #endif @@ -191,44 +480,451 @@ if (cackey_pcsc_handle == NULL) { cackey_pcsc_handle = malloc(sizeof(*cackey_pcsc_handle)); if (cackey_pcsc_handle == NULL) { CACKEY_DEBUG_PRINTF("Call to malloc() failed, returning in failure"); + cackey_slots_disconnect_all(); + return(-1); } + CACKEY_DEBUG_PRINTF("SCardEstablishContext() called"); scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle); if (scard_est_context_ret != SCARD_S_SUCCESS) { CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %li), returning in failure", (long) scard_est_context_ret); free(cackey_pcsc_handle); + + cackey_slots_disconnect_all(); return(-1); } } #ifdef HAVE_SCARDISVALIDCONTEXT + CACKEY_DEBUG_PRINTF("SCardIsValidContext() called"); scard_isvalid_ret = SCardIsValidContext(*cackey_pcsc_handle); if (scard_isvalid_ret != SCARD_S_SUCCESS) { - CACKEY_DEBUG_PRINTF("Handle has become invalid, trying to re-establish..."); + CACKEY_DEBUG_PRINTF("Handle has become invalid (SCardIsValidContext = %li), trying to re-establish...", (long) scard_isvalid_ret); + CACKEY_DEBUG_PRINTF("SCardEstablishContext() called"); scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_pcsc_handle); if (scard_est_context_ret != SCARD_S_SUCCESS) { CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %li), returning in failure", (long) scard_est_context_ret); free(cackey_pcsc_handle); + + cackey_slots_disconnect_all(); return(-1); } CACKEY_DEBUG_PRINTF("Handle has been re-established"); } #endif - /* Connect to a reader, if needed */ + CACKEY_DEBUG_PRINTF("Sucessfully connected to PC/SC, returning in success"); + + return(0); +} + +/* APDU Related Functions */ +/** Le = 0x00 to indicate not to send Le **/ +static int cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned char lc, unsigned char *data, unsigned char 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; + DWORD protocol; + DWORD xmit_len, recv_len; + LONG scard_conn_ret, 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 (!slot) { + CACKEY_DEBUG_PRINTF("Invalid slot specified."); + + return(-1); + } + + pcsc_connect_ret = cackey_pcsc_connect(); + if (pcsc_connect_ret < 0) { + CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, returning in failure"); + + return(-1); + } + + /* Connect to reader, if needed */ + if (!slot->pcsc_card_connected) { + CACKEY_DEBUG_PRINTF("SCardConnect(%s) called", slot->pcsc_reader); + scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &slot->pcsc_card, &protocol); + + if (scard_conn_ret != SCARD_S_SUCCESS) { + CACKEY_DEBUG_PRINTF("Connection to card failed, returning in failure (SCardConnect() = %li)", (long) scard_conn_ret); + + return(-1); + } + + slot->pcsc_card_connected = 1; + } /* Transmit */ + xmit_len = 0; + xmit_buf[xmit_len++] = class; + xmit_buf[xmit_len++] = instruction; + xmit_buf[xmit_len++] = p1; + xmit_buf[xmit_len++] = p2; + if (data) { + xmit_buf[xmit_len++] = lc; + for (idx = 0; idx < lc; idx++) { + xmit_buf[xmit_len++] = data[idx]; + } + } + + if (le != 0x00) { + xmit_buf[xmit_len++] = le; + } + + CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len); + + recv_len = sizeof(recv_buf); + scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T1, recv_buf, &recv_len); + if (scard_xmit_ret != SCARD_S_SUCCESS) { + CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %lx)", (unsigned long) scard_xmit_ret); + + if (scard_xmit_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) { + CACKEY_DEBUG_PRINTF("Reset successful, retransmitting"); + scard_xmit_ret = SCardTransmit(slot->pcsc_card, SCARD_PCI_T0, xmit_buf, xmit_len, SCARD_PCI_T0, recv_buf, &recv_len); + + if (scard_xmit_ret != SCARD_S_SUCCESS) { + CACKEY_DEBUG_PRINTF("Retransmit failed, returning in failure after disconnecting the card"); + + SCardDisconnect(slot->pcsc_card, SCARD_RESET_CARD); + slot->pcsc_card_connected = 0; + + return(-1); + } + } else { + CACKEY_DEBUG_PRINTF("Disconnecting card"); + + SCardDisconnect(slot->pcsc_card, SCARD_RESET_CARD); + slot->pcsc_card_connected = 0; + + CACKEY_DEBUG_PRINTF("Returning in failure"); + return(-1); + } + } else { + CACKEY_DEBUG_PRINTF("Disconnecting card"); + + SCardDisconnect(slot->pcsc_card, SCARD_RESET_CARD); + slot->pcsc_card_connected = 0; + + CACKEY_DEBUG_PRINTF("Returning in failure"); + return(-1); + } + } + + CACKEY_DEBUG_PRINTBUF("Returned Value:", recv_buf, recv_len); + + if (recv_len < 2) { + /* Minimal response length is 2 bytes, returning in failure */ + CACKEY_DEBUG_PRINTF("Response too small, returning in failure (recv_len = %lu)", (unsigned long) recv_len); + + return(-1); + } + + /* Determine result code */ + major_rc = recv_buf[recv_len - 2]; + minor_rc = recv_buf[recv_len - 1]; + if (respcode) { + *respcode = (major_rc << 8) | minor_rc; + } + + /* Adjust message buffer */ + recv_len -= 2; + + /* Add bytes to return value */ + tmp_respdata_len = 0; + if (respdata && respdata_len) { + tmp_respdata_len = *respdata_len; + + bytes_to_copy = *respdata_len; + + if (recv_len < bytes_to_copy) { + bytes_to_copy = recv_len; + } + + CACKEY_DEBUG_PRINTF("Copying %lu bytes to the buffer", (unsigned long) bytes_to_copy); + + memcpy(respdata, recv_buf, bytes_to_copy); + respdata += bytes_to_copy; + + *respdata_len = bytes_to_copy; + tmp_respdata_len -= bytes_to_copy; + } else { + if (recv_len != 0) { + CACKEY_DEBUG_PRINTF("Throwing away %lu bytes, nowhere to put them!", (unsigned long) recv_len); + } + } + + if (major_rc == 0x61) { + /* We need to READ */ + CACKEY_DEBUG_PRINTF("Buffer read required"); + + 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); + if (pcsc_getresp_ret < 0) { + CACKEY_DEBUG_PRINTF("Buffer read failed! Returning in failure"); + + return(-1); + } + + if (respdata_len) { + *respdata_len += tmp_respdata_len; + } + + CACKEY_DEBUG_PRINTF("Returning in success (buffer read complete)"); + return(0); + } + + if (major_rc == 0x90) { + /* Success */ + CACKEY_DEBUG_PRINTF("Returning in success (major_rc = 0x90)"); + + return(0); + } + + + CACKEY_DEBUG_PRINTF("APDU Returned an error, returning in failure"); + + return(-1); +} + +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) { + size_t offset = 0, max_offset, max_count; + unsigned char cmd[2]; + uint16_t respcode; + int send_ret; + + CACKEY_DEBUG_PRINTF("Called"); + + max_offset = count; + max_count = 64; + + cmd[0] = t_or_v; + + while (1) { + if (offset >= max_offset) { + CACKEY_DEBUG_PRINTF("Buffer too small, returning what we got..."); + + break; + } + + count = max_offset - offset; + if (count > max_count) { + count = max_count; + } + + cmd[1] = count; + + 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); + if (send_ret < 0) { + if (respcode == 0x6A86) { + if (max_count == 1) { + break; + } + + max_count = max_count / 2; + + continue; + } + + CACKEY_DEBUG_PRINTF("cackey_send_apdu() failed, returning in failure"); + + return(-1); + } + + offset += count; + + if (count < max_count) { + CACKEY_DEBUG_PRINTF("Short read -- count = %i, cmd[1] = %i", count, cmd[1]); + + break; + } + } + + CACKEY_DEBUG_PRINTF("Returning in success, read %lu bytes", (unsigned long) offset); + + return(offset); +} + +static int cackey_select_applet(struct cackey_slot *slot, unsigned char *aid, size_t aid_len) { + int send_ret; + + CACKEY_DEBUG_PRINTF("Called"); + + CACKEY_DEBUG_PRINTBUF("Selecting applet:", aid, aid_len); + + send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_SELECT, GSCIS_PARAM_SELECT_APPLET, 0x0C, aid_len, aid, 0x00, NULL, NULL, NULL); + if (send_ret < 0) { + CACKEY_DEBUG_PRINTF("Failed to open applet, returning in failure"); + + return(-1); + } + + CACKEY_DEBUG_PRINTF("Successfully selected file"); + + return(0); +} + +static int cackey_read_tlv(struct cackey_slot *slot, int follow_url) { + struct cackey_tlv_entity curr_entity; + unsigned char tlen_buf[2], tval_buf[1024], *tval; + unsigned char vlen_buf[2], vval_buf[8192], *vval; + ssize_t tlen, vlen; + ssize_t read_ret; + size_t offset_t = 0, offset_v = 0; + int select_ret; + + CACKEY_DEBUG_PRINTF("Called"); + + read_ret = cackey_read_buffer(slot, tlen_buf, sizeof(tlen_buf), 1, offset_t); + if (read_ret != sizeof(tlen_buf)) { + CACKEY_DEBUG_PRINTF("Read failed, returning in failure"); + + return(0); + } + + tlen = (tlen_buf[1] << 8) | tlen_buf[0]; + + read_ret = cackey_read_buffer(slot, vlen_buf, sizeof(vlen_buf), 2, offset_v); + if (read_ret != sizeof(vlen_buf)) { + CACKEY_DEBUG_PRINTF("Read failed, returning in failure"); + + return(0); + } + + vlen = (vlen_buf[1] << 8) | vlen_buf[0]; + + CACKEY_DEBUG_PRINTF("Tag Length = %i, Value Length = %i", tlen, vlen); + + tlen -= 2; + offset_t += 2; + + vlen -= 2; + offset_v += 2; + + if (tlen > sizeof(tval_buf)) { + CACKEY_DEBUG_PRINTF("Tag length is too large, returning in failure"); + + return(0); + } + + if (vlen > sizeof(vval_buf)) { + CACKEY_DEBUG_PRINTF("Value length is too large, returning in failure"); + + return(0); + } + + read_ret = cackey_read_buffer(slot, tval_buf, tlen, 1, offset_t); + if (read_ret != tlen) { + CACKEY_DEBUG_PRINTF("Unable to read entire T-buffer, returning in failure"); + + return(0); + } + + read_ret = cackey_read_buffer(slot, vval_buf, vlen, 2, offset_v); + if (read_ret != vlen) { + CACKEY_DEBUG_PRINTF("Unable to read entire V-buffer, returning in failure"); + + return(0); + } + + tval = tval_buf; + vval = vval_buf; + while (tlen > 0 && vlen > 0) { + curr_entity.tag = *tval; + tval++; + tlen--; + + if (*tval == 0xff) { + curr_entity.length = (tval[2] << 8) | tval[1]; + tval += 3; + tlen -= 3; + } else { + curr_entity.length = *tval; + tval++; + tlen--; + } + + CACKEY_DEBUG_PRINTF("Tag: %s (%02x)", CACKEY_DEBUG_FUNC_TAG_TO_STR(curr_entity.tag), (unsigned int) curr_entity.tag); + CACKEY_DEBUG_PRINTBUF("Value:", vval, curr_entity.length); + vval += curr_entity.length; + vlen -= curr_entity.length; + + switch (curr_entity.tag) { + case GSCIS_TAG_CARDURL: + if (follow_url) { + unsigned char aid[7]; + memcpy(aid, vval, 5); + memcpy(aid + 5, vval + 8, 2); + + select_ret = cackey_select_applet(slot, aid, 7); + if (select_ret < 0) { + CACKEY_DEBUG_PRINTF("Failed to select applet"); + break; + } + + cackey_read_tlv(slot, 0); + } + break; + } + } + + return(0); +} + +static int cackey_select_file(struct cackey_slot *slot, uint16_t ef) { + unsigned char fid_buf[2]; + int send_ret; + + CACKEY_DEBUG_PRINTF("Called"); + + /* Open the elementary file */ + fid_buf[0] = (ef >> 8) & 0xff; + fid_buf[1] = ef & 0xff; + + send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_SELECT, 0x02, 0x0C, sizeof(fid_buf), fid_buf, 0x00, NULL, NULL, NULL); + if (send_ret < 0) { + CACKEY_DEBUG_PRINTF("Failed to open file, returning in failure"); + + return(-1); + } + + CACKEY_DEBUG_PRINTF("Successfully selected file"); + + return(0); +} + +/* Returns 1 if a token is in the specified slot, 0 otherwise */ +static int cackey_token_present(struct cackey_slot *slot) { + unsigned char ccc_aid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00}; + int send_ret; + + /* Select the CCC Applet */ + send_ret = cackey_select_applet(slot, ccc_aid, sizeof(ccc_aid)); + if (send_ret < 0) { + return(0); + } + + cackey_read_tlv(slot, 1); + + return(1); } /* Returns 0 on success */ static int cackey_mutex_create(void **mutex) { pthread_mutex_t *pthread_mutex; @@ -701,10 +1397,15 @@ } for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { cackey_sessions[idx].active = 0; } + + for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) { + cackey_slots[idx].active = 0; + cackey_slots[idx].pcsc_reader = NULL; + } cackey_initialized = 1; if (!cackey_biglock_init) { mutex_init_ret = cackey_mutex_create(&cackey_biglock); @@ -743,10 +1444,18 @@ for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) { if (cackey_sessions[idx].active) { C_CloseSession(idx); } } + + cackey_slots_disconnect_all(); + + for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) { + if (cackey_slots[idx].pcsc_reader) { + free(cackey_slots[idx].pcsc_reader); + } + } cackey_initialized = 0; CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); @@ -788,13 +1497,21 @@ CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); } -/* We only support 1 slot. If the slot exists, the token exists. */ +/* + * Process list of readers, and create mapping between reader name and slot ID + */ CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { - CK_ULONG count, slot_present = 0, currslot; + int mutex_retval; + int pcsc_connect_ret; + CK_ULONG count, slot_count = 0, currslot; + char *pcsc_readers, *pcsc_readers_s, *pcsc_readers_e; + DWORD pcsc_readers_len; + LONG scard_listreaders_ret; + size_t curr_reader_len; CACKEY_DEBUG_PRINTF("Called."); if (pulCount == NULL) { CACKEY_DEBUG_PRINTF("Error. pulCount is NULL."); @@ -806,55 +1523,146 @@ CACKEY_DEBUG_PRINTF("Error. Not initialized."); return(CKR_CRYPTOKI_NOT_INITIALIZED); } - /* XXX: Determine if slot is present */ + mutex_retval = cackey_mutex_lock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Locking failed."); + + return(CKR_GENERAL_ERROR); + } + + /* Clear list of slots */ + if (pSlotList) { + /* Only update the list of slots if we are actually being supply the slot information */ + cackey_slots_disconnect_all(); + + for (currslot = 0; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) { + if (cackey_slots[currslot].pcsc_reader) { + free(cackey_slots[currslot].pcsc_reader); + + cackey_slots[currslot].pcsc_reader = NULL; + } + + cackey_slots[currslot].active = 0; + } + } + + /* Determine list of readers */ + pcsc_connect_ret = cackey_pcsc_connect(); + if (pcsc_connect_ret < 0) { + CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, assuming no slots"); + + slot_count = 0; + } else { + pcsc_readers_len = 0; + + scard_listreaders_ret = SCardListReaders(*cackey_pcsc_handle, NULL, NULL, &pcsc_readers_len); + if (scard_listreaders_ret == SCARD_S_SUCCESS && pcsc_readers_len != 0) { + pcsc_readers = malloc(pcsc_readers_len); + pcsc_readers_s = pcsc_readers; + + scard_listreaders_ret = SCardListReaders(*cackey_pcsc_handle, NULL, pcsc_readers, &pcsc_readers_len); + if (scard_listreaders_ret == SCARD_S_SUCCESS) { + pcsc_readers_e = pcsc_readers + pcsc_readers_len; + + currslot = 0; + while (pcsc_readers < pcsc_readers_e) { + curr_reader_len = strlen(pcsc_readers); + + if ((pcsc_readers + curr_reader_len) > pcsc_readers_e) { + break; + } + + if (curr_reader_len == 0) { + break; + } + + if (currslot >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) { + CACKEY_DEBUG_PRINTF("Found more readers than slots are available!"); + + break; + } + + CACKEY_DEBUG_PRINTF("Found reader: %s", pcsc_readers); + + /* Only update the list of slots if we are actually being supply the slot information */ + if (pSlotList) { + cackey_slots[currslot].active = 1; + cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers); + cackey_slots[currslot].pcsc_card_connected = 0; + } + currslot++; + + pcsc_readers += curr_reader_len + 1; + } + + if (currslot > 0) { + slot_count = currslot; + } + } + + free(pcsc_readers_s); + } + } + + mutex_retval = cackey_mutex_unlock(cackey_biglock); + if (mutex_retval != 0) { + CACKEY_DEBUG_PRINTF("Error. Unlocking failed."); + + return(CKR_GENERAL_ERROR); + } if (pSlotList == NULL) { - *pulCount = slot_present; + *pulCount = slot_count; CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); } count = *pulCount; - if (count < slot_present) { - CACKEY_DEBUG_PRINTF("Error. User allocated %lu entries, but we have %lu entries.", count, slot_present); + if (count < slot_count) { + CACKEY_DEBUG_PRINTF("Error. User allocated %lu entries, but we have %lu entries.", count, slot_count); return(CKR_BUFFER_TOO_SMALL); } - for (currslot = 0; currslot < slot_present; currslot++) { + for (currslot = 0; currslot < slot_count; currslot++) { pSlotList[currslot] = currslot; } - *pulCount = slot_present; + *pulCount = slot_count; CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); tokenPresent = tokenPresent; /* Supress unused variable warning */ } CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { - static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; static CK_UTF8CHAR slotDescription[] = "CACKey Slot"; + int bytes_to_copy; CACKEY_DEBUG_PRINTF("Called."); if (pInfo == NULL) { CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); return(CKR_ARGUMENTS_BAD); } - if (slotID != 0) { - /* Again, we only support one slot -- slot 0 */ - CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", 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_SLOT_ID_INVALID); + } + + if (cackey_slots[slotID].active == 0) { + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); return(CKR_SLOT_ID_INVALID); } if (!cackey_initialized) { @@ -865,13 +1673,22 @@ memset(pInfo->slotDescription, ' ', sizeof(pInfo->slotDescription)); memcpy(pInfo->slotDescription, slotDescription, sizeof(slotDescription) - 1); memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); - memcpy(pInfo->manufacturerID, manufacturerID, sizeof(manufacturerID) - 1); - pInfo->flags = CKF_TOKEN_PRESENT; + bytes_to_copy = strlen(cackey_slots[slotID].pcsc_reader); + 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 = 0; + + if (cackey_token_present(&cackey_slots[slotID])) { + pInfo->flags |= CKF_TOKEN_PRESENT; + } pInfo->hardwareVersion.major = (cackey_getversion() >> 16) & 0xff; pInfo->hardwareVersion.minor = (cackey_getversion() >> 8) & 0xff; pInfo->firmwareVersion.major = 0x00; @@ -893,13 +1710,18 @@ CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); return(CKR_ARGUMENTS_BAD); } - if (slotID != 0) { - /* Again, we only support one slot -- slot 0 */ - CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", 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_SLOT_ID_INVALID); + } + + if (cackey_slots[slotID].active == 0) { + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); return(CKR_SLOT_ID_INVALID); } if (!cackey_initialized) { @@ -906,20 +1728,12 @@ CACKEY_DEBUG_PRINTF("Error. Not initialized."); return(CKR_CRYPTOKI_NOT_INITIALIZED); } - /* XXX: Verify connection is valid */ - if (0) { - CACKEY_DEBUG_PRINTF("Error. Tried to connect to slot, but failed."); - - return(CKR_SLOT_ID_INVALID); - } - - /* XXX: Get list of identities */ - if (0) { - CACKEY_DEBUG_PRINTF("Error. No identities found in slot."); + if (!cackey_token_present(&cackey_slots[slotID])) { + CACKEY_DEBUG_PRINTF("No token is present in slotID = %lu", slotID); return(CKR_TOKEN_NOT_PRESENT); } memset(pInfo->label, ' ', sizeof(pInfo->label)); @@ -942,11 +1756,11 @@ pInfo->hardwareVersion.minor = (cackey_getversion() >> 8) & 0xff; pInfo->firmwareVersion.major = 0x00; pInfo->firmwareVersion.minor = 0x00; - pInfo->flags = CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH | CKF_TOKEN_INITIALIZED; + pInfo->flags = CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED; pInfo->ulMaxSessionCount = (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])) - 1; pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION; pInfo->ulMaxRwSessionCount = 0; pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; @@ -1021,13 +1835,18 @@ } CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { CACKEY_DEBUG_PRINTF("Called."); - if (slotID != 0) { - /* Again, we only support one slot -- slot 0 */ - CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", 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_SLOT_ID_INVALID); + } + + if (cackey_slots[slotID].active == 0) { + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); return(CKR_SLOT_ID_INVALID); } if (pInfo == NULL) { @@ -1112,20 +1931,27 @@ } CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) { struct cackey_identity *identities; unsigned long idx, num_ids, id_idx, curr_id_type; +#if 0 CK_BYTE sigbuf[1024]; ssize_t sigbuflen; +#endif int mutex_retval; int found_session = 0; CACKEY_DEBUG_PRINTF("Called."); - if (slotID != 0) { - /* We only support one slot -- slot 0 */ - CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", 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_SLOT_ID_INVALID); + } + + if (cackey_slots[slotID].active == 0) { + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); return(CKR_SLOT_ID_INVALID); } if ((flags & CKF_SERIAL_SESSION) != CKF_SERIAL_SESSION) { @@ -1297,13 +2123,18 @@ uint32_t idx; int mutex_retval; CACKEY_DEBUG_PRINTF("Called."); - if (slotID != 0) { - /* Again, we only support one slot -- slot 0 */ - CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), only one slot available: 0", 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_SLOT_ID_INVALID); + } + + if (cackey_slots[slotID].active == 0) { + CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID); return(CKR_SLOT_ID_INVALID); } if (!cackey_initialized) { ADDED test.c Index: test.c ================================================================== --- test.c +++ test.c @@ -0,0 +1,543 @@ +#include "mypkcs11.h" + +#include +#include +#include +#include +#include + +static char *pkcs11_attribute_to_name(CK_ATTRIBUTE_TYPE attrib) { + static char retbuf[1024]; + + switch (attrib) { + case 0x00000000: return "CKA_CLASS"; + case 0x00000001: return "CKA_TOKEN"; + case 0x00000002: return "CKA_PRIVATE"; + case 0x00000003: return "CKA_LABEL"; + case 0x00000010: return "CKA_APPLICATION"; + case 0x00000011: return "CKA_VALUE"; + case 0x00000012: return "CKA_OBJECT_ID"; + case 0x00000080: return "CKA_CERTIFICATE_TYPE"; + case 0x00000081: return "CKA_ISSUER"; + case 0x00000082: return "CKA_SERIAL_NUMBER"; + case 0x00000083: return "CKA_AC_ISSUER"; + case 0x00000084: return "CKA_OWNER"; + case 0x00000085: return "CKA_ATTR_TYPES"; + case 0x00000086: return "CKA_TRUSTED"; + case 0x00000100: return "CKA_KEY_TYPE"; + case 0x00000101: return "CKA_SUBJECT"; + case 0x00000102: return "CKA_ID"; + case 0x00000103: return "CKA_SENSITIVE"; + case 0x00000104: return "CKA_ENCRYPT"; + case 0x00000105: return "CKA_DECRYPT"; + case 0x00000106: return "CKA_WRAP"; + case 0x00000107: return "CKA_UNWRAP"; + case 0x00000108: return "CKA_SIGN"; + case 0x00000109: return "CKA_SIGN_RECOVER"; + case 0x0000010A: return "CKA_VERIFY"; + case 0x0000010B: return "CKA_VERIFY_RECOVER"; + case 0x0000010C: return "CKA_DERIVE"; + case 0x00000110: return "CKA_START_DATE"; + case 0x00000111: return "CKA_END_DATE"; + case 0x00000120: return "CKA_MODULUS"; + case 0x00000121: return "CKA_MODULUS_BITS"; + case 0x00000122: return "CKA_PUBLIC_EXPONENT"; + case 0x00000123: return "CKA_PRIVATE_EXPONENT"; + case 0x00000124: return "CKA_PRIME_1"; + case 0x00000125: return "CKA_PRIME_2"; + case 0x00000126: return "CKA_EXPONENT_1"; + case 0x00000127: return "CKA_EXPONENT_2"; + case 0x00000128: return "CKA_COEFFICIENT"; + case 0x00000130: return "CKA_PRIME"; + case 0x00000131: return "CKA_SUBPRIME"; + case 0x00000132: return "CKA_BASE"; + case 0x00000133: return "CKA_PRIME_BITS"; + case 0x00000134: return "CKA_SUB_PRIME_BITS"; + case 0x00000160: return "CKA_VALUE_BITS"; + case 0x00000161: return "CKA_VALUE_LEN"; + case 0x00000162: return "CKA_EXTRACTABLE"; + case 0x00000163: return "CKA_LOCAL"; + case 0x00000164: return "CKA_NEVER_EXTRACTABLE"; + case 0x00000165: return "CKA_ALWAYS_SENSITIVE"; + case 0x00000166: return "CKA_KEY_GEN_MECHANISM"; + case 0x00000170: return "CKA_MODIFIABLE"; + case 0x00000180: return "CKA_EC_PARAMS"; + case 0x00000181: return "CKA_EC_POINT"; + case 0x00000200: return "CKA_SECONDARY_AUTH"; + case 0x00000201: return "CKA_AUTH_PIN_FLAGS"; + case 0x00000300: return "CKA_HW_FEATURE_TYPE"; + case 0x00000301: return "CKA_RESET_ON_INIT"; + case 0x00000302: return "CKA_HAS_RESET"; + } + + snprintf(retbuf, sizeof(retbuf), "0x%08lx", (unsigned long) attrib); + retbuf[sizeof(retbuf) - 1] = '\0'; + + return(retbuf); +} + +int main_pkcs11(void) { + CK_C_INITIALIZE_ARGS initargs; + CK_INFO clientinfo; + CK_ULONG numSlots, currSlot; + CK_SLOT_ID_PTR slots; + CK_SLOT_INFO slotInfo; + CK_TOKEN_INFO tokenInfo; + CK_SESSION_HANDLE hSession; + CK_SESSION_INFO sessionInfo; + CK_OBJECT_HANDLE hObject, *privateKeyObjects_root, *privateKeyObjects, *currPrivKey; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, NULL, 0}, + {CKA_TOKEN, NULL, 0}, + {CKA_LABEL, NULL, 0}, + {CKA_PRIVATE, NULL, 0}, + {CKA_ID, NULL, 0}, + {CKA_SERIAL_NUMBER, NULL, 0}, + {CKA_SUBJECT, NULL, 0}, + {CKA_ISSUER, NULL, 0}, + {CKA_PRIVATE, NULL, 0}, + {CKA_CERTIFICATE_TYPE, NULL, 0}, + {CKA_KEY_TYPE, NULL, 0}, + {CKA_SIGN, NULL, 0}, + {CKA_VALUE, NULL, 0} + }, *curr_attr; + CK_ULONG curr_attr_idx; + CK_ULONG byte_idx; + CK_UTF8CHAR user_pin[1024], *pucValue; + CK_OBJECT_CLASS objectClass; + CK_BYTE signature[1024], encrypted_buf[16384], decrypted_buf[16384]; + CK_ULONG signature_len, encrypted_buflen, decrypted_buflen; + CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL, 0}; + CK_RV chk_rv; + int i; + + privateKeyObjects = malloc(sizeof(*privateKeyObjects) * 1024); + privateKeyObjects_root = privateKeyObjects; + for (i = 0; i < 1024; i++) { + privateKeyObjects[i] = CK_INVALID_HANDLE; + } + + initargs.CreateMutex = NULL; + initargs.DestroyMutex = NULL; + initargs.LockMutex = NULL; + initargs.UnlockMutex = NULL; + initargs.flags = CKF_OS_LOCKING_OK; + initargs.pReserved = NULL; + initargs.LibraryParameters = NULL; + + chk_rv = C_Initialize(&initargs); + if (chk_rv != CKR_OK) { + initargs.CreateMutex = NULL; + initargs.DestroyMutex = NULL; + initargs.LockMutex = NULL; + initargs.UnlockMutex = NULL; + initargs.flags = 0; + initargs.pReserved = NULL; + + chk_rv = C_Initialize(&initargs); + if (chk_rv != CKR_OK) { + printf("C_Initialize() failed."); + + return(1); + } + } + + chk_rv = C_GetInfo(&clientinfo); + if (chk_rv != CKR_OK) { + return(1); + } + + printf("PKCS#11 Client Version: %i.%i, Library Version %i.%i\n", clientinfo.cryptokiVersion.major, clientinfo.cryptokiVersion.minor, clientinfo.libraryVersion.major, clientinfo.libraryVersion.minor); + printf("PKCS#11 ManufID: %.*s, LibraryDesc: %.*s\n", 32, clientinfo.manufacturerID, 32, clientinfo.libraryDescription); + + chk_rv = C_GetSlotList(FALSE, NULL, &numSlots); + if (chk_rv != CKR_OK) { + return(1); + } + + printf("Number of Slots: %lu\n", numSlots); + + slots = malloc(sizeof(*slots) * numSlots); + + chk_rv = C_GetSlotList(FALSE, slots, &numSlots); + if (chk_rv != CKR_OK) { + return(1); + } + + for (currSlot = 0; currSlot < numSlots; currSlot++) { + printf(" Slot %lu:\n", currSlot); + + chk_rv = C_GetSlotInfo(slots[currSlot], &slotInfo); + if (chk_rv != CKR_OK) { + return(1); + } + + printf(" Desc : %.*s\n", 32, slotInfo.slotDescription); + printf(" ManufID: %.*s\n", 32, slotInfo.manufacturerID); + printf(" HWVers : %i.%i\n", slotInfo.hardwareVersion.major, slotInfo.hardwareVersion.minor); + printf(" FWVers : %i.%i\n", slotInfo.firmwareVersion.major, slotInfo.firmwareVersion.minor); + printf(" Flags : "); + if ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) { + printf("CKF_TOKEN_PRESENT "); + } + if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == CKF_REMOVABLE_DEVICE) { + printf("CKF_REMOVABLE_DEVICE "); + } + if ((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT) { + printf("CKF_HW_SLOT "); + } + printf("\n"); + + if ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) { + printf(" Token:\n"); + + chk_rv = C_GetTokenInfo(slots[currSlot], &tokenInfo); + if (chk_rv != CKR_OK) { + return(1); + } + + printf(" Label : %.*s\n", 32, tokenInfo.label); + printf(" ManufID: %.*s\n", 32, tokenInfo.manufacturerID); + printf(" Model : %.*s\n", 16, tokenInfo.model); + printf(" SerNo : %.*s\n", 16, tokenInfo.serialNumber); + printf(" HWVers : %i.%i\n", tokenInfo.hardwareVersion.major, tokenInfo.hardwareVersion.minor); + printf(" FWVers : %i.%i\n", tokenInfo.firmwareVersion.major, tokenInfo.firmwareVersion.minor); + printf(" Flags : "); + if ((tokenInfo.flags & CKF_RNG) == CKF_RNG) { + printf("CKF_RNG "); + } + if ((tokenInfo.flags & CKF_WRITE_PROTECTED) == CKF_WRITE_PROTECTED) { + printf("CKF_WRITE_PROTECTED "); + } + if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED) { + printf("CKF_LOGIN_REQUIRED "); + } + if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == CKF_USER_PIN_INITIALIZED) { + printf("CKF_USER_PIN_INITIALIZED "); + } + if ((tokenInfo.flags & CKF_RESTORE_KEY_NOT_NEEDED) == CKF_RESTORE_KEY_NOT_NEEDED) { + printf("CKF_RESTORE_KEY_NOT_NEEDED "); + } + if ((tokenInfo.flags & CKF_CLOCK_ON_TOKEN) == CKF_CLOCK_ON_TOKEN) { + printf("CKF_CLOCK_ON_TOKEN "); + } + if ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == CKF_PROTECTED_AUTHENTICATION_PATH) { + printf("CKF_PROTECTED_AUTHENTICATION_PATH "); + } + if ((tokenInfo.flags & CKF_DUAL_CRYPTO_OPERATIONS) == CKF_DUAL_CRYPTO_OPERATIONS) { + printf("CKF_DUAL_CRYPTO_OPERATIONS "); + } + if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED) { + printf("CKF_TOKEN_INITIALIZED "); + } + if ((tokenInfo.flags & CKF_SECONDARY_AUTHENTICATION) == CKF_SECONDARY_AUTHENTICATION) { + printf("CKF_SECONDARY_AUTHENTICATION "); + } + if ((tokenInfo.flags & CKF_USER_PIN_COUNT_LOW) == CKF_USER_PIN_COUNT_LOW) { + printf("CKF_USER_PIN_COUNT_LOW "); + } + if ((tokenInfo.flags & CKF_USER_PIN_FINAL_TRY) == CKF_USER_PIN_FINAL_TRY) { + printf("CKF_USER_PIN_FINAL_TRY "); + } + if ((tokenInfo.flags & CKF_USER_PIN_LOCKED) == CKF_USER_PIN_LOCKED) { + printf("CKF_USER_PIN_LOCKED "); + } + if ((tokenInfo.flags & CKF_USER_PIN_TO_BE_CHANGED) == CKF_USER_PIN_TO_BE_CHANGED) { + printf("CKF_USER_PIN_TO_BE_CHANGED "); + } + if ((tokenInfo.flags & CKF_SO_PIN_COUNT_LOW) == CKF_SO_PIN_COUNT_LOW) { + printf("CKF_SO_PIN_COUNT_LOW "); + } + if ((tokenInfo.flags & CKF_SO_PIN_FINAL_TRY) == CKF_SO_PIN_FINAL_TRY) { + printf("CKF_SO_PIN_FINAL_TRY "); + } + if ((tokenInfo.flags & CKF_SO_PIN_LOCKED) == CKF_SO_PIN_LOCKED) { + printf("CKF_SO_PIN_LOCKED "); + } + if ((tokenInfo.flags & CKF_SO_PIN_TO_BE_CHANGED) == CKF_SO_PIN_TO_BE_CHANGED) { + printf("CKF_SO_PIN_TO_BE_CHANGED "); + } + printf("\n"); + } + } + + chk_rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION, NULL, NULL, &hSession); + if (chk_rv == CKR_OK) { + if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED) { + printf("** ENTER PIN: "); + fflush(stdout); + + fgets((char *) user_pin, sizeof(user_pin), stdin); + while (user_pin[strlen((char *) user_pin) - 1] < ' ') { + user_pin[strlen((char *) user_pin) - 1] = '\0'; + } + + chk_rv = C_Login(hSession, CKU_USER, user_pin, strlen((char *) user_pin)); + } else { + chk_rv = C_Login(hSession, CKU_USER, NULL, 0); + } + if (chk_rv == CKR_OK) { + printf("Login to device succeed.\n"); + } else { + printf("Login to device failed.\n"); + } + + chk_rv = C_GetSessionInfo(hSession, &sessionInfo); + if (chk_rv == CKR_OK) { + printf("Session Info:\n"); + printf(" Slot ID: %lu\n", (unsigned long) sessionInfo.slotID); + printf(" Dev Err: %lu\n", (unsigned long) sessionInfo.ulDeviceError); + + printf(" State : "); + if (sessionInfo.state == CKS_RO_PUBLIC_SESSION) { + printf("CKS_RO_PUBLIC_SESSION\n"); + } else if (sessionInfo.state == CKS_RO_USER_FUNCTIONS) { + printf("CKS_RO_USER_FUNCTIONS\n"); + } else if (sessionInfo.state == CKS_RW_PUBLIC_SESSION) { + printf("CKS_RW_PUBLIC_SESSION\n"); + } else if (sessionInfo.state == CKS_RW_USER_FUNCTIONS) { + printf("CKS_RW_USER_FUNCTIONS\n"); + } else if (sessionInfo.state == CKS_RO_PUBLIC_SESSION) { + printf("CKS_RW_SO_FUNCTIONS\n"); + } else { + printf("Unknown (%lu)", (unsigned long) sessionInfo.state); + } + + printf(" Flags : "); + if ((sessionInfo.flags & CKF_RW_SESSION) == CKF_RW_SESSION) { + printf("CKF_RW_SESSION "); + } + if ((sessionInfo.flags & CKF_SERIAL_SESSION) == CKF_SERIAL_SESSION) { + printf("CKF_SERIAL_SESSION "); + } + printf("\n"); + } else { + printf("GetSessionInfo() failed.\n"); + } + + chk_rv = C_FindObjectsInit(hSession, NULL, 0); + if (chk_rv == CKR_OK) { + while (1) { + chk_rv = C_FindObjects(hSession, &hObject, 1, &ulObjectCount); + if (chk_rv != CKR_OK) { + printf("FindObjects() failed.\n"); + break; + } + + if (ulObjectCount == 0) { + break; + } + + if (ulObjectCount != 1) { + printf("FindObjects() returned a weird number of objects. Asked for 1, got %lu.\n", ulObjectCount); + break; + } + + printf(" Object Info (object %lu):\n", (unsigned long) hObject); + + for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) { + curr_attr = &template[curr_attr_idx]; + if (curr_attr->pValue) { + free(curr_attr->pValue); + } + + curr_attr->pValue = NULL; + } + + chk_rv = C_GetAttributeValue(hSession, hObject, &template[0], sizeof(template) / sizeof(template[0])); + if (chk_rv == CKR_ATTRIBUTE_TYPE_INVALID || chk_rv == CKR_ATTRIBUTE_SENSITIVE || chk_rv == CKR_BUFFER_TOO_SMALL) { + chk_rv = CKR_OK; + } + + if (chk_rv == CKR_OK) { + for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) { + curr_attr = &template[curr_attr_idx]; + + if (((CK_LONG) curr_attr->ulValueLen) != ((CK_LONG) -1)) { + curr_attr->pValue = malloc(curr_attr->ulValueLen); + } + } + + chk_rv = C_GetAttributeValue(hSession, hObject, &template[0], sizeof(template) / sizeof(template[0])); + if (chk_rv == CKR_OK || chk_rv == CKR_ATTRIBUTE_SENSITIVE || chk_rv == CKR_ATTRIBUTE_TYPE_INVALID || chk_rv == CKR_BUFFER_TOO_SMALL) { + for (curr_attr_idx = 0; curr_attr_idx < (sizeof(template) / sizeof(template[0])); curr_attr_idx++) { + curr_attr = &template[curr_attr_idx]; + + if (curr_attr->pValue) { + switch (curr_attr->type) { + case CKA_LABEL: + printf(" [%lu] %20s: %.*s\n", hObject, pkcs11_attribute_to_name(curr_attr->type), (int) curr_attr->ulValueLen, (char *) curr_attr->pValue); + break; + case CKA_CLASS: + objectClass = *((CK_OBJECT_CLASS *) curr_attr->pValue); + + if (objectClass == CKO_PRIVATE_KEY) { + *privateKeyObjects = hObject; + privateKeyObjects++; + } + case CKA_TOKEN: + case CKA_ID: + case CKA_SERIAL_NUMBER: + case CKA_PRIVATE: + case CKA_CERTIFICATE_TYPE: + case CKA_KEY_TYPE: + case CKA_SIGN: + case CKA_DECRYPT: + pucValue = curr_attr->pValue; + + printf(" [%lu] %20s: ", hObject, pkcs11_attribute_to_name(curr_attr->type)); + + for (byte_idx = 0; byte_idx < curr_attr->ulValueLen; byte_idx++) { + printf("%02x ", (unsigned int) pucValue[byte_idx]); + } + + printf(";; %p/%lu\n", curr_attr->pValue, curr_attr->ulValueLen); + + break; + case CKA_SUBJECT: + case CKA_ISSUER: + pucValue = curr_attr->pValue; + + printf(" [%lu] %20s: ", hObject, pkcs11_attribute_to_name(curr_attr->type)); + + for (byte_idx = 0; byte_idx < curr_attr->ulValueLen; byte_idx++) { + printf("\\x%02x", (unsigned int) pucValue[byte_idx]); + } + + printf(" ;; %p/%lu\n", curr_attr->pValue, curr_attr->ulValueLen); + + break; + default: + printf(" [%lu] %20s: %p/%lu\n", hObject, pkcs11_attribute_to_name(curr_attr->type), curr_attr->pValue, curr_attr->ulValueLen); + + break; + } + } else { + printf(" [%lu] %20s: (not found)\n", hObject, pkcs11_attribute_to_name(curr_attr->type)); + } + + free(curr_attr->pValue); + curr_attr->pValue = NULL; + } + } else { + printf("GetAttributeValue()/2 failed.\n"); + } + } else { + printf("GetAttributeValue(hObject=%lu)/1 failed (rv = %lu).\n", (unsigned long) hObject, (unsigned long) chk_rv); + } + + } + + chk_rv = C_FindObjectsFinal(hSession); + if (chk_rv != CKR_OK) { + printf("FindObjectsFinal() failed.\n"); + } + } else { + printf("FindObjectsInit() failed.\n"); + } + + printf("--- Operations ---\n"); + + for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) { + chk_rv = C_SignInit(hSession, &mechanism, *currPrivKey); + if (chk_rv == CKR_OK) { + signature_len = sizeof(signature); + + chk_rv = C_Sign(hSession, (CK_BYTE_PTR) "Test", strlen("Test"), (CK_BYTE_PTR) &signature, &signature_len); + if (chk_rv == CKR_OK) { + printf("[%04lu/%02lx] Signature: ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism); + + for (byte_idx = 0; byte_idx < signature_len; byte_idx++) { + printf("%02x ", (unsigned int) signature[byte_idx]); + } + + printf("\n"); + } else { + printf("Sign() failed.\n"); + } + } else { + printf("SignInit() failed.\n"); + } + } + + for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) { + chk_rv = C_EncryptInit(hSession, &mechanism, *currPrivKey); + if (chk_rv == CKR_OK) { + encrypted_buflen = sizeof(encrypted_buf); + + chk_rv = C_Encrypt(hSession, (CK_BYTE_PTR) "Test", strlen("Test"), encrypted_buf, &encrypted_buflen); + if (chk_rv == CKR_OK) { + printf("[%04lu/%02lx] Encrypted(Test): ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism); + + for (byte_idx = 0; byte_idx < encrypted_buflen; byte_idx++) { + printf("%02x ", (unsigned int) encrypted_buf[byte_idx]); + } + + printf("\n"); + } else { + printf("Encrypt() failed.\n"); + } + } else { + printf("EncryptInit() failed.\n"); + } + } + + for (currPrivKey = privateKeyObjects_root; *currPrivKey != CK_INVALID_HANDLE; currPrivKey++) { + chk_rv = C_DecryptInit(hSession, &mechanism, *currPrivKey); + if (chk_rv == CKR_OK) { + decrypted_buflen = sizeof(decrypted_buf); + + chk_rv = C_Decrypt(hSession, (CK_BYTE_PTR) "\x4c\x36\x0f\x86\x2d\xb7\xb2\x46\x92\x11\x7e\x5f\xd1\xeb\x2c\xb0\xdb\x34\x60\xb8\x0c\xf8\x27\xb5\xfb\xce\xd1\xf4\x58\xa3\x20\x52\x9d\x97\x08\xd8\x2b\x5e\xb2\x37\x46\x72\x45\x7c\x66\x23\x53\xb5\xa5\x16\x61\x96\xbc\x5c\x8d\x85\x18\x24\xcf\x74\x7f\xc2\x23\x15\xd6\x42\x72\xa5\x2b\x29\x29\x1d\xa6\xea\x2b\xcb\x57\x59\xb3\x5f\xe2\xf8\x30\x12\x2f\x1b\xfa\xbd\xa9\x19\xef\x5c\xbb\x48\xdc\x28\x42\xdd\x90\xbe\x63\xeb\x59\x0c\xaf\x59\xcb\xe4\x6a\xf2\x56\x24\x41\xc2\x77\x7b\xc9\xf8\x02\x0f\x67\x3d\x2a\x98\x91\x14\xa2\x57", 128, decrypted_buf, &decrypted_buflen); + if (chk_rv == CKR_OK) { + printf("[%04lu/%02lx] Decrypted(It works!): ", (unsigned long) *currPrivKey, (unsigned long) mechanism.mechanism); + + for (byte_idx = 0; byte_idx < decrypted_buflen; byte_idx++) { + printf("%02x ", (unsigned int) decrypted_buf[byte_idx]); + } + + printf("\n"); + } else { + printf("Decrypt() failed.\n"); + } + } else { + printf("DecryptInit() failed.\n"); + } + } + + chk_rv = C_CloseSession(hSession); + if (chk_rv != CKR_OK) { + printf("CloseSession failed.\n"); + } + } else { + printf("OpenSession failed.\n"); + } + + C_Finalize(NULL); + + if (slots) { + free(slots); + } + + if (privateKeyObjects_root) { + free(privateKeyObjects_root); + } + + return(0); +} + +int main(void) { + int retval = 0, ck_retval; + + printf("Testing libcackey...\n"); + + ck_retval = main_pkcs11(); + + if (ck_retval != 0) { + retval = ck_retval; + } + + printf("Testing libcackey... DONE. Status = %i\n", ck_retval); + + return(retval); +}