Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -1,10 +1,10 @@ CC = @PTHREAD_CC@ CFLAGS = @CFLAGS@ @PTHREAD_CFLAGS@ -DEBUGCFLAGS = @CFLAGS@ @PTHREAD_CFLAGS@ +DEBUGCFLAGS = @CFLAGS@ @PTHREAD_CFLAGS@ -DCACKEY_DEBUG=1 CPPFLAGS = @CPPFLAGS@ @DEFS@ -I./pkcs11/ -DEBUGCPPFLAGS = @CPPFLAGS@ @DEFS@ +DEBUGCPPFLAGS = @CPPFLAGS@ -DCACKEY_DEBUG=1 -I./pkcs11/ @DEFS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ @PTHREAD_LIBS@ SHOBJFLAGS = @SHOBJFLAGS@ SHOBJLDFLAGS = @SHOBJLDFLAGS@ AR = @AR@ Index: aclocal/dc_pcscheaders.m4 ================================================================== --- aclocal/dc_pcscheaders.m4 +++ aclocal/dc_pcscheaders.m4 @@ -9,14 +9,24 @@ headerdir="${headerpath}/${subdir}" CFLAGS="${SAVE_CFLAGS} -I${headerdir}" CPPFLAGS="${SAVE_CPPFLAGS} -I${headerdir}" unset ac_cv_header_pcsclite_h + unset ac_cv_header_winscard_h AC_CHECK_HEADER(pcsclite.h, [ AC_DEFINE(HAVE_PCSCLITE_H, [1], [Define if you have the PCSC-Lite header file (you should)]) + ADD_CFLAGS=" -I${headerdir}" + ADD_CPPFLAGS=" -I${headerdir}" + + break + ]) + + AC_CHECK_HEADER(winscard.h, [ + AC_DEFINE(HAVE_WINSCARD_H, [1], [Define if you have the PCSC-Lite header file (you should)]) + ADD_CFLAGS=" -I${headerdir}" ADD_CPPFLAGS=" -I${headerdir}" break ]) @@ -27,6 +37,28 @@ fi done CFLAGS="${SAVE_CFLAGS}${ADD_CFLAGS}" CPPFLAGS="${SAVE_CPPFLAGS}${ADD_CPPFLAGS}" + + unset ac_cv_header_winscard_h + AC_CHECK_HEADER(winscard.h, [ + AC_DEFINE(HAVE_WINSCARD_H, [1], [Define if you have the PCSC-Lite header file (you should)]) + ]) +]) + +AC_DEFUN(DC_PCSC_LIBS, [ + for lib in pcsclite pcsc-lite pcsc; do + AC_CHECK_LIB(${lib}, SCardEstablishContext, [ + LIBS="${LIBS} -l${lib}" + + break + ]) + done + + AC_CHECK_FUNCS(SCardIsValidContext) +]) + +AC_DEFUN(DC_PCSC, [ + DC_PCSC_HEADERS + DC_PCSC_LIBS ]) Index: cackey.c ================================================================== --- cackey.c +++ cackey.c @@ -3,10 +3,13 @@ #endif #ifdef HAVE_PCSCLITE_H # include #endif +#ifdef HAVE_WINSCARD_H +# include +#endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_INTTYPES_H # include @@ -129,16 +132,20 @@ CK_MECHANISM_TYPE decrypt_mechanism; CK_VOID_PTR decrypt_mech_parm; CK_ULONG decrypt_mech_parmlen; }; +/* CACKEY Global Handles */ static void *cackey_biglock = NULL; -static struct cackey_session cackey_sessions[8]; +static struct cackey_session cackey_sessions[128]; static int cackey_initialized = 0; static int cackey_biglock_init = 0; CK_C_INITIALIZE_ARGS cackey_args; +/* PCSC Global Handles */ +static LPSCARDCONTEXT cackey_pcsc_handle = NULL; + static unsigned long cackey_getversion(void) { static unsigned long retval = 255; unsigned long major = 0; unsigned long minor = 0; char *major_str = NULL; @@ -169,10 +176,60 @@ 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) { + LONG scard_est_context_ret; +#ifdef HAVE_SCARDISVALIDCONTEXT + LONG scard_isvalid_ret; +#endif + + CACKEY_DEBUG_PRINTF("Called."); + + 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"); + + return(-1); + } + + 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); + + return(-1); + } + } + +#ifdef HAVE_SCARDISVALIDCONTEXT + 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..."); + + 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); + + return(-1); + } + + CACKEY_DEBUG_PRINTF("Handle has been re-established"); + } +#endif + + /* Connect to a reader, if needed */ + + /* Transmit */ +} /* Returns 0 on success */ static int cackey_mutex_create(void **mutex) { pthread_mutex_t *pthread_mutex; int pthread_retval; @@ -292,12 +349,11 @@ CK_OBJECT_CLASS ck_object_class; CK_CERTIFICATE_TYPE ck_certificate_type; CK_KEY_TYPE ck_key_type; CK_UTF8CHAR ucTmpBuf[1024]; unsigned char certificate[16384]; - ssize_t getcert_ret, certificate_len = -1, x509_read_ret; - int fd; + ssize_t certificate_len = -1, x509_read_ret; int pValue_free; CACKEY_DEBUG_PRINTF("Called (objectClass = %lu, identity_num = %lu).", (unsigned long) objectclass, identity_num); if (objectclass != CKO_CERTIFICATE && objectclass != CKO_PUBLIC_KEY && objectclass != CKO_PRIVATE_KEY) { @@ -697,11 +753,11 @@ return(CKR_OK); } CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) { static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; - static CK_UTF8CHAR libraryDescription[] = "SSH Agent PKCS#11"; + static CK_UTF8CHAR libraryDescription[] = "CACKey"; CACKEY_DEBUG_PRINTF("Called."); if (pInfo == NULL) { CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); @@ -735,11 +791,10 @@ } /* We only support 1 slot. If the slot exists, the token exists. */ 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 fd; CACKEY_DEBUG_PRINTF("Called."); if (pulCount == NULL) { CACKEY_DEBUG_PRINTF("Error. pulCount is NULL."); @@ -783,11 +838,11 @@ 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[] = "SSH Agent Slot"; + static CK_UTF8CHAR slotDescription[] = "CACKey Slot"; CACKEY_DEBUG_PRINTF("Called."); if (pInfo == NULL) { CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); @@ -828,12 +883,11 @@ } CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { static CK_UTF8CHAR manufacturerID[] = "U.S. Government"; static CK_UTF8CHAR defaultLabel[] = "Unknown Token"; - static CK_UTF8CHAR model[] = "SSH Agent Token"; - int fd, bytestocopy; + static CK_UTF8CHAR model[] = "CAC Token"; CACKEY_DEBUG_PRINTF("Called."); if (pInfo == NULL) { CACKEY_DEBUG_PRINTF("Error. pInfo is NULL."); @@ -854,11 +908,11 @@ return(CKR_CRYPTOKI_NOT_INITIALIZED); } /* XXX: Verify connection is valid */ if (0) { - CACKEY_DEBUG_PRINTF("Error. Tried to connect to slot, but failed. fd = %i", fd); + CACKEY_DEBUG_PRINTF("Error. Tried to connect to slot, but failed."); return(CKR_SLOT_ID_INVALID); } /* XXX: Get list of identities */ @@ -1057,16 +1111,15 @@ return(CKR_FUNCTION_NOT_SUPPORTED); } 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, curr_ssh_id_idx; + unsigned long idx, num_ids, id_idx, curr_id_type; CK_BYTE sigbuf[1024]; ssize_t sigbuflen; int mutex_retval; int found_session = 0; - int fd; CACKEY_DEBUG_PRINTF("Called."); if (slotID != 0) { /* We only support one slot -- slot 0 */ @@ -2126,11 +2179,10 @@ CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { static CK_BYTE buf[16384]; ssize_t buflen; CK_RV retval = CKR_GENERAL_ERROR; int mutex_retval; - int fd; CACKEY_DEBUG_PRINTF("Called."); if (!cackey_initialized) { CACKEY_DEBUG_PRINTF("Error. Not initialized."); @@ -2579,11 +2631,10 @@ static CK_BYTE sigbuf[1024]; ssize_t sigbuflen; CK_RV retval = CKR_GENERAL_ERROR; int terminate_sign = 1; int mutex_retval; - int fd; CACKEY_DEBUG_PRINTF("Called."); if (!cackey_initialized) { CACKEY_DEBUG_PRINTF("Error. Not initialized."); ADDED cackey_spm.c Index: cackey_spm.c ================================================================== --- /dev/null +++ cackey_spm.c @@ -0,0 +1,113 @@ +/* + * GSC-IS (v2.1) Service Call Level Service Provider Module for PC/SC Lite and + * DoD CAC/CACv2/PIV/PIVv2 Cards + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cackey_spm.h" + +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif + +unsigned long gscBsiUtilAcquireContext(unsigned long hCard, unsigned char *AID, struct BSIAuthenticator strctAuthenticator[], unsigned long authNb) { +} + +unsigned long gscBsiUtilConnect(unsigned char *readerName, unsigned long *hCard) { +} + +unsigned long gscBsiUtilDisconnect(unsigned long hCard) { +} + +unsigned long gscBsiUtilBeginTransaction(unsigned long hCard, _Bool blType) { +} + +unsigned long gscBsiUtilEndTransaction(unsigned long hCard) { +} + +unsigned long gscBsiUtilGetVersion(unsigned char **version) { + int sprintf_ret; + + if (version == NULL) { + return(BSI_UNKNOWN_ERROR); + } + + if (*version == NULL) { + sprintf_ret = sprintf(NULL, "2,1,0,%s", PACKAGE_VERSION); + + if (sprintf_ret <= 0) { + return(BSI_UNKNOWN_ERROR); + } + + *version = malloc(sprintf_ret + 1); + } + + /* Hopefully their buffer is large enough ... */ + sprintf(*version, "2,1,0,%s", PACKAGE_VERSION); + + return(BSI_OK); +} + +unsigned long gscBsiUtilGetCardProperties(unsigned long hCard, unsigned char **CCCUniqueID, unsigned long *cardCapability) { +} + +unsigned long gscBsiUtilGetCardStatus(unsigned long hCard) { +} + +unsigned long gscBsiUtilGetExtendedErrorText(unsigned long hCard, unsigned char **errorText) { + if (errorText == NULL) { + return(BSI_UNKNOWN_ERROR); + } + + *errorText = NULL; + + return(BSI_NO_TEXT_AVAILABLE); +} + +unsigned long gscBsiUtilGetReaderList(unsigned char ***readerList) { +} + +unsigned long gscBsiUtilPassthru(unsigned long hCard, unsigned char *cardCommand, unsigned char **cardResponse) { +} + +unsigned long gscBsiUtilReleaseContext(unsigned long hCard, unsigned char *AID) { +} + +unsigned long gscBsiGcDataCreate(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char *value) { +} + +unsigned long gscBsiGcDataDelete(unsigned long hCard, unsigned char *AID, unsigned char tag) { +} + +unsigned long gscBsiGcGetContainerProperties(unsigned long hCard, unsigned char *AID, struct GCacr *strctGCacr, struct GCContainerSize *strctContainerSizes, unsigned char **containerVersion) { +} + +unsigned long gscBsiGcReadTagList(unsigned long hCard, unsigned char *AID, unsigned char **tagArray) { +} + +unsigned long gscBsiGcReadValue(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char **value) { +} + +unsigned long gscBsiGcUpdateValue(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char *value) { +} + +unsigned long gscBsiGetChallenge(unsigned long hCard, unsigned char *AID, unsigned char **challenge) { +} + +unsigned long gscBsiSkiInternalAuthenticate(unsigned long hCard, unsigned char *AID, unsigned char algoID, unsigned char *challenge, unsigned char **cryptogram) { +} + +unsigned long gscBsiPkiCompute(unsigned long hCard, unsigned char *AID, unsigned char algoID, unsigned char *message, unsigned char **result) { +} + +unsigned long gscBsiPkiGetCertificate(unsigned long hCard, unsigned char *AID, unsigned char **Certificate) { +} + +unsigned long gscBsiGetCryptoProperties(unsigned long hCard, unsigned char *AID, struct CRYPTOacr *strctCRYPTOacr, unsigned long *keyLen) { +} ADDED cackey_spm.h Index: cackey_spm.h ================================================================== --- /dev/null +++ cackey_spm.h @@ -0,0 +1,119 @@ +/* + * GSC-IS (v2.1) Service Call Level Service Provider Module for PC/SC Lite and + * DoD CAC/CACv2/PIV/PIVv2 Cards + */ + +/* Access ... ? */ +#define BSI_AM_XAUTH 0x02 +#define BSI_AM_SECURE_CHANNEL_GP 0x04 +#define BSI_AM_PIN 0x06 +#define BSI_AM_SECURE_CHANNEL_ISO 0x0B + +/* Access Control Rules */ +#define BSI_ACR_ALWYS 0x00 +#define BSI_ACR_NEVER 0x01 +#define BSI_ACR_XAUTH 0x02 +#define BSI_ACR_XAUTH_OR_PIN 0x03 +#define BSI_SECURE_CHANNEL_GP 0x04 /* typo in spec? */ +#define BSI_ACR_SECURE_CHANNEL_GP 0x04 +#define BSI_ACR_PIN_ALWAYS 0x05 +#define BSI_ACR_PIN 0x06 +#define BSI_ACR_XAUTH_THEN_PIN 0x07 +#define BSI_ACR_UPDATE_ONCE 0x08 +#define BSI_ACR_PIN_THEN_XAUTH 0x09 +#define BSI_SECURE_CHANNEL_ISO 0x0B /* typo in spec? */ +#define BSI_ACR_SECURE_CHANNEL_ISO 0x0B +#define BSI_ACR_XAUTH_AND_PIN 0x0C + +/* Algorithms */ +#define BSI_CKM_DES3_ECB 0x81 +#define BSI_CKM_DES3_CBC 0x82 +#define BSI_CKM_RSA_NO_PAD 0xA3 + +/* Return Codes */ +#define BSI_OK 0x00 +#define BSI_ACCESS_DENIED 0x01 +#define BSI_ACR_NOT_AVAILABLE 0x02 +#define BSI_BAD_AID 0x03 +#define BSI_BAD_ALGO_ID 0x04 +#define BSI_BAD_AUTH 0x05 +#define BSI_BAD_HANDLE 0x06 +#define BSI_BAD_PARAM 0x07 +#define BSI_BAD_TAG 0x08 +#define BSI_CARD_ABSENT 0x09 +#define BSI_CARD_REMOVED 0x0A +#define BSI_NO_SPSSERVICE 0x0B +#define BSI_IO_ERROR 0x0C +#define BSI_INSUFFICIENT_BUFFER 0x0E +#define BSI_NO_CARDSERVICE 0x0F +#define BSI_NO_MORE_SPACE 0x10 +#define BSI_PIN_BLOCKED 0x11 +#define BSI_TAG_EXISTS 0x13 +#define BSI_TIMEOUT_ERROR 0x14 +#define BSI_TERMINAL_AUTH 0x15 +#define BSI_NO_TEXT_AVAILABLE 0x16 +#define BSI_UNKNOWN_ERROR 0x17 +#define BSI_UNKNOWN_READER 0x18 +#define BSI_SC_LOCKED 0x19 +#define BSI_NOT_TRANSACTED 0x20 + +#define MaxNbAM 50 + +struct BSIAcr { + unsigned long ACRType; + unsigned long keyIDOrReference[MaxNbAM]; + unsigned long AuthNb; + unsigned long ACRID; +}; + +struct GCacr { + struct BSIAcr createACR; + struct BSIAcr deleteACR; + struct BSIAcr readTagListACR; + struct BSIAcr readValueACR; + struct BSIAcr updateValueACR; +}; + +struct GCContainerSize { + unsigned long maxNbDataItems; + unsigned long maxValueStorageSize; + +}; + +struct CRYPTOacr { + struct BSIAcr getChallengeACR; + struct BSIAcr internalAuthenticateACR; + struct BSIAcr pkiComputeACR; + struct BSIAcr createACR; + struct BSIAcr deleteACR; + struct BSIAcr readTagListACR; + struct BSIAcr readValueACR; + struct BSIAcr updateValueACR; +}; + +struct BSIAuthenticator { +}; + +unsigned long gscBsiUtilAcquireContext(unsigned long hCard, unsigned char *AID, struct BSIAuthenticator strctAuthenticator[], unsigned long authNb); +unsigned long gscBsiUtilConnect(unsigned char *readerName, unsigned long *hCard); +unsigned long gscBsiUtilDisconnect(unsigned long hCard); +unsigned long gscBsiUtilBeginTransaction(unsigned long hCard, _Bool blType); +unsigned long gscBsiUtilEndTransaction(unsigned long hCard); +unsigned long gscBsiUtilGetVersion(unsigned char **version); +unsigned long gscBsiUtilGetCardProperties(unsigned long hCard, unsigned char **CCCUniqueID, unsigned long *cardCapability); +unsigned long gscBsiUtilGetCardStatus(unsigned long hCard); +unsigned long gscBsiUtilGetExtendedErrorText(unsigned long hCard, unsigned char **errorText); +unsigned long gscBsiUtilGetReaderList(unsigned char ***readerList); +unsigned long gscBsiUtilPassthru(unsigned long hCard, unsigned char *cardCommand, unsigned char **cardResponse); +unsigned long gscBsiUtilReleaseContext(unsigned long hCard, unsigned char *AID); +unsigned long gscBsiGcDataCreate(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char *value); +unsigned long gscBsiGcDataDelete(unsigned long hCard, unsigned char *AID, unsigned char tag); +unsigned long gscBsiGcGetContainerProperties(unsigned long hCard, unsigned char *AID, struct GCacr *strctGCacr, struct GCContainerSize *strctContainerSizes, unsigned char **containerVersion); +unsigned long gscBsiGcReadTagList(unsigned long hCard, unsigned char *AID, unsigned char **tagArray); +unsigned long gscBsiGcReadValue(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char **value); +unsigned long gscBsiGcUpdateValue(unsigned long hCard, unsigned char *AID, unsigned char tag, unsigned char *value); +unsigned long gscBsiGetChallenge(unsigned long hCard, unsigned char *AID, unsigned char **challenge); +unsigned long gscBsiSkiInternalAuthenticate(unsigned long hCard, unsigned char *AID, unsigned char algoID, unsigned char *challenge, unsigned char **cryptogram); +unsigned long gscBsiPkiCompute(unsigned long hCard, unsigned char *AID, unsigned char algoID, unsigned char *message, unsigned char **result); +unsigned long gscBsiPkiGetCertificate(unsigned long hCard, unsigned char *AID, unsigned char **Certificate); +unsigned long gscBsiGetCryptoProperties(unsigned long hCard, unsigned char *AID, struct CRYPTOacr *strctCRYPTOacr, unsigned long *keyLen); Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -61,12 +61,12 @@ #ifdef HAVE_PTHREAD_H # include #endif ]) -dnl Check for PC/SC headers -DC_PCSC_HEADERS +dnl Check for PC/SC headers and libraries +DC_PCSC dnl Upate LDFLAGS to include setting the run-time linker path to the same as our compile-time linker DC_SYNC_RPATH dnl If we updated LIBOBJS, update SHLIBOBJS -- must be last.