Ubuntu

Merge lp:~serialorder/ubuntu/precise/coolkey/fixmOldCACAssertError into lp:ubuntu/precise/coolkey

Proposed by Manny Vindiola on 2013-01-15
Status: Work in progress
Proposed branch: lp:~serialorder/ubuntu/precise/coolkey/fixmOldCACAssertError
Merge into: lp:ubuntu/precise/coolkey
Diff against target: 26677 lines (+13805/-12410) 49 files modified
To merge this branch: bzr merge lp:~serialorder/ubuntu/precise/coolkey/fixmOldCACAssertError
Reviewer Review Type Date Requested Status
Marc Deslauriers Needs Fixing on 2013-01-23
Ubuntu branches 2013-01-15 Pending
Review via email: mp+143333@code.launchpad.net

Description of the Change

Fixes an error that caused firefox to crash when a CAC was inserted into the SCR3310.
The error was based on failing to initialize a variable.
I have verified that the package builds and that firefox no longer crashes and the CAC can be used
succesfully within firefox

To post a comment you must log in.
Marc Deslauriers (mdeslaur) wrote :

Thanks for the merge request. Here are some comments:

1- Please file a bug for this issue if you want it to get fixed in stable releases, as an SRU needs to have an associated bug. Please add the bug number to the debian/changelog file.
2- Please rebase this merge request against the dev release (Raring). Once the fix is included in raring, it can be backported to the stable releases (Quantal, Precise)
3- Please add proper tags to the patch header. (See http://dep.debian.net/deps/dep3/)
4- Please add the name of the patch to debian/changelog to make it easier to track in the future.

Thanks!

review: Needs Fixing

Unmerged revisions

13. By Manny Vindiola on 2013-01-15

Fix Firefox crash due to "Assertion `mOldCAC' failed" error
based on patch from www.spinics.net/linux/fedora/coolkey/msg00368.html

12. By Manny Vindiola on 2013-01-15

Fix "Assertion `mOldCAC' failed" error based on patch from
www.spinics.net/linux/fedora/coolkey/msg00368.html

11. By A. Maitland Bottoms <email address hidden> on 2012-04-11

* The coolkey device driver has been updated to follow the new Card
  Compatibility Container (CCC) specification, so that
  Gemalto TOPDLGX4 144K CAC cards are now supported.
* Handle pcscd restarting.
* debian/control: Standards-Version: 3.9.2 -> 3.9.3.
  Dep3 headers updated in debian/patches files;
  Dep5 Machine-readable debian/copyright

Preview Diff

1=== modified file '.pc/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch/src/coolkey/slot.cpp'
2--- .pc/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch/src/coolkey/slot.cpp 2011-07-20 13:18:57 +0000
3+++ .pc/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch/src/coolkey/slot.cpp 2013-01-15 15:55:32 +0000
4@@ -589,6 +589,7 @@
5 if( ! CKYCardConnection_IsConnected(conn) ) {
6 int i = 0;
7 //for cranky readers try again a few more times
8+ status = CKYSCARDERR;
9 while( i++ < 5 && status != CKYSUCCESS )
10 {
11 status = CKYCardConnection_Connect(conn, readerName);
12@@ -679,7 +680,13 @@
13 log->log("CoolKey Select failed 0x%x\n", status);
14 status = getCACAid();
15 if (status != CKYSUCCESS) {
16- goto loser;
17+ log->log("CAC Select failed 0x%x\n", status);
18+ if (status == CKYSCARDERR) {
19+ log->log("CAC Card Failure 0x%x\n",
20+ CKYCardConnection_GetLastError(conn));
21+ disconnect();
22+ }
23+ return;
24 }
25 state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
26 /* skip the read of the cuid. We really don't need it and,
27@@ -690,15 +697,6 @@
28 needLogin = 1;
29 mCoolkey = 0;
30 return;
31-
32-loser:
33- log->log("CAC Select failed 0x%x\n", status);
34- if (status == CKYSCARDERR) {
35- log->log("CAC Card Failure 0x%x\n",
36- CKYCardConnection_GetLastError(conn));
37- disconnect();
38- }
39- return;
40 }
41 mCoolkey = 1;
42 log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time);
43@@ -2185,6 +2183,7 @@
44 {
45 CKYStatus status;
46 CKYISOStatus apduRC;
47+ *nextSize = 0;
48
49 if (mOldCAC) {
50 /* get the first 100 bytes of the cert */
51@@ -3399,6 +3398,10 @@
52 status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
53 input, NULL, output, getNonce(), &result);
54 }
55+ /* map the ISO not logged in code to the coolkey one */
56+ if (status == CKYISO_CONDITION_NOT_SATISFIED) {
57+ status = (CKYStatus) CKYISO_UNAUTHORIZED;
58+ }
59 if (status != CKYSUCCESS) {
60 if ( status == CKYSCARDERR ) {
61 handleConnectionError();
62
63=== added directory '.pc/Handle-pcscd-restarting'
64=== added directory '.pc/Handle-pcscd-restarting/src'
65=== added directory '.pc/Handle-pcscd-restarting/src/coolkey'
66=== added file '.pc/Handle-pcscd-restarting/src/coolkey/Makefile.am'
67--- .pc/Handle-pcscd-restarting/src/coolkey/Makefile.am 1970-01-01 00:00:00 +0000
68+++ .pc/Handle-pcscd-restarting/src/coolkey/Makefile.am 2013-01-15 15:55:32 +0000
69@@ -0,0 +1,82 @@
70+# ***** BEGIN COPYRIGHT BLOCK *****
71+# Copyright (C) 2005 Red Hat, Inc.
72+# All rights reserved.
73+#
74+# This library is free software; you can redistribute it and/or
75+# modify it under the terms of the GNU Lesser General Public
76+# License as published by the Free Software Foundation version
77+# 2.1 of the License.
78+#
79+# This library is distributed in the hope that it will be useful,
80+# but WITHOUT ANY WARRANTY; without even the implied warranty of
81+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
82+# Lesser General Public License for more details.
83+#
84+# You should have received a copy of the GNU Lesser General Public
85+# License along with this library; if not, write to the Free Software
86+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
87+# ***** END COPYRIGHT BLOCK *****
88+
89+# Process this file with automake to create Makefile.in
90+
91+SUBDIRS =
92+AM_CPP_FLAGS =
93+EXTRA_DIST = coolkeypk11.def coolkeypk11.rc
94+if IS_WINDOWS
95+pkcs11dir = $(libdir)
96+else
97+pkcs11dir = $(libdir)/pkcs11
98+endif
99+pkcs11_LTLIBRARIES = libcoolkeypk11.la
100+
101+libcoolkeypk11_la_SOURCES = \
102+ coolkey.cpp \
103+ dllmain.cpp \
104+ locking.cpp \
105+ log.cpp \
106+ machdep.cpp \
107+ object.cpp \
108+ PKCS11Exception.cpp \
109+ slot.cpp \
110+ locking.h \
111+ log.h \
112+ machdep.h \
113+ mypkcs11.h \
114+ object.h \
115+ params.h \
116+ PKCS11Exception.h \
117+ pkcs11f.h \
118+ pkcs11.h \
119+ pkcs11n.h \
120+ pkcs11t.h \
121+ slot.h \
122+ $(NULL)
123+
124+libcoolkeypk11_la_LDFLAGS = -avoid-version -export-symbols coolkeypk11.sym -no-undefined
125+libcoolkeypk11_la_CPPFLAGS = $(CPPFLAGS) -DNSS_HIDE_NONSTANDARD_OBJECTS=1 -I$(top_srcdir)/src/libckyapplet $(PCSC_CFLAGS) $(ZLIB_CFLAGS)
126+libcoolkeypk11_la_DEPENDENCIES = coolkeypk11.sym
127+libcoolkeypk11_la_LIBADD = @LIBCKYAPPLET@ $(ZLIB_LIBS)
128+
129+
130+#
131+# sigh, libtool doesn't maintain Linux and Solaris versioning info in
132+# their .def file. So convert a very general, easy to work an any platform
133+# coreconf .def file to a simplistic but acceptable libtool .sym file
134+#
135+coolkeypk11.sym: coolkeypk11.def
136+ grep -v ';+' $< | grep -v ';-' | sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' > $@
137+
138+clean-generic:
139+ rm -f coolkeypk11.sym
140+
141+# remove the static and libtool libraries if necessary
142+install-data-hook:
143+ rm -f $(DESTDIR)$(pkcs11dir)/libcoolkeypk11.a
144+ rm -f $(DESTDIR)$(pkcs11dir)/libcoolkeypk11.la
145+if IS_WINDOWS
146+ rm -f $(DESTDIR)$(pkcs11dir)/libcoolkeypk11.lib
147+ mv $(DESTDIR)$(pkcs11dir)/libcoolkeypk11.dll $(DESTDIR)$(pkcs11dir)/coolkeypk11.dll
148+ cp $(ZLIB_LIB)/../zlib1.dll $(DESTDIR)/$(libdir)/zlib1.dll
149+endif
150+
151+
152
153=== added file '.pc/Handle-pcscd-restarting/src/coolkey/slot.cpp'
154--- .pc/Handle-pcscd-restarting/src/coolkey/slot.cpp 1970-01-01 00:00:00 +0000
155+++ .pc/Handle-pcscd-restarting/src/coolkey/slot.cpp 2013-01-15 15:55:32 +0000
156@@ -0,0 +1,3554 @@
157+/* ***** BEGIN COPYRIGHT BLOCK *****
158+ * Copyright (C) 2005 Red Hat, Inc.
159+ * All rights reserved.
160+ *
161+ * This library is free software; you can redistribute it and/or
162+ * modify it under the terms of the GNU Lesser General Public
163+ * License as published by the Free Software Foundation version
164+ * 2.1 of the License.
165+ *
166+ * This library is distributed in the hope that it will be useful,
167+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
168+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
169+ * Lesser General Public License for more details.
170+ *
171+ * You should have received a copy of the GNU Lesser General Public
172+ * License along with this library; if not, write to the Free Software
173+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
174+ * ***** END COPYRIGHT BLOCK *****/
175+
176+#include <string>
177+#include "mypkcs11.h"
178+#include <stdio.h>
179+#include <assert.h>
180+#include "log.h"
181+#include "PKCS11Exception.h"
182+#include <winscard.h>
183+#include "slot.h"
184+#include "zlib.h"
185+#include "params.h"
186+
187+#include "machdep.h"
188+
189+#define MIN(x, y) ((x) < (y) ? (x) : (y))
190+
191+
192+
193+#ifdef DEBUG
194+#define PRINTF(args) printf args
195+#else
196+#define PRINTF(args)
197+#endif
198+// #define DISPLAY_WHOLE_GET_DATA 1
199+
200+
201+// The Cyberflex Access 32k egate ATR
202+const CKYByte ATR[] =
203+{ 0x3b, 0x75, 0x94, 0x00, 0x00, 0x62, 0x02, 0x02, 0x02, 0x01 };
204+const CKYByte ATR1[] =
205+{ 0x3b, 0x75, 0x94, 0x00, 0x00, 0x62, 0x02, 0x02, 0x03, 0x01 };
206+const CKYByte ATR3[] =
207+{ 0x3b, 0x76, 0x94, 0x00, 0x00, 0xff, 0x62, 0x76, 0x01, 0x00, 0x00 };
208+/* RSA SecurID */
209+const CKYByte ATR2[] =
210+{ 0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72,
211+ 0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 };
212+
213+SlotList::SlotList(Log *log_) : log(log_)
214+{
215+ // initialize things to NULL so we can recover from an exception
216+ slots = NULL;
217+ numSlots = 0;
218+ readerStates = NULL;
219+ numReaders = 0;
220+ context = NULL;
221+ shuttingDown = FALSE;
222+
223+ try {
224+
225+ context = CKYCardContext_Create(SCARD_SCOPE_USER);
226+ if( context == NULL) {
227+ throw PKCS11Exception(CKR_GENERAL_ERROR,
228+ "Failed to create card context\n");
229+ }
230+ updateSlotList();
231+ } catch( PKCS11Exception &) {
232+ CKYCardContext_Destroy(context);
233+ if (readerStates) {
234+ CKYReader_DestroyArray(readerStates, numReaders);
235+ }
236+ throw;
237+ }
238+}
239+
240+SlotList::~SlotList()
241+{
242+ if( slots ) {
243+ assert( numSlots > 0 );
244+ for( unsigned int i=0; i < numSlots; ++i ) {
245+ delete slots[i];
246+ }
247+ delete [] slots;
248+ slots = NULL;
249+ numSlots = 0;
250+ }
251+ if (readerStates) {
252+ CKYReader_DestroyArray(readerStates, numReaders);
253+ readerStates = NULL;
254+ numReaders = 0;
255+ }
256+ if (context) {
257+ CKYCardContext_Destroy(context);
258+ context = NULL;
259+ }
260+}
261+void
262+SlotList::shutdown()
263+{
264+ shuttingDown = TRUE;
265+ CKYCardContext_Cancel(context);
266+}
267+
268+void
269+SlotList::updateSlotList()
270+{
271+ Slot **newSlots = NULL;
272+ Slot **oldSlots = NULL;
273+
274+ readerListLock.getLock();
275+
276+ updateReaderList();
277+
278+ if (numSlots == numReaders) {
279+ readerListLock.releaseLock();
280+ return;
281+ }
282+ assert(numSlots < numReaders);
283+ if (numSlots > numReaders) {
284+ readerListLock.releaseLock();
285+ throw PKCS11Exception(CKR_GENERAL_ERROR,
286+ "Reader and slot count inconsistent\n");
287+ }
288+
289+ try {
290+ newSlots = new Slot*[numReaders];
291+ if (newSlots == NULL )
292+ throw PKCS11Exception(CKR_HOST_MEMORY);
293+ memset(newSlots, 0, numReaders*sizeof(Slot*));
294+
295+ memcpy(newSlots, slots, sizeof(slots[0]) * numSlots);
296+
297+ for (unsigned int i=numSlots; i < numReaders; i++) {
298+ newSlots[i] = new
299+ Slot(CKYReader_GetReaderName(&readerStates[i]), log, context);
300+ }
301+
302+ oldSlots = slots;
303+ slots = newSlots; // update the pointer first
304+ numSlots = numReaders; // now update the count
305+ if (oldSlots) { // ok we can free the old value now
306+ delete [] oldSlots;
307+ }
308+ } catch( PKCS11Exception &) {
309+ // Recover by deleting everything that was created.
310+ if( newSlots ) {
311+ assert(numSlots < numReaders );
312+ for( unsigned int i=numSlots; i < numReaders; ++i ) {
313+ if( newSlots[i] ) {
314+ delete newSlots[i];
315+ }
316+ }
317+ delete [] newSlots;
318+ }
319+ readerListLock.releaseLock();
320+ throw;
321+ }
322+ readerListLock.releaseLock();
323+
324+}
325+
326+bool
327+SlotList::readerExists(const char *readerName, unsigned int *hint)
328+{
329+ unsigned int start = 0;
330+ unsigned int i;
331+
332+ if (hint && (*hint < numReaders)) {
333+ start = *hint;
334+ }
335+
336+ /*
337+ * We use 'hint' as a way of deciding where to
338+ * start. This way we can handle the normal case where the name list
339+ * and the readerState matches one for one with a single string compare.
340+ */
341+ for (i=start; i < numReaders; i++) {
342+ if (strcmp(CKYReader_GetReaderName(&readerStates[i]),readerName) == 0) {
343+ if (hint) {
344+ *hint = i+1;
345+ }
346+ return TRUE;
347+ }
348+ }
349+ /* we guessed wrong, check the first part of the reader states */
350+ for (i=0; i < start; i++) {
351+ if (strcmp(CKYReader_GetReaderName(&readerStates[i]),readerName) == 0) {
352+ if (hint) {
353+ *hint = i+1;
354+ }
355+ return TRUE;
356+ }
357+ }
358+ /* OK, we've found a genuinely new reader */
359+ return FALSE;
360+}
361+
362+bool
363+SlotList::readerNameExistsInList(const char *readerName,CKYReaderNameList *readerNameList)
364+{
365+ if( !readerName || !readerNameList) {
366+ return FALSE;
367+ }
368+
369+ int i = 0;
370+ int readerNameCnt = CKYReaderNameList_GetCount(*readerNameList);
371+
372+ const char *curReaderName = NULL;
373+ for(i=0; i < readerNameCnt; i++) {
374+ curReaderName = CKYReaderNameList_GetValue(*readerNameList,i);
375+
376+ if(!strcmp(curReaderName,readerName)) {
377+ return TRUE;
378+ }
379+
380+ }
381+
382+ return FALSE;
383+}
384+
385+/*
386+ * you need to hold the ReaderList Lock before you can update the ReaderList
387+ */
388+#define MAX_READER_DELTA 4
389+void
390+SlotList::updateReaderList()
391+{
392+ CKYReaderNameList readerNames = NULL;
393+
394+ CKYStatus status = CKYCardContext_ListReaders(context, &readerNames);
395+ if ( status != CKYSUCCESS ) {
396+ throw PKCS11Exception(CKR_GENERAL_ERROR,
397+ "Failed to list readers: 0x%x\n",
398+ CKYCardContext_GetLastError(context));
399+ }
400+
401+ if (!readerStates) {
402+ /* fresh Reader State list, just create it */
403+ readerStates = CKYReader_CreateArray(readerNames, (CKYSize *)&numReaders);
404+
405+ /* if we have no readers, make sure we have at least one to keep things
406+ * happy */
407+ if (readerStates == NULL &&
408+ CKYReaderNameList_GetCount(readerNames) == 0) {
409+ readerStates = (SCARD_READERSTATE *)
410+ malloc(sizeof(SCARD_READERSTATE));
411+ if (readerStates) {
412+ CKYReader_Init(readerStates);
413+ status = CKYReader_SetReaderName(readerStates, "E-Gate 0 0");
414+ if (status != CKYSUCCESS) {
415+ CKYReader_DestroyArray(readerStates, 1);
416+ readerStates = NULL;
417+ } else {
418+ numReaders = 1;
419+ }
420+ }
421+ }
422+ CKYReaderNameList_Destroy(readerNames);
423+
424+ if (readerStates == NULL) {
425+ throw PKCS11Exception(CKR_HOST_MEMORY,
426+ "Failed to allocate ReaderStates\n");
427+ }
428+ return;
429+ }
430+
431+ /* it would be tempting at this point just to see if we have more readers
432+ * then specified previously. The problem with this is it is possible that
433+ * some readers have been deleted, so the only way to tell if we have
434+ * new readers is to see if there are any readers on the list that we
435+ * don't recognize.
436+ */
437+
438+ /* first though, let's check to see if any previously removed readers have
439+ * come back from the dead. If the ignored bit has been set, we do not need
440+ * it any more.
441+ */
442+
443+ const char *curReaderName = NULL;
444+ unsigned long knownState = 0;
445+ for(int ri = 0 ; ri < numReaders; ri ++) {
446+
447+ knownState = CKYReader_GetKnownState(&readerStates[ri]);
448+ if( !(knownState & SCARD_STATE_IGNORE)) {
449+ continue;
450+ }
451+
452+ curReaderName = CKYReader_GetReaderName(&readerStates[ri]);
453+ if(readerNameExistsInList(curReaderName,&readerNames)) {
454+ CKYReader_SetKnownState(&readerStates[ri], knownState & ~SCARD_STATE_IGNORE);
455+
456+ }
457+ }
458+
459+ const char *newReadersData[MAX_READER_DELTA];
460+ const char **newReaders = &newReadersData[0];
461+ unsigned int newReaderCount = 0;
462+ unsigned int hint = 0;
463+
464+ try {
465+ CKYReaderNameIterator iter;
466+
467+ for (iter = CKYReaderNameList_GetIterator(readerNames);
468+ !CKYReaderNameIterator_End(iter);
469+ iter = CKYReaderNameIterator_Next(iter)) {
470+ const char *thisReaderName = CKYReaderNameIterator_GetValue(iter);
471+ if (!readerExists(thisReaderName, &hint)) {
472+ if (newReaderCount == MAX_READER_DELTA) {
473+ /* oops, we overflowed our buffer, alloc a new one right
474+ * quick. This code is very unlikely, so it's not fast,
475+ * but it's meant to keep working, even in this weird
476+ * condition. NOTE: it assumes that we can't have any
477+ * more new readers than candidate readers we are
478+ * checking */
479+ int maxReaders = CKYReaderNameList_GetCount(readerNames);
480+ assert(maxReaders > MAX_READER_DELTA);
481+ newReaders = new const char *[maxReaders];
482+ if (!newReaders) {
483+ throw PKCS11Exception(CKR_HOST_MEMORY,
484+ "Could allocate space for %d new readers\n",
485+ maxReaders);
486+ }
487+ memcpy(newReaders, newReadersData,
488+ MAX_READER_DELTA*sizeof(newReadersData[0]));
489+ }
490+ newReaders[newReaderCount++] = thisReaderName;
491+ }
492+ }
493+ /* OK, we haven't added any new readers, blow out now */
494+ if (newReaderCount == 0) {
495+ CKYReaderNameList_Destroy(readerNames);
496+ return;
497+ }
498+
499+ status = CKYReader_AppendArray(&readerStates, numReaders,
500+ newReaders, newReaderCount);
501+ if (status != CKYSUCCESS) {
502+ throw PKCS11Exception(CKR_GENERAL_ERROR,
503+ "Couldn't append %d new reader states\n",
504+ newReaderCount);
505+ }
506+ numReaders += newReaderCount;
507+
508+ CKYReaderNameList_Destroy(readerNames);
509+ /* free newReaders if w were forced to alloc it */
510+ if (newReaders != &newReadersData[0]) {
511+ delete [] newReaders;
512+ }
513+ return;
514+
515+ } catch( PKCS11Exception &) {
516+ CKYReaderNameList_Destroy(readerNames);
517+ /* free newReaders if w were forced to alloc it */
518+ if (newReaders != &newReadersData[0]) {
519+ delete [] newReaders;
520+ }
521+
522+ throw;
523+ }
524+}
525+
526+
527+Slot::Slot(const char *readerName_, Log *log_, CKYCardContext* context_)
528+ : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
529+ slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN),
530+ isVersion1Key(false), needLogin(false), fullTokenName(false),
531+ mCoolkey(false), mOldCAC(false),
532+#ifdef USE_SHMEM
533+ shmem(readerName_),
534+#endif
535+ sessionHandleCounter(1), objectHandleCounter(1)
536+{
537+
538+ tokenFWVersion.major = 0;
539+ tokenFWVersion.minor = 0;
540+
541+
542+ try {
543+ conn = CKYCardConnection_Create(context);
544+ if( conn == 0 ) {
545+ throw PKCS11Exception(CKR_GENERAL_ERROR);
546+ }
547+ hwVersion.major = 255;
548+ hwVersion.minor = 255;
549+
550+ //Initialize login state for both Version 1 keys and older keys
551+ reverify = false;
552+ nonceValid = false;
553+ loggedIn = false;
554+ pinCache.invalidate();
555+ pinCache.clearPin();
556+ //readSlotInfo();
557+ manufacturer = strdup("Unknown");
558+ if (!manufacturer) {
559+ throw PKCS11Exception(CKR_HOST_MEMORY);
560+ }
561+ readerName = strdup(readerName_);
562+ if (!readerName) {
563+ throw PKCS11Exception(CKR_HOST_MEMORY);
564+ }
565+ CKYStatus ret = CKYBuffer_InitFromLen(&nonce, NONCE_SIZE);
566+ if (ret != CKYSUCCESS) {
567+ throw PKCS11Exception(CKR_HOST_MEMORY);
568+ }
569+ CKYBuffer_InitEmpty(&cardATR);
570+ CKYBuffer_InitEmpty(&mCUID);
571+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
572+ CKYBuffer_InitEmpty(&cardAID[i]);
573+ }
574+ } catch(PKCS11Exception &) {
575+ if (conn) {
576+ CKYCardConnection_Destroy(conn);
577+ }
578+ if (manufacturer) {
579+ free(manufacturer);
580+ }
581+ if (readerName) {
582+ free(readerName);
583+ }
584+ throw;
585+ }
586+}
587+
588+void
589+Slot::readSlotInfo(void)
590+{
591+#ifdef WIN32 /* Mac doesn't have the SCardGetAttrib function */
592+ CKYStatus status;
593+ CKYBuffer attrBuf;
594+
595+ CKYBuffer_InitEmpty(&attrBuf);
596+ status = CKYCardConnection_GetAttribute(conn,
597+ SCARD_ATTR_VENDOR_IFD_VERSION, &attrBuf);
598+ if (status == CKYSUCCESS) {
599+ const CKYByte *type = CKYBuffer_Data(&attrBuf);
600+
601+ if (CKYBuffer_Size(&attrBuf) == sizeof(unsigned long)) {
602+ /* buffer data is returned in machine order, not network or
603+ * applet order */
604+ unsigned long version = *(unsigned long *)type;
605+ hwVersion.major = (CK_BYTE) (version >> 24) & 0xff;
606+ hwVersion.minor = (CK_BYTE) (version >> 16) & 0xff;
607+ }
608+ status = CKYCardConnection_GetAttribute(conn,
609+ SCARD_ATTR_VENDOR_NAME, &attrBuf);
610+ if (status == CKYSUCCESS) {
611+ free(manufacturer);
612+ /* make sure manufacturer is NULL terminated */
613+ CKYBuffer_AppendChar(&attrBuf,0);
614+ manufacturer = strdup((const char *)CKYBuffer_Data(&attrBuf));
615+ slotInfoFound = true;
616+ }
617+ } else {
618+ PRINTF(("readSlotInfo failed\n"));
619+ }
620+ CKYBuffer_FreeData(&attrBuf);
621+#endif /* WIN32 */
622+}
623+
624+Slot::~Slot()
625+{
626+ if (conn) {
627+ CKYCardConnection_Destroy(conn);
628+ }
629+ if (readerName) {
630+ free(readerName);
631+ }
632+ if (personName) {
633+ free(personName);
634+ }
635+ if (manufacturer) {
636+ free(manufacturer);
637+ }
638+ CKYBuffer_FreeData(&nonce);
639+ CKYBuffer_FreeData(&cardATR);
640+ CKYBuffer_FreeData(&mCUID);
641+ for (int i=0; i < MAX_CERT_SLOTS; i++) {
642+ CKYBuffer_FreeData(&cardAID[i]);
643+ }
644+}
645+
646+template <class C>
647+class ArrayFreer {
648+ private:
649+ C *ptr;
650+ public:
651+ ArrayFreer(C* cptr) : ptr(cptr) { }
652+ ~ArrayFreer() {
653+ if( ptr ) {
654+ delete [] ptr;
655+ }
656+ }
657+ void release() { ptr = NULL; }
658+};
659+
660+CK_RV
661+SlotList::getSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
662+ CK_ULONG_PTR pulCount)
663+{
664+ CK_RV rv = CKR_OK;
665+ unsigned int i;
666+
667+ if( pulCount == NULL ) {
668+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
669+ }
670+
671+ if (pSlotList == NULL) {
672+ updateSlotList();
673+ }
674+
675+ //
676+ // first, figure out which slots have tokens present
677+ //
678+ bool * tokenIsPresent = new bool[numSlots];
679+ if( tokenIsPresent == NULL ) {
680+ throw PKCS11Exception(CKR_HOST_MEMORY);
681+ }
682+ ArrayFreer<bool> deleteTokIsPres(tokenIsPresent);
683+
684+ unsigned int numPresent = 0;
685+ for( i = 0; i < numSlots; ++i ) {
686+ tokenIsPresent[i] = slots[i]->isTokenPresent();
687+ numPresent += tokenIsPresent[i];
688+ }
689+
690+ //
691+ // now fill in the slot list if it was supplied
692+ //
693+ if( pSlotList != NULL ) {
694+ if( tokenPresent ) {
695+ // only slots with tokens present
696+ if( *pulCount >= numPresent ) {
697+ // we have enough space to copy the slot IDs
698+ unsigned int j;
699+ for( i=0, j=0; i < numSlots; ++i ) {
700+ if( tokenIsPresent[i] ) {
701+ assert(j < numPresent);
702+ pSlotList[j++] = slotIndexToID(i);
703+ }
704+ }
705+ assert( j == numPresent );
706+ } else {
707+ // not enough space
708+ rv = CKR_BUFFER_TOO_SMALL;
709+ }
710+ } else {
711+ // all slots, even without tokens present
712+ if( *pulCount >= numSlots ) {
713+ // we have enough space to copy the slot IDs
714+ for( i=0; i < numSlots; ++i ) {
715+ pSlotList[i] = slotIndexToID(i);
716+ }
717+ } else {
718+ // not enough space
719+ rv = CKR_BUFFER_TOO_SMALL;
720+ }
721+ }
722+ }
723+
724+ // set the number of slots
725+ if( tokenPresent ) {
726+ *pulCount = numPresent;
727+ } else {
728+ *pulCount = numSlots;
729+ }
730+
731+ return rv;
732+}
733+
734+void
735+Slot::connectToToken()
736+{
737+ CKYStatus status = CKYSCARDERR;
738+ OSTime time = OSTimeNow();
739+
740+ mCoolkey = 0;
741+ tokenFWVersion.major = 0;
742+ tokenFWVersion.minor = 0;
743+
744+ // try to connect to the card
745+ if( ! CKYCardConnection_IsConnected(conn) ) {
746+ int i = 0;
747+ //for cranky readers try again a few more times
748+ status = CKYSCARDERR;
749+ while( i++ < 5 && status != CKYSUCCESS )
750+ {
751+ status = CKYCardConnection_Connect(conn, readerName);
752+ if( status != CKYSUCCESS &&
753+ CKYCardConnection_GetLastError(conn) == SCARD_E_PROTO_MISMATCH )
754+ {
755+ log->log("Unable to connect to token status %d ConnGetGetLastError %x .\n",status,CKYCardConnection_GetLastError(conn));
756+
757+ }
758+ else
759+ {
760+ break;
761+ }
762+ OSSleep(100000);
763+ }
764+
765+ if( status != CKYSUCCESS)
766+ {
767+ state = UNKNOWN;
768+ return;
769+ }
770+ }
771+
772+ log->log("time connect: Connect Time %d ms\n", OSTimeNow() - time);
773+ if (!slotInfoFound) {
774+ readSlotInfo();
775+ }
776+ log->log("time connect: Read Slot %d ms\n", OSTimeNow() - time);
777+
778+ // Get card state. See if it is present, and if the ATR matches
779+ unsigned long cardState;
780+ status = CKYCardConnection_GetStatus(conn, &cardState, &cardATR);
781+ if( status != CKYSUCCESS ) {
782+ disconnect();
783+ return;
784+ }
785+ log->log("time connect: connection status %d ms\n", OSTimeNow() - time);
786+ if( cardState & SCARD_PRESENT ) {
787+ state = CARD_PRESENT;
788+ }
789+
790+ if (Params::hasParam("noAppletOK"))
791+ {
792+ state |= APPLET_SELECTABLE;
793+ mCoolkey = 1;
794+ }
795+
796+ /* support CAC card. identify the card based on applets, not the ATRS */
797+ state |= ATR_MATCH;
798+
799+ /* our production cards should "ALWAYS" have an applet, even if it
800+ * doesn't exit */
801+ if ( CKYBuffer_DataIsEqual(&cardATR, ATR3, sizeof (ATR3)) ) {
802+ state |= ATR_MATCH | APPLET_SELECTABLE;
803+ mCoolkey = 1;
804+
805+ }
806+
807+ Transaction trans;
808+ status = trans.begin(conn);
809+
810+ /* CAC card are cranky after they are first inserted.
811+ * don't continue until we can convince the tranaction to work */
812+ for (int count = 0; count < 10 && status == CKYSCARDERR
813+ && CKYCardConnection_GetLastError(conn) == SCARD_W_RESET_CARD; count++) {
814+ log->log("CAC Card Reset detected retry %d: time %d ms\n", count,
815+ OSTimeNow() - time);
816+ CKYCardConnection_Disconnect(conn);
817+ OSSleep(100000); /* 100 ms */
818+ status = CKYCardConnection_Connect(conn, readerName);
819+ if (status != CKYSUCCESS) {
820+ continue;
821+ }
822+ status = trans.begin(conn);
823+ }
824+
825+ /* Can't get a transaction, give up */
826+ if (status != CKYSUCCESS) {
827+ log->log("Transaction Failed 0x%x\n", status);
828+ handleConnectionError();
829+ }
830+
831+ // see if the applet is selectable
832+
833+ log->log("time connnect: Begin transaction %d ms\n", OSTimeNow() - time);
834+ status = CKYApplet_SelectCoolKeyManager(conn, NULL);
835+ if (status != CKYSUCCESS) {
836+ log->log("CoolKey Select failed 0x%x\n", status);
837+ status = getCACAid();
838+ if (status != CKYSUCCESS) {
839+ log->log("CAC Select failed 0x%x\n", status);
840+ if (status == CKYSCARDERR) {
841+ log->log("CAC Card Failure 0x%x\n",
842+ CKYCardConnection_GetLastError(conn));
843+ disconnect();
844+ }
845+ return;
846+ }
847+ state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
848+ /* skip the read of the cuid. We really don't need it and,
849+ * the only way to get it from the cac is to reset it.
850+ * other apps may be running now, so resetting the cac is a bit
851+ * unfriendly */
852+ isVersion1Key = 0;
853+ needLogin = 1;
854+ mCoolkey = 0;
855+ return;
856+ }
857+ mCoolkey = 1;
858+ log->log("time connect: Select Applet %d ms\n", OSTimeNow() - time);
859+
860+ state |= APPLET_SELECTABLE;
861+
862+ // now see if the applet is personalized
863+ CKYAppletRespGetLifeCycleV2 lifeCycleV2;
864+ status = CKYApplet_GetLifeCycleV2(conn, &lifeCycleV2, NULL);
865+ if (status != CKYSUCCESS) {
866+ if (status == CKYSCARDERR) {
867+ disconnect();
868+ }
869+ return;
870+ }
871+ log->log("time connect: Get Personalization %d ms\n", OSTimeNow() - time);
872+ if (lifeCycleV2.lifeCycle == CKY_APPLICATION_PERSONALIZED )
873+ {
874+ state |= APPLET_PERSONALIZED;
875+ }
876+ isVersion1Key = (lifeCycleV2.protocolMajorVersion == 1);
877+ needLogin = (lifeCycleV2.pinCount != 0);
878+ tokenFWVersion.major = lifeCycleV2.protocolMajorVersion;
879+ tokenFWVersion.minor = lifeCycleV2.protocolMinorVersion;
880+}
881+
882+bool
883+Slot::cardStateMayHaveChanged()
884+{
885+ CKYStatus status;
886+
887+log->log("calling IsConnected\n");
888+ if( !CKYCardConnection_IsConnected(conn) ) {
889+ return true;
890+ }
891+log->log("IsConnected returned false\n");
892+
893+ // If the card has been removed or reset, this call will fail.
894+ unsigned long cardState;
895+ CKYBuffer aid;
896+ CKYBuffer_InitEmpty(&aid);
897+ status = CKYCardConnection_GetStatus(conn, &cardState, &aid);
898+ CKYBuffer_FreeData(&aid);
899+ if( status != CKYSUCCESS ) {
900+ disconnect();
901+ return true;
902+ }
903+ return false;
904+}
905+
906+void
907+Slot::invalidateLogin(bool hard)
908+{
909+ if (isVersion1Key) {
910+ if (hard) {
911+ reverify = false; /* no need to revalidate in the future,
912+ * we're clearing the nonce now */
913+ nonceValid = false;
914+ CKYBuffer_Zero(&nonce);
915+ CKYBuffer_Resize(&nonce,8);
916+ } else {
917+ reverify = true;
918+ }
919+ } else {
920+ loggedIn = false;
921+ if (hard) {
922+ pinCache.invalidate();
923+ pinCache.clearPin();
924+ }
925+ }
926+}
927+
928+void
929+Slot::disconnect()
930+{
931+ CKYCardConnection_Disconnect(conn);
932+ state = UNKNOWN;
933+ closeAllSessions();
934+ invalidateLogin(false);
935+}
936+
937+CKYStatus
938+Slot::getCACAid()
939+{
940+ CKYBuffer tBuf;
941+ CKYBuffer vBuf;
942+ CKYSize tlen, vlen;
943+ CKYOffset toffset, voffset;
944+ int certSlot = 0;
945+ int i,length = 0;
946+ CKYStatus status;
947+
948+ CKYBuffer_InitEmpty(&tBuf);
949+ CKYBuffer_InitEmpty(&vBuf);
950+
951+ /* clear out the card AID's */
952+ for (i=0; i < MAX_CERT_SLOTS; i++) {
953+ CKYBuffer_Resize(&cardAID[i],0);
954+ }
955+
956+ status = CACApplet_SelectCCC(conn,NULL);
957+ if (status != CKYSUCCESS) {
958+ /* are we an old CAC */
959+ status = CACApplet_SelectPKI(conn, &cardAID[0], 0, NULL);
960+ if (status != CKYSUCCESS) {
961+ /* no, just fail */
962+ return status;
963+ }
964+ /* yes, fill in the old applets */
965+ mOldCAC = true;
966+ for (i=1; i< MAX_CERT_SLOTS; i++) {
967+ CACApplet_SelectPKI(conn, &cardAID[i], i, NULL);
968+ }
969+ return CKYSUCCESS;
970+ }
971+ /* definately not an old CAC */
972+ mOldCAC = false;
973+
974+ /* read the TLV */
975+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
976+ if (status != CKYSUCCESS) {
977+ goto done;
978+ }
979+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
980+ if (status != CKYSUCCESS) {
981+ goto done;
982+ }
983+ tlen = CKYBuffer_Size(&tBuf);
984+ vlen = CKYBuffer_Size(&vBuf);
985+
986+ for(toffset = 2, voffset=2;
987+ certSlot < MAX_CERT_SLOTS && toffset < tlen && voffset < vlen ;
988+ voffset += length) {
989+
990+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
991+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
992+ toffset += 2;
993+ if (length == 0xff) {
994+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
995+ toffset +=2;
996+ }
997+ if (tag != CAC_TAG_CARDURL) {
998+ continue;
999+ }
1000+ /* CARDURL tags must be at least 10 bytes long */
1001+ if (length < 10) {
1002+ continue;
1003+ }
1004+ /* check the app type, should be TLV_APP_PKI */
1005+ if (CKYBuffer_GetChar(&vBuf, voffset+5) != CAC_TLV_APP_PKI) {
1006+ continue;
1007+ }
1008+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf, voffset, 5);
1009+ if (status != CKYSUCCESS) {
1010+ goto done;
1011+ }
1012+ status = CKYBuffer_AppendBuffer(&cardAID[certSlot], &vBuf,
1013+ voffset+8, 2);
1014+ if (status != CKYSUCCESS) {
1015+ goto done;
1016+ }
1017+ cardEF[certSlot] = CKYBuffer_GetShortLE(&vBuf, voffset+6);
1018+
1019+ certSlot++;
1020+ }
1021+ status = CKYSUCCESS;
1022+ if (certSlot == 0) {
1023+ status = CKYAPDUFAIL; /* probably neeed a beter error code */
1024+ }
1025+
1026+done:
1027+ CKYBuffer_FreeData(&tBuf);
1028+ CKYBuffer_FreeData(&vBuf);
1029+ return status;
1030+}
1031+
1032+void
1033+Slot::refreshTokenState()
1034+{
1035+ if( cardStateMayHaveChanged() ) {
1036+ log->log("card changed\n");
1037+ invalidateLogin(true);
1038+ closeAllSessions();
1039+ unloadObjects();
1040+ connectToToken();
1041+
1042+ if( state & APPLET_PERSONALIZED ) {
1043+ try {
1044+ loadObjects();
1045+ } catch(PKCS11Exception&) {
1046+ log->log("refreshTokenState: Failed to load objects.\n");
1047+ unloadObjects();
1048+ }
1049+ } else if (state & APPLET_SELECTABLE) {
1050+ initEmpty();
1051+ }
1052+
1053+ }
1054+}
1055+
1056+bool
1057+Slot::isTokenPresent()
1058+{
1059+ refreshTokenState();
1060+ log->log("isTokenPresent, card state is 0x%x\n", state);
1061+ return (state & APPLET_SELECTABLE) != 0;
1062+}
1063+
1064+CK_SESSION_HANDLE
1065+makeSessionHandle(CK_SLOT_ID slotID, SessionHandleSuffix suffix)
1066+{
1067+ assert( (slotID & 0x000000ff) == slotID );
1068+ return (slotID << 24) | suffix;
1069+}
1070+
1071+void
1072+SlotList::decomposeSessionHandle(CK_SESSION_HANDLE hSession, CK_SLOT_ID& slotID,
1073+ SessionHandleSuffix& suffix) const
1074+{
1075+ slotID = hSession >> 24;
1076+ suffix = SessionHandleSuffix(hSession);
1077+ try {
1078+ validateSlotID(slotID);
1079+ } catch(PKCS11Exception&) {
1080+ log->log("Invalid slotID %d pulled from session handle 0x%08x\n",
1081+ slotID, hSession);
1082+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
1083+ }
1084+}
1085+
1086+void
1087+SlotList::openSession(Session::Type type, CK_SLOT_ID slotID,
1088+ CK_SESSION_HANDLE_PTR phSession)
1089+{
1090+ validateSlotID(slotID);
1091+
1092+ SessionHandleSuffix suffix =
1093+ slots[slotIDToIndex(slotID)]->openSession(type);
1094+
1095+ *phSession = makeSessionHandle(slotID, suffix);
1096+}
1097+
1098+void
1099+SlotList::closeSession(CK_SESSION_HANDLE hSession)
1100+{
1101+ CK_SLOT_ID slotID;
1102+ SessionHandleSuffix suffix;
1103+
1104+ decomposeSessionHandle(hSession, slotID, suffix);
1105+
1106+ slots[slotIDToIndex(slotID)]->closeSession(suffix);
1107+}
1108+
1109+
1110+SessionHandleSuffix
1111+Slot::openSession(Session::Type type)
1112+{
1113+ ensureTokenPresent();
1114+ return generateNewSession(type);
1115+}
1116+
1117+class SessionHandleSuffixMatch {
1118+ private:
1119+ SessionHandleSuffix suffix;
1120+ public:
1121+ explicit SessionHandleSuffixMatch(SessionHandleSuffix s) : suffix(s) { }
1122+ bool operator()(const Session& session) {
1123+ return session.getHandleSuffix() == suffix;
1124+ }
1125+};
1126+
1127+bool
1128+Slot::isValidSession(SessionHandleSuffix handleSuffix) const
1129+{
1130+ SessionConstIter iter;
1131+ iter = findConstSession(handleSuffix);
1132+ return (iter != sessions.end());
1133+}
1134+
1135+void
1136+Slot::closeSession(SessionHandleSuffix handleSuffix)
1137+{
1138+ refreshTokenState();
1139+
1140+ SessionIter iter;
1141+ iter = findSession(handleSuffix);
1142+ if( iter == sessions.end() ) {
1143+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID,
1144+ "Invalid session handle suffix 0x%08x passed to closeSession\n",
1145+ (unsigned long)handleSuffix);
1146+ } else {
1147+ log->log("Closed session 0x%08x\n", (unsigned long)handleSuffix);
1148+ sessions.erase(iter);
1149+ }
1150+}
1151+
1152+CK_RV
1153+Slot::getSlotInfo(CK_SLOT_INFO_PTR pSlotInfo)
1154+{
1155+ static CK_VERSION firmwareVersion = {0,0};
1156+
1157+ if( pSlotInfo == NULL ) {
1158+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
1159+ }
1160+ pSlotInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT;
1161+ /*pSlotInfo->flags = CKF_REMOVABLE_DEVICE; */
1162+ if( isTokenPresent() )
1163+ pSlotInfo->flags |= CKF_TOKEN_PRESENT;
1164+ memset(pSlotInfo->slotDescription, ' ', 64);
1165+ memcpy(pSlotInfo->slotDescription, readerName,
1166+ MIN(64, strlen(readerName)) );
1167+ memset(pSlotInfo->manufacturerID, ' ', 32);
1168+ memcpy(pSlotInfo->manufacturerID, manufacturer,
1169+ MIN(32, strlen(manufacturer)) );
1170+ pSlotInfo->hardwareVersion = hwVersion;
1171+ pSlotInfo->firmwareVersion = firmwareVersion;
1172+
1173+ return CKR_OK;
1174+}
1175+
1176+inline unsigned char
1177+hex(unsigned long digit)
1178+{
1179+ return (digit > 9 )? (char)(digit+'a'-10) : (char)(digit+'0');
1180+}
1181+
1182+void
1183+Slot::makeCUIDString(char *serialNumber, int maxSize,
1184+ const unsigned char *cuids)
1185+{
1186+ signed int i; // must be signed or for loop won't exit!
1187+ char *cp;
1188+
1189+ memset(serialNumber, ' ', maxSize);
1190+ // CUID is an 8 digit hex number with leading zeros.
1191+ // we count down from 8 stripping hex digits. If there is not
1192+ // enough space, we truncate the top digits
1193+ unsigned long cuid =
1194+ ((unsigned long) cuids[6]) << 24 |
1195+ ((unsigned long) cuids[7]) << 16 |
1196+ ((unsigned long) cuids[8]) << 8 |
1197+ ((unsigned long) cuids[9]) ;
1198+
1199+ for (i = MIN(maxSize,8)-1, cp= serialNumber; i >= 0;
1200+ cp++, i--) {
1201+ unsigned long digit = cuid >> (i*4);
1202+ // if we truncated the beginning. show that with a '*'
1203+ *cp = (digit > 0xf) ? '*' : hex(digit);
1204+ cuid -= digit << (i*4);
1205+ }
1206+}
1207+
1208+
1209+void
1210+Slot::makeSerialString(char *serialNumber, int maxSize,
1211+ const unsigned char *cuid)
1212+{
1213+ memset(serialNumber, ' ', maxSize);
1214+
1215+ // otherwise we use the eepromSerialNumber as a hex value
1216+ if (cuid) {
1217+ makeCUIDString(serialNumber, maxSize, cuid);
1218+ }
1219+ return;
1220+}
1221+
1222+void
1223+Slot::makeLabelString(char *label, int maxSize, const unsigned char *cuid)
1224+{
1225+ int personLen;
1226+ memset(label, ' ', maxSize);
1227+ if (fullTokenName) {
1228+ personLen = strlen(personName);
1229+ memcpy(label, personName, MIN(personLen, maxSize));
1230+ // UTF8 Truncate fixup! don't drop halfway through a UTF8 character
1231+ return;
1232+ }
1233+
1234+//
1235+// Legacy tokens only 'speak' english.
1236+//
1237+#define COOLKEY "CoolKey"
1238+#define POSSESSION " for "
1239+ if (!personName || personName[0] == '\0' ) {
1240+ const int coolKeySize = sizeof(COOLKEY) ;
1241+ memcpy(label, COOLKEY, coolKeySize-1);
1242+ makeSerialString(&label[coolKeySize], maxSize-coolKeySize, cuid);
1243+ return;
1244+ }
1245+ const int prefixSize = sizeof (COOLKEY POSSESSION )-1;
1246+ memcpy(label, COOLKEY POSSESSION, prefixSize);
1247+ personLen = strlen(personName);
1248+ memcpy(&label[prefixSize], personName,
1249+ MIN(personLen, maxSize-prefixSize));
1250+
1251+}
1252+
1253+void
1254+Slot::makeModelString(char *model, int maxSize, const unsigned char *cuid)
1255+{
1256+ char *cp = model;
1257+ memset(model, ' ', maxSize);
1258+ assert(maxSize >= 8);
1259+
1260+ if (!cuid) {
1261+ return;
1262+ }
1263+
1264+ *cp++ = hex(cuid[2] >> 4);
1265+ *cp++ = hex(cuid[2] & 0xf);
1266+ *cp++ = hex(cuid[3] >> 4);
1267+ *cp++ = hex(cuid[3] & 0xf);
1268+ *cp++ = hex(cuid[4] >> 4);
1269+ *cp++ = hex(cuid[4] & 0xf);
1270+ *cp++ = hex(cuid[5] >> 4);
1271+ *cp++ = hex(cuid[5] & 0xf);
1272+ makeCUIDString(&model[8],maxSize -8, cuid);
1273+
1274+ return;
1275+}
1276+
1277+struct _manList {
1278+ unsigned short type;
1279+ const char *string;
1280+};
1281+
1282+static const struct _manList manList[] = {
1283+ { 0x4090, "Axalto" },
1284+ { 0x2050, "Oberthur" },
1285+ { 0x4780, "RSA" }
1286+};
1287+
1288+static int manListSize = sizeof(manList)/sizeof(manList[0]);
1289+
1290+void
1291+Slot::makeManufacturerString(char *man, int maxSize, const unsigned char *cuid)
1292+{
1293+ char *cp = man;
1294+ memset(man, ' ', maxSize);
1295+
1296+ if (!cuid) {
1297+ return;
1298+ }
1299+ unsigned short fabricator = ((unsigned short)cuid[0]) << 8 | cuid[1];
1300+
1301+ assert(maxSize >=4 );
1302+
1303+ /* first give the raw manufacture ID for CUID calculations */
1304+ *cp++ = hex(cuid[0] >> 4);
1305+ *cp++ = hex(cuid[0] & 0xf);
1306+ *cp++ = hex(cuid[1] >> 4);
1307+ *cp++ = hex(cuid[1] & 0xf);
1308+ cp++; /* leave a space */
1309+
1310+
1311+ for (int i=0; i < manListSize; i++) {
1312+ if (fabricator == manList[i].type) {
1313+ int len = strlen(manList[i].string);
1314+ memcpy(cp,manList[i].string, MIN(len,maxSize-5));
1315+ break;
1316+ }
1317+ }
1318+ /* just leave the number bare if we don't recognize it */
1319+}
1320+
1321+CK_RV
1322+Slot::getTokenInfo(CK_TOKEN_INFO_PTR pTokenInfo)
1323+{
1324+ if(pTokenInfo == NULL ) {
1325+ throw PKCS11Exception(CKR_ARGUMENTS_BAD);
1326+ }
1327+ ensureTokenPresent();
1328+ const unsigned char *cuid = CKYBuffer_Data(&mCUID);
1329+
1330+ /// format the token string
1331+ makeLabelString((char *)pTokenInfo->label, sizeof(pTokenInfo->label),cuid);
1332+ makeSerialString((char *)pTokenInfo->serialNumber,
1333+ sizeof(pTokenInfo->serialNumber), cuid);
1334+ makeModelString((char *)pTokenInfo->model,
1335+ sizeof(pTokenInfo->model), cuid);
1336+ makeManufacturerString((char *)pTokenInfo->manufacturerID,
1337+ sizeof(pTokenInfo->manufacturerID), cuid);
1338+
1339+ pTokenInfo->flags = CKF_WRITE_PROTECTED;
1340+ if (state & APPLET_PERSONALIZED) {
1341+ pTokenInfo->flags |= CKF_TOKEN_INITIALIZED;
1342+ if (needLogin) {
1343+ pTokenInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
1344+ }
1345+ }
1346+ pTokenInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
1347+ pTokenInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
1348+ pTokenInfo->ulMaxRwSessionCount = 0;
1349+ pTokenInfo->ulMaxPinLen = 32;
1350+ pTokenInfo->ulMinPinLen = 0;
1351+ pTokenInfo->ulTotalPublicMemory = publicTotal;
1352+ pTokenInfo->ulFreePublicMemory = publicFree;
1353+ pTokenInfo->ulTotalPrivateMemory = CK_EFFECTIVELY_INFINITE;
1354+ pTokenInfo->ulFreePrivateMemory = privateFree;
1355+ pTokenInfo->hardwareVersion.major = cuid ? cuid[4] : 0;
1356+ pTokenInfo->hardwareVersion.minor = cuid ? cuid[5] : 0;
1357+ pTokenInfo->firmwareVersion = tokenFWVersion;
1358+
1359+
1360+ return CKR_OK;
1361+}
1362+
1363+void
1364+SlotList::validateSlotID(CK_SLOT_ID slotID) const
1365+{
1366+ if( slotID < 1 || slotID > numSlots ) {
1367+ throw PKCS11Exception(CKR_SLOT_ID_INVALID);
1368+ }
1369+}
1370+
1371+#define PKCS11_WAIT_LATENCY 500 /* 500 msec or 1/2 sec */
1372+#define PKCS11_CARD_ERROR_LATENCY 300
1373+void
1374+SlotList::waitForSlotEvent(CK_FLAGS flag, CK_SLOT_ID_PTR slotp, CK_VOID_PTR res)
1375+{
1376+ unsigned long timeout = (flag ==CKF_DONT_BLOCK) ? 0 : PKCS11_WAIT_LATENCY;
1377+ unsigned int i;
1378+ bool found = FALSE;
1379+ CKYStatus status;
1380+ SCARD_READERSTATE *myReaderStates = NULL;
1381+ unsigned int myNumReaders = 0;
1382+#ifndef notdef
1383+ do {
1384+ readerListLock.getLock();
1385+ try {
1386+ updateReaderList();
1387+ } catch(PKCS11Exception&) {
1388+ readerListLock.releaseLock();
1389+ if (myReaderStates) {
1390+ delete [] myReaderStates;
1391+ }
1392+ throw;
1393+ }
1394+
1395+ if (myNumReaders != numReaders) {
1396+ if (myReaderStates) {
1397+ delete [] myReaderStates;
1398+ }
1399+ myReaderStates = new SCARD_READERSTATE [numReaders];
1400+ }
1401+ memcpy(myReaderStates, readerStates,
1402+ sizeof(SCARD_READERSTATE)*numReaders);
1403+ myNumReaders = numReaders;
1404+ readerListLock.releaseLock();
1405+ status = CKYCardContext_WaitForStatusChange(context,
1406+ myReaderStates, myNumReaders, timeout);
1407+ if (status == CKYSUCCESS) {
1408+ for (i=0; i < myNumReaders; i++) {
1409+ SCARD_READERSTATE *rsp = &myReaderStates[i];
1410+ unsigned long eventState = CKYReader_GetEventState(rsp);
1411+ if (eventState & SCARD_STATE_CHANGED) {
1412+ readerListLock.getLock();
1413+ CKYReader_SetKnownState(&readerStates[i], eventState & ~SCARD_STATE_CHANGED);
1414+ readerListLock.releaseLock();
1415+ *slotp = slotIndexToID(i);
1416+ found = TRUE;
1417+ break;
1418+ }
1419+ }
1420+ }
1421+
1422+ if (found || (flag == CKF_DONT_BLOCK) || shuttingDown) {
1423+ break;
1424+ }
1425+
1426+ #ifndef WIN32
1427+ if (status != CKYSUCCESS) {
1428+
1429+ if ( (CKYCardContext_GetLastError(context) ==
1430+ SCARD_E_READER_UNAVAILABLE) ||
1431+ (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT))
1432+ {
1433+ OSSleep(timeout*PKCS11_CARD_ERROR_LATENCY);
1434+ }
1435+
1436+
1437+ }
1438+ #endif
1439+ } while ((status == CKYSUCCESS) ||
1440+ (CKYCardContext_GetLastError(context) == SCARD_E_TIMEOUT) ||
1441+ ( CKYCardContext_GetLastError(context) == SCARD_E_READER_UNAVAILABLE));
1442+#else
1443+ do {
1444+ OSSleep(100);
1445+ } while ((flag != CKF_DONT_BLOCK) && !shuttingDown);
1446+#endif
1447+
1448+ if (myReaderStates) {
1449+ delete [] myReaderStates;
1450+ }
1451+
1452+ if (!found) {
1453+ throw PKCS11Exception(CKR_NO_EVENT);
1454+ }
1455+ return;
1456+}
1457+
1458+void
1459+Slot::handleConnectionError()
1460+{
1461+ long error = CKYCardConnection_GetLastError(conn);
1462+
1463+ log->log("Connection Error = 0x%x\n", error);
1464+
1465+ // Force a reconnect after a token operation fails. The most
1466+ // common reason for it to fail is that it has been removed, but
1467+ // it doesn't hurt to do it in other cases either (such as a reset).
1468+ disconnect();
1469+
1470+ // Convert the PCSC error to a PKCS #11 error, and throw the exception.
1471+ CK_RV ckrv;
1472+ switch( error ) {
1473+ case SCARD_E_NO_SMARTCARD:
1474+ case SCARD_W_RESET_CARD:
1475+ case SCARD_W_REMOVED_CARD:
1476+ ckrv = CKR_DEVICE_REMOVED;
1477+ break;
1478+ default:
1479+ ckrv = CKR_DEVICE_ERROR;
1480+ break;
1481+ }
1482+ throw PKCS11Exception(ckrv);
1483+}
1484+
1485+list<ListObjectInfo>
1486+Slot::getObjectList()
1487+{
1488+ list<ListObjectInfo> objInfoList;
1489+
1490+ while(true) {
1491+ CKYISOStatus result;
1492+ ListObjectInfo info;
1493+ CKYByte seq = objInfoList.size() == 0 ? CKY_LIST_RESET : CKY_LIST_NEXT;
1494+ CKYStatus status=CKYApplet_ListObjects(conn, seq, &info.obj, &result);
1495+ if (status != CKYSUCCESS) {
1496+ // we failed because of a connection error
1497+ if (status == CKYSCARDERR) {
1498+ handleConnectionError();
1499+ }
1500+ // we failed simply because we hit the end of the list
1501+ // (in which case we are done)
1502+ if ((result == CKYISO_SUCCESS) || (result == CKYISO_SEQUENCE_END)) {
1503+ break;
1504+ }
1505+ // we failed fror some other reason...
1506+ throw PKCS11Exception(CKR_DEVICE_ERROR);
1507+ }
1508+
1509+ log->log("===Object\n");
1510+ log->log("===id: 0x%04x\n", info.obj.objectID);
1511+ log->log("===size: %d\n", info.obj.objectSize);
1512+ log->log("===acl: 0x%02x,0x%02x,0x%02x\n", info.obj.readACL,
1513+ info.obj.writeACL, info.obj.deleteACL);
1514+ log->log("\n");
1515+
1516+ objInfoList.push_back(info);
1517+ }
1518+
1519+ return objInfoList;
1520+}
1521+
1522+// Should already have a transaction
1523+void
1524+Slot::selectApplet()
1525+{
1526+ CKYStatus status;
1527+ status = CKYApplet_SelectCoolKeyManager(conn, NULL);
1528+ if ( status == CKYSCARDERR ) handleConnectionError();
1529+ if ( status != CKYSUCCESS) {
1530+ // could not select applet: this just means it's not there
1531+ disconnect();
1532+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
1533+ }
1534+}
1535+
1536+void
1537+Slot::selectCACApplet(CKYByte instance)
1538+{
1539+ CKYStatus status;
1540+ CKYBuffer *aid = &cardAID[instance];
1541+
1542+ if (CKYBuffer_Size(aid) == 0) {
1543+ disconnect();
1544+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
1545+ return;
1546+ }
1547+
1548+ status = CKYApplet_SelectFile(conn, aid, NULL);
1549+ if ( status == CKYSCARDERR ) handleConnectionError();
1550+ if ( status != CKYSUCCESS) {
1551+ // could not select applet: this just means it's not there
1552+ disconnect();
1553+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
1554+ }
1555+ if (mOldCAC) {
1556+ return;
1557+ }
1558+ status = CACApplet_SelectFile(conn, cardEF[instance], NULL);
1559+ if ( status == CKYSCARDERR ) handleConnectionError();
1560+ if ( status != CKYSUCCESS) {
1561+ disconnect();
1562+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
1563+ }
1564+}
1565+// assume we are already in a transaction
1566+void
1567+Slot::readMuscleObject(CKYBuffer *data, unsigned long objectID,
1568+ unsigned int objSize)
1569+{
1570+ CKYStatus status;
1571+
1572+ status = CKYApplet_ReadObjectFull(conn, objectID, 0, objSize,
1573+ getNonce(), data, NULL);
1574+ if (status == CKYSCARDERR) {
1575+ handleConnectionError();
1576+ }
1577+ if (status != CKYSUCCESS) {
1578+ throw PKCS11Exception(CKR_DEVICE_ERROR);
1579+ }
1580+ return;
1581+}
1582+
1583+
1584+class DERCertObjIDMatch {
1585+ private:
1586+ unsigned short certnum;
1587+ const Slot &slot;
1588+ public:
1589+ DERCertObjIDMatch(unsigned short cn, const Slot &s) :
1590+ certnum(cn), slot(s) { }
1591+
1592+ bool operator()(const ListObjectInfo& info) {
1593+ return (slot.getObjectClass(info.obj.objectID) == 'C')
1594+ && ( slot.getObjectIndex(info.obj.objectID) == certnum );
1595+ }
1596+};
1597+
1598+class ObjectHandleMatch {
1599+ private:
1600+ CK_OBJECT_HANDLE handle;
1601+ public:
1602+ ObjectHandleMatch(CK_OBJECT_HANDLE handle_) : handle(handle_) { }
1603+ bool operator()(const PKCS11Object& obj) {
1604+ return obj.getHandle() == handle;
1605+ }
1606+};
1607+
1608+class KeyNumMatch {
1609+ private:
1610+ CKYByte keyNum;
1611+ const Slot &slot;
1612+ public:
1613+ KeyNumMatch(CKYByte keyNum_, const Slot &s) : keyNum(keyNum_), slot(s) { }
1614+ bool operator() (const PKCS11Object& obj) {
1615+ unsigned long objID = obj.getMuscleObjID();
1616+ return (slot.getObjectClass(objID) == 'k')
1617+ && (slot.getObjectIndex(objID) == keyNum);
1618+ }
1619+};
1620+
1621+class ObjectCertCKAIDMatch {
1622+ private:
1623+ CKYByte cka_id;
1624+ public:
1625+ ObjectCertCKAIDMatch(CKYByte cka_id_) : cka_id(cka_id_) {}
1626+ bool operator()(const PKCS11Object& obj) {
1627+ const CKYBuffer *id;
1628+ const CKYBuffer *objClass;
1629+ CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
1630+ objClass = obj.getAttribute(CKA_CLASS);
1631+ if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass,
1632+ (CKYByte *)&certClass, sizeof(certClass))) {
1633+ return false;
1634+ }
1635+ id = obj.getAttribute(CKA_ID);
1636+ return (id != NULL && CKYBuffer_DataIsEqual(id,&cka_id, 1))
1637+ ? true : false;
1638+ }
1639+};
1640+
1641+CK_OBJECT_HANDLE
1642+Slot::generateUnusedObjectHandle()
1643+{
1644+ CK_OBJECT_HANDLE handle;
1645+ ObjectConstIter iter;
1646+ do {
1647+ handle = ++objectHandleCounter;
1648+ iter = find_if(tokenObjects.begin(), tokenObjects.end(),
1649+ ObjectHandleMatch(handle));
1650+ } while( handle == CK_INVALID_HANDLE || iter != tokenObjects.end() );
1651+ return handle;
1652+}
1653+
1654+void
1655+Slot::addKeyObject(list<PKCS11Object>& objectList, const ListObjectInfo& info,
1656+ CK_OBJECT_HANDLE handle, bool isCombined)
1657+{
1658+ ObjectConstIter iter;
1659+ Key keyObj(info.obj.objectID, &info.data, handle);
1660+ CK_OBJECT_CLASS objClass = keyObj.getClass();
1661+ const CKYBuffer *id;
1662+
1663+
1664+ if (isCombined &&
1665+ ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY))) {
1666+ id = keyObj.getAttribute(CKA_ID);
1667+ if ((!id) || (CKYBuffer_Size(id) != 1)) {
1668+ throw PKCS11Exception(CKR_DEVICE_ERROR,
1669+ "Missing or invalid CKA_ID value");
1670+ }
1671+ iter = find_if(objectList.begin(), objectList.end(),
1672+ ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
1673+ if ( iter == objectList.end() ) {
1674+ // We failed to find a cert with a matching CKA_ID. This
1675+ // can happen if the cert is not present on the token, or
1676+ // the der encoded cert stored on the token was corrupted.
1677+ throw PKCS11Exception(CKR_DEVICE_ERROR,
1678+ "Failed to find cert with matching CKA_ID value");
1679+ }
1680+ keyObj.completeKey(*iter);
1681+ }
1682+ objectList.push_back(keyObj);
1683+
1684+}
1685+
1686+void
1687+Slot::addObject(list<PKCS11Object>& objectList, const ListObjectInfo& info,
1688+ CK_OBJECT_HANDLE handle)
1689+{
1690+ objectList.push_back(PKCS11Object(info.obj.objectID, &info.data, handle));
1691+}
1692+
1693+void
1694+Slot::addCertObject(list<PKCS11Object>& objectList,
1695+ const ListObjectInfo& certAttrs,
1696+ const CKYBuffer *derCert, CK_OBJECT_HANDLE handle)
1697+{
1698+ Cert certObj(certAttrs.obj.objectID,
1699+ &certAttrs.data, handle, derCert);
1700+ if (personName == NULL) {
1701+ personName = strdup(certObj.getLabel());
1702+ fullTokenName = false;
1703+ }
1704+
1705+ objectList.push_back(certObj);
1706+}
1707+void
1708+Slot::unloadObjects()
1709+{
1710+ tokenObjects.clear();
1711+ free(personName);
1712+ personName = NULL;
1713+ fullTokenName = false;
1714+}
1715+
1716+#ifdef USE_SHMEM
1717+
1718+// The shared memory segment is used to cache the raw token objects from
1719+// the card so mupltiple instances do not need to read all the data in
1720+// by themselves. It also allows us to recover data from a token on
1721+// reinsertion if that token is inserted into the same 'slot' as it was
1722+// originally.
1723+//
1724+// There is one memory segment for each slot.
1725+//
1726+// The process that creates the shared memory segment will initialize the
1727+// valid byte to '0'. Otherwise the Memory Segment must be accessed while
1728+// in a transaction for the connection to a reader that the memory segment
1729+// represents is held.
1730+//
1731+// If the memory segment is not valid, does not match the CUID of the
1732+// current token, or does not match the current data version, the current
1733+// process will read the object data out of the card and into shared memory.
1734+// Since access to the shared memory is protected by the interprocess
1735+// transaction lock on the reader, data consistancy is
1736+// maintained.
1737+//
1738+// shared memory is layed out as follows:
1739+//
1740+// Header:
1741+// 1 short (version) shared mem layout version number (currrent 1,0)
1742+// 1 short (header size) size in bytes of the shared memory header
1743+// 1 byte (valid) segment is valid or not (valid =1; not valid =0 )
1744+// 1 byte (reserved) (set to zero)
1745+// 10 bytes (CUID) Unique card identifier.
1746+// 1 short (reserved) (set to zero)
1747+// 1 short (data version) version number of the embeded data
1748+// 1 short (header offset) offset to the card's data header.
1749+// 1 short (data offset) offset to the uncompressed card data.
1750+// 1 long (header size) size in bytes of the card's data header.
1751+// 1 long (data size) size in bytes of the uncompressed data.
1752+// .
1753+// .
1754+// DataHeader:
1755+// n bytes DataHeader.
1756+// .
1757+// .
1758+// Data:
1759+// n bytes Data.
1760+//
1761+// All data in the shared memory header is stored in machine order, packing,
1762+// and size. Data in the DataHeader and Data sections are stored in applet
1763+// byte order.
1764+//
1765+// Shared memory segments are fixed size (equal to the object memory size of
1766+// the token).
1767+//
1768+
1769+struct SlotSegmentHeader {
1770+ unsigned short version;
1771+ unsigned short headerSize;
1772+ unsigned char valid;
1773+ unsigned char reserved;
1774+ unsigned char cuid[10];
1775+ unsigned short reserved2;
1776+ unsigned short dataVersion;
1777+ unsigned short dataHeaderOffset;
1778+ unsigned short dataOffset;
1779+ unsigned long dataHeaderSize;
1780+ unsigned long dataSize;
1781+ unsigned long cert2Offset;
1782+ unsigned long cert2Size;
1783+};
1784+
1785+#define MAX_OBJECT_STORE_SIZE 15000
1786+//
1787+// previous development versions used a segment prefix of
1788+// "coolkeypk11s"
1789+//
1790+#define SEGMENT_PREFIX "coolkeypk11s"
1791+#define CAC_FAKE_CUID "CAC Certs"
1792+SlotMemSegment::SlotMemSegment(const char *readerName):
1793+ segmentAddr(NULL), segmentSize(0), segment(NULL)
1794+{
1795+ bool needInit;
1796+ char *segName;
1797+
1798+ segName = new char[strlen(readerName)+sizeof(SEGMENT_PREFIX)+1];
1799+ if (!segName) {
1800+ // just run without shared memory
1801+ return;
1802+ }
1803+ sprintf(segName,SEGMENT_PREFIX"%s",readerName);
1804+ segment = SHMem::initSegment(segName, MAX_OBJECT_STORE_SIZE, needInit);
1805+ delete [] segName;
1806+ if (!segment) {
1807+ // just run without shared memory
1808+ return;
1809+ }
1810+ segmentAddr = segment->getSHMemAddr();
1811+ assert(segmentAddr);
1812+ // paranoia, shouldn't happen..
1813+ if (!segmentAddr) {
1814+ delete segment;
1815+ segment = NULL;
1816+ return;
1817+ }
1818+
1819+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1820+ if (needInit) {
1821+ segmentHeader->valid = 0;
1822+ }
1823+ segmentSize = segment->getSHMemSize();
1824+}
1825+
1826+SlotMemSegment::~SlotMemSegment()
1827+{
1828+ if (segment) {
1829+ delete segment;
1830+ }
1831+}
1832+
1833+bool
1834+SlotMemSegment::CUIDIsEqual(const CKYBuffer *cuid) const
1835+{
1836+ if (!segment) {
1837+ return false;
1838+ }
1839+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1840+
1841+ return
1842+ CKYBuffer_DataIsEqual(cuid, (CKYByte *)segmentHeader->cuid,
1843+ sizeof(segmentHeader->cuid)) ? true : false;
1844+}
1845+
1846+void
1847+SlotMemSegment::setCUID(const CKYBuffer *cuid)
1848+{
1849+ if (!segment) {
1850+ return;
1851+ }
1852+
1853+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1854+
1855+ if (CKYBuffer_Size(cuid) != sizeof(segmentHeader->cuid)) {
1856+ // should throw and exception?
1857+ return;
1858+ }
1859+ memcpy (segmentHeader->cuid, CKYBuffer_Data(cuid),
1860+ sizeof(segmentHeader->cuid));
1861+}
1862+
1863+const unsigned char *
1864+SlotMemSegment::getCUID() const
1865+{
1866+ if (!segment) {
1867+ return NULL;
1868+ }
1869+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1870+ return segmentHeader->cuid;
1871+}
1872+
1873+unsigned short
1874+SlotMemSegment::getVersion() const
1875+{
1876+ if (!segment) {
1877+ return 0;
1878+ }
1879+
1880+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1881+ return segmentHeader->version;
1882+}
1883+
1884+unsigned short
1885+SlotMemSegment::getDataVersion() const
1886+{
1887+ if (!segment) {
1888+ return 0;
1889+ }
1890+
1891+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1892+ return segmentHeader->dataVersion;
1893+}
1894+
1895+void
1896+SlotMemSegment::setVersion(unsigned short version)
1897+{
1898+ if (!segment) {
1899+ return;
1900+ }
1901+
1902+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1903+ segmentHeader->version = version;
1904+}
1905+
1906+
1907+void
1908+SlotMemSegment::setDataVersion(unsigned short version)
1909+{
1910+ if (!segment) {
1911+ return;
1912+ }
1913+
1914+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1915+ segmentHeader->dataVersion = version;
1916+}
1917+
1918+bool
1919+SlotMemSegment::isValid() const
1920+{
1921+ if (!segment) {
1922+ return false;
1923+ }
1924+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1925+ return segmentHeader->valid == 1;
1926+}
1927+
1928+void
1929+SlotMemSegment::readHeader(CKYBuffer *dataHeader) const
1930+{
1931+ if (!segment) {
1932+ return;
1933+ }
1934+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1935+ int size = segmentHeader->dataHeaderSize;
1936+ CKYByte *data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
1937+ CKYBuffer_Replace(dataHeader, 0, data, size);
1938+}
1939+
1940+void
1941+SlotMemSegment::readData(CKYBuffer *objData) const
1942+{
1943+ if (!segment) {
1944+ return;
1945+ }
1946+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1947+ int size = segmentHeader->dataSize;
1948+ CKYByte *data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
1949+ CKYBuffer_Replace(objData, 0, data, size);
1950+}
1951+
1952+
1953+void
1954+SlotMemSegment::writeHeader(const CKYBuffer *dataHeader)
1955+{
1956+ if (!segment) {
1957+ return;
1958+ }
1959+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1960+ int size = CKYBuffer_Size(dataHeader);
1961+ segmentHeader->headerSize = sizeof *segmentHeader;
1962+ segmentHeader->dataHeaderSize = size;
1963+ segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
1964+ segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size;
1965+ CKYByte *data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
1966+ memcpy(data, CKYBuffer_Data(dataHeader), size);
1967+}
1968+
1969+void
1970+SlotMemSegment::writeData(const CKYBuffer *objData)
1971+{
1972+ if (!segment) {
1973+ return;
1974+ }
1975+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1976+ int size = CKYBuffer_Size(objData);
1977+ segmentHeader->dataSize = size;
1978+ CKYByte *data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
1979+ memcpy(data, CKYBuffer_Data(objData), size);
1980+}
1981+
1982+void
1983+SlotMemSegment::readCACCert(CKYBuffer *objData, CKYByte instance) const
1984+{
1985+ if (!segment) {
1986+ return;
1987+ }
1988+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
1989+ int size;
1990+ CKYByte *data;
1991+
1992+ switch (instance) {
1993+ case 0:
1994+ data = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
1995+ size = segmentHeader->dataHeaderSize;
1996+ break;
1997+ case 1:
1998+ data = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
1999+ size = segmentHeader->dataSize;
2000+ break;
2001+ case 2:
2002+ data = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
2003+ size = segmentHeader->cert2Size;
2004+ break;
2005+ default:
2006+ CKYBuffer_Resize(objData, 0);
2007+ return;
2008+ }
2009+ CKYBuffer_Replace(objData, 0, data, size);
2010+}
2011+
2012+
2013+void
2014+SlotMemSegment::writeCACCert(const CKYBuffer *data, CKYByte instance)
2015+{
2016+ if (!segment) {
2017+ return;
2018+ }
2019+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
2020+ int size = CKYBuffer_Size(data);
2021+ CKYByte *shmData;
2022+ switch (instance) {
2023+ case 0:
2024+ segmentHeader->headerSize = sizeof *segmentHeader;
2025+ segmentHeader->dataHeaderOffset = sizeof *segmentHeader;
2026+ segmentHeader->dataHeaderSize = size;
2027+ segmentHeader->dataOffset = segmentHeader->dataHeaderOffset + size;
2028+ segmentHeader->dataSize = 0;
2029+ segmentHeader->cert2Offset = segmentHeader->dataOffset;
2030+ segmentHeader->cert2Size = 0;
2031+ shmData = (CKYByte *) &segmentAddr[segmentHeader->dataHeaderOffset];
2032+ break;
2033+ case 1:
2034+ segmentHeader->dataSize = size;
2035+ segmentHeader->cert2Offset = segmentHeader->dataOffset + size;
2036+ segmentHeader->cert2Size = 0;
2037+ shmData = (CKYByte *) &segmentAddr[segmentHeader->dataOffset];
2038+ break;
2039+ case 2:
2040+ segmentHeader->cert2Size = size;
2041+ shmData = (CKYByte *) &segmentAddr[segmentHeader->cert2Offset];
2042+ break;
2043+ default:
2044+ return;
2045+ }
2046+ memcpy(shmData, CKYBuffer_Data(data), size);
2047+}
2048+
2049+void
2050+SlotMemSegment::clearValid(CKYByte instance)
2051+{
2052+
2053+ if (!segment) {
2054+ return;
2055+ }
2056+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
2057+ switch (instance) {
2058+ case 0:
2059+ segmentHeader->headerSize = 0;
2060+ segmentHeader->dataHeaderSize = 0;
2061+ /* fall through */
2062+ case 1:
2063+ segmentHeader->dataSize = 0;
2064+ }
2065+ segmentHeader->valid = 0;
2066+}
2067+
2068+void
2069+SlotMemSegment::setValid()
2070+{
2071+ if (!segment) {
2072+ return;
2073+ }
2074+ SlotSegmentHeader *segmentHeader = (SlotSegmentHeader *)segmentAddr;
2075+ segmentHeader->valid = 1;
2076+}
2077+
2078+#endif
2079+
2080+void
2081+Slot::initEmpty(void)
2082+{
2083+ // check the shared memory area first
2084+ // shared memory is protected by our transaction call on the card
2085+ //
2086+ Transaction trans;
2087+ CKYStatus status = trans.begin(conn);
2088+ if( status != CKYSUCCESS ) {
2089+ handleConnectionError();
2090+ }
2091+
2092+ loadReaderObject();
2093+ readCUID();
2094+}
2095+
2096+void
2097+Slot::readCUID(void)
2098+{
2099+ // check the shared memory area first
2100+ // shared memory is protected by our transaction call on the card
2101+ //
2102+ CKYStatus status;
2103+ if (state & CAC_CARD) {
2104+ status = CACApplet_SelectCardManager(conn, NULL);
2105+ } else {
2106+ status = CKYApplet_SelectCardManager(conn, NULL);
2107+ }
2108+ CKYBuffer_Resize(&mCUID, 0);
2109+ if (status == CKYSCARDERR) {
2110+ handleConnectionError();
2111+ }
2112+ status = CKYApplet_GetCUID(conn, &mCUID, NULL);
2113+ if (status == CKYSCARDERR) {
2114+ handleConnectionError();
2115+ }
2116+}
2117+
2118+list<ListObjectInfo>
2119+Slot::fetchSeparateObjects()
2120+{
2121+ int i;
2122+
2123+ list<ListObjectInfo> objInfoList;
2124+ std::list<ListObjectInfo>::iterator iter;
2125+
2126+ OSTime time = OSTimeNow();
2127+ readCUID();
2128+ selectApplet();
2129+ log->log(
2130+ "time fetch separate: getting cuid & applet select (again) %d ms\n",
2131+ OSTimeNow() - time);
2132+
2133+#ifdef USE_SHMEM
2134+ shmem.clearValid(0);
2135+#endif
2136+
2137+ //
2138+ // get the list of objects on the muscle token
2139+ //
2140+ objInfoList = getObjectList();
2141+
2142+
2143+ log->log("time fetch separate: getObjectList %d ms\n",OSTimeNow() - time);
2144+ //
2145+ // get the content of each object
2146+ //
2147+ for (i=0, iter = objInfoList.begin(); iter != objInfoList.end();
2148+ ++iter, i++) {
2149+ // check the ACL to make sure this will succeed.
2150+ unsigned short readPerm = iter->obj.readACL;
2151+
2152+ log->log("Object has read perm 0x%04x\n", readPerm);
2153+ if ( (!isVersion1Key && ((readPerm & 0x2) == readPerm)) ||
2154+ (isVersion1Key && ((readPerm & 0x1))) ) {
2155+ readMuscleObject(&iter->data, iter->obj.objectID,
2156+ iter->obj.objectSize);
2157+ log->log("Object:\n");
2158+ log->dump(&iter->data);
2159+ }
2160+ }
2161+ log->log("time fetch separate: readObjects %dms\n", OSTimeNow() - time);
2162+ return objInfoList;
2163+}
2164+
2165+list<ListObjectInfo>
2166+Slot::fetchCombinedObjects(const CKYBuffer *header)
2167+{
2168+ CKYBuffer objBuffer;
2169+ CKYStatus status;
2170+
2171+ list<ListObjectInfo> objInfoList;
2172+ CKYBuffer_InitEmpty(&objBuffer);
2173+ unsigned short compressedOffset = CKYBuffer_GetShort(
2174+ header, OBJ_COMP_OFFSET_OFFSET);
2175+ unsigned short compressedSize = CKYBuffer_GetShort(
2176+ header, OBJ_COMP_SIZE_OFFSET);
2177+ OSTime time = OSTimeNow();
2178+
2179+#ifdef USE_SHMEM
2180+
2181+ // check the shared memory area first
2182+ // shared memory is protected by our transaction call on the card
2183+ //
2184+ CKYBuffer_Resize(&mCUID,0);
2185+ CKYBuffer_AppendBuffer(&mCUID, header, OBJ_CUID_OFFSET, OBJ_CUID_SIZE);
2186+ unsigned short dataVersion = CKYBuffer_GetShort(
2187+ header, OBJ_OBJECT_VERSION_OFFSET);
2188+
2189+ if (shmem.isValid() && shmem.CUIDIsEqual(&mCUID) &&
2190+ shmem.getDataVersion() == dataVersion) {
2191+ shmem.readData(&objBuffer);
2192+ } else {
2193+ shmem.clearValid(0);
2194+ shmem.setCUID(&mCUID);
2195+ shmem.setVersion(SHMEM_VERSION);
2196+ shmem.setDataVersion(dataVersion);
2197+ CKYBuffer dataHeader;
2198+ CKYBuffer_InitFromBuffer(&dataHeader, header, 0,
2199+ (CKYSize) compressedOffset);
2200+
2201+ shmem.writeHeader(&dataHeader);
2202+ CKYBuffer_FreeData(&dataHeader);
2203+ log->log("time fetch combined: play with shared memory %d ms\n",
2204+ OSTimeNow() - time);
2205+#endif
2206+ CKYBuffer_Reserve(&objBuffer, compressedSize);
2207+ CKYSize headerSize = CKYBuffer_Size(header);
2208+ CKYSize headerBytes = headerSize - compressedOffset;
2209+
2210+
2211+ CKYBuffer_AppendBuffer(&objBuffer,header,compressedOffset,headerBytes);
2212+ log->log("time fetch combined: "
2213+ "headerbytes = %d compressedOffset = %d compressedSize = %d\n",
2214+ headerBytes, compressedOffset, compressedSize);
2215+ status = CKYApplet_ReadObjectFull(conn, COMBINED_ID,
2216+ headerSize, compressedSize - headerBytes, getNonce(),
2217+ &objBuffer, NULL);
2218+ log->log("time fetch combined: read status = %d objectBuffSize = %d\n",
2219+ status, CKYBuffer_Size(&objBuffer));
2220+ if (status == CKYSCARDERR) {
2221+ CKYBuffer_FreeData(&objBuffer);
2222+ handleConnectionError();
2223+ }
2224+ log->log("time fetch combined: "
2225+ "Read Object Data %d ms (object size = %d bytes)\n",
2226+ OSTimeNow() - time, compressedSize);
2227+ if (CKYBuffer_GetShort(header, OBJ_COMP_TYPE_OFFSET) == COMP_ZLIB) {
2228+ CKYBuffer compBuffer;
2229+ CKYSize guessFinalSize = CKYBuffer_Size(&objBuffer);
2230+ CKYSize objSize = 0;
2231+ int zret = Z_MEM_ERROR;
2232+
2233+ CKYBuffer_InitFromCopy(&compBuffer,&objBuffer);
2234+ do {
2235+ guessFinalSize *= 2;
2236+ status = CKYBuffer_Resize(&objBuffer, guessFinalSize);
2237+ if (status != CKYSUCCESS) {
2238+ break;
2239+ }
2240+ objSize = guessFinalSize;
2241+ zret = uncompress((Bytef *)CKYBuffer_Data(&objBuffer),&objSize,
2242+ CKYBuffer_Data(&compBuffer), CKYBuffer_Size(&compBuffer));
2243+ } while (zret == Z_BUF_ERROR);
2244+ log->log("time fetch combined: "
2245+ "uncompress objects %d ms (object size = %d bytes)\n",
2246+ OSTimeNow() - time, objSize);
2247+
2248+ CKYBuffer_FreeData(&compBuffer);
2249+ if (zret != Z_OK) {
2250+ CKYBuffer_FreeData(&objBuffer);
2251+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2252+ "Corrupted compressed object Data");
2253+ }
2254+ CKYBuffer_Resize(&objBuffer,objSize);
2255+ }
2256+
2257+ // uncompress...
2258+#ifdef USE_SHMEM
2259+ shmem.writeData(&objBuffer);
2260+ shmem.setDataVersion(dataVersion);
2261+ shmem.setValid();
2262+ }
2263+#endif
2264+
2265+ //
2266+ // now pull apart the objects
2267+ //
2268+ unsigned short offset =
2269+ CKYBuffer_GetShort(&objBuffer, OBJ_OBJECT_OFFSET_OFFSET);
2270+ unsigned short objectCount = CKYBuffer_GetShort(
2271+ &objBuffer, OBJ_OBJECT_COUNT_OFFSET);
2272+ int tokenNameSize = CKYBuffer_GetChar(&objBuffer,OBJ_TOKENNAME_SIZE_OFFSET);
2273+ int i;
2274+ CKYSize size = CKYBuffer_Size(&objBuffer);
2275+
2276+ if (offset < tokenNameSize+OBJ_TOKENNAME_OFFSET) {
2277+ CKYBuffer_FreeData(&objBuffer);
2278+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2279+ "Tokenname/object Data overlap");
2280+ }
2281+ if (personName) {
2282+ free(personName);
2283+ }
2284+ personName = (char *)malloc(tokenNameSize+1);
2285+ memcpy(personName,CKYBuffer_Data(&objBuffer)+OBJ_TOKENNAME_OFFSET,
2286+ tokenNameSize);
2287+ personName[tokenNameSize] = 0;
2288+ fullTokenName = true;
2289+
2290+ for (i=0; i < objectCount && offset < size; i++) {
2291+ ListObjectInfo info;
2292+ unsigned long objectID = CKYBuffer_GetLong(&objBuffer, offset);
2293+ unsigned long attrsCount= CKYBuffer_GetShort(&objBuffer, offset+8);
2294+ unsigned long start = offset;
2295+ unsigned int j;
2296+
2297+ info.obj.objectID = objectID;
2298+ offset +=10;
2299+
2300+ /* get the length of the attribute block */
2301+ for (j=0; j < attrsCount; j++) {
2302+ CKYByte attributeDataType=CKYBuffer_GetChar(&objBuffer, offset +4);
2303+
2304+ offset += 5;
2305+
2306+ switch (attributeDataType) {
2307+ case DATATYPE_STRING:
2308+ offset += CKYBuffer_GetShort(&objBuffer, offset) + 2;
2309+ break;
2310+ case DATATYPE_BOOL_FALSE:
2311+ case DATATYPE_BOOL_TRUE:
2312+ break;
2313+ case DATATYPE_INTEGER:
2314+ offset += 4;
2315+ break;
2316+ }
2317+ }
2318+ if (offset > size) {
2319+ CKYBuffer_FreeData(&objBuffer);
2320+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2321+ "Inconsistent combined object data");
2322+ }
2323+ CKYSize objSize = offset - start;
2324+ CKYBuffer_Reserve(&info.data, objSize +1);
2325+ // tell the object parsing code that this is a new, compact type
2326+ CKYBuffer_AppendChar(&info.data,1);
2327+ // copy the object
2328+ CKYBuffer_AppendBuffer(&info.data, &objBuffer, start, objSize);
2329+ objInfoList.push_back(info);
2330+ }
2331+ CKYBuffer_FreeData(&objBuffer);
2332+ log->log("fetch combined: format objects %d ms\n", OSTimeNow() - time);
2333+ return objInfoList;
2334+}
2335+
2336+CKYStatus
2337+Slot::readCACCertificateFirst(CKYBuffer *cert, CKYSize *nextSize,
2338+ bool throwException)
2339+{
2340+ CKYStatus status;
2341+ CKYISOStatus apduRC;
2342+ *nextSize = 0;
2343+
2344+ if (mOldCAC) {
2345+ /* get the first 100 bytes of the cert */
2346+ status = CACApplet_GetCertificateFirst(conn, cert, nextSize, &apduRC);
2347+ if (throwException && (status != CKYSUCCESS)) {
2348+ handleConnectionError();
2349+ }
2350+
2351+ if(throwException && CKYBuffer_Size(cert) == 0) {
2352+ handleConnectionError();
2353+ }
2354+ return status;
2355+ }
2356+
2357+ CKYBuffer tBuf;
2358+ CKYBuffer vBuf;
2359+ CKYSize tlen, vlen;
2360+ CKYOffset toffset, voffset;
2361+ int length = 0;
2362+
2363+ CKYBuffer_InitEmpty(&tBuf);
2364+ CKYBuffer_InitEmpty(&vBuf);
2365+ CKYBuffer_Resize(cert, 0);
2366+
2367+ /* handle the new CAC card read */
2368+ /* read the TLV */
2369+ status = CACApplet_ReadFile(conn, CAC_TAG_FILE, &tBuf, NULL);
2370+ if (status != CKYSUCCESS) {
2371+ goto done;
2372+ }
2373+ status = CACApplet_ReadFile(conn, CAC_VALUE_FILE, &vBuf, NULL);
2374+ if (status != CKYSUCCESS) {
2375+ goto done;
2376+ }
2377+ tlen = CKYBuffer_Size(&tBuf);
2378+ vlen = CKYBuffer_Size(&vBuf);
2379+
2380+ /* look for the Cert out of the TLV */
2381+ for(toffset = 2, voffset=2; toffset < tlen && voffset < vlen ;
2382+ voffset += length) {
2383+
2384+ CKYByte tag = CKYBuffer_GetChar(&tBuf, toffset);
2385+ length = CKYBuffer_GetChar(&tBuf, toffset+1);
2386+ toffset += 2;
2387+ if (length == 0xff) {
2388+ length = CKYBuffer_GetShortLE(&tBuf, toffset);
2389+ toffset +=2;
2390+ }
2391+ if (tag != CAC_TAG_CERTIFICATE) {
2392+ continue;
2393+ }
2394+ CKYBuffer_AppendBuffer(cert, &vBuf, voffset, length);
2395+ break;
2396+ }
2397+ status = CKYSUCCESS;
2398+
2399+done:
2400+ CKYBuffer_FreeData(&tBuf);
2401+ CKYBuffer_FreeData(&vBuf);
2402+ return status;
2403+}
2404+
2405+/*
2406+ * only necessary for old CAC cards. New CAC cards have to read the
2407+ * whole cert in anyway above....
2408+ */
2409+CKYStatus
2410+Slot::readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize)
2411+{
2412+ CKYISOStatus apduRC;
2413+ assert(mOldCAC);
2414+ return CACApplet_GetCertificateAppend(conn, cert, nextSize, &apduRC);
2415+}
2416+
2417+void
2418+Slot::loadCACCert(CKYByte instance)
2419+{
2420+ CKYStatus status = CKYSUCCESS;
2421+ CKYBuffer cert;
2422+ CKYBuffer rawCert;
2423+ CKYBuffer shmCert;
2424+ CKYSize nextSize;
2425+
2426+ OSTime time = OSTimeNow();
2427+
2428+ CKYBuffer_InitEmpty(&cert);
2429+ CKYBuffer_InitEmpty(&rawCert);
2430+ CKYBuffer_InitEmpty(&shmCert);
2431+
2432+ //
2433+ // not all CAC cards have all the PKI instances
2434+ // catch the applet selection errors if they don't
2435+ //
2436+ try {
2437+ selectCACApplet(instance);
2438+ } catch(PKCS11Exception& e) {
2439+ // all CAC's must have instance '0', throw the error it
2440+ // they don't.
2441+ if (instance == 0) throw e;
2442+ // If the CAC doesn't have instance '2', and we were updating
2443+ // the shared memory, set it to valid now.
2444+ if ((instance == 2) && !shmem.isValid()) {
2445+ shmem.setValid();
2446+ }
2447+ return;
2448+ }
2449+
2450+ log->log("CAC Cert %d: select CAC applet: %d ms\n",
2451+ instance, OSTimeNow() - time);
2452+
2453+ if (instance == 0) {
2454+ readCACCertificateFirst(&rawCert, &nextSize, true);
2455+ log->log("CAC Cert %d: fetch CAC Cert: %d ms\n",
2456+ instance, OSTimeNow() - time);
2457+ }
2458+
2459+ unsigned short dataVersion = 1;
2460+ CKYBool needRead = 1;
2461+
2462+ /* see if it matches the shared memory */
2463+ if (shmem.isValid() && shmem.getDataVersion() == dataVersion) {
2464+ shmem.readCACCert(&shmCert, instance);
2465+ CKYSize certSize = CKYBuffer_Size(&rawCert);
2466+ CKYSize shmCertSize = CKYBuffer_Size(&shmCert);
2467+ const CKYByte *shmData = CKYBuffer_Data(&shmCert);
2468+
2469+ if (instance != 0) {
2470+ needRead = 0;
2471+ }
2472+
2473+ if (shmCertSize >= certSize) {
2474+ if (memcmp(shmData, CKYBuffer_Data(&rawCert), certSize) == 0) {
2475+ /* yes it does, no need to read the rest of the cert, use
2476+ * the cache */
2477+ CKYBuffer_Replace(&rawCert, 0, shmData, shmCertSize);
2478+ needRead = 0;
2479+ }
2480+ }
2481+ if (!needRead && (shmCertSize == 0)) {
2482+ /* no cert of this type, just return */
2483+ return;
2484+ }
2485+ }
2486+ CKYBuffer_FreeData(&shmCert);
2487+
2488+ if (needRead) {
2489+ /* it doesn't, read the new cert and update the cache */
2490+ if (instance == 0) {
2491+ shmem.clearValid(0);
2492+ shmem.setVersion(SHMEM_VERSION);
2493+ shmem.setDataVersion(dataVersion);
2494+ } else {
2495+ status = readCACCertificateFirst(&rawCert, &nextSize, false);
2496+
2497+ if (status != CKYSUCCESS) {
2498+ /* CAC only requires the Certificate in pki '0' */
2499+ /* if pki '1' or '2' are empty, treat it as a non-fatal error*/
2500+ if (instance == 2) {
2501+ /* we've attempted to read all the certs, shared memory
2502+ * is now valid */
2503+ shmem.setValid();
2504+ }
2505+ return;
2506+ }
2507+ }
2508+
2509+ if (nextSize) {
2510+ status = readCACCertificateAppend(&rawCert, nextSize);
2511+ }
2512+ log->log("CAC Cert %d: Fetch rest : %d ms\n",
2513+ instance, OSTimeNow() - time);
2514+ if (status != CKYSUCCESS) {
2515+ handleConnectionError();
2516+ }
2517+ shmem.writeCACCert(&rawCert, instance);
2518+ if (instance == 2) {
2519+ shmem.setValid();
2520+ }
2521+ }
2522+
2523+
2524+ log->log("CAC Cert %d: Cert has been read: %d ms\n",
2525+ instance, OSTimeNow() - time);
2526+ if (!mOldCAC || CKYBuffer_GetChar(&rawCert,0) == 1) {
2527+ CKYSize guessFinalSize = CKYBuffer_Size(&rawCert);
2528+ CKYSize certSize = 0;
2529+ CKYOffset offset = mOldCAC ? 1 : 0;
2530+ int zret = Z_MEM_ERROR;
2531+
2532+ do {
2533+ guessFinalSize *= 2;
2534+ status = CKYBuffer_Resize(&cert, guessFinalSize);
2535+ if (status != CKYSUCCESS) {
2536+ break;
2537+ }
2538+ certSize = guessFinalSize;
2539+ zret = uncompress((Bytef *)CKYBuffer_Data(&cert),&certSize,
2540+ CKYBuffer_Data(&rawCert)+offset,
2541+ CKYBuffer_Size(&rawCert)-offset);
2542+ } while (zret == Z_BUF_ERROR);
2543+
2544+ if (zret != Z_OK) {
2545+ CKYBuffer_FreeData(&rawCert);
2546+ CKYBuffer_FreeData(&cert);
2547+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2548+ "Corrupted compressed CAC Cert");
2549+ }
2550+ CKYBuffer_Resize(&cert,certSize);
2551+ } else {
2552+ CKYBuffer_InitFromBuffer(&cert,&rawCert,1,CKYBuffer_Size(&rawCert)-1);
2553+ }
2554+ CKYBuffer_FreeData(&rawCert);
2555+ log->log("CAC Cert %d: Cert has been uncompressed: %d ms\n",
2556+ instance, OSTimeNow() - time);
2557+
2558+ CACCert certObj(instance, &cert);
2559+ CACPrivKey privKey(instance, certObj);
2560+ CACPubKey pubKey(instance, certObj);
2561+ tokenObjects.push_back(privKey);
2562+ tokenObjects.push_back(pubKey);
2563+ tokenObjects.push_back(certObj);
2564+
2565+ if (personName == NULL) {
2566+ const char *name = certObj.getName();
2567+ if (name) {
2568+ personName = strdup(name);
2569+ fullTokenName = true;
2570+ }
2571+ }
2572+}
2573+
2574+void
2575+Slot::loadObjects()
2576+{
2577+ // throw away all token objects!
2578+
2579+ Transaction trans;
2580+ CKYBuffer header;
2581+ CKYBuffer_InitEmpty(&header);
2582+ CKYStatus status = trans.begin(conn);
2583+ if( status != CKYSUCCESS ) {
2584+ handleConnectionError();
2585+ }
2586+ OSTime time = OSTimeNow();
2587+
2588+
2589+ list<ListObjectInfo> objInfoList;
2590+ std::list<ListObjectInfo>::iterator iter;
2591+
2592+ if (state & CAC_CARD) {
2593+ loadCACCert(0);
2594+ loadCACCert(1);
2595+ loadCACCert(2);
2596+ status = trans.end();
2597+ loadReaderObject();
2598+ return;
2599+ }
2600+
2601+ selectApplet();
2602+ log->log("time load object: Select Applet (again) %d ms\n",
2603+ OSTimeNow() - time);
2604+
2605+
2606+ status = CKYApplet_ReadObjectFull(conn, COMBINED_ID, 0,
2607+ CKY_MAX_READ_CHUNK_SIZE, getNonce(), &header, NULL);
2608+ log->log("time load object: ReadCombined Header %d ms\n",
2609+ OSTimeNow() - time);
2610+ if (status == CKYSCARDERR) {
2611+ CKYBuffer_FreeData(&header);
2612+ handleConnectionError();
2613+ }
2614+ bool isCombined = (status == CKYSUCCESS) ? true : false;
2615+ try {
2616+ objInfoList = isCombined ? fetchCombinedObjects(&header)
2617+ : fetchSeparateObjects();
2618+ } catch(PKCS11Exception& e) {
2619+ CKYBuffer_FreeData(&header);
2620+ throw(e);
2621+ }
2622+ log->log("time load object: Fetch %d ms\n", OSTimeNow() - time);
2623+ CKYBuffer_FreeData(&header);
2624+ status = trans.end();
2625+
2626+ //
2627+ // load up the keys, certs and others.
2628+ //
2629+ for( iter = objInfoList.begin(); iter != objInfoList.end(); ++iter ) {
2630+ CKYByte type = getObjectClass(iter->obj.objectID);
2631+ if( type == 'k' ) {
2632+ CK_OBJECT_HANDLE handle = generateUnusedObjectHandle();
2633+ addKeyObject(tokenObjects, *iter, handle, isCombined);
2634+ } else if( type == 'c' ) {
2635+ // cert attribute object. find the DER encoding
2636+ unsigned short certnum = getObjectIndex(iter->obj.objectID);
2637+ if( certnum > 9 ) {
2638+ //invalid object id
2639+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2640+ "Invalid object id %08x",iter->obj.objectID);
2641+ }
2642+ std::list<ListObjectInfo>::iterator derCert;
2643+ /*
2644+ * Old tokens stored certs separately from the attributes
2645+ */
2646+ if (!isCombined) {
2647+ derCert = find_if(objInfoList.begin(), objInfoList.end(),
2648+ DERCertObjIDMatch(certnum, *this));
2649+ if( derCert == objInfoList.end() ) {
2650+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2651+ "No DER cert object for cert %d\n", certnum);
2652+ }
2653+ }
2654+ CK_OBJECT_HANDLE handle = generateUnusedObjectHandle();
2655+ addCertObject(tokenObjects, *iter,
2656+ isCombined ? NULL : &derCert->data, handle);
2657+ } else if ( type == 'C' ) {
2658+ // This is a DER Cert object (as opposed to a cert attribute
2659+ // object, 'c' above). skip it.
2660+ } else if (type == 'd') {
2661+ CK_OBJECT_HANDLE handle = generateUnusedObjectHandle();
2662+ addObject(tokenObjects, *iter, handle);
2663+ } else {
2664+ log->log("Ignoring unknown object %08x\n",iter->obj.objectID);
2665+ }
2666+ }
2667+ log->log("time load objects: Process %d ms\n", OSTimeNow() - time);
2668+
2669+ loadReaderObject();
2670+}
2671+
2672+void
2673+Slot::loadReaderObject(void)
2674+{
2675+ // now generate an Moz "reader" object.
2676+ CK_OBJECT_HANDLE handle = generateUnusedObjectHandle();
2677+ Reader rdr(READER_ID, handle, readerName, &cardATR, mCoolkey);
2678+ tokenObjects.push_back(rdr);
2679+}
2680+
2681+void
2682+Slot::closeAllSessions()
2683+{
2684+ sessions.clear();
2685+ log->log("cleared all sessions\n");
2686+}
2687+
2688+SessionHandleSuffix
2689+Slot::generateNewSession(Session::Type type)
2690+{
2691+ SessionHandleSuffix suffix;
2692+ SessionIter iter;
2693+
2694+ do {
2695+ suffix = (++sessionHandleCounter) & 0x00ffffff;
2696+ iter = findSession(suffix);
2697+ } while( iter != sessions.end() );
2698+
2699+ sessions.push_back(Session(suffix, type));
2700+
2701+ return suffix;
2702+}
2703+
2704+void
2705+SlotList::getSessionInfo(CK_SESSION_HANDLE hSession,
2706+ CK_SESSION_INFO_PTR pInfo)
2707+{
2708+
2709+ CK_SLOT_ID slotID;
2710+ SessionHandleSuffix suffix;
2711+
2712+ decomposeSessionHandle(hSession, slotID, suffix);
2713+
2714+ slots[slotIDToIndex(slotID)]->getSessionInfo(suffix, pInfo);
2715+
2716+ pInfo->slotID = slotID;
2717+}
2718+
2719+void
2720+Slot::ensureTokenPresent()
2721+{
2722+ if( ! isTokenPresent() ) {
2723+ throw PKCS11Exception(CKR_DEVICE_REMOVED);
2724+ }
2725+}
2726+
2727+SessionIter
2728+Slot::findSession(SessionHandleSuffix suffix)
2729+{
2730+ return find_if(sessions.begin(), sessions.end(),
2731+ SessionHandleSuffixMatch(suffix));
2732+}
2733+
2734+SessionConstIter
2735+Slot::findConstSession(SessionHandleSuffix suffix) const
2736+{
2737+ return find_if(sessions.begin(), sessions.end(),
2738+ SessionHandleSuffixMatch(suffix));
2739+}
2740+
2741+void
2742+Slot::getSessionInfo(SessionHandleSuffix handleSuffix,
2743+ CK_SESSION_INFO_PTR pInfo)
2744+{
2745+ refreshTokenState();
2746+
2747+ SessionIter iter = findSession(handleSuffix);
2748+ if( iter == sessions.end() ) {
2749+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID,
2750+ "Unknown session handle suffix 0x%08x passed to "
2751+ "getSessionInfo\n", (unsigned long) handleSuffix);
2752+ } else {
2753+ if( iter->getType() == Session::RO ) {
2754+ pInfo->state = isLoggedIn() ?
2755+ CKS_RO_USER_FUNCTIONS : CKS_RO_PUBLIC_SESSION;
2756+ pInfo->flags = CKF_SERIAL_SESSION;
2757+ } else {
2758+ pInfo->state = isLoggedIn() ?
2759+ CKS_RW_USER_FUNCTIONS : CKS_RW_PUBLIC_SESSION;
2760+ pInfo->flags = CKF_RW_SESSION | CKF_SERIAL_SESSION;
2761+ }
2762+ pInfo->ulDeviceError = CKYCardConnection_GetLastError(conn);
2763+ }
2764+}
2765+
2766+void
2767+SlotList::login(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin,
2768+ CK_ULONG ulPinLen)
2769+{
2770+ CK_SLOT_ID slotID;
2771+ SessionHandleSuffix suffix;
2772+
2773+ decomposeSessionHandle(hSession, slotID, suffix);
2774+
2775+ slots[slotIDToIndex(slotID)]->login(suffix, pPin, ulPinLen);
2776+}
2777+
2778+void
2779+Slot::testNonce()
2780+{
2781+ reverify = false;
2782+ if (!nonceValid) {
2783+ return;
2784+ }
2785+#ifdef notdef
2786+ Transaction trans;
2787+ CKYStatus status = trans.begin(conn);
2788+ try {
2789+ if ( status != CKYSUCCESS ) handleConnectionError();
2790+
2791+ selectApplet();
2792+ } catch (PKCS11Exception &) {
2793+ invalidateLogin(true);
2794+ return;
2795+ }
2796+
2797+ CKYBuffer data;
2798+ CKYBuffer_InitEmpty(&data);
2799+
2800+ status = CKYApplet_ReadObject(conn, 0xffffffff, 0, 1, &nonce, &data, NULL);
2801+ trans.end();
2802+ CKYBuffer_FreeData(&data);
2803+ if( status != CKYSUCCESS ) {
2804+ invalidateLogin(true);
2805+ return;
2806+ }
2807+#else
2808+ invalidateLogin(true);
2809+#endif
2810+}
2811+
2812+bool
2813+Slot::isLoggedIn()
2814+{
2815+ if (isVersion1Key) {
2816+ if (reverify) {
2817+ testNonce();
2818+ }
2819+ return nonceValid;
2820+ }
2821+ return loggedIn;
2822+}
2823+
2824+void
2825+Slot::login(SessionHandleSuffix handleSuffix, CK_UTF8CHAR_PTR pPin,
2826+ CK_ULONG ulPinLen)
2827+{
2828+ refreshTokenState();
2829+
2830+ if( ! isValidSession(handleSuffix) ) {
2831+ log->log("Invalid session handle suffix 0x%08x passed to "
2832+ "Slot::login\n", (unsigned long) handleSuffix);
2833+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
2834+ }
2835+
2836+ if (!isVersion1Key) {
2837+ pinCache.set((const char *)pPin, ulPinLen);
2838+ } else if (nonceValid) {
2839+ throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN);
2840+ }
2841+
2842+ Transaction trans;
2843+ CKYStatus status = trans.begin(conn);
2844+ if(status != CKYSUCCESS ) handleConnectionError();
2845+
2846+ if (state & CAC_CARD) {
2847+ selectCACApplet(0);
2848+ } else {
2849+ selectApplet();
2850+ }
2851+
2852+ if (isVersion1Key) {
2853+ attemptLogin((const char *)pPin);
2854+ } else if (state & CAC_CARD) {
2855+ attemptCACLogin();
2856+ } else {
2857+ oldAttemptLogin();
2858+ }
2859+}
2860+
2861+void
2862+Slot::attemptCACLogin()
2863+{
2864+ loggedIn = false;
2865+ pinCache.invalidate();
2866+
2867+ CKYStatus status;
2868+ CKYISOStatus result;
2869+
2870+ status = CACApplet_VerifyPIN(conn,
2871+ (const char *)CKYBuffer_Data(pinCache.get()), &result);
2872+ if( status == CKYSCARDERR ) {
2873+ handleConnectionError();
2874+ }
2875+ switch( result ) {
2876+ case CKYISO_SUCCESS:
2877+ break;
2878+ case 0x6981:
2879+ throw PKCS11Exception(CKR_PIN_LOCKED);
2880+ default:
2881+ if ((result & 0xff00) == 0x6300) {
2882+ throw PKCS11Exception(CKR_PIN_INCORRECT);
2883+ }
2884+ throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x",
2885+ result);
2886+ }
2887+
2888+ pinCache.validate();
2889+ loggedIn = true;
2890+}
2891+
2892+void
2893+Slot::oldAttemptLogin()
2894+{
2895+ loggedIn = false;
2896+ pinCache.invalidate();
2897+
2898+ CKYStatus status;
2899+ CKYISOStatus result;
2900+ status = CKYApplet_VerifyPinV0(conn, CKY_OLD_USER_PIN_NUM,
2901+ (const char *)CKYBuffer_Data(pinCache.get()), &result);
2902+ if( status == CKYSCARDERR ) {
2903+ handleConnectionError();
2904+ }
2905+ switch( result ) {
2906+ case CKYISO_SUCCESS:
2907+ break;
2908+ case CKYISO_AUTH_FAILED:
2909+ throw PKCS11Exception(CKR_PIN_INCORRECT);
2910+ case CKYISO_IDENTITY_BLOCKED:
2911+ throw PKCS11Exception(CKR_PIN_LOCKED);
2912+ default:
2913+ throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x",
2914+ result);
2915+ }
2916+
2917+ pinCache.validate();
2918+ loggedIn = true;
2919+}
2920+
2921+// should already be in a transaction, and applet selected
2922+void
2923+Slot::attemptLogin(const char *pin)
2924+{
2925+ CKYStatus status;
2926+ CKYISOStatus result;
2927+ status = CKYApplet_VerifyPIN(conn, CKY_USER_PIN_NUM, pin, &nonce, &result);
2928+ if( status == CKYSCARDERR ) {
2929+ handleConnectionError();
2930+ }
2931+
2932+ switch( result ) {
2933+ case CKYISO_SUCCESS:
2934+ break;
2935+ case CKYISO_AUTH_FAILED:
2936+ throw PKCS11Exception(CKR_PIN_INCORRECT);
2937+ case CKYISO_IDENTITY_BLOCKED:
2938+ throw PKCS11Exception(CKR_PIN_LOCKED);
2939+ default:
2940+ throw PKCS11Exception(CKR_DEVICE_ERROR,
2941+ "Applet returned 0x%04x", result);
2942+ }
2943+ nonceValid = true;
2944+
2945+}
2946+
2947+void
2948+SlotList::logout(CK_SESSION_HANDLE hSession)
2949+{
2950+ CK_SLOT_ID slotID;
2951+ SessionHandleSuffix suffix;
2952+
2953+ decomposeSessionHandle(hSession, slotID, suffix);
2954+
2955+ slots[slotIDToIndex(slotID)]->logout(suffix);
2956+}
2957+
2958+//
2959+// The old "logout All" from pre-version 1 CoolKeys.
2960+//
2961+void
2962+Slot::oldLogout()
2963+{
2964+ invalidateLogin(true);
2965+
2966+ Transaction trans;
2967+ CKYStatus status = trans.begin(conn);
2968+ if( status != CKYSUCCESS) handleConnectionError();
2969+
2970+ selectApplet();
2971+
2972+ status = CKYApplet_LogoutAllV0(conn, NULL);
2973+ if (status != CKYSUCCESS) {
2974+ if (status == CKYSCARDERR) {
2975+ handleConnectionError();
2976+ }
2977+ throw PKCS11Exception(CKR_DEVICE_ERROR);
2978+ }
2979+}
2980+
2981+//
2982+//
2983+void
2984+Slot::CACLogout()
2985+{
2986+ /* use get properties which has the side effect of logging out */
2987+ invalidateLogin(true);
2988+}
2989+
2990+void
2991+Slot::logout(SessionHandleSuffix suffix)
2992+{
2993+ refreshTokenState();
2994+
2995+ if( !isValidSession(suffix) ) {
2996+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
2997+ }
2998+
2999+ if (state & CAC_CARD) {
3000+ CACLogout();
3001+ return;
3002+ }
3003+
3004+ if (!isVersion1Key) {
3005+ oldLogout();
3006+ return;
3007+ }
3008+
3009+ if (!nonceValid) {
3010+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
3011+ }
3012+
3013+ Transaction trans;
3014+ CKYStatus status = trans.begin(conn);
3015+ if( status != CKYSUCCESS) handleConnectionError();
3016+
3017+ status = CKYApplet_Logout(conn, CKY_USER_PIN_NUM, getNonce(), NULL);
3018+ invalidateLogin(true);
3019+ if (status != CKYSUCCESS) {
3020+ if (status == CKYSCARDERR) {
3021+ handleConnectionError();
3022+ }
3023+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3024+ }
3025+
3026+}
3027+
3028+void
3029+SlotList::findObjectsInit(CK_SESSION_HANDLE hSession,
3030+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
3031+{
3032+ CK_SLOT_ID slotID;
3033+ SessionHandleSuffix suffix;
3034+
3035+ decomposeSessionHandle(hSession, slotID, suffix);
3036+
3037+ slots[slotIDToIndex(slotID)]->findObjectsInit(suffix, pTemplate, ulCount);
3038+}
3039+
3040+void
3041+Slot::findObjectsInit(SessionHandleSuffix suffix, CK_ATTRIBUTE_PTR pTemplate,
3042+ CK_ULONG ulCount)
3043+{
3044+ refreshTokenState();
3045+
3046+ SessionIter session = findSession(suffix);
3047+ if( session == sessions.end() ) {
3048+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3049+ }
3050+
3051+ session->foundObjects.clear();
3052+
3053+ ObjectConstIter iter;
3054+ for( iter = tokenObjects.begin(); iter != tokenObjects.end(); ++iter) {
3055+ if( iter->matchesTemplate(pTemplate, ulCount) ) {
3056+ log->log("C_FindObjectsInit found matching object 0x%08x\n",
3057+ iter->getHandle());
3058+ session->foundObjects.push_back(iter->getHandle());
3059+ }
3060+ }
3061+
3062+ session->curFoundObject = session->foundObjects.begin();
3063+}
3064+
3065+void
3066+SlotList::findObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
3067+ CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
3068+{
3069+ CK_SLOT_ID slotID;
3070+ SessionHandleSuffix suffix;
3071+
3072+ decomposeSessionHandle(hSession, slotID, suffix);
3073+
3074+ slots[slotIDToIndex(slotID)]->findObjects(suffix, phObject,
3075+ ulMaxObjectCount, pulObjectCount);
3076+}
3077+
3078+void
3079+Slot::findObjects(SessionHandleSuffix suffix, CK_OBJECT_HANDLE_PTR phObject,
3080+ CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
3081+{
3082+ refreshTokenState();
3083+
3084+ SessionIter session = findSession(suffix);
3085+ if( session == sessions.end() ) {
3086+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3087+ }
3088+
3089+ unsigned int objectsReturned = 0;
3090+ while( objectsReturned < ulMaxObjectCount &&
3091+ session->curFoundObject != session->foundObjects.end() )
3092+ {
3093+ phObject[objectsReturned++] = *(session->curFoundObject++);
3094+ }
3095+
3096+ *pulObjectCount = objectsReturned;
3097+}
3098+
3099+void
3100+SlotList::getAttributeValue(CK_SESSION_HANDLE hSession,
3101+ CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
3102+ const
3103+{
3104+ CK_SLOT_ID slotID;
3105+ SessionHandleSuffix suffix;
3106+
3107+ decomposeSessionHandle(hSession, slotID, suffix);
3108+
3109+ slots[slotIDToIndex(slotID)]->getAttributeValue(suffix, hObject,
3110+ pTemplate, ulCount);
3111+}
3112+
3113+void
3114+Slot::getAttributeValue(SessionHandleSuffix suffix,
3115+ CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
3116+{
3117+ refreshTokenState();
3118+
3119+ if( ! isValidSession(suffix) ) {
3120+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3121+ }
3122+
3123+ ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
3124+ ObjectHandleMatch(hObject));
3125+
3126+ if( iter == tokenObjects.end() ) {
3127+ throw PKCS11Exception(CKR_OBJECT_HANDLE_INVALID);
3128+ }
3129+
3130+ iter->getAttributeValue(pTemplate, ulCount, log);
3131+}
3132+
3133+void
3134+SlotList::signInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
3135+ CK_OBJECT_HANDLE hKey)
3136+{
3137+ CK_SLOT_ID slotID;
3138+ SessionHandleSuffix suffix;
3139+
3140+ decomposeSessionHandle(hSession, slotID, suffix);
3141+
3142+ slots[slotIDToIndex(slotID)]->signInit(suffix, pMechanism, hKey);
3143+}
3144+
3145+void
3146+SlotList::decryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
3147+ CK_OBJECT_HANDLE hKey)
3148+{
3149+ CK_SLOT_ID slotID;
3150+ SessionHandleSuffix suffix;
3151+
3152+ decomposeSessionHandle(hSession, slotID, suffix);
3153+
3154+ slots[slotIDToIndex(slotID)]->decryptInit(suffix, pMechanism, hKey);
3155+}
3156+
3157+void
3158+SlotList::sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
3159+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
3160+ CK_ULONG_PTR pulSignatureLen)
3161+{
3162+ CK_SLOT_ID slotID;
3163+ SessionHandleSuffix suffix;
3164+
3165+ decomposeSessionHandle(hSession, slotID, suffix);
3166+
3167+ slots[slotIDToIndex(slotID)]->sign(suffix, pData, ulDataLen,
3168+ pSignature, pulSignatureLen);
3169+}
3170+
3171+void
3172+SlotList::decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
3173+ CK_ULONG ulDataLen, CK_BYTE_PTR pDecryptedData,
3174+ CK_ULONG_PTR pulDecryptedDataLen)
3175+{
3176+ CK_SLOT_ID slotID;
3177+ SessionHandleSuffix suffix;
3178+
3179+ decomposeSessionHandle(hSession, slotID, suffix);
3180+
3181+ slots[slotIDToIndex(slotID)]->decrypt(suffix, pData, ulDataLen,
3182+ pDecryptedData, pulDecryptedDataLen);
3183+}
3184+
3185+void
3186+SlotList::seedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
3187+ CK_ULONG ulDataLen)
3188+{
3189+ CK_SLOT_ID slotID;
3190+ SessionHandleSuffix suffix;
3191+
3192+ decomposeSessionHandle(hSession, slotID, suffix);
3193+
3194+ slots[slotIDToIndex(slotID)]->seedRandom(suffix, pData, ulDataLen);
3195+}
3196+
3197+void
3198+SlotList::generateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
3199+ CK_ULONG ulDataLen)
3200+{
3201+ CK_SLOT_ID slotID;
3202+ SessionHandleSuffix suffix;
3203+
3204+ decomposeSessionHandle(hSession, slotID, suffix);
3205+
3206+ slots[slotIDToIndex(slotID)]->generateRandom(suffix, pData, ulDataLen);
3207+}
3208+
3209+void
3210+Slot::ensureValidSession(SessionHandleSuffix suffix)
3211+{
3212+ if( ! isValidSession(suffix) ) {
3213+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3214+ }
3215+}
3216+
3217+//
3218+// Looks up an object and pulls the key number from the Muscle Object ID.
3219+// Keys in Muscle have IDs of the form 'kn ', where 'n' is the key number
3220+// from 0-9.
3221+//
3222+CKYByte
3223+Slot::objectHandleToKeyNum(CK_OBJECT_HANDLE hKey)
3224+{
3225+ ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
3226+ ObjectHandleMatch(hKey));
3227+
3228+ if( iter == tokenObjects.end() ) {
3229+ // no such object
3230+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
3231+ }
3232+
3233+ if( getObjectClass(iter->getMuscleObjID()) != 'k' ) {
3234+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
3235+ }
3236+ unsigned short keyNum = getObjectIndex(iter->getMuscleObjID());
3237+ if( keyNum > 9 ) {
3238+ throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
3239+ }
3240+ return keyNum & 0xFF;
3241+}
3242+
3243+void
3244+Slot::signInit(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
3245+ CK_OBJECT_HANDLE hKey)
3246+{
3247+ refreshTokenState();
3248+ SessionIter session = findSession(suffix);
3249+ if( session == sessions.end() ) {
3250+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3251+ }
3252+ session->signatureState.initialize(objectHandleToKeyNum(hKey));
3253+}
3254+
3255+void
3256+Slot::decryptInit(SessionHandleSuffix suffix, CK_MECHANISM_PTR pMechanism,
3257+ CK_OBJECT_HANDLE hKey)
3258+{
3259+ refreshTokenState();
3260+ SessionIter session = findSession(suffix);
3261+ if( session == sessions.end() ) {
3262+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3263+ }
3264+ session->decryptionState.initialize(objectHandleToKeyNum(hKey));
3265+}
3266+
3267+/**
3268+ * Padding algorithm defined in RSA's PKCS #1.
3269+ * to: pre-allocated buffer to receive the padded data
3270+ * toLen: the length of the buffer. This should be the same as the size
3271+ * of the RSA modulus. (toLen - 3) > fromLen.
3272+ * from: data to be padded.
3273+ * fromLen: size of data to be padded. fromLen < (toLen-3).
3274+ * Returns: nonzero for success, zero for failure.
3275+ */
3276+static void
3277+padRSAType1(const CKYBuffer *raw, CKYBuffer *padded)
3278+{
3279+ int i = 0;
3280+ unsigned int padLen = CKYBuffer_Size(padded) - 3 - CKYBuffer_Size(raw);
3281+
3282+ /* First byte: 00 */
3283+ CKYBuffer_SetChar(padded, i++, 0x00);
3284+
3285+ /* Second Byte: Block Type == 01 */
3286+ CKYBuffer_SetChar(padded, i++, 0x01);
3287+
3288+ /* Padding String, each byte is 0xFF for block type 01 */
3289+ CKYBuffer_SetChars(padded, i, 0xFF, padLen);
3290+ i += padLen;
3291+
3292+ /* Separator byte: 00 */
3293+ CKYBuffer_SetChar(padded, i++, 0x00);
3294+
3295+ /* Finally, the data */
3296+ CKYBuffer_Replace(padded, i, CKYBuffer_Data(raw), CKYBuffer_Size(raw));
3297+}
3298+
3299+static void
3300+stripRSAPadding(CKYBuffer *stripped, const CKYBuffer *padded)
3301+{
3302+ unsigned int size = CKYBuffer_Size(padded);
3303+ if( size < 2 ) {
3304+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3305+ }
3306+ if( CKYBuffer_GetChar(padded,0) != 0 ) {
3307+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3308+ }
3309+
3310+ unsigned int dataStart = 3;
3311+
3312+ CKYByte blockType = CKYBuffer_GetChar(padded, 1);
3313+ // There are three block types in PKCS #1 padding: 00, 01, and 02.
3314+ switch(blockType) {
3315+ case 0x00:
3316+ // The padding string is all zeroes. The first nonzero byte
3317+ // is the beginning of the data.
3318+ for( ; dataStart < size; ++dataStart ) {
3319+ if( CKYBuffer_GetChar(padded,dataStart) != 0 ) {
3320+ break;
3321+ }
3322+ }
3323+ if( dataStart == size ) {
3324+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3325+ }
3326+ break;
3327+ case 0x01:
3328+ // The padding string is all 0xFF, followed by a 0x00 separator byte,
3329+ // and then the data.
3330+ for( ; dataStart < size; ++dataStart ) {
3331+ if( CKYBuffer_GetChar(padded,dataStart) == 0xff ) {
3332+ // padding, continue;
3333+ } else if( CKYBuffer_GetChar(padded,dataStart) == 0x00 ) {
3334+ // end of padding
3335+ break;
3336+ } else {
3337+ // invalid character
3338+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3339+ }
3340+ }
3341+ if( dataStart == size ) {
3342+ // we never found the separator byte
3343+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3344+ }
3345+ dataStart++; // data starts after separator byte
3346+ break;
3347+ case 0x02:
3348+ // padding is non-zero. First non-zero byte is the separator,
3349+ // and then the data.
3350+ for( ; dataStart < size; ++dataStart) {
3351+ if( CKYBuffer_GetChar(padded,dataStart) == 0x00 ) {
3352+ break;
3353+ }
3354+ }
3355+ if( dataStart == size ) {
3356+ // we never found the separator byte
3357+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID);
3358+ }
3359+ dataStart++; // data starts after separator byte
3360+ break;
3361+ default:
3362+ throw PKCS11Exception(CKR_ENCRYPTED_DATA_INVALID,
3363+ "Unknown PKCS#1 block type %x", blockType);
3364+ }
3365+
3366+ CKYStatus status = CKYBuffer_Replace(stripped, 0,
3367+ CKYBuffer_Data(padded)+dataStart, size-dataStart);
3368+ if (status != CKYSUCCESS) {
3369+ throw PKCS11Exception(CKR_HOST_MEMORY);
3370+ }
3371+}
3372+
3373+class RSASignatureParams : public CryptParams {
3374+ public:
3375+ RSASignatureParams(unsigned int keysize) : CryptParams(keysize) { }
3376+
3377+ CKYByte getDirection() const { return CKY_DIR_ENCRYPT; }
3378+
3379+ CryptOpState& getOpState(Session& session) const {
3380+ return session.signatureState;
3381+ }
3382+
3383+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
3384+ // RSA_NO_PAD requires RSA PKCS #1 Type 1 padding
3385+ CKYStatus status = CKYBuffer_Resize(paddedInput,getKeySize()/8);
3386+ if (status != CKYSUCCESS) {
3387+ throw PKCS11Exception(CKR_HOST_MEMORY);
3388+ }
3389+ padRSAType1(unpaddedInput, paddedInput);
3390+ return;
3391+ }
3392+
3393+ void
3394+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
3395+ // no need to unpad ciphertext
3396+ CKYBuffer_Replace(unpaddedOutput, 0, CKYBuffer_Data(paddedOutput),
3397+ CKYBuffer_Size(paddedOutput));
3398+
3399+ }
3400+};
3401+
3402+class RSADecryptParams: public CryptParams {
3403+ public:
3404+ RSADecryptParams(unsigned int keysize) : CryptParams(keysize) { }
3405+
3406+ CKYByte getDirection() const { return CKY_DIR_DECRYPT; }
3407+
3408+ CryptOpState& getOpState(Session& session) const {
3409+ return session.decryptionState;
3410+ }
3411+
3412+ void padInput(CKYBuffer *paddedInput, const CKYBuffer *unpaddedInput) const {
3413+ // no need to unpad ciphertext
3414+ CKYBuffer_Replace(paddedInput, 0, CKYBuffer_Data(unpaddedInput),
3415+ CKYBuffer_Size(unpaddedInput));
3416+ }
3417+
3418+ void
3419+ unpadOutput(CKYBuffer *unpaddedOutput, const CKYBuffer *paddedOutput) const {
3420+ // strip off PKCS #1 padding
3421+ stripRSAPadding( unpaddedOutput, paddedOutput );
3422+ return;
3423+ }
3424+};
3425+
3426+void
3427+Slot::sign(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
3428+ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
3429+ CK_ULONG_PTR pulSignatureLen)
3430+{
3431+ RSASignatureParams params(CryptParams::DEFAULT_KEY_SIZE);
3432+ cryptRSA(suffix, pData, ulDataLen, pSignature, pulSignatureLen,
3433+ params);
3434+}
3435+
3436+void
3437+Slot::decrypt(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
3438+ CK_ULONG ulDataLen, CK_BYTE_PTR pDecryptedData,
3439+ CK_ULONG_PTR pulDecryptedDataLen)
3440+{
3441+ RSADecryptParams params(CryptParams::DEFAULT_KEY_SIZE);
3442+ cryptRSA(suffix, pData, ulDataLen, pDecryptedData, pulDecryptedDataLen,
3443+ params);
3444+}
3445+
3446+void
3447+Slot::cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
3448+ CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
3449+ CK_ULONG_PTR pulOutputLen, CryptParams& params)
3450+{
3451+ refreshTokenState();
3452+ SessionIter session = findSession(suffix);
3453+ if( session == sessions.end() ) {
3454+ throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
3455+ }
3456+ // version 1 keys may not need login. We catch the error
3457+ // on the operation. The token will not allow us to sign with
3458+ // a protected key unless we are logged in.
3459+ // can be removed when version 0 support is depricated.
3460+ if (!isVersion1Key && ! isLoggedIn() ) {
3461+ throw PKCS11Exception(CKR_USER_NOT_LOGGED_IN);
3462+ }
3463+ CryptOpState& opState = params.getOpState(*session);
3464+ CKYBuffer *result = &opState.result;
3465+ CKYByte keyNum = opState.keyNum;
3466+
3467+ unsigned int keySize = getKeySize(keyNum);
3468+
3469+ if(keySize != CryptParams::DEFAULT_KEY_SIZE)
3470+ params.setKeySize(keySize);
3471+
3472+ if( CKYBuffer_Size(result) == 0 ) {
3473+ // we haven't already peformed the decryption, so do it now.
3474+ if( pInput == NULL || ulInputLen == 0) {
3475+ throw PKCS11Exception(CKR_DATA_LEN_RANGE);
3476+ }
3477+ // OK, this is gross. We should get our own C++ like buffer
3478+ // management at this point. This code has nothing to do with
3479+ // the applet, it shouldn't be using applet specific buffers.
3480+ CKYBuffer input;
3481+ CKYBuffer inputPad;
3482+ CKYBuffer output;
3483+ CKYBuffer_InitEmpty(&output);
3484+ CKYBuffer_InitEmpty(&inputPad);
3485+ CKYStatus status = CKYBuffer_InitFromData(&input, pInput, ulInputLen);
3486+ if (status != CKYSUCCESS) {
3487+ throw PKCS11Exception(CKR_HOST_MEMORY);
3488+ }
3489+ try {
3490+ params.padInput(&inputPad, &input);
3491+ performRSAOp(&output, &inputPad, keyNum, params.getDirection());
3492+ params.unpadOutput(result, &output);
3493+ CKYBuffer_FreeData(&input);
3494+ CKYBuffer_FreeData(&inputPad);
3495+ CKYBuffer_FreeData(&output);
3496+ } catch(PKCS11Exception& e) {
3497+ CKYBuffer_FreeData(&input);
3498+ CKYBuffer_FreeData(&inputPad);
3499+ CKYBuffer_FreeData(&output);
3500+ throw(e);
3501+ }
3502+ }
3503+
3504+ if( pulOutputLen == NULL ) {
3505+ throw PKCS11Exception(CKR_DATA_INVALID,
3506+ "output length is NULL");
3507+ }
3508+
3509+ if( pOutput != NULL ) {
3510+ if( *pulOutputLen < CKYBuffer_Size(result) ) {
3511+ *pulOutputLen = CKYBuffer_Size(result);
3512+ throw PKCS11Exception(CKR_BUFFER_TOO_SMALL);
3513+ }
3514+ memcpy(pOutput, CKYBuffer_Data(result), CKYBuffer_Size(result));
3515+ }
3516+ *pulOutputLen = CKYBuffer_Size(result);
3517+}
3518+
3519+const CKYBuffer *
3520+Slot::getNonce()
3521+{
3522+ if (!isVersion1Key) {
3523+ return NULL;
3524+ }
3525+ return &nonce;
3526+}
3527+
3528+void
3529+Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input,
3530+ CKYByte keyNum, CKYByte direction)
3531+{
3532+ //
3533+ // establish a transaction
3534+ //
3535+ Transaction trans;
3536+ CKYStatus status = trans.begin(conn);
3537+ if( status != CKYSUCCESS ) handleConnectionError();
3538+
3539+ //
3540+ // select the applet
3541+ //
3542+ if (state & CAC_CARD) {
3543+ selectCACApplet(keyNum);
3544+ } else {
3545+ selectApplet();
3546+ }
3547+
3548+ CKYISOStatus result;
3549+ int loginAttempted = 0;
3550+retry:
3551+ if (state & CAC_CARD) {
3552+ status = CACApplet_SignDecrypt(conn, input, output, &result);
3553+ } else {
3554+ status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
3555+ input, NULL, output, getNonce(), &result);
3556+ }
3557+ /* map the ISO not logged in code to the coolkey one */
3558+ if (status == CKYISO_CONDITION_NOT_SATISFIED) {
3559+ status = (CKYStatus) CKYISO_UNAUTHORIZED;
3560+ }
3561+ if (status != CKYSUCCESS) {
3562+ if ( status == CKYSCARDERR ) {
3563+ handleConnectionError();
3564+ }
3565+ if (result == CKYISO_DATA_INVALID) {
3566+ throw PKCS11Exception(CKR_DATA_INVALID);
3567+ }
3568+ // version0 keys could be logged out in the middle by someone else,
3569+ // reauthenticate... This code can go away when we depricate.
3570+ // version0 applets.
3571+ if (!isVersion1Key && !loginAttempted &&
3572+ (result == CKYISO_UNAUTHORIZED)) {
3573+ // try to reauthenticate
3574+ try {
3575+ oldAttemptLogin();
3576+ } catch(PKCS11Exception& ) {
3577+ // attemptLogin can throw things like CKR_PIN_INCORRECT
3578+ // that don't make sense from a crypto operation. This is
3579+ // a result of pin caching. We will reformat any login
3580+ // exception to a CKR_DEVICE_ERROR.
3581+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3582+ }
3583+ loginAttempted = true;
3584+ goto retry; // easier to understand than a while loop in this case.
3585+ }
3586+ throw PKCS11Exception( result == CKYISO_UNAUTHORIZED ?
3587+ CKR_USER_NOT_LOGGED_IN : CKR_DEVICE_ERROR);
3588+ }
3589+}
3590+
3591+void
3592+Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
3593+ CK_ULONG ulDataLen)
3594+{
3595+ if (state & CAC_CARD) {
3596+ /* should throw unsupported */
3597+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3598+ }
3599+
3600+ Transaction trans;
3601+ CKYStatus status = trans.begin(conn);
3602+ if( status != CKYSUCCESS ) handleConnectionError();
3603+
3604+ CKYBuffer random;
3605+ CKYBuffer seed;
3606+ CKYOffset offset = 0;
3607+ CKYISOStatus result;
3608+ int i;
3609+
3610+ CKYBuffer_InitEmpty(&random);
3611+ CKYBuffer_InitFromData(&seed, pData, ulDataLen);
3612+
3613+
3614+ while (ulDataLen) {
3615+ CKYByte len = (CKYByte) MIN(ulDataLen, 0xff);
3616+
3617+ status = CKYApplet_GetRandom(conn, &random, len, &result);
3618+ if (status != CKYSUCCESS) break;
3619+
3620+ for (i=0; i < len ; i++) {
3621+ CKYBuffer_SetChar(&random, i,
3622+ CKYBuffer_GetChar(&random,i) ^
3623+ CKYBuffer_GetChar(&seed,i+offset));
3624+ }
3625+ status = CKYApplet_SeedRandom(conn, &random, &result);
3626+ if (status != CKYSUCCESS) break;
3627+
3628+ ulDataLen -= (unsigned char)len;
3629+ offset += (unsigned char)len;
3630+ }
3631+
3632+ CKYBuffer_FreeData(&random);
3633+ CKYBuffer_FreeData(&seed);
3634+
3635+ if (status != CKYSUCCESS) {
3636+ if ( status == CKYSCARDERR ) {
3637+ handleConnectionError();
3638+ }
3639+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3640+ }
3641+}
3642+
3643+void
3644+Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData,
3645+ CK_ULONG ulDataLen)
3646+{
3647+ if (state & CAC_CARD) {
3648+ /* should throw unsupported */
3649+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3650+ }
3651+
3652+ Transaction trans;
3653+ CKYStatus status = trans.begin(conn);
3654+ if( status != CKYSUCCESS ) handleConnectionError();
3655+
3656+ CKYBuffer random;
3657+ CKYBuffer_InitEmpty(&random);
3658+
3659+ CKYISOStatus result;
3660+
3661+ while (ulDataLen) {
3662+ CKYByte len = (CKYByte) MIN(ulDataLen, 0xff);
3663+
3664+ status = CKYApplet_GetRandomAppend(conn, &random, len, &result);
3665+ if (status != CKYSUCCESS) break;
3666+
3667+ ulDataLen -= (unsigned char)len;
3668+ }
3669+ CKYBuffer_FreeData(&random);
3670+
3671+ if (status != CKYSUCCESS) {
3672+ if ( status == CKYSCARDERR ) {
3673+ handleConnectionError();
3674+ }
3675+ throw PKCS11Exception(CKR_DEVICE_ERROR);
3676+ }
3677+}
3678+
3679+#define MAX_NUM_KEYS 8
3680+unsigned int
3681+Slot::getKeySize(CKYByte keyNum)
3682+{
3683+ unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE;
3684+ int modSize = 0;
3685+
3686+ if(keyNum >= MAX_NUM_KEYS) {
3687+ return keySize;
3688+ }
3689+
3690+ ObjectConstIter iter;
3691+ iter = find_if(tokenObjects.begin(), tokenObjects.end(),
3692+ KeyNumMatch(keyNum,*this));
3693+
3694+ if( iter == tokenObjects.end() ) {
3695+ return keySize;
3696+ }
3697+
3698+ CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS);
3699+
3700+ if(modulus) {
3701+ modSize = CKYBuffer_Size(modulus);
3702+ if(CKYBuffer_GetChar(modulus,0) == 0x0) {
3703+ modSize--;
3704+ }
3705+ if(modSize > 0)
3706+ keySize = modSize * 8;
3707+ }
3708+
3709+ return keySize;
3710+}
3711
3712=== added directory '.pc/Handle-pcscd-restarting/src/libckyapplet'
3713=== added file '.pc/Handle-pcscd-restarting/src/libckyapplet/cky_card.c'
3714--- .pc/Handle-pcscd-restarting/src/libckyapplet/cky_card.c 1970-01-01 00:00:00 +0000
3715+++ .pc/Handle-pcscd-restarting/src/libckyapplet/cky_card.c 2013-01-15 15:55:32 +0000
3716@@ -0,0 +1,1198 @@
3717+/* ***** BEGIN COPYRIGHT BLOCK *****
3718+ * Copyright (C) 2005 Red Hat, Inc.
3719+ * All rights reserved.
3720+ *
3721+ * This library is free software; you can redistribute it and/or
3722+ * modify it under the terms of the GNU Lesser General Public
3723+ * License as published by the Free Software Foundation version
3724+ * 2.1 of the License.
3725+ *
3726+ * This library is distributed in the hope that it will be useful,
3727+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3728+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3729+ * Lesser General Public License for more details.
3730+ *
3731+ * You should have received a copy of the GNU Lesser General Public
3732+ * License along with this library; if not, write to the Free Software
3733+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3734+ * ***** END COPYRIGHT BLOCK ***** */
3735+
3736+#include <winscard.h>
3737+#include <stdlib.h>
3738+#include <string.h>
3739+#include "cky_basei.h" /* friend class */
3740+#include "cky_base.h"
3741+#include "cky_card.h"
3742+#include "dynlink.h"
3743+
3744+#ifndef WINAPI
3745+#define WINAPI
3746+#endif
3747+
3748+#ifndef SCARD_E_NO_READERS_AVAILABLE
3749+#define SCARD_E_NO_READERS_AVAILABLE ((unsigned long)0x8010002EL)
3750+#endif
3751+
3752+#define NEW(type,count) (type *)malloc((count)*sizeof(type))
3753+
3754+/*
3755+ * protect against scard API not being installed.
3756+ */
3757+
3758+typedef long (WINAPI * SCardEstablishContextFn) (
3759+ unsigned long dwScope,
3760+ const void * pvReserved1,
3761+ const void * pvReserved2,
3762+ LPSCARDCONTEXT phContext);
3763+
3764+typedef long (WINAPI * SCardReleaseContextFn) (
3765+ SCARDCONTEXT hContext);
3766+
3767+typedef long (WINAPI * SCardBeginTransactionFn) (
3768+ long hCard);
3769+
3770+typedef long (WINAPI * SCardEndTransactionFn) (
3771+ long hCard,
3772+ unsigned long dwDisposition);
3773+
3774+typedef long (WINAPI * SCardConnectFn) (
3775+ SCARDCONTEXT hContext,
3776+ const char *szReader,
3777+ unsigned long dwShareMode,
3778+ unsigned long dwPreferredProtocols,
3779+ long *phCard,
3780+ unsigned long *pdwActiveProtocol);
3781+
3782+typedef long (WINAPI * SCardDisconnectFn) (
3783+ long hCard,
3784+ unsigned long dwDisposition);
3785+
3786+typedef long (WINAPI * SCardTransmitFn) (
3787+ long hCard,
3788+ LPCSCARD_IO_REQUEST pioSendPci,
3789+ const unsigned char *pbSendBuffer,
3790+ unsigned long cbSendLength,
3791+ LPSCARD_IO_REQUEST pioRecvPci,
3792+ unsigned char *pbRecvBuffer,
3793+ unsigned long *pcbRecvLength);
3794+
3795+typedef long (WINAPI * SCardReconnectFn) (
3796+ long hCard,
3797+ unsigned long dwShareMode,
3798+ unsigned long dwPreferredProtocols,
3799+ unsigned long dwInitialization,
3800+ unsigned long *pdwActiveProtocol);
3801+
3802+typedef long (WINAPI * SCardListReadersFn) (
3803+ SCARDCONTEXT hContext,
3804+ const char *mszGroups,
3805+ char *mszReaders,
3806+ unsigned long *pcchReaders);
3807+
3808+typedef long (WINAPI * SCardStatusFn) (
3809+ long hCard,
3810+ char *mszReaderNames,
3811+ unsigned long *pcchReaderLen,
3812+ unsigned long *pdwState,
3813+ unsigned long *pdwProtocol,
3814+ unsigned char *pbAtr,
3815+ unsigned long *pcbAtrLen);
3816+
3817+typedef long (WINAPI * SCardGetAttribFn) (
3818+ long hCard,
3819+ unsigned long dwAttId,
3820+ char *pbAttr,
3821+ unsigned long *pchAttrLen);
3822+
3823+typedef long (WINAPI * SCardGetStatusChangeFn) (
3824+ SCARDCONTEXT hContext,
3825+ unsigned long dwTimeout,
3826+ SCARD_READERSTATE *rgReaderStates,
3827+ unsigned long cReaders);
3828+
3829+typedef long (WINAPI * SCardCancelFn) (
3830+ SCARDCONTEXT hContext);
3831+
3832+typedef struct _SCard {
3833+ SCardEstablishContextFn SCardEstablishContext;
3834+ SCardReleaseContextFn SCardReleaseContext;
3835+ SCardBeginTransactionFn SCardBeginTransaction;
3836+ SCardEndTransactionFn SCardEndTransaction;
3837+ SCardConnectFn SCardConnect;
3838+ SCardDisconnectFn SCardDisconnect;
3839+ SCardTransmitFn SCardTransmit;
3840+ SCardReconnectFn SCardReconnect;
3841+ SCardListReadersFn SCardListReaders;
3842+ SCardStatusFn SCardStatus;
3843+ SCardGetAttribFn SCardGetAttrib;
3844+ SCardGetStatusChangeFn SCardGetStatusChange;
3845+ SCardCancelFn SCardCancel;
3846+ SCARD_IO_REQUEST *SCARD_PCI_T0_;
3847+ SCARD_IO_REQUEST *SCARD_PCI_T1_;
3848+} SCard;
3849+
3850+#define GET_ADDRESS(library, scard, name) \
3851+ status= ckyShLibrary_getAddress(library, \
3852+ (void**) &scard->name, MAKE_DLL_SYMBOL(name)); \
3853+ if (status != CKYSUCCESS) { \
3854+ goto fail; \
3855+ }
3856+
3857+#ifdef WIN32
3858+#define SCARD_LIB_NAME "winscard.dll"
3859+#else
3860+#ifdef MAC
3861+#define SCARD_LIB_NAME "PCSC.Framework/PCSC"
3862+#else
3863+#ifdef LINUX
3864+#define SCARD_LIB_NAME "libpcsclite.so"
3865+#else
3866+#ifndef SCARD_LIB_NAME
3867+#error "define wincard library for this platform"
3868+#endif
3869+#endif
3870+#endif
3871+#endif
3872+
3873+static SCard *
3874+ckySCard_Init(void)
3875+{
3876+ ckyShLibrary library;
3877+ CKYStatus status;
3878+ SCard *scard = NEW(SCard, 1);
3879+
3880+ if (!scard) {
3881+ return NULL;
3882+ }
3883+
3884+ library = ckyShLibrary_open(SCARD_LIB_NAME);
3885+ if (!library) {
3886+ goto fail;
3887+ }
3888+
3889+ GET_ADDRESS(library, scard, SCardEstablishContext);
3890+ GET_ADDRESS(library, scard, SCardReleaseContext);
3891+ GET_ADDRESS(library, scard, SCardBeginTransaction);
3892+ GET_ADDRESS(library, scard, SCardEndTransaction);
3893+ /* expands to SCardConnectA on Windows */
3894+ GET_ADDRESS(library, scard, SCardConnect);
3895+ GET_ADDRESS(library, scard, SCardDisconnect);
3896+ GET_ADDRESS(library, scard, SCardTransmit);
3897+ GET_ADDRESS(library, scard, SCardReconnect);
3898+ /* expands to SCardListReadersA on Windows */
3899+ GET_ADDRESS(library, scard, SCardListReaders);
3900+ /* expands to SCardStatusA on Windows */
3901+ GET_ADDRESS(library, scard, SCardStatus);
3902+#ifdef WIN32
3903+ GET_ADDRESS(library, scard, SCardGetAttrib);
3904+#endif
3905+ /* SCardGetStatusChangeA */
3906+ GET_ADDRESS(library, scard, SCardGetStatusChange);
3907+ GET_ADDRESS(library, scard, SCardCancel);
3908+
3909+ status = ckyShLibrary_getAddress( library,
3910+ (void**) &scard->SCARD_PCI_T0_, MAKE_DLL_SYMBOL(g_rgSCardT0Pci));
3911+ if( status != CKYSUCCESS ) {
3912+ goto fail;
3913+ }
3914+
3915+ status = ckyShLibrary_getAddress( library,
3916+ (void**) &scard->SCARD_PCI_T1_, MAKE_DLL_SYMBOL(g_rgSCardT1Pci));
3917+ if( status != CKYSUCCESS ) {
3918+ goto fail;
3919+ }
3920+ return scard;
3921+
3922+fail:
3923+ if (library) {
3924+ ckyShLibrary_close(library);
3925+ }
3926+ free(scard);
3927+ return NULL;
3928+}
3929+/*
3930+ * Implement CKYReaderNameLists and CKYCardConnectionLists
3931+ */
3932+/* make the list code happy */
3933+static void
3934+CKYReaderName_Destroy(char *data) {
3935+ free(data);
3936+}
3937+
3938+#include "cky_list.i" /* implemnentation of the lists define by cky_list.h */
3939+CKYLIST_IMPLEMENT(CKYReaderName, char *)
3940+CKYLIST_IMPLEMENT(CKYCardConnection, CKYCardConnection *)
3941+
3942+
3943+/*
3944+ * CKReader objects represent Readers attached to the system.
3945+ * The objects themselves are really SCard SCARD_READERSTATE objects.
3946+ * These objects are used in 2 ways:
3947+ * 1) the application creates static SCARD_READERSTATE's and use
3948+ * CKYReader_Init() to initialize the structure. In this case
3949+ * the application can call any of the reader 'methods' (functions
3950+ * starting with CKReader) on these objects. When finished the
3951+ * application is responsible for calling CKYReader_FreeData() to free
3952+ * any data held by the reader object.
3953+ * 2) Acquire an array of readers with CKYReader_CreateArray(). In this
3954+ * case the application can call any method on any particular array member
3955+ * In the end the Application is responsible for calling
3956+ * CKYReader_DestroyArray() to free the entire array.
3957+ */
3958+
3959+void
3960+CKYReader_Init(SCARD_READERSTATE *reader)
3961+{
3962+ reader->szReader = NULL;
3963+ reader->pvUserData = 0;
3964+ reader->cbAtr = 0;
3965+ reader->dwCurrentState = SCARD_STATE_UNAWARE;
3966+}
3967+
3968+void
3969+CKYReader_FreeData(SCARD_READERSTATE *reader)
3970+{
3971+ if (reader->szReader) {
3972+ free((void *)reader->szReader);
3973+ }
3974+ CKYReader_Init(reader);
3975+}
3976+
3977+CKYStatus
3978+CKYReader_SetReaderName(SCARD_READERSTATE *reader, const char *name)
3979+{
3980+ free((void *)reader->szReader);
3981+ reader->szReader = strdup(name);
3982+ return (reader->szReader)? CKYSUCCESS: CKYNOMEM;
3983+}
3984+
3985+const char *
3986+CKYReader_GetReaderName(const SCARD_READERSTATE *reader)
3987+{
3988+ return reader->szReader;
3989+}
3990+
3991+/* see openSC or PCSC for the semantics of Known State and Event States */
3992+CKYStatus
3993+CKYReader_SetKnownState(SCARD_READERSTATE *reader, unsigned long state)
3994+{
3995+ reader->dwCurrentState = state;
3996+ return CKYSUCCESS;
3997+}
3998+
3999+unsigned long
4000+CKYReader_GetKnownState(const SCARD_READERSTATE *reader)
4001+{
4002+ return reader->dwCurrentState;
4003+}
4004+
4005+unsigned long
4006+CKYReader_GetEventState(const SCARD_READERSTATE *reader)
4007+{
4008+ return reader->dwEventState;
4009+}
4010+
4011+/* Caller must have init'ed the buffer before calling
4012+ * any data in the existing buffer is overwritten */
4013+CKYStatus
4014+CKYReader_GetATR(const SCARD_READERSTATE *reader, CKYBuffer *buf)
4015+{
4016+ CKYStatus ret;
4017+
4018+ ret = CKYBuffer_Resize(buf, reader->cbAtr);
4019+ if (ret != CKYSUCCESS) {
4020+ return ret;
4021+ }
4022+ return CKYBuffer_Replace(buf, 0, reader->rgbAtr, reader->cbAtr);
4023+}
4024+
4025+SCARD_READERSTATE *
4026+CKYReader_CreateArray(const CKYReaderNameList readerNames,
4027+ unsigned long *returnReaderCount)
4028+{
4029+ unsigned long i,j;
4030+ unsigned long readerCount;
4031+ SCARD_READERSTATE *readers;
4032+ CKYStatus ret;
4033+
4034+ readerCount=CKYReaderNameList_GetCount(readerNames);
4035+ if (readerCount == 0) {
4036+ return NULL;
4037+ }
4038+ readers = NEW(SCARD_READERSTATE, readerCount);
4039+ if (readers == NULL) {
4040+ return NULL;
4041+ }
4042+
4043+ for (i=0; i < readerCount; i++) {
4044+ CKYReader_Init(&readers[i]);
4045+ ret = CKYReader_SetReaderName(&readers[i],
4046+ CKYReaderNameList_GetValue(readerNames,i));
4047+ if (ret != CKYSUCCESS) {
4048+ break;
4049+ }
4050+ }
4051+ if (ret != CKYSUCCESS) {
4052+ for (j=0; j < i; j++) {
4053+ CKYReader_FreeData(&readers[j]);
4054+ }
4055+ free(readers);
4056+ return NULL;
4057+ }
4058+ if (returnReaderCount) {
4059+ *returnReaderCount=readerCount;
4060+ }
4061+
4062+ return readers;
4063+}
4064+
4065+/*
4066+ * add more reader states to an existing reader state array.
4067+ * The existing reader will have a new pointer, which will be updated only
4068+ * after the new one is complete, and before the old one is freed. The 'add'
4069+ * array is not modified or freed.
4070+ */
4071+CKYStatus
4072+CKYReader_AppendArray(SCARD_READERSTATE **array, unsigned long arraySize,
4073+ const char **readerNames, unsigned long numReaderNames)
4074+{
4075+ unsigned long i,j;
4076+ SCARD_READERSTATE *readers;
4077+ SCARD_READERSTATE *old;
4078+ CKYStatus ret = CKYSUCCESS;
4079+
4080+ readers = NEW(SCARD_READERSTATE, arraySize+numReaderNames);
4081+ if (readers == NULL) {
4082+ return CKYNOMEM;
4083+ }
4084+ /* copy the original readers, inheriting all the pointer memory */
4085+ memcpy(readers, *array, arraySize*sizeof(SCARD_READERSTATE));
4086+
4087+ /* initialize and add the new reader states. */
4088+ for (i=0; i < numReaderNames; i++) {
4089+ CKYReader_Init(&readers[i+arraySize]);
4090+ ret = CKYReader_SetReaderName(&readers[i+arraySize],readerNames[i]);
4091+ if (ret != CKYSUCCESS) {
4092+ break;
4093+ }
4094+ }
4095+
4096+ /* we failed, only free the new reader states, ownership of the new
4097+ * ones will revert back to the original */
4098+ if (ret != CKYSUCCESS) {
4099+ for (j=0; j < i; j++) {
4100+ CKYReader_FreeData(&readers[j+arraySize]);
4101+ }
4102+ free(readers);
4103+ return ret;
4104+ }
4105+
4106+ /* Now we swap the readers states */
4107+ old = *array;
4108+ *array = readers;
4109+ /* it's now safe to free the old one */
4110+ free(old);
4111+
4112+ return CKYSUCCESS;
4113+}
4114+
4115+void
4116+CKYReader_DestroyArray(SCARD_READERSTATE *reader, unsigned long readerCount)
4117+{
4118+ unsigned long i;
4119+
4120+ for (i=0; i < readerCount; i++) {
4121+ CKYReader_FreeData(&reader[i]);
4122+ }
4123+ free(reader);
4124+}
4125+
4126+/*
4127+ * CKYCardContexts are wrapped access to the SCard Context, which is
4128+ * part of the openSC/ Microsoft PCSC interface. Applications will
4129+ * typically open one context to get access to the SCard Subsystem.
4130+ *
4131+ * To protect ourselves from systems without the SCard library installed,
4132+ * the SCard calls are looked up from the library and called through
4133+ * a function pointer.
4134+ */
4135+struct _CKYCardContext {
4136+ SCARDCONTEXT context;
4137+ SCard *scard;
4138+ unsigned long scope;
4139+ unsigned long lastError;
4140+};
4141+
4142+
4143+static CKYStatus
4144+ckyCardContext_init(CKYCardContext *ctx)
4145+{
4146+ static SCard *scard;
4147+
4148+ ctx->lastError = 0;
4149+ ctx->context = 0;
4150+ if (!scard) {
4151+ scard = ckySCard_Init();
4152+ if (!scard) {
4153+ return CKYNOSCARD;
4154+ }
4155+ }
4156+ ctx->scard = scard;
4157+ return CKYSUCCESS;
4158+}
4159+
4160+static CKYStatus
4161+ckyCardContext_release(CKYCardContext *ctx)
4162+{
4163+ unsigned long rv = ctx->scard->SCardReleaseContext(ctx->context);
4164+ ctx->context = 0;
4165+ if (rv != SCARD_S_SUCCESS) {
4166+ ctx->lastError = rv;
4167+ return CKYSCARDERR;
4168+ }
4169+ return CKYSUCCESS;
4170+}
4171+
4172+static CKYStatus
4173+ckyCardContext_establish(CKYCardContext *ctx, unsigned long scope)
4174+{
4175+ unsigned long rv;
4176+
4177+ if (ctx->context) {
4178+ ckyCardContext_release(ctx);
4179+ }
4180+ rv = ctx->scard->SCardEstablishContext(scope, NULL, NULL, &ctx->context);
4181+ if (rv != SCARD_S_SUCCESS) {
4182+ ctx->lastError = rv;
4183+ return CKYSCARDERR;
4184+ }
4185+ return CKYSUCCESS;
4186+}
4187+
4188+CKYCardContext *
4189+CKYCardContext_Create(unsigned long scope)
4190+{
4191+ CKYCardContext *ctx;
4192+ CKYStatus ret;
4193+
4194+ ctx = NEW(CKYCardContext, 1);
4195+ if (ctx == NULL) {
4196+ return NULL;
4197+ }
4198+ ret = ckyCardContext_init(ctx);
4199+ if (ret != CKYSUCCESS) {
4200+ CKYCardContext_Destroy(ctx);
4201+ return NULL;
4202+ }
4203+ ctx->scope = scope;
4204+ ret = ckyCardContext_establish(ctx, scope);
4205+#ifdef MAC
4206+/* Apple won't establish a connnection if pcscd is not running. Because of
4207+ * the way securityd controls pcscd, this may not necessarily be an error
4208+ * condition. Detect this case and continue. We'll establish the connection
4209+ * later..
4210+ */
4211+ if (ctx->lastError == SCARD_F_INTERNAL_ERROR) {
4212+ ctx->context = 0; /* make sure it's not established */
4213+ return ctx;
4214+ }
4215+#endif
4216+ if (ret != CKYSUCCESS) {
4217+ CKYCardContext_Destroy(ctx);
4218+ return NULL;
4219+ }
4220+ return ctx;
4221+}
4222+
4223+CKYStatus
4224+CKYCardContext_Destroy(CKYCardContext *ctx)
4225+{
4226+ CKYStatus ret = CKYSUCCESS;
4227+ if (ctx == NULL) {
4228+ return CKYSUCCESS;
4229+ }
4230+ if (ctx->context) {
4231+ ret = ckyCardContext_release(ctx);
4232+ }
4233+ free(ctx);
4234+ return ret;
4235+}
4236+
4237+SCARDCONTEXT
4238+CKYCardContext_GetContext(const CKYCardContext *ctx)
4239+{
4240+ return ctx->context;
4241+}
4242+
4243+CKYStatus
4244+CKYCardContext_ListReaders(CKYCardContext *ctx, CKYReaderNameList *readerNames)
4245+{
4246+ unsigned long readerLen;
4247+ unsigned long rv;
4248+ char * readerStr = NULL;
4249+ char *cur;
4250+ char ** readerList;
4251+ int count,i;
4252+
4253+
4254+ /* return NULL in the case nothing is found, or there is an error */
4255+ *readerNames = NULL;
4256+
4257+ /* if we aren't established yet, do so now */
4258+ if (!ctx->context) {
4259+ CKYStatus ret = ckyCardContext_establish(ctx, ctx->scope);
4260+ if (ret != CKYSUCCESS) {
4261+
4262+#ifdef MAC
4263+ if (ctx->lastError == SCARD_F_INTERNAL_ERROR) {
4264+ /* Still can't establish, just treat it as 'zero' readers */
4265+ return CKYSUCCESS;
4266+ }
4267+#endif
4268+ return ret;
4269+ }
4270+ }
4271+
4272+ /* get the initial length */
4273+ readerLen = 0;
4274+ rv = ctx->scard->SCardListReaders(ctx->context, NULL /*groups*/,
4275+ NULL, &readerLen);
4276+ /* handle the other errors from SCardListReaders */
4277+ if (rv == SCARD_E_NO_READERS_AVAILABLE) {
4278+ /* not really an error: there are no readers */
4279+ return CKYSUCCESS;
4280+ }
4281+
4282+ if( rv != SCARD_S_SUCCESS ) {
4283+ ctx->lastError = rv;
4284+ return CKYSCARDERR;
4285+ }
4286+
4287+ /* if no readers, return OK and a NULL list */
4288+ if (readerLen == 0) {
4289+ return CKYSUCCESS;
4290+ }
4291+
4292+ /*
4293+ * Keep trying to read in the buffer, allowing that the required buffer
4294+ * length may change between calls to SCardListReaders.
4295+ */
4296+ do {
4297+ if (readerLen < 1 || readerLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
4298+ return CKYNOMEM;
4299+ }
4300+ readerStr = NEW(char,readerLen);
4301+ if (readerStr == NULL) {
4302+ return CKYNOMEM;
4303+ }
4304+
4305+ rv = ctx->scard->SCardListReaders(ctx->context, NULL /*groups*/,
4306+ readerStr, &readerLen);
4307+
4308+ /* we've found it, pop out with readerStr allocated */
4309+ if (rv == SCARD_S_SUCCESS) {
4310+ break;
4311+ }
4312+
4313+ /* Nope, free the reader we allocated */
4314+ free(readerStr);
4315+ readerStr = NULL;
4316+
4317+ } while( rv == SCARD_E_INSUFFICIENT_BUFFER );
4318+
4319+ /* handle the other errors from SCardListReaders */
4320+ if (rv == SCARD_E_NO_READERS_AVAILABLE) {
4321+ /* not really an error: there are no readers */
4322+ ctx->lastError = SCARD_E_NO_READERS_AVAILABLE;
4323+ return CKYSUCCESS;
4324+ }
4325+ if (rv != SCARD_S_SUCCESS) {
4326+ /* stash the error and fail */
4327+ ctx->lastError = rv;
4328+ return CKYSCARDERR;
4329+ }
4330+
4331+ /*
4332+ * Windows returns the list of readers as a series of null terminated
4333+ * strings, terminated with an additional NULL. For example, if there
4334+ * are three readers name "Reader 1", "Reader 2", "Reader 3", the returned
4335+ * readerStr would look like: "Reader 1\0Reader 2\0Reader N\0\0".
4336+ *
4337+ * We need to return a list of ReaderNames. This is currently a pointer
4338+ * to an array of string pointers, terminated by a NULL.
4339+ *
4340+ * +--------------+
4341+ * | Reader 1 ptr | -> "Reader 1"
4342+ * +--------------+
4343+ * | Reader 2 ptr | -> "Reader 2"
4344+ * +--------------+
4345+ * | Reader N ptr | -> "Reader N"
4346+ * +--------------+
4347+ * | NULL |
4348+ * +--------------+
4349+ *
4350+ * NOTE: This code explicitly knows the underlying format for
4351+ * CKYReaderNameLists defined in cky_list.i. If cky_list.i is changes,
4352+ * this code will need to be changed as well.
4353+ */
4354+ /* find the count of readers */
4355+ for (cur = readerStr, count = 0; *cur; cur += strlen(cur)+1, count++ )
4356+ /* Empty */ ;
4357+ readerList = NEW(char *,count+1);
4358+ if (readerList == NULL) {
4359+ goto fail;
4360+ }
4361+
4362+ /* now copy the readers into the array */
4363+ for (i=0, cur=readerStr; i < count ; cur+=strlen(cur) +1, i++) {
4364+ readerList[i] = strdup(cur);
4365+ if (readerList[i] == NULL) {
4366+ goto fail;
4367+ }
4368+ }
4369+ readerList[count] = NULL;
4370+ free(readerStr);;
4371+ *readerNames = (CKYReaderNameList) readerList;
4372+ return CKYSUCCESS;
4373+
4374+fail:
4375+ if (readerStr) {
4376+ free(readerStr);
4377+ }
4378+ if (readerList) {
4379+ CKYReaderNameList_Destroy((CKYReaderNameList) readerList);
4380+ }
4381+ return CKYNOMEM;
4382+}
4383+
4384+/*
4385+ * The original C++ API had to very similiar functions that returned
4386+ * either reader names or connections based on ATR. This is a single
4387+ * function that can return both. The exported interface calls this
4388+ * one with one of the lists set to NULL.
4389+ *
4390+ * NOTE: this function "knows" the underlying format for lists and
4391+ * hand builds the related lists.
4392+ */
4393+CKYStatus
4394+ckyCardContext_findReadersByATR(CKYCardContext *ctx,
4395+ CKYReaderNameList *returnReaders,
4396+ CKYCardConnectionList *returnConn,
4397+ const CKYBuffer *targetATR)
4398+{
4399+ CKYReaderNameList readerNames;
4400+ CKYBuffer ATR;
4401+ CKYCardConnection **connList = NULL;
4402+ CKYCardConnection **connPtr = NULL;
4403+ char **readerList = NULL;
4404+ char **readerPtr = NULL;
4405+ int readerCount, i;
4406+ CKYStatus ret;
4407+
4408+ CKYBuffer_InitEmpty(&ATR);
4409+
4410+ /* if we aren't established yet, do so now */
4411+ if (!ctx->context) {
4412+ ret = ckyCardContext_establish(ctx, ctx->scope);
4413+ if (ret != CKYSUCCESS) {
4414+ return ret;
4415+ }
4416+ }
4417+
4418+ /* initialize our returned values to empty */
4419+ if (returnReaders) {
4420+ *returnReaders = NULL;
4421+ }
4422+ if (returnConn) {
4423+ *returnConn = NULL;
4424+ }
4425+
4426+ ret = CKYCardContext_ListReaders(ctx, &readerNames);
4427+ if (ret != CKYSUCCESS) {
4428+ return ret;
4429+ }
4430+
4431+ readerCount = CKYReaderNameList_GetCount(readerNames);
4432+
4433+ /* none found, return success */
4434+ if (readerCount == 0) {
4435+ CKYReaderNameList_Destroy(readerNames);
4436+ return CKYSUCCESS;
4437+ }
4438+
4439+ /* now initialize our name and connection lists */
4440+ if (returnConn) {
4441+ connList = NEW(CKYCardConnection *, readerCount);
4442+ connPtr = connList;
4443+ if (connList == NULL) {
4444+ goto fail;
4445+ }
4446+ }
4447+ if (returnReaders) {
4448+ readerList = NEW(char *, readerCount);
4449+ readerPtr = readerList;
4450+ if (readerList == NULL) {
4451+ goto fail;
4452+ }
4453+ }
4454+
4455+ ret = CKYBuffer_Resize(&ATR, CKY_MAX_ATR_LEN);
4456+ if (ret != CKYSUCCESS) {
4457+ goto fail;
4458+ }
4459+
4460+ /* now walk the reader list trying to get connections */
4461+ for (i=0; i < readerCount ; i++) {
4462+ CKYCardConnection * conn = CKYCardConnection_Create(ctx);
4463+ unsigned long state;
4464+ const char *thisReader = CKYReaderNameList_GetValue(readerNames, i);
4465+
4466+
4467+ if (!conn) {
4468+ goto loop;
4469+ }
4470+ ret = CKYCardConnection_Connect(conn, thisReader);
4471+ if (ret != CKYSUCCESS) {
4472+ goto loop;
4473+ }
4474+ ret = CKYCardConnection_GetStatus(conn, &state, &ATR);
4475+ if (ret != CKYSUCCESS) {
4476+ goto loop;
4477+ }
4478+ if (CKYBuffer_IsEqual(targetATR, &ATR)) {
4479+ if (connPtr) {
4480+ *connPtr++ = conn; /* adopt */
4481+ conn = NULL;
4482+ }
4483+ if (readerPtr) {
4484+ *readerPtr++ = strdup(thisReader);
4485+ }
4486+ }
4487+
4488+loop:
4489+ /* must happen each time through the loop */
4490+ if (conn) {
4491+ CKYCardConnection_Destroy(conn);
4492+ }
4493+ }
4494+
4495+ /* done with the reader names now */
4496+ CKYReaderNameList_Destroy(readerNames);
4497+ /* and the ATR buffer */
4498+ CKYBuffer_FreeData(&ATR);
4499+
4500+ /* terminate out lists and return them */
4501+ if (readerPtr) {
4502+ *readerPtr = NULL;
4503+ *returnReaders = (CKYReaderNameList) readerList;
4504+ }
4505+ if (connPtr) {
4506+ *connPtr = NULL;
4507+ *returnConn = (CKYCardConnectionList) connList;
4508+ }
4509+ return CKYSUCCESS;
4510+
4511+fail:
4512+ if (readerNames) {
4513+ CKYReaderNameList_Destroy(readerNames);
4514+ }
4515+ if (connList) {
4516+ free(connList);
4517+ }
4518+ if (readerList) {
4519+ free(readerList);
4520+ }
4521+ CKYBuffer_FreeData(&ATR);
4522+ return CKYNOMEM;
4523+}
4524+
4525+CKYStatus
4526+CKYCardContext_FindCardsByATR(CKYCardContext *ctx,
4527+ CKYCardConnectionList *cardList, const CKYBuffer *targetATR)
4528+{
4529+ return ckyCardContext_findReadersByATR(ctx, NULL, cardList, targetATR);
4530+}
4531+
4532+CKYStatus
4533+CKYCardContext_FindReadersByATR(CKYCardContext *ctx,
4534+ CKYReaderNameList *readerNames, const CKYBuffer *targetATR)
4535+{
4536+ return ckyCardContext_findReadersByATR(ctx, readerNames, NULL, targetATR);
4537+}
4538+
4539+CKYCardConnection *
4540+CKYCardContext_CreateConnection(CKYCardContext *ctx)
4541+{
4542+ return CKYCardConnection_Create(ctx);
4543+}
4544+
4545+CKYStatus
4546+CKYCardContext_WaitForStatusChange(CKYCardContext *ctx,
4547+ SCARD_READERSTATE *readers, unsigned long readerCount,
4548+ unsigned long timeout)
4549+{
4550+ unsigned long rv;
4551+
4552+ /* if we aren't established yet, do so now */
4553+ if (!ctx->context) {
4554+ CKYStatus ret = ckyCardContext_establish(ctx, ctx->scope);
4555+ if (ret != CKYSUCCESS) {
4556+ return ret;
4557+ }
4558+ }
4559+ rv = ctx->scard->SCardGetStatusChange(ctx->context, timeout,
4560+ readers, readerCount);
4561+ if (rv != SCARD_S_SUCCESS) {
4562+ ctx->lastError = rv;
4563+ return CKYSCARDERR;
4564+ }
4565+ return CKYSUCCESS;
4566+}
4567+
4568+CKYStatus
4569+CKYCardContext_Cancel(CKYCardContext *ctx)
4570+{
4571+ unsigned long rv;
4572+
4573+ /* if we aren't established yet, we can't be in change status then */
4574+ if (!ctx->context) {
4575+ return CKYSUCCESS;
4576+ }
4577+ rv = ctx->scard->SCardCancel(ctx->context);
4578+
4579+ if (rv != SCARD_S_SUCCESS) {
4580+ ctx->lastError = rv;
4581+ return CKYSCARDERR;
4582+ }
4583+ return CKYSUCCESS;
4584+}
4585+
4586+unsigned long
4587+CKYCardContext_GetLastError(const CKYCardContext *ctx)
4588+{
4589+ return ctx->lastError;
4590+}
4591+
4592+/*
4593+ * Connections represent the connection to the actual smart cards.
4594+ * Applications usually has one of these for each card inserted in
4595+ * the system. Connections are where we can get information about
4596+ * each card, as well as transmit commands (APDU's) to the card.
4597+ */
4598+/* In the originaly C++ library, lastError was set to the last return
4599+ * code from any SCARD call. In this C version of the library, lastError
4600+ * is the last non-successful SCARD call. lastError will be set
4601+ * if the function returns CKYSCARDERR.
4602+ */
4603+struct _CKYCardConnection {
4604+ const CKYCardContext *ctx;
4605+ SCard *scard; /* cache a copy from the context */
4606+ SCARDHANDLE cardHandle;
4607+ unsigned long lastError;
4608+ CKYBool inTransaction;
4609+ unsigned long protocol;
4610+};
4611+
4612+static void
4613+ckyCardConnection_init(CKYCardConnection *conn, const CKYCardContext *ctx)
4614+{
4615+ conn->ctx = ctx;
4616+ conn->scard = ctx->scard;
4617+ conn->cardHandle = 0;
4618+ conn->lastError = 0;
4619+ conn->inTransaction = 0;
4620+ conn->protocol = SCARD_PROTOCOL_T0;
4621+}
4622+
4623+CKYCardConnection *
4624+CKYCardConnection_Create(const CKYCardContext *ctx)
4625+{
4626+ CKYCardConnection *conn;
4627+
4628+ /* don't even try if we don't have a Card Context */
4629+ if (ctx == NULL) {
4630+ return NULL;
4631+ }
4632+
4633+ conn = NEW(CKYCardConnection, 1);
4634+ if (conn == NULL) {
4635+ return NULL;
4636+ }
4637+ ckyCardConnection_init(conn, ctx);
4638+ return conn;
4639+}
4640+
4641+
4642+CKYStatus
4643+CKYCardConnection_Destroy(CKYCardConnection *conn)
4644+{
4645+ if (conn == NULL) {
4646+ return CKYSUCCESS;
4647+ }
4648+ if (conn->inTransaction) {
4649+ CKYCardConnection_EndTransaction(conn);
4650+ }
4651+ CKYCardConnection_Disconnect(conn);
4652+ free(conn);
4653+ return CKYSUCCESS;
4654+}
4655+
4656+CKYStatus
4657+CKYCardConnection_Connect(CKYCardConnection *conn, const char *readerName)
4658+{
4659+ CKYStatus ret;
4660+ unsigned long rv;
4661+
4662+ ret = CKYCardConnection_Disconnect(conn);
4663+ if (ret != CKYSUCCESS) {
4664+ return ret;
4665+ }
4666+ rv = conn->scard->SCardConnect( conn->ctx->context, readerName,
4667+ SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &conn->cardHandle, &conn->protocol);
4668+ if (rv != SCARD_S_SUCCESS) {
4669+ conn->lastError = rv;
4670+ return CKYSCARDERR;
4671+ }
4672+ return CKYSUCCESS;
4673+}
4674+
4675+CKYStatus
4676+CKYCardConnection_Disconnect(CKYCardConnection *conn)
4677+{
4678+ unsigned long rv;
4679+ if (conn->cardHandle == 0) {
4680+ return CKYSUCCESS;
4681+ }
4682+ rv = conn->scard->SCardDisconnect( conn->cardHandle, SCARD_LEAVE_CARD);
4683+ conn->cardHandle = 0;
4684+ if (rv != SCARD_S_SUCCESS) {
4685+ conn->lastError = rv;
4686+ return CKYSCARDERR;
4687+ }
4688+ return CKYSUCCESS;
4689+}
4690+
4691+CKYBool
4692+CKYCardConnection_IsConnected(const CKYCardConnection *conn)
4693+{
4694+ return (conn->cardHandle != 0);
4695+}
4696+
4697+CKYStatus
4698+ckyCardConnection_reconnectRaw(CKYCardConnection *conn, unsigned long init)
4699+{
4700+ unsigned long rv;
4701+ unsigned long protocol;
4702+
4703+ rv = conn->scard->SCardReconnect(conn->cardHandle,
4704+ SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 , init, &protocol);
4705+ if (rv != SCARD_S_SUCCESS) {
4706+ conn->lastError = rv;
4707+ return CKYSCARDERR;
4708+ }
4709+ return CKYSUCCESS;
4710+}
4711+
4712+CKYStatus
4713+CKYCardConnection_Reconnect(CKYCardConnection *conn)
4714+{
4715+ return ckyCardConnection_reconnectRaw(conn, SCARD_LEAVE_CARD);
4716+}
4717+
4718+CKYStatus CKYCardConnection_Reset(CKYCardConnection *conn)
4719+{
4720+ return ckyCardConnection_reconnectRaw(conn, SCARD_RESET_CARD);
4721+}
4722+
4723+CKYStatus
4724+CKYCardConnection_BeginTransaction(CKYCardConnection *conn)
4725+{
4726+ unsigned long rv;
4727+ rv = conn->scard->SCardBeginTransaction(conn->cardHandle);
4728+ if (rv != SCARD_S_SUCCESS) {
4729+ conn->lastError = rv;
4730+ return CKYSCARDERR;
4731+ }
4732+ conn->inTransaction = 1;
4733+ return CKYSUCCESS;
4734+}
4735+
4736+CKYStatus
4737+CKYCardConnection_EndTransaction(CKYCardConnection *conn)
4738+{
4739+ unsigned long rv;
4740+ if (!conn->inTransaction) {
4741+ return CKYSUCCESS; /* C++ library returns success in this case, but
4742+ * it may be better to return an error ? */
4743+ }
4744+ rv = conn->scard->SCardEndTransaction(conn->cardHandle, SCARD_LEAVE_CARD);
4745+ conn->inTransaction = 0;
4746+ if (rv != SCARD_S_SUCCESS) {
4747+ conn->lastError = rv;
4748+ return CKYSCARDERR;
4749+ }
4750+ return CKYSUCCESS;
4751+}
4752+
4753+CKYStatus
4754+CKYCardConnection_TransmitAPDU(CKYCardConnection *conn, CKYAPDU *apdu,
4755+ CKYBuffer *response)
4756+{
4757+ CKYStatus ret;
4758+ unsigned long rv;
4759+
4760+ ret = CKYBuffer_Resize(response, CKYAPDU_MAX_LEN);
4761+ if (ret != CKYSUCCESS) {
4762+ return ret;
4763+ }
4764+
4765+ if( conn->protocol == SCARD_PROTOCOL_T0 ) {
4766+ rv = conn->scard->SCardTransmit(conn->cardHandle,
4767+ conn->scard->SCARD_PCI_T0_,
4768+ CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf),
4769+ NULL, response->data, &response->len);
4770+ } else {
4771+ rv = conn->scard->SCardTransmit(conn->cardHandle,
4772+ conn->scard->SCARD_PCI_T1_,
4773+ CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf),
4774+ NULL, response->data, &response->len);
4775+ }
4776+
4777+ if (rv != SCARD_S_SUCCESS) {
4778+ conn->lastError =rv;
4779+ return CKYSCARDERR;
4780+ }
4781+
4782+ return CKYSUCCESS;
4783+}
4784+
4785+CKYStatus
4786+CKYCardConnection_ExchangeAPDU(CKYCardConnection *conn, CKYAPDU *apdu,
4787+ CKYBuffer *response)
4788+{
4789+ CKYStatus ret;
4790+
4791+ ret = CKYCardConnection_TransmitAPDU(conn, apdu, response);
4792+ if (ret != CKYSUCCESS) {
4793+ return ret;
4794+ }
4795+
4796+ if (CKYBuffer_Size(response) == 2 && CKYBuffer_GetChar(response,0) == 0x61) {
4797+ /* get the response */
4798+ CKYAPDU getResponseAPDU;
4799+
4800+ CKYAPDU_Init(&getResponseAPDU);
4801+ CKYAPDU_SetCLA(&getResponseAPDU, 0x00);
4802+ CKYAPDU_SetINS(&getResponseAPDU, 0xc0);
4803+ CKYAPDU_SetP1(&getResponseAPDU, 0x00);
4804+ CKYAPDU_SetP2(&getResponseAPDU, 0x00);
4805+ CKYAPDU_SetReceiveLen(&getResponseAPDU, CKYBuffer_GetChar(response,1));
4806+ ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU, response);
4807+ CKYAPDU_FreeData(&getResponseAPDU);
4808+ }
4809+ return ret;
4810+}
4811+
4812+CKYStatus
4813+CKYCardConnection_GetStatus(CKYCardConnection *conn,
4814+ unsigned long *state, CKYBuffer *ATR)
4815+{
4816+ unsigned long readerLen = 0;
4817+ unsigned long protocol;
4818+ unsigned long rv;
4819+ CKYSize atrLen;
4820+ char *readerStr;
4821+ CKYStatus ret;
4822+
4823+
4824+ /*
4825+ * Get initial length. We have to do all this because the Muscle
4826+ * implementation of PCSC requires us to supply a non-NULL argument
4827+ * for readerName before it will tell us the ATR, which is all we really
4828+ * care about.
4829+ */
4830+ rv = conn->scard->SCardStatus(conn->cardHandle,
4831+ NULL /*readerName*/, &readerLen, state, &protocol, NULL, &atrLen);
4832+ if ( rv != SCARD_S_SUCCESS ) {
4833+ conn->lastError = rv;
4834+ return CKYSCARDERR;
4835+ }
4836+
4837+ do {
4838+ if (readerLen < 1 || readerLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
4839+ return CKYNOMEM;
4840+ }
4841+ /* Mac & Linux return '0' or ATR length, just use the max value */
4842+ if (atrLen == 0) {
4843+ atrLen = CKY_MAX_ATR_LEN;
4844+ }
4845+ if (atrLen < 1 || atrLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
4846+ return CKYNOMEM;
4847+ }
4848+ ret = CKYBuffer_Resize(ATR, atrLen);
4849+ if (ret != CKYSUCCESS) {
4850+ return ret;
4851+ }
4852+ readerStr = NEW(char, readerLen);
4853+ if (readerStr == NULL) {
4854+ return CKYNOMEM;
4855+ }
4856+
4857+ rv = conn->scard->SCardStatus(conn->cardHandle, readerStr, &readerLen,
4858+ state, &protocol, ATR->data, &atrLen);
4859+ ATR->len = atrLen;
4860+ free(readerStr);
4861+ } while (rv == SCARD_E_INSUFFICIENT_BUFFER);
4862+
4863+ if (rv != SCARD_S_SUCCESS) {
4864+ conn->lastError = rv;
4865+ return CKYSCARDERR;
4866+ }
4867+ return CKYSUCCESS;
4868+}
4869+
4870+CKYStatus
4871+CKYCardConnection_GetAttribute(CKYCardConnection *conn,
4872+ unsigned long attrID, CKYBuffer *attrBuf)
4873+{
4874+#ifdef WIN32
4875+ unsigned long len = 0;
4876+ unsigned long rv;
4877+
4878+ /*
4879+ * Get initial length. We have to do all this because the Muscle
4880+ * implementation of PCSC requires us to supply a non-NULL argument
4881+ * for readerName before it will tell us the ATR, which is all we really
4882+ * care about.
4883+ */
4884+ rv = conn->scard->SCardGetAttrib(conn->cardHandle, attrID, NULL, &len);
4885+ if ( rv != SCARD_S_SUCCESS ) {
4886+ conn->lastError = rv;
4887+ return CKYSCARDERR;
4888+ }
4889+ CKYBuffer_Resize(attrBuf, len);
4890+
4891+ rv = conn->scard->SCardGetAttrib(conn->cardHandle, attrID,
4892+ attrBuf->data, &attrBuf->len);
4893+ if( rv != SCARD_S_SUCCESS ) {
4894+ conn->lastError = rv;
4895+ return CKYSCARDERR;
4896+ }
4897+ return CKYSUCCESS;
4898+#else
4899+ conn->lastError = -1;
4900+ return CKYSCARDERR;
4901+#endif
4902+}
4903+
4904+const CKYCardContext *
4905+CKYCardConnection_GetContext(const CKYCardConnection *conn)
4906+{
4907+ return conn->ctx;
4908+}
4909+
4910+unsigned long
4911+CKYCardConnection_GetLastError(const CKYCardConnection *conn)
4912+{
4913+ return conn->lastError;
4914+}
4915
4916=== modified file '.pc/applied-patches'
4917--- .pc/applied-patches 2011-12-14 11:44:21 +0000
4918+++ .pc/applied-patches 2013-01-15 15:55:32 +0000
4919@@ -5,6 +5,6 @@
4920 coolkey-latest.patch
4921 coolkey-simple-bugs.patch
4922 coolkey-thread-fix.patch
4923-coolkey-cac.patch
4924-coolkey-cac-1.patch
4925+coolkey-cac-rhl5.patch
4926 0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch
4927+Handle-pcscd-restarting
4928
4929=== removed directory '.pc/coolkey-cac-1.patch'
4930=== removed directory '.pc/coolkey-cac-1.patch/src'
4931=== removed directory '.pc/coolkey-cac-1.patch/src/coolkey'
4932=== removed file '.pc/coolkey-cac-1.patch/src/coolkey/object.cpp'
4933--- .pc/coolkey-cac-1.patch/src/coolkey/object.cpp 2010-12-22 19:12:07 +0000
4934+++ .pc/coolkey-cac-1.patch/src/coolkey/object.cpp 1970-01-01 00:00:00 +0000
4935@@ -1,1068 +0,0 @@
4936-/* ***** BEGIN COPYRIGHT BLOCK *****
4937- * Copyright (C) 2005 Red Hat, Inc.
4938- * All rights reserved.
4939- *
4940- * This library is free software; you can redistribute it and/or
4941- * modify it under the terms of the GNU Lesser General Public
4942- * License as published by the Free Software Foundation version
4943- * 2.1 of the License.
4944- *
4945- * This library is distributed in the hope that it will be useful,
4946- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4947- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4948- * Lesser General Public License for more details.
4949- *
4950- * You should have received a copy of the GNU Lesser General Public
4951- * License along with this library; if not, write to the Free Software
4952- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4953- * ***** END COPYRIGHT BLOCK *****/
4954-
4955-#include "mypkcs11.h"
4956-#include "PKCS11Exception.h"
4957-#include "object.h"
4958-#include <algorithm>
4959-#include <string.h>
4960-
4961-using std::find_if;
4962-
4963-
4964-bool AttributeMatch::operator()(const PKCS11Attribute& cmp)
4965-{
4966- return (attr->type == cmp.getType()) &&
4967- CKYBuffer_DataIsEqual(cmp.getValue(),
4968- (const CKYByte *)attr->pValue, attr->ulValueLen);
4969-}
4970-
4971-class AttributeTypeMatch
4972-{
4973- private:
4974- CK_ATTRIBUTE_TYPE type;
4975- public:
4976- AttributeTypeMatch(CK_ATTRIBUTE_TYPE type_) : type(type_) { }
4977- bool operator()(const PKCS11Attribute& cmp) {
4978- return cmp.getType() == type;
4979- }
4980-};
4981-
4982-PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_)
4983- : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL)
4984-{
4985- CKYBuffer_InitEmpty(&pubKey);
4986-}
4987-
4988-PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data,
4989- CK_OBJECT_HANDLE handle_) : muscleObjID(muscleObjID_), handle(handle_),
4990- label(NULL), name(NULL)
4991-{
4992- CKYBuffer_InitEmpty(&pubKey);
4993-
4994- CKYByte type = CKYBuffer_GetChar(data,0);
4995- // verify object ID is what we think it is
4996- if( CKYBuffer_GetLong(data,1) != muscleObjID ) {
4997- throw PKCS11Exception(CKR_DEVICE_ERROR,
4998- "PKCS #11 actual object id does not match stated id");
4999- }
5000- if (type == 0) {
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches