Merge lp:~serialorder/ubuntu/precise/coolkey/fixmOldCACAssertError into lp:ubuntu/precise/coolkey
- Precise (12.04)
- fixmOldCACAssertError
- Merge into precise
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
.pc/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch/src/coolkey/slot.cpp (+13/-10) .pc/Handle-pcscd-restarting/src/coolkey/Makefile.am (+82/-0) .pc/Handle-pcscd-restarting/src/coolkey/slot.cpp (+3554/-0) .pc/Handle-pcscd-restarting/src/libckyapplet/cky_card.c (+1198/-0) .pc/applied-patches (+2/-2) .pc/coolkey-cac-1.patch/src/coolkey/object.cpp (+0/-1068) .pc/coolkey-cac-1.patch/src/coolkey/slot.cpp (+0/-3547) .pc/coolkey-cac-rhl5.patch/src/coolkey/slot.cpp (+3357/-0) .pc/coolkey-cac-rhl5.patch/src/coolkey/slot.h (+600/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_applet.c (+1345/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_applet.h (+544/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_base.c (+626/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_base.h (+275/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_factory.c (+633/-0) .pc/coolkey-cac-rhl5.patch/src/libckyapplet/cky_factory.h (+221/-0) .pc/coolkey-cac.patch/src/coolkey/slot.cpp (+0/-3357) .pc/coolkey-cac.patch/src/coolkey/slot.h (+0/-600) .pc/coolkey-cac.patch/src/libckyapplet/cky_applet.c (+0/-1345) .pc/coolkey-cac.patch/src/libckyapplet/cky_applet.h (+0/-544) .pc/coolkey-cac.patch/src/libckyapplet/cky_base.c (+0/-626) .pc/coolkey-cac.patch/src/libckyapplet/cky_base.h (+0/-275) .pc/coolkey-cac.patch/src/libckyapplet/cky_factory.c (+0/-633) .pc/coolkey-cac.patch/src/libckyapplet/cky_factory.h (+0/-221) debian/README.Debian (+11/-2) debian/changelog (+30/-27) debian/compat (+1/-1) debian/control (+4/-5) debian/coolkey.dirs (+0/-1) debian/copyright (+86/-112) debian/libckyapplet1-dev.lintian-overrides (+1/-0) debian/patches/0001-Fix-working-with-empty-certificates-in-not-zero-slot.patch (+1/-6) debian/patches/99-fixmAsserterror.patch (+16/-0) debian/patches/Handle-pcscd-restarting (+75/-0) debian/patches/coolkey-cac-1.patch (+4/-0) debian/patches/coolkey-cac-rhl5.patch (+1032/-0) debian/patches/coolkey-cac.patch (+5/-0) debian/patches/coolkey-cache-dir-move.patch (+7/-0) debian/patches/coolkey-gcc43.patch (+8/-0) debian/patches/coolkey-latest.patch (+8/-0) debian/patches/coolkey-pcsc-lite (+1/-1) debian/patches/coolkey-simple-bugs.patch (+6/-0) debian/patches/coolkey-thread-fix.patch (+13/-0) debian/patches/series (+3/-2) debian/rules (+10/-6) src/coolkey/Makefile.am (+1/-1) src/coolkey/object.cpp (+0/-4) src/coolkey/slot.cpp (+26/-14) src/libckyapplet/cky_applet.h (+1/-0) src/libckyapplet/cky_card.c (+5/-0) |
To merge this branch: | bzr merge lp:~serialorder/ubuntu/precise/coolkey/fixmOldCACAssertError |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marc Deslauriers | Needs Fixing | ||
Ubuntu branches | Pending | ||
Review via email: mp+143333@code.launchpad.net |
Commit message
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
Unmerged revisions
- 13. By Manny Vindiola
-
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
-
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>
-
* 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) { |
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. dep.debian. net/deps/ dep3/)
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://
4- Please add the name of the patch to debian/changelog to make it easier to track in the future.
Thanks!