Initial import
authorEugene Crosser <crosser@average.org>
Sun, 29 Sep 2013 20:35:59 +0000 (00:35 +0400)
committerEugene Crosser <crosser@average.org>
Sun, 29 Sep 2013 20:35:59 +0000 (00:35 +0400)
Makefile [new file with mode: 0644]
pcsc_cr.c [new file with mode: 0644]
pcsc_cr.h [new file with mode: 0644]
test_cr.c [new file with mode: 0644]
token.h [new file with mode: 0644]
ykneo.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..db68800
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+# http://pcsclite.alioth.debian.org/pcsclite.html
+
+CFLAGS += -g $(shell pkg-config --cflags libpcsclite)
+LDLIBS += $(shell pkg-config --libs libpcsclite)
+
+test_cr: test_cr.o pcsc_cr.o ykneo.o
diff --git a/pcsc_cr.c b/pcsc_cr.c
new file mode 100644 (file)
index 0000000..0354c32
--- /dev/null
+++ b/pcsc_cr.c
@@ -0,0 +1,99 @@
+#include <string.h>
+#include "token.h"
+#include <reader.h>
+
+extern struct token_interface ykneo_interface;
+
+static struct token_interface *types[] = {
+       &ykneo_interface,
+       NULL,
+};
+
+SCARD_IO_REQUEST pioSendPci;
+
+static LONG find_hb(LPTSTR atr, DWORD atrsize, LPTSTR *hb, LPDWORD hbsize)
+{
+       int i, j, cont;
+       if (atrsize < 2) return SCARD_W_UNSUPPORTED_CARD;
+       switch (atr[0]) {
+       case 0x3B: break;
+       case 0x3F: break;
+       default: return SCARD_W_UNSUPPORTED_CARD;
+       }
+       *hbsize = atr[1]&0x0f;
+       i=1;
+       do {
+               cont = atr[i]>>4;
+               for (j = 0; j < 4; j++) if (cont & (0x01 << j)) i++;
+       } while ((cont & 0x08) && (i < atrsize));
+       if ((i + (*hbsize) + 2) != atrsize)
+               return SCARD_W_UNSUPPORTED_CARD;
+       *hb = atr + i + 1;
+       return SCARD_S_SUCCESS;
+}
+
+long pcsc_cr(unsigned char *chal, int csize, unsigned char *resp, int *rsize)
+{
+       struct token_interface *type;
+       LONG rc;
+       SCARDCONTEXT hContext;
+       LPTSTR readers, rdr;
+       SCARDHANDLE hCard;
+       DWORD nrdrs = SCARD_AUTOALLOCATE, activeproto;
+       BYTE atr[33];
+       DWORD atrsize;
+       LPTSTR hb;
+       DWORD hbsize;
+       DWORD lrsize;
+       int i;
+
+       rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+       if (rc) return rc;
+       rc = SCardListReaders(hContext, NULL, (LPTSTR)&readers, &nrdrs);
+       if (rc) return rc;
+       for (rdr=readers; rdr < readers + nrdrs - 1; rdr += strlen(rdr) + 1) {
+               rc = SCardConnect(hContext, rdr, SCARD_SHARE_SHARED,
+                       SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+                       &hCard, &activeproto);
+               if (rc) continue;
+               switch (activeproto) {
+               case SCARD_PROTOCOL_T0:
+                       pioSendPci = *SCARD_PCI_T0;
+                       break;
+               case SCARD_PROTOCOL_T1:
+                       pioSendPci = *SCARD_PCI_T1;
+                       break;
+               }
+               atrsize = sizeof(atr);
+               rc = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING,
+                       atr, &atrsize);
+               if (rc) goto disconnect;
+               rc = find_hb(atr, atrsize, &hb, &hbsize);
+               if (rc) goto disconnect;
+               for (i = 0; types[i]; i++) {
+                       type = types[i];
+                       rc = type->check_atr_hb(hb, hbsize);
+                       if (rc == 0) break;
+               }
+               if (rc) goto disconnect;
+               rc = type->prologue(hCard, NULL);
+               if (rc == 0) break;
+       disconnect:
+               (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
+       }
+       if (rc) goto free_out;
+       lrsize = *rsize;
+       rc = type->trancieve(hCard, NULL, chal, csize, resp, &lrsize);
+       if (rc) goto disc_free_out;
+       *rsize = lrsize;
+       rc = type->epilogue(hCard, NULL);
+disc_free_out:
+       (void)SCardDisconnect(hCard, SCARD_EJECT_CARD);
+free_out:
+       (void)SCardFreeMemory(hContext, readers);
+       return rc;
+}
+
+char *pcsc_errstr(long err) {
+       return pcsc_stringify_error(err);
+}
diff --git a/pcsc_cr.h b/pcsc_cr.h
new file mode 100644 (file)
index 0000000..da97333
--- /dev/null
+++ b/pcsc_cr.h
@@ -0,0 +1,7 @@
+#ifndef _PCSC_CR_H
+#define _PCSC_CR_H
+
+long pcsc_cr(unsigned char *chal, int csize, unsigned char *resp, int *rsize);
+char *pcsc_errstr(long err);
+
+#endif
diff --git a/test_cr.c b/test_cr.c
new file mode 100644 (file)
index 0000000..2d66d5f
--- /dev/null
+++ b/test_cr.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include "pcsc_cr.h"
+
+char chal[] = {
+0x0f,0x65,0xd1,0x3a,0xfe,0xcb,0xc4,0xb9,0x52,0xb1,0x60,0xcf,0xe8,0x55,0x6a,0xdd,0xfb,0xef,0xf6,0x55,0x83,0x4c,0x8d,0xea,0x38,0xea,0x3b,0x26,0xf7,0x0a,0xe8,0x0d,0x31,0x38,0xee,0x16,0x5d,0xab,0x8b,0x7f,0xf0,0x1b,0xe3,0xbe,0xd8,0x4b,0x6e,0x44,0x42,0x8d,0x0f,0xc1,0x3b,0x23,0xea,0xfe,0xc0,0x68,0xc1,0x0f,0x60,0x6c,0xf4};
+
+int main(int argc, char *argv[])
+{
+       unsigned char rbuf[20];
+       int rsize = sizeof(rbuf);
+       int i;
+       long rc;
+
+       memset(rbuf, 0xFE, sizeof(rbuf));
+       rc = pcsc_cr(chal, sizeof(chal), rbuf, &rsize);
+       printf("rc=%ld (%s) rsize=%d:", rc, pcsc_errstr(rc), rsize);
+       for (i = 0; i < rsize; i++) printf(" %02x", rbuf[i]);
+       printf("\n");
+       return rc;
+}
diff --git a/token.h b/token.h
new file mode 100644 (file)
index 0000000..743aafb
--- /dev/null
+++ b/token.h
@@ -0,0 +1,16 @@
+#ifndef _TOKEN_H
+#define _TOKEN_H
+
+#include <winscard.h>
+
+extern SCARD_IO_REQUEST pioSendPci;
+
+struct token_interface {
+       DWORD (*check_atr_hb)(LPTSTR str, DWORD size);
+       DWORD (*prologue)(SCARDHANDLE hCard,LPTSTR envp[]);
+       DWORD (*trancieve)(SCARDHANDLE hCard,LPTSTR envp[],
+               LPTSTR send, DWORD sendsize, LPTSTR recv, LPDWORD recvsize_p);
+       DWORD (*epilogue)(SCARDHANDLE hCard,LPTSTR envp[]);
+};
+
+#endif
diff --git a/ykneo.c b/ykneo.c
new file mode 100644 (file)
index 0000000..3399f71
--- /dev/null
+++ b/ykneo.c
@@ -0,0 +1,65 @@
+#include <string.h>
+#include <alloca.h>
+
+#include "token.h"
+
+#define NAMEPFX "YubikeyNEO"
+
+static const BYTE selcmd[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0,
+                               0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00};
+static const BYTE cr_cmd[] = {0x00, 0x01, 0x38, 0x00};
+
+static DWORD ykn_check_atr_hb(LPTSTR str, DWORD size)
+{
+       if (size < strlen(NAMEPFX)) return SCARD_W_UNSUPPORTED_CARD;
+       if (memcmp(str, NAMEPFX, strlen(NAMEPFX)))
+               return SCARD_W_UNSUPPORTED_CARD;
+       return SCARD_S_SUCCESS;
+}
+
+static DWORD ykn_prologue(SCARDHANDLE hCard,LPTSTR envp[])
+{
+       BYTE buf[258];
+       DWORD rsize = sizeof(buf);
+       DWORD rc = SCardBeginTransaction(hCard);
+       if (rc) return rc;
+       rc = SCardTransmit(hCard, &pioSendPci, selcmd, sizeof(selcmd),
+               NULL, buf, &rsize);
+       if (rc) return rc;
+       if ((buf[rsize-2] == 0x90) && (buf[rsize-1] == 0x00))
+               return SCARD_S_SUCCESS;
+       else return SCARD_W_CARD_NOT_AUTHENTICATED;
+}
+
+static DWORD ykn_trancieve(SCARDHANDLE hCard,LPTSTR envp[],
+       LPTSTR send, DWORD sendsize, LPTSTR recv, LPDWORD recvsize_p)
+{
+       DWORD rc;
+       DWORD rsize = *recvsize_p + 2;
+       BYTE *rbuf = alloca(rsize);
+       BYTE *sbuf = alloca(sendsize + 6);
+       memcpy(sbuf, cr_cmd, sizeof(cr_cmd));
+       sbuf[sizeof(cr_cmd)] = sendsize;
+       memcpy(sbuf + sizeof(cr_cmd) + 1, send, sendsize);
+       sbuf[sendsize + 5] = rsize;
+       rc = SCardTransmit(hCard, &pioSendPci, sbuf, sendsize + 6,
+               NULL, rbuf, &rsize);
+       if (rc) return rc;
+       if ((rbuf[rsize-2] != 0x90) || (rbuf[rsize-1] != 0x00))
+               return SCARD_W_CARD_NOT_AUTHENTICATED;
+       memcpy(recv, rbuf, rsize - 2);
+       *recvsize_p = rsize - 2;
+       return SCARD_S_SUCCESS;
+}
+
+static DWORD ykn_epilogue(SCARDHANDLE hCard,LPTSTR envp[])
+{
+       return SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
+}
+
+struct token_interface ykneo_interface = {
+       .check_atr_hb   = ykn_check_atr_hb,
+       .prologue       = ykn_prologue,
+       .trancieve      = ykn_trancieve,
+       .epilogue       = ykn_epilogue,
+};