summaryrefslogtreecommitdiff
path: root/lib/libsectok/sc7816.c
diff options
context:
space:
mode:
authorJim Rees <rees@cvs.openbsd.org>2001-06-07 15:17:34 +0000
committerJim Rees <rees@cvs.openbsd.org>2001-06-07 15:17:34 +0000
commite79bf55dc158d93c85332d7364cc081c5ed7f004 (patch)
tree0f156334f09069ae3055840248ec836e9d39d4cc /lib/libsectok/sc7816.c
parentbe748640a8100f6e89cc57bac4fe6358cb57b868 (diff)
libsectok for secure tokens (smartcard, iButton, etc)
Diffstat (limited to 'lib/libsectok/sc7816.c')
-rw-r--r--lib/libsectok/sc7816.c504
1 files changed, 504 insertions, 0 deletions
diff --git a/lib/libsectok/sc7816.c b/lib/libsectok/sc7816.c
new file mode 100644
index 00000000000..8b0464f3667
--- /dev/null
+++ b/lib/libsectok/sc7816.c
@@ -0,0 +1,504 @@
+/*
+ * sc7816 library for use with pc/sc ifd drivers
+ *
+ * See copyright notice at end of file
+ *
+ * Jim Rees
+ * Mukesh Agrawal
+ * University of Michigan CITI, August 2000
+ */
+static char *rcsid = "$Id: sc7816.c,v 1.1 2001/06/07 15:17:33 rees Exp $";
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#ifdef SCPERF
+#define SCPERF_FIRST_APPEARANCE
+#endif /* SCPERF */
+
+#include "sectok.h"
+#include "ifdhandler.h"
+
+#define MAX_READERS 32
+
+#ifdef DL_READERS
+static char defaultConfigFilePath[] = "/etc/reader.conf";
+
+int DBUpdateReaders(char *readerconf, void (callback) (char *name, unsigned long channelId, char *driverFile));
+
+/* the callback for DBUpdateReaders */
+void addReader(char *name, unsigned long channelID, char *driverFile);
+void *lookupSym(void *handle, char *name);
+#endif
+
+int openReader(int readerNum, int flags);
+
+typedef struct {
+ unsigned long channelID;
+ char *driverPath;
+ unsigned int driverLoaded;
+ /* for now, i'm only worry about the "bare essentials" */
+ u_long (*open)(unsigned long channelID);
+ u_long (*close)(void);
+ u_long (*data)(struct SCARD_IO_HEADER junk,
+ unsigned char *cmdData, unsigned long cmdLen,
+ unsigned char *respData, unsigned long *respLen,
+ struct SCARD_IO_HEADER *moreJunk);
+ u_long (*power)(unsigned long command);
+ u_long (*getcapa)(unsigned long selector, unsigned char *buffer);
+ u_long (*setcapa)(unsigned long selector, unsigned char *buffer);
+ u_long (*cardpresent)(void);
+} readerInfo;
+
+char *scerrtab[] = {
+ "ok",
+ "no such tty",
+ "out of memory",
+ "timeout",
+ "slag!",
+ "card type not supported",
+ "no card in reader",
+ "not implemented",
+ "error loading driver",
+ "communications error",
+ "reader not open",
+ "unknown error",
+};
+
+unsigned int numReaders;
+readerInfo readers[MAX_READERS];
+
+/* NI, 11/1/2000 : Now the body of scopen() is in scxopen() to allow
+ specifing a path to the config file or the driver. scopen() is
+ an entry function for scxopen() to maintain backward compatibility. */
+int
+scopen(int ttyn, int flags, int *ep)
+{
+ return scxopen (ttyn, flags, ep, NULL, NULL);
+}
+
+/*
+ NI:
+
+ if (config_path != NULL and driver_name != NULL) error;
+ if (config_path != NULL) use reader.conf there;
+ if (driver_path != NULL) use the specified driver;
+ if (config_path == NULL and driver_path == NULL) use /etc/reader.conf;
+*/
+int
+scxopen(int ttyn, int flags, int *ep,
+ char *config_path, char *driver_path)
+{
+ int i, r;
+#ifdef DL_READERS
+ static char todos_driver_path[] = "/usr/local/pcsc/lib/libtodos_ag.so";
+ char *configFilePath = defaultConfigFilePath;
+#endif
+
+#ifdef SCPERF
+ SetTime ("scopen() start");
+#endif /* SCPERF */
+
+#ifdef DL_READERS
+ if (config_path != NULL && driver_path != NULL) {
+ /* both config path and driver path are
+ specified. thus conflict. */
+ return SCECNFFILES;
+ }
+ else if (config_path != NULL) {
+ /* config file specified */
+ configFilePath = config_path;
+ }
+ else if (driver_path != NULL) {
+ /* driver path is specified */
+ numReaders = 0;
+
+ addReader(NULL, 0x10000, driver_path);
+ addReader(NULL, 0x10001, driver_path);
+
+ goto open_readers;
+ }
+
+ for (i = 0; i < numReaders; i++) {
+ if (readers[i].driverPath) {
+ free(readers[i].driverPath);
+ readers[i].driverPath = NULL;
+ }
+ }
+ numReaders = 0;
+
+ if (DBUpdateReaders(configFilePath, addReader) < 0) {
+ /* This usually means there is no reader.conf. Supply a default. */
+ addReader(NULL, 0x10000, todos_driver_path);
+ addReader(NULL, 0x10001, todos_driver_path);
+ }
+#else
+ numReaders = 4;
+#endif
+
+ open_readers:
+ r = openReader(ttyn, flags);
+ if (ep)
+ *ep = r;
+
+ if (!r && (flags & SCODSR)) {
+ /* Wait for card present */
+ while (!sccardpresent(ttyn))
+ sleep(1);
+ }
+
+#ifdef SCPERF
+ SetTime ("scopen() end");
+#endif /* SCPERF */
+
+ return r ? -1 : ttyn;
+}
+
+int
+openReader(int readerNum, int flags)
+{
+ void *libHandle;
+ readerInfo *reader;
+
+#ifdef DEBUG
+ fprintf(stderr, "openReader %d\n", readerNum);
+#endif
+
+ if (readerNum < 0 || readerNum >= numReaders)
+ return SCEDRVR;
+ reader = &readers[readerNum];
+
+ if (!reader->driverLoaded) {
+#ifdef DL_READERS
+ if (!reader->driverPath)
+ return SCEDRVR;
+ libHandle = dlopen(reader->driverPath, RTLD_LAZY);
+ if (!libHandle) {
+#ifdef DEBUG
+ fprintf(stderr, "%s: %s\n", reader->driverPath, dlerror());
+#endif
+ return SCEDRVR;
+ }
+ reader->open = lookupSym(libHandle, "IO_Create_Channel");
+ if (reader->open == NULL)
+ return SCEDRVR;
+
+ reader->close = lookupSym(libHandle, "IO_Close_Channel");
+ if (reader->close == NULL)
+ return SCEDRVR;
+
+ reader->data = lookupSym(libHandle, "IFD_Transmit_to_ICC");
+ if (reader->data == NULL)
+ return SCEDRVR;
+
+ reader->power = lookupSym(libHandle, "IFD_Power_ICC");
+ if (reader->power == NULL)
+ return SCEDRVR;
+
+ reader->getcapa = lookupSym(libHandle, "IFD_Get_Capabilities");
+ if (reader->getcapa == NULL)
+ return SCEDRVR;
+
+ reader->setcapa = lookupSym(libHandle, "IFD_Set_Capabilities");
+ if (reader->setcapa == NULL)
+ return SCEDRVR;
+
+ reader->cardpresent = lookupSym(libHandle, "IFD_Is_ICC_Present");
+#else /* DL_READERS */
+ reader->open = IO_Create_Channel;
+ reader->close = IO_Close_Channel;
+ reader->data = IFD_Transmit_to_ICC;
+ reader->power = IFD_Power_ICC;
+ reader->getcapa = IFD_Get_Capabilities;
+ reader->setcapa = IFD_Set_Capabilities;
+ reader->cardpresent = IFD_Is_ICC_Present;
+ reader->channelID = (0x10000 | readerNum);
+#endif /* DL_READERS */
+
+ reader->driverLoaded = 1;
+ }
+
+ /* send flags to the driver */
+ reader->setcapa(SCTAG_OPEN_FLAGS, (u_char *)&flags);
+ /* if this returns an error, setcapa is not supported in this driver,
+ but that's OK. */
+
+ if (reader->open(reader->channelID))
+ return SCECOMM;
+ else
+ return 0;
+}
+
+int
+scclose(int readerNum)
+{
+ readerInfo *reader = &readers[readerNum];
+
+ if (reader->driverLoaded == 0)
+ return -1;
+
+ return (reader->close()) ? -1 : 0;
+}
+
+int
+sccardpresent(int ttyn)
+{
+ readerInfo *reader = &readers[ttyn];
+ unsigned long v;
+
+ if (!reader->driverLoaded)
+ return 0;
+
+ if (reader->cardpresent)
+ v = reader->cardpresent();
+ else if (reader->getcapa(SCTAG_IFD_CARDPRESENT, (unsigned char *) &v))
+ return 1;
+
+ return (v == IFD_ICC_PRESENT || v == 0) ? 1 : 0;
+}
+
+int
+scxreset(int ttyn, int flags, unsigned char *atr, int *ep)
+{
+ readerInfo *reader = &readers[ttyn];
+ int n = 0, r = SCEOK;
+ struct scparam param;
+
+#ifdef SCPERF
+ SetTime ("scxreset() start");
+#endif /* SCPERF */
+
+ if (reader->driverLoaded == 0) {
+ r = SCECLOSED;
+ goto out;
+ }
+
+ if (!sccardpresent(ttyn)) {
+ r = SCENOCARD;
+ goto out;
+ }
+
+ /* send flags to the driver */
+ reader->setcapa(SCTAG_RESET_FLAGS, (u_char *)&flags);
+ /* if this returns an error, setcapa is not supported in this driver,
+ but that's OK. */
+
+ if (reader->power(IFD_RESET)) {
+#ifdef DEBUG
+ fprintf(stderr, "power failed!\n");
+#endif
+ r = SCESLAG;
+ goto out;
+ }
+
+ if (atr && reader->getcapa(TAG_IFD_ATR, atr)) {
+#ifdef DEBUG
+ fprintf(stderr, "reset failed!\n");
+#endif
+ r = SCESLAG;
+ goto out;
+ }
+
+ if (reader->getcapa(SCTAG_IFD_ATRLEN, (unsigned char *) &n) || n <= 0) {
+ /* can't get atr len, take a wild guess */
+ if (atr) {
+ for (n = MAX_ATR_SIZE - 1; !atr[n]; n--)
+ ;
+ n--;
+ } else
+ n = MAX_ATR_SIZE;
+ }
+
+ if (flags & SCRV)
+ parse_atr(-1, flags, atr, n, &param);
+
+ out:
+ if (ep)
+ *ep = r;
+
+#ifdef SCPERF
+ SetTime ("scxreset() end");
+#endif /* SCPERF */
+
+ return n;
+}
+
+int
+screset(int ttyn, unsigned char *atr, int *ep)
+{
+ return scxreset(ttyn, 0, atr, ep);
+}
+
+int
+scrw(int ttyn, int cla, int ins, int p1, int p2, int ilen, unsigned char *ibuf, int olen, unsigned char *obuf, int *sw1p, int *sw2p)
+{
+ unsigned char cmd[6+255], rsp[255+2];
+ unsigned long n;
+ int le;
+ readerInfo *reader = &readers[ttyn];
+ struct SCARD_IO_HEADER garbage;
+
+ if (reader->driverLoaded == 0)
+ return SCECLOSED;
+
+ cmd[0] = cla;
+ cmd[1] = ins;
+ cmd[2] = p1;
+ cmd[3] = p2;
+
+ ilen &= 0xff;
+ le = (255 < olen) ? 255 : olen;
+
+ if (ilen && ibuf) {
+ /* Send "in" data */
+ cmd[4] = ilen;
+ memcpy(&cmd[5], ibuf, ilen);
+ ilen += 5;
+ if (le)
+ cmd[ilen++] = le;
+ n = obuf ? sizeof rsp : 2;
+ if (reader->data(garbage, cmd, ilen, rsp, &n, NULL) || n < 2)
+ return -1;
+ if (rsp[n-2] == 0x61 && olen && obuf) {
+ /* Response available; get it (driver should do this but some don't) */
+ cmd[1] = 0xc0;
+ cmd[2] = cmd[3] = 0;
+ cmd[4] = rsp[n-1];
+ n = sizeof rsp;
+ if (reader->data(garbage, cmd, 5, rsp, &n, NULL))
+ return -1;
+ }
+ } else {
+ /* Get "out" data */
+ cmd[4] = olen;
+ n = sizeof rsp;
+ if (reader->data(garbage, cmd, 5, rsp, &n, NULL))
+ return -1;
+ }
+
+ if (n >= 2) {
+ *sw1p = rsp[n-2];
+ *sw2p = rsp[n-1];
+ n -= 2;
+ }
+
+ if (n && olen)
+ memcpy(obuf, rsp, (n < olen) ? n : olen);
+
+ return n;
+}
+
+int
+scwrite(int ttyn, int cla, int ins, int p1, int p2, int p3, unsigned char *buf, int *sw1p, int *sw2p)
+{
+ int rv;
+#ifdef SCPERF
+ char *scperf_buf;
+
+ scperf_buf = malloc (64);
+
+ sprintf (scperf_buf, "scwrite (ins %02x, p3 %02x) start", ins, p3);
+ SetTime(scperf_buf);
+
+ /* Ihis does not free scperf. It looks like memory leak ...
+ and it is, but it is actually the right behavior.
+ print_time() will print the messages later, so the buffer
+ must be there. */
+#endif /* SCPERF */
+ rv = scrw(ttyn, cla, ins, p1, p2, p3, buf, 0, NULL, sw1p, sw2p);
+
+#ifdef SCPERF
+ SetTime("scwrite() end");
+#endif /* SCPERF */
+ return (rv >= 0) ? p3 : -1;
+}
+
+int
+scread(int ttyn, int cla, int ins, int p1, int p2, int p3, unsigned char *buf, int *sw1p, int *sw2p)
+{
+ int rv;
+#ifdef SCPERF
+ char *scperf_buf;
+
+ scperf_buf = malloc (64);
+
+ sprintf (scperf_buf, "scread (ins %02x, p3 %02x) start", ins, p3);
+ SetTime(scperf_buf);
+
+ /* Ihis does not free scperf. It looks like memory leak ...
+ and it is, but it is actually the right behavior.
+ print_time() will print the messages later, so the buffer
+ must be there. */
+#endif /* SCPERF */
+ rv = scrw(ttyn, cla, ins, p1, p2, 0, NULL, p3, buf, sw1p, sw2p);
+
+#ifdef SCPERF
+ SetTime("scread() end");
+#endif /* SCPERF */
+ return rv;
+}
+
+#ifdef DL_READERS
+void
+addReader(char *name, unsigned long channelID, char *driverFile)
+{
+ readerInfo *reader;
+
+ if (numReaders >= MAX_READERS)
+ return;
+
+ reader = &readers[numReaders++];
+
+ reader->channelID = channelID;
+ reader->driverPath = strdup(driverFile);
+ reader->driverLoaded = 0;
+}
+
+void *
+lookupSym(void *handle, char *name)
+{
+#ifdef __linux__
+ return dlsym(handle, name);
+#elif __sun
+ return dlsym(handle, name);
+#else
+ char undername[32];
+
+ sprintf(undername, "_%s", name);
+ return dlsym(handle, undername);
+#endif
+}
+#endif /* DL_READERS */
+
+/*
+copyright 2000
+the regents of the university of michigan
+all rights reserved
+
+permission is granted to use, copy, create derivative works
+and redistribute this software and such derivative works
+for any purpose, so long as the name of the university of
+michigan is not used in any advertising or publicity
+pertaining to the use or distribution of this software
+without specific, written prior authorization. if the
+above copyright notice or any other identification of the
+university of michigan is included in any copy of any
+portion of this software, then the disclaimer below must
+also be included.
+
+this software is provided as is, without representation
+from the university of michigan as to its fitness for any
+purpose, and without warranty by the university of
+michigan of any kind, either express or implied, including
+without limitation the implied warranties of
+merchantability and fitness for a particular purpose. the
+regents of the university of michigan shall not be liable
+for any damages, including special, indirect, incidental, or
+consequential damages, with respect to any claim arising
+out of or in connection with the use of the software, even
+if it has been or is hereafter advised of the possibility of
+such damages.
+*/