The package rpms/esc.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/esc.git/commit/?id=f2041c7865b832....
Change:
+ExcludeArch: aarch64 i686
Thanks.
Full change:
============
commit f2041c7865b832eb44e4385c148d062c5f7ab605
Author: Jack Magne <jmagne(a)localhost.localdomain>
Date: Thu Jun 7 17:32:27 2018 -0700
Remove coolkey dependency and have esc work against opensc, port to master.
diff --git a/esc b/esc
index 34b5c9a..cce19fc 100755
--- a/esc
+++ b/esc
@@ -44,6 +44,8 @@ COMPREG_DAT=compreg.dat
LOCK_FILE=lock
PARENT_LOCK_FILE=.parentlock
+export OPENSC_CONF=$ESC_PATH/opensc.esc.conf
+
function isProgRunning {
userID=$(whoami)
diff --git a/esc-1.1.1-fix1.patch b/esc-1.1.1-fix1.patch
new file mode 100644
index 0000000..02a330d
--- /dev/null
+++ b/esc-1.1.1-fix1.patch
@@ -0,0 +1,8237 @@
+diff -up ./esc/opensc.esc.conf.fix1 ./esc/opensc.esc.conf
+--- ./esc/opensc.esc.conf.fix1 2018-04-26 11:44:38.429986239 -0700
++++ ./esc/opensc.esc.conf 2018-04-26 11:44:38.429986239 -0700
+@@ -0,0 +1,48 @@
++app default {
++ enable_default_driver = true;
++
++ card_atr
++ 3B:FF:14:00:FF:81:31:FE:45:80:25:A0:00:00:00:56:57:53:43:36:35:30:03:03:38 {
++ pkcs11_enable_InitToken = yes;
++ }
++
++ card_atr
++ 3B:FF:14:00:FF:81:31:FE:45:80:25:A0:00:00:00:56:57:53:43:36:35:30:01:00:39 {
++ pkcs11_enable_InitToken = yes;
++ }
++
++ card_atr
++ 3B:FF:14:00:FF:81:31:FE:45:80:25:A0:00:00:00:56:57:53:43:36:35:30:03:00:3B {
++ pkcs11_enable_InitToken = yes;
++ }
++ reader_driver ctapi {
++ }
++ reader_driver pcsc {
++ }
++ reader_driver openct {
++ };
++ card_drivers = coolkey, cac, piv, default;
++ secure_messaging local_authentic {
++ module_path = /usr/lib64;
++ }
++ framework pkcs15 {
++ builtin_emulators = coolkey, cac, piv;
++ }
++}
++app opensc-pkcs11 {
++ pkcs11 {
++ }
++}
++app onepin-opensc-pkcs11 {
++ pkcs11 {
++ slots_per_card = 1;
++ }
++}
++app tokend {
++ framework tokend {
++ }
++}
++app cardmod {
++ reader_driver cardmod {
++ }
++}
+diff -up ./esc/src/app/daemon/manifest.mn.fix1 ./esc/src/app/daemon/manifest.mn
+--- ./esc/src/app/daemon/manifest.mn.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/app/daemon/manifest.mn 2018-04-26 14:55:48.926180480 -0700
+@@ -30,13 +30,13 @@ endif
+
+
+
+-DEFINES += -I$(SYS_INC)/nspr4 -I$(SYS_INC)/nss3
-I$(SYS_INC)/$(MOZ_OFFSET)/nspr -I$(SYS_INC)/$(MOZ_OFFSET)/nss
++DEFINES += -I$(SYS_INC)/nspr4 -I$(SYS_INC)/nss3
-I$(SYS_INC)/$(MOZ_OFFSET)/nspr -I$(SYS_INC)/$(MOZ_OFFSET)/nss -I$(SYS_INC)/PCSC
-I$(CORE_DEPTH)/src/lib/coolkey
+
+ DEFINES += $(shell pkg-config --cflags xft)
+
+ CPPFLAGS += $(DEFINES) -g
+
+-LDFLAGS += -lstdc++ -L$(CORE_DIST)/$(OBJDIR)/lib -L$(XULRUNNER_LIBS_LDFLAGS) -lnss3
-lnspr4 -lssl3 -lckyapplet $(shell pkg-config --libs xft)
++LDFLAGS += -lstdc++ -L$(CORE_DIST)/$(OBJDIR)/lib -L$(XULRUNNER_LIBS_LDFLAGS) -lnss3
-lnspr4 -lssl3 $(shell pkg-config --libs xft)
+ LDFLAGS += -lckymanager -lhttpchunked -lm -lnss3 -lplc4 -lplds4 -lX11
+ # MODULE public and private header directories are implicitly REQUIRED.
+
+diff -up ./esc/src/app/xpcom/Makefile.sdk.fix1 ./esc/src/app/xpcom/Makefile.sdk
+--- ./esc/src/app/xpcom/Makefile.sdk.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/app/xpcom/Makefile.sdk 2018-04-26 11:44:38.430986233 -0700
+@@ -144,8 +144,8 @@ NSPR_INCLUDE = /usr/include/nspr4
+ GECKO_INCLUDES = -I $(GECKO_SDK_PATH)/include -I $(GECKO_INCLUDE_PATH) -I
$(NSPR_INCLUDE) -I $(NSS_INCLUDE) -I $(GECKO_INCLUDE_PATH)/xpcom
+
+
+-COOL_INCLUDES = -I $(CORE_INC)/ckymanager -I $(CORE_INC)/httpchuncked
+-COOL_LDFLAGS = -L$(CORE_DIST)/lib -lckymanager -lhttpchunked $(CKY_LIB_LDD)
-lckyapplet
++COOL_INCLUDES = -I $(CORE_INC)/ckymanager -I $(CORE_INC)/httpchuncked -I
/usr/include/PCSC -I $(CORE_DEPTH)/src/lib/coolkey
++COOL_LDFLAGS = -L$(CORE_DIST)/lib -lckymanager -lhttpchunked
+
+ OBJECT = rhCoolKey.o
+
+@@ -258,6 +258,7 @@ $(DEPLOY_OBJDIR):
+
+ cd $(CORE_DEPTH)/$(DEPLOY_OFFSET)/app/xul/esc; zip -r test.zip * -x *\CVS\* \*.fix*;
unzip -d esc test.zip ; rm -f test.zip
+ $(PYTHON_BIN) $(GECKO_SDK_PATH)/bin/install_app.py
$(CORE_DEPTH)$(DEPLOY_OFFSET)/app/xul/esc/esc $(DEPLOY_OBJDIR)/esc --appName esc
++ $(NSINSTALL) $(CORE_DEPTH)/opensc.esc.conf $(DEPLOY_OBJDIR)/esc
+
+ ifeq ($(OS_ARCH), Darwin)
+ mkdir $(DEPLOY_OBJDIR)/$(XULRUNNER_FRAME_BASE)
+diff -up ./esc/src/app/xul/esc/application.ini.fix1
./esc/src/app/xul/esc/application.ini
+--- ./esc/src/app/xul/esc/application.ini.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/application.ini 2018-04-26 11:44:38.431986227 -0700
+@@ -25,7 +25,7 @@ Vendor=RedHat
+ Name=ESC
+ ;
+ ; This field specifies your application's version. This field is optional.
+-Version=1.1.0-24
++Version=1.1.1-1
+ ;
+ ; This field specifies your application's build ID (timestamp). This field is
+ ; required.
+@@ -47,6 +47,6 @@ MinVersion=6.0.0
+ ; application requires. It should be specified if your application uses
+ ; unfrozen interfaces. Specifying 1.8 matches all releases with a version
+ ; prefixed by 1.8 (e.g., 1.8a4, 1.8b, 1.8.2).
+-MaxVersion=50.0.0
++MaxVersion=60.0.0
+
+ [Shell]
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/advancedinfo.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/advancedinfo.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/advancedinfo.xul.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/advancedinfo.xul 2018-04-26
11:44:38.431986227 -0700
+@@ -33,7 +33,6 @@
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+ <script src="AdvancedInfo.js"/>
+ <script src="ESC.js"/>
+-<script src="TRAY.js"/>
+ <grid class="logoBox">
+ <rows >
+ <row>
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/config.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/config.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/config.xul.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/config.xul 2018-04-26 11:44:38.432986221
-0700
+@@ -30,7 +30,6 @@
+ onunload="cleanup();"
+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul...
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+-<script src="TRAY.js"/>
+ <script src="ESC.js"/>
+ <hbox class="logoBox" >
+ <image id="logoImage"/>
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/ESC.js.fix1
./esc/src/app/xul/esc/chrome/content/esc/ESC.js
+--- ./esc/src/app/xul/esc/chrome/content/esc/ESC.js.fix1 2017-07-24 16:46:36.000000000
-0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/ESC.js 2018-04-26 11:44:38.433986216 -0700
+@@ -151,7 +151,6 @@ jsNotify.prototype = {
+ //
+ function cleanup()
+ {
+- TrayRemoveWindow(null);
+ try {
+ netkey.rhCoolKeyUnSetNotifyCallback(gNotify);
+ } catch(e) {
+@@ -1881,11 +1880,6 @@ function hiddenWindowStartup()
+
+ // We do want notify events though
+ var doPreserveNotify = true;
+-
+-
+- SetMenuItemsText();
+- HideWindow();
+- TrayRemoveWindow(doPreserveNotify);
+ }
+
+ function IdentifyWindow()
+@@ -2950,7 +2944,6 @@ function DoFormatCoolKey(type)
+ var screennamepwd = null;
+ var tokencode = null;
+
+-
+ if (!FormatCoolKey(keyType, keyID, lType, screenname, pin,screennamepwd,tokencode))
+ {
+ failed = 1;
+@@ -2997,10 +2990,6 @@ function OnCoolKeyInserted(keyType, keyI
+ var allowNotify = DoCoolKeyGetConfigValue(ESC_ALLOW_NOTIFICATIONS);
+
+ recordMessage("Key inserted!" + "Window " + IdentifyWindow());
+- if(gHiddenPage)
+- {
+- TrayShowNotificationIcon();
+- }
+
+ if (!GetCoolKeyIsEnrolled(keyType, keyID) )
+ {
+@@ -3024,7 +3013,6 @@ function OnCoolKeyInserted(keyType, keyI
+ SelectRowByKeyID(keyType, keyID);
+
+ }
+-
+ if(gHiddenPage)
+ {
+ var phoneHomeSuccess = 1;
+@@ -3269,12 +3257,11 @@ function Validate()
+
+ function OnCoolKeyStateChange(keyType, keyID, keyState, data,strData)
+ {
+- // alert("KeyID: " + keyID + "\n" +
+- // "KeyState: " + keyState + "\n" +
+- // "Data: " + data);
++ //alert("KeyID: " + keyID + "\n" +
++ // "KeyState: " + keyState + "\n" +
++ // "Data: " + data);
+ //alert("State Change ="+keyState);
+
+-
+ switch(keyState)
+ {
+ case 1000: // KeyInserted
+@@ -4804,3 +4791,8 @@ function GetESCLogPathName(aName)
+
+
+ }
++
++function TraySendNotificationMessage(aTitle,aMessage,aSeverity,aTimeout,aIcon)
++{
++ //alert(aMessage);
++}
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/esc.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/esc.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/esc.xul.fix1 2017-07-24 16:46:36.000000000
-0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/esc.xul 2018-04-26 11:44:38.433986216 -0700
+@@ -30,7 +30,6 @@
+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul...
+
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+- <script src= "TRAY.js"/>
+ <script src="ESC.js"/>
+ <vbox flex ="1" >
+ <hbox class="logoBox" >
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/hiddenWindow.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/hiddenWindow.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/hiddenWindow.xul.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/hiddenWindow.xul 2018-04-26
11:44:38.434986210 -0700
+@@ -21,6 +21,5 @@
+ onload="hiddenWindowStartup();"
+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul...
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+-<script src="TRAY.js"/>
+ <script src="ESC.js"/>
+ </window>
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/security.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/security.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/security.xul.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/security.xul 2018-04-26 11:44:38.434986210
-0700
+@@ -31,7 +31,6 @@
+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul...
+
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+- <script src= "TRAY.js"/>
+ <script src="ESC.js"/>
+
+ <groupbox flex="1">
+diff -up ./esc/src/app/xul/esc/chrome/content/esc/settings.xul.fix1
./esc/src/app/xul/esc/chrome/content/esc/settings.xul
+--- ./esc/src/app/xul/esc/chrome/content/esc/settings.xul.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/app/xul/esc/chrome/content/esc/settings.xul 2018-04-26 11:44:38.435986204
-0700
+@@ -32,7 +32,6 @@
+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul...
+
+ <stringbundle id="esc_strings"
src="chrome://esc/locale/esc.properties"/>
+- <script src="TRAY.js"/>
+ <script src="ESC.js"/>
+ <tabbox id="tablist" hidden="true">
+ <tabs>
+diff -up ./esc/src/lib/coolkey/cky_applet.c.fix1 ./esc/src/lib/coolkey/cky_applet.c
+--- ./esc/src/lib/coolkey/cky_applet.c.fix1 2018-04-26 11:44:38.436986198 -0700
++++ ./esc/src/lib/coolkey/cky_applet.c 2018-04-26 11:44:38.436986198 -0700
+@@ -0,0 +1,2119 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include <stdio.h>
++#include "cky_applet.h"
++#include <string.h>
++
++#define MIN(x, y) ((x) < (y) ? (x) : (y))
++
++/*****************************************************************
++ *
++ * Generic factorys are used by the generic APDU processing
++ * to customize the formatting of APDU. Typically APDUs are formatted
++ * using parameterized calls of the form CKYAPDUFactory_ADPUNAME.
++ * The generic processing code, however needs calls with a common
++ * Signature. To accomplish the conversion, we build generic versions
++ * which take a void * parameter. Trivial APDU's can pass NULL or a pointer
++ * to the single parameter that they need. More complicated APDU's use
++ * CKYAppletArg* data structures defined above to pass more arguments.
++ *
++ * Generic factorys then call the standard CKYAPDUFactor_ADPUNAME() functions
++ * to build the APDUs. These functions are intended only as arguments
++ * to the generic ADPU calls, and not to be called directly.
++ *
++ *****************************************************************/
++CKYStatus
++CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_SelectFile(apdu, 4, 0, (const CKYBuffer *)param);
++}
++
++CKYStatus
++CACAppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_SelectFile(apdu, 2, 12, (const CKYBuffer *)param);
++}
++
++CKYStatus
++P15AppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_SelectFile(apdu, 0, 0, (const CKYBuffer *)param);
++}
++
++CKYStatus
++CKYAppletFactory_SelectCardManager(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_SelectCardManager(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_GetCPLCData(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetCPLCData(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_ListKeys(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_ListKeys(apdu, *( CKYByte *)param);
++}
++
++CKYStatus
++CKYAppletFactory_ComputeCryptInit(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgComputeCrypt *ccs=(const CKYAppletArgComputeCrypt *)param;
++ return CKYAPDUFactory_ComputeCryptInit(apdu, ccs->keyNumber, ccs->mode,
++ ccs->direction, ccs->location);
++
++}
++
++CKYStatus
++CKYAppletFactory_ComputeCryptProcess(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgComputeCrypt *ccs=(const CKYAppletArgComputeCrypt *)param;
++ return CKYAPDUFactory_ComputeCryptProcess(apdu, ccs->keyNumber,
++ ccs->location, ccs->data);
++
++}
++
++CKYStatus
++CKYAppletFactory_ComputeCryptFinal(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgComputeCrypt *ccs=(const CKYAppletArgComputeCrypt *)param;
++ return CKYAPDUFactory_ComputeCryptFinal(apdu, ccs->keyNumber,
++ ccs->location, ccs->data, ccs->sig);
++}
++
++CKYStatus
++CKYAppletFactory_ComputeCryptOneStep(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgComputeCrypt *ccs=(const CKYAppletArgComputeCrypt *)param;
++ return CKYAPDUFactory_ComputeCryptOneStep(apdu, ccs->keyNumber,ccs->mode,
++ ccs->direction, ccs->location, ccs->data, ccs->sig);
++}
++
++CKYStatus
++CKYAppletFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgComputeECCSignature *ccs=(const CKYAppletArgComputeECCSignature
*)param;
++ return CKYAPDUFactory_ComputeECCSignatureOneStep(apdu, ccs->keyNumber,
++ ccs->location, ccs->data, ccs->sig);
++}
++
++CKYStatus
++CKYAppletFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, const void *param)
++{
++
++ const CKYAppletArgComputeECCKeyAgreement *ccs=(const
CKYAppletArgComputeECCKeyAgreement *)param;
++ return CKYAPDUFactory_ComputeECCKeyAgreementOneStep(apdu, ccs->keyNumber,
ccs->location, ccs->publicValue, ccs->secretKey);
++}
++
++CKYStatus
++CKYAppletFactory_CreatePIN(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgCreatePIN *cps = (const CKYAppletArgCreatePIN *)param;
++ return CKYAPDUFactory_CreatePIN(apdu, cps->pinNumber, cps->maxAttempts,
++ cps->pinValue);
++}
++
++CKYStatus
++CKYAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgVerifyPIN *vps = (const CKYAppletArgVerifyPIN *)param;
++ return CKYAPDUFactory_VerifyPIN(apdu, vps->pinNumber, vps->pinValue);
++}
++
++CKYStatus
++CKYAppletFactory_ChangePIN(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgChangePIN *cps = (const CKYAppletArgChangePIN *)param;
++ return CKYAPDUFactory_ChangePIN(apdu, cps->pinNumber, cps->oldPin,
++ cps->newPin);
++}
++
++CKYStatus
++CKYAppletFactory_ListPINs(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_ListPINs(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_Logout(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_Logout(apdu, *(const CKYByte *)param);
++}
++
++/* Future add WriteObject */
++
++CKYStatus
++CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgWriteObject *wos = (const CKYAppletArgWriteObject *)param;
++ return
CKYAPDUFactory_WriteObject(apdu,wos->objectID,wos->offset,wos->size,wos->data);
++}
++
++CKYStatus
++CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgCreateObject *cos=(const CKYAppletArgCreateObject *)param;
++ return CKYAPDUFactory_CreateObject(apdu, cos->objectID, cos->size,
++ cos->readACL, cos->writeACL, cos->deleteACL);
++}
++
++CKYStatus
++CKYAppletFactory_DeleteObject(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgDeleteObject *dos=(const CKYAppletArgDeleteObject *)param;
++ return CKYAPDUFactory_DeleteObject(apdu, dos->objectID, dos->zero);
++
++}
++
++CKYStatus
++CKYAppletFactory_ReadObject(CKYAPDU *apdu, const void *param)
++{
++ const CKYAppletArgReadObject *ros = (const CKYAppletArgReadObject *)param;
++ return CKYAPDUFactory_ReadObject(apdu, ros->objectID,
++ ros->offset, ros->size);
++}
++
++CKYStatus
++CKYAppletFactory_ListObjects(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_ListObjects(apdu, *(const CKYByte *)param);
++}
++
++CKYStatus
++CKYAppletFactory_GetStatus(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetStatus(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_Noop(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_Noop(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_GetBuildID(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetBuildID(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_GetLifeCycle(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetLifeCycle(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_GetLifeCycleV2(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetLifeCycleV2(apdu);
++}
++CKYStatus
++CKYAppletFactory_GetRandom(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetRandom(apdu, *(CKYByte *)param);
++}
++
++CKYStatus
++CKYAppletFactory_SeedRandom(CKYAPDU *apdu, const void *param)
++{
++ const CKYBuffer *buf=(CKYBuffer *)param;
++ return CKYAPDUFactory_SeedRandom(apdu, buf);
++}
++
++CKYStatus
++CKYAppletFactory_GetIssuerInfo(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetIssuerInfo(apdu);
++}
++
++CKYStatus
++CKYAppletFactory_GetBuiltinACL(CKYAPDU *apdu, const void *param)
++{
++ return CKYAPDUFactory_GetBuiltinACL(apdu);
++}
++
++CKYStatus
++CACAppletFactory_SignDecryptStep(CKYAPDU *apdu, const void *param)
++{
++ const CKYBuffer *buf=(CKYBuffer *)param;
++ return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_STEP, buf);
++}
++
++CKYStatus
++CACAppletFactory_SignDecryptFinal(CKYAPDU *apdu, const void *param)
++{
++ const CKYBuffer *buf=(CKYBuffer *)param;
++ return CACAPDUFactory_SignDecrypt(apdu, CAC_P1_FINAL, buf);
++}
++
++CKYStatus
++PIVAppletFactory_SignDecrypt(CKYAPDU *apdu, const void *param)
++{
++ const PIVAppletArgSignDecrypt *psd = (const PIVAppletArgSignDecrypt *)param;
++ return PIVAPDUFactory_SignDecrypt(apdu, psd->chain, psd->alg, psd->key,
++ psd->len, psd->buf);
++}
++
++CKYStatus
++P15AppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
++{
++ const P15AppletArgVerifyPIN *vps = (const P15AppletArgVerifyPIN *)param;
++ return P15APDUFactory_VerifyPIN(apdu, vps->pinRef, vps->pinVal);
++}
++
++CKYStatus
++CACAppletFactory_GetCertificate(CKYAPDU *apdu, const void *param)
++{
++ CKYSize *size=(CKYSize*)param;
++ return CACAPDUFactory_GetCertificate(apdu, *size);
++}
++
++CKYStatus
++PIVAppletFactory_GetCertificate(CKYAPDU *apdu, const void *param)
++{
++ CKYBuffer *tag =(CKYBuffer*)param;
++ return PIVAPDUFactory_GetData(apdu, tag, 0);
++}
++
++CKYStatus
++CACAppletFactory_ReadFile(CKYAPDU *apdu, const void *param)
++{
++ const CACAppletArgReadFile *rfs = (const CACAppletArgReadFile *)param;
++ return CACAPDUFactory_ReadFile(apdu, rfs->offset, rfs->type, rfs->count);
++}
++
++CKYStatus
++CACAppletFactory_GetProperties(CKYAPDU *apdu, const void *param)
++{
++ return CACAPDUFactory_GetProperties(apdu);
++}
++
++/*
++ * deprecates 0.x functions
++ */
++CKYStatus
++CKYAppletFactory_LogoutAllV0(CKYAPDU *apdu, const void *param)
++{
++ CKYByte data[2] = { 0, 0};
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_LOGOUT_ALL);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetSendData(apdu, data, sizeof(data));
++}
++
++CKYStatus
++P15AppletFactory_ReadRecord(CKYAPDU *apdu, const void *param)
++{
++ const P15AppletArgReadRecord *rrs = (const P15AppletArgReadRecord *)param;
++ return P15APDUFactory_ReadRecord(apdu, rrs->record,
++ rrs->short_ef, rrs->flags, rrs->size);
++}
++
++CKYStatus
++P15AppletFactory_ReadBinary(CKYAPDU *apdu, const void *param)
++{
++ const P15AppletArgReadBinary *res = (const P15AppletArgReadBinary *)param;
++ return P15APDUFactory_ReadBinary(apdu, res->offset,
++ res->short_ef, res->flags, res->size);
++}
++
++CKYStatus
++P15AppletFactory_ManageSecurityEnvironment(CKYAPDU *apdu, const void *param)
++{
++ const P15AppletArgManageSecurityEnvironment *mse =
++ (const P15AppletArgManageSecurityEnvironment *)param;
++ return P15APDUFactory_ManageSecurityEnvironment(apdu, mse->p1,
++ mse->p2, mse->keyRef);
++}
++
++CKYStatus
++P15AppletFactory_PerformSecurityOperation(CKYAPDU *apdu, const void *param)
++{
++ const P15AppletArgPerformSecurityOperation *pso =
++ (const P15AppletArgPerformSecurityOperation *)param;
++ return P15APDUFactory_PerformSecurityOperation(apdu, pso->dir, pso->chain,
++ pso->retLen, pso->data);
++}
++/*****************************************************************
++ *
++ * Generic Fill routines used by several calls in common
++ * and globally accessible
++ *
++ *****************************************************************/
++
++/* a null fill function for those APDU's which do not return data */
++CKYStatus
++CKYAppletFill_Null(const CKYBuffer *response, CKYSize size, void *param)
++{
++ return CKYSUCCESS;
++}
++
++/* a Buffer Replace fill function for those APDU's which return unformated
++ * chunks of data */
++CKYStatus
++CKYAppletFill_ReplaceBuffer(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYBuffer *buf = (CKYBuffer *)param;
++
++ if (buf == NULL) {
++ return CKYSUCCESS;
++ }
++ return CKYBuffer_Replace(buf, 0, CKYBuffer_Data(response),
++ CKYBuffer_Size(response) -2);
++}
++
++/* a Buffer Append fill function. Can be used with any APDU that uses Buffer
++ * Replace. Repeated calls continuously fill the buffer. Most useful for read.
++ */
++CKYStatus
++CKYAppletFill_AppendBuffer(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYBuffer *buf = (CKYBuffer *)param;
++
++ return CKYBuffer_AppendData(buf, CKYBuffer_Data(response),
++ CKYBuffer_Size(response) -2);
++}
++
++
++CKYStatus
++CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYByte *v = (CKYByte *)param;
++
++ *v = CKYBuffer_GetChar(response, 0);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYAppletFill_Short(const CKYBuffer *response, CKYSize size, void *param)
++{
++ unsigned short *v = (unsigned short *)param;
++
++ *v = CKYBuffer_GetShort(response, 0);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYAppletFill_Long(const CKYBuffer *response, CKYSize size, void *param)
++{
++ unsigned long *v = (unsigned long *)param;
++
++ *v = CKYBuffer_GetLong(response, 0);
++ return CKYSUCCESS;
++}
++
++/*****************************************************************
++ *
++ * Utilities shared by all the fetch Cards.
++ *
++ *****************************************************************/
++/*
++ * verify the we got a successful response. Responses should include
++ * the expected data returned plus a 2 byte return code. This return
++ * code should be 0x9000 on success.
++ */
++CKYBool
++CKYApplet_VerifyResponse(const CKYBuffer *buf, CKYSize dataSize,
++ CKYISOStatus *apduRC) {
++ CKYSize size = CKYBuffer_Size(buf);
++ CKYISOStatus rc = CKYISO_INVRESPONSE;
++ CKYBool valid = 0;
++
++ /* is there enough size for the return code ? */
++ if (size < 2) {
++ goto done;
++ }
++ /* fetch the data */
++ rc = CKYBuffer_GetShort(buf, size-2);
++
++ /* is there enough size for the expected data ? */
++ if ((dataSize != CKY_SIZE_UNKNOWN) && (size != dataSize+2)) {
++ goto done;
++ }
++
++ /* did we return successfully? */
++ valid = (rc == CKYISO_SUCCESS) || ((rc & CKYISO_MORE_MASK) == CKYISO_MORE);
++
++done:
++ if (apduRC) {
++ *apduRC = rc;
++ }
++ return valid;
++}
++
++
++/*
++ * most commands have identical operations. Isolate the differences in
++ * call back functions, and create a generic APDU handler which Creates
++ * APDU's, Does the exchange, and fills in the results.
++ */
++CKYStatus
++CKYApplet_HandleAPDU(CKYCardConnection *conn,
++ CKYAppletFactory afFunc, const void *afArg,
++ const CKYBuffer *nonce, CKYSize size,
++ CKYFillFunction fillFunc, void *fillArg, CKYISOStatus *apduRC)
++{
++ CKYAPDU apdu;
++ CKYBuffer response;
++ CKYStatus ret;
++
++ if (apduRC) {
++ *apduRC = CKYISO_NORESPONSE;
++ }
++
++ /* initialize the response and APDU buffers */
++ CKYBuffer_InitEmpty(&response);
++ ret = CKYAPDU_Init(&apdu);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++
++ /* fill in the APDU buffer with the correct values */
++ ret = (*afFunc)(&apdu, afArg);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ /* if NONCE supplied, add it to the end of the apdu */
++ if (nonce) {
++ /*
++ * Local Secured commands need the nonce returned from Login to
++ * verify that they are valid. Nonce's are just added to the end
++ * of the APDU much like
++ */
++ ret = CKYAPDU_AppendSendDataBuffer(&apdu, nonce);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ }
++
++ /* send it to the card */
++ ret = CKYCardConnection_ExchangeAPDU(conn, &apdu, &response);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++
++ /* verify we got the expected response */
++ if (!CKYApplet_VerifyResponse(&response, size, apduRC)) {
++ ret = CKYAPDUFAIL;
++ goto done;
++ }
++
++ /* Fill in our output data structure */
++ ret = (*fillFunc)(&response, size, fillArg);
++done:
++ CKYBuffer_FreeData(&response);
++ CKYAPDU_FreeData(&apdu);
++ return ret;
++}
++
++
++/*****************************************************************
++ *
++ * The following convience functions convert APDU calls
++ * into function calls, with input and output parameters.
++ * The application is still responsible for 1) creating a connection
++ * to the card, 2) Getting a tranaction long, then 3) selecting
++ * the appropriate applet (or Card manager). Except for those
++ * calls that have been noted, the appropriate applet is the CoolKey
++ * applet.
++ *
++ *****************************************************************/
++/*
++ * Select an applet. Must happen after we start a transaction and before
++ * we issue any applet specific command.
++ */
++CKYStatus
++CKYApplet_SelectFile(CKYCardConnection *conn, const CKYBuffer *AID,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, AID, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++}
++
++static CKYByte coolkeyid[] = {0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00 };
++/*
++ * Select the CoolKey applet. Must happen after we start a transaction and
++ * before we issue any applet specific command.
++ */
++CKYStatus
++CKYApplet_SelectCoolKeyManager(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer COOLKEYAID;
++ CKYBuffer_InitFromData(&COOLKEYAID, coolkeyid, sizeof(coolkeyid));
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &COOLKEYAID,
++ NULL, 0, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&COOLKEYAID);
++ return ret;
++}
++
++static CKYByte CACPKIid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01 };
++/*
++ * Select the CoolKey applet. Must happen after we start a transaction and
++ * before we issue any applet specific command.
++ */
++CKYStatus
++CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cacAID,
++ CKYByte instance, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer_AppendData(cacAID, CACPKIid, sizeof(CACPKIid));
++ CKYBuffer_AppendChar(cacAID, instance);
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, cacAID,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ if (ret != CKYSUCCESS) {
++ CKYBuffer_Resize(cacAID, 0);
++ }
++ return ret;
++}
++
++/*
++ * Select the card manager. Must happen after we start a transaction and before
++ * we issue any card manager commands.
++ */
++CKYStatus
++CKYApplet_SelectCardManager(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectCardManager, NULL,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++}
++
++static CKYByte cacmgrid[] = {0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
++CKYStatus
++CACApplet_SelectCardManager(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer CAC_CM_AID;
++ CKYBuffer_InitFromData(&CAC_CM_AID, cacmgrid, sizeof(cacmgrid));
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&CAC_CM_AID);
++ return ret;
++}
++
++static CKYByte cacCCCid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00 };
++CKYStatus
++CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer CAC_CM_AID;
++ CKYBuffer_InitFromData(&CAC_CM_AID, cacCCCid, sizeof(cacCCCid));
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &CAC_CM_AID,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&CAC_CM_AID);
++ return ret;
++}
++
++CKYStatus
++CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer efBuf;
++ CKYBuffer_InitEmpty(&efBuf);
++ CKYBuffer_AppendShortLE(&efBuf, ef);
++ ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SelectFile, &efBuf,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&efBuf);
++ return ret;
++}
++
++/*
++ * GetCPLC cluster -- must be called with CM selected
++ */
++static CKYStatus
++ckyAppletFill_GetCPLCData(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespGetCPLCData *gcdp = (CKYAppletRespGetCPLCData *)param;
++
++ gcdp->CPLCtag = CKYBuffer_GetShort(response, 0);
++ gcdp->length = CKYBuffer_GetChar(response, 2);
++ gcdp->fabricator = CKYBuffer_GetShort(response, 3);
++ gcdp->romType = CKYBuffer_GetShort(response, 5);
++ gcdp->romOSID = CKYBuffer_GetShort(response, 7);
++ gcdp->romOSDate = CKYBuffer_GetShort(response, 9);
++ gcdp->romOSLevel = CKYBuffer_GetShort(response, 11);
++ gcdp->eepromFabricationDate = CKYBuffer_GetShort(response, 13);
++ gcdp->eepromSerialNumber = CKYBuffer_GetLong(response, 15);
++ gcdp->eepromBatchID = CKYBuffer_GetShort(response, 19);
++ gcdp->eepromModuleFabricator = CKYBuffer_GetShort(response, 21);
++ gcdp->eepromModuleDate = CKYBuffer_GetShort(response, 23);
++ gcdp->eepromICManufacturer = CKYBuffer_GetShort(response, 25);
++ gcdp->eepromEmbeddingDate = CKYBuffer_GetShort(response, 27);
++ gcdp->eepromPrePersonalizer = CKYBuffer_GetShort(response, 29);
++ gcdp->eepromPrePersonalizeDate = CKYBuffer_GetShort(response, 31);
++ gcdp->eepromPrePersonalizeID = CKYBuffer_GetLong(response, 33);
++ gcdp->eepromPersonalizer = CKYBuffer_GetShort(response, 37);
++ gcdp->eepromPersonalizeDate = CKYBuffer_GetShort(response, 39);
++ gcdp->eepromPersonalizeID = CKYBuffer_GetLong(response, 41);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetCPLCData(CKYCardConnection *conn, CKYAppletRespGetCPLCData *cplc,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetCPLCData, NULL, NULL,
++ CKY_SIZE_GET_CPLCDATA, ckyAppletFill_GetCPLCData, cplc, apduRC);
++}
++
++/*
++ * Get CUID. The CUID exists in the CPLC data. We use the same basic
++ * APDU, but use a differ fill function to collect it.
++ */
++static CKYStatus
++ckyAppletFill_GetCUID(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYBuffer *cuid = (CKYBuffer *)param;
++ CKYStatus ret;
++
++ ret = CKYBuffer_Resize(cuid,10);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ /* fabricator 2 bytes */
++ CKYBuffer_SetChar(cuid, 0, CKYBuffer_GetChar(response, 3));
++ CKYBuffer_SetChar(cuid, 1, CKYBuffer_GetChar(response, 4));
++ /* IC Type 2 bytes */
++ CKYBuffer_SetChar(cuid, 2, CKYBuffer_GetChar(response, 5));
++ CKYBuffer_SetChar(cuid, 3, CKYBuffer_GetChar(response, 6));
++ /* Batch ID 2 bytes */
++ CKYBuffer_SetChar(cuid, 4, CKYBuffer_GetChar(response, 19));
++ CKYBuffer_SetChar(cuid, 5, CKYBuffer_GetChar(response, 20));
++ /* IC Serial Number 4 bytes */
++ CKYBuffer_SetChar(cuid, 6, CKYBuffer_GetChar(response, 15));
++ CKYBuffer_SetChar(cuid, 7, CKYBuffer_GetChar(response, 16));
++ CKYBuffer_SetChar(cuid, 8, CKYBuffer_GetChar(response, 17));
++ CKYBuffer_SetChar(cuid, 9, CKYBuffer_GetChar(response, 18));
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetCUID(CKYCardConnection *conn, CKYBuffer *cuid, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetCPLCData, NULL, NULL,
++ CKY_SIZE_GET_CPLCDATA, ckyAppletFill_GetCUID, cuid, apduRC);
++}
++
++/*
++ * Get MSN. The MSN exists in the CPLC data. We use the same basic
++ * APDU, but use a differ fill function to collect it.
++ */
++static CKYStatus
++ckyAppletFill_GetMSN(const CKYBuffer *response, CKYSize size, void *param)
++{
++ unsigned long *msn = (unsigned long *)param;
++ *msn = CKYBuffer_GetLong(response, 41);
++
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetMSN(CKYCardConnection *conn, unsigned long *msn,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetCPLCData, NULL, NULL,
++ CKY_SIZE_GET_CPLCDATA, ckyAppletFill_GetMSN, msn, apduRC);
++}
++
++/*
++ * ListKeys cluster
++ */
++static CKYStatus
++ckyAppletFill_ListKeys(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespListKeys *lkp = (CKYAppletRespListKeys *)param;
++
++ lkp->keyNum = CKYBuffer_GetChar(response, 0);
++ lkp->keyType = CKYBuffer_GetChar(response, 1);
++ lkp->keyPartner = CKYBuffer_GetChar(response, 2);
++ lkp->keySize = CKYBuffer_GetShort(response, 3);
++ lkp->readACL = CKYBuffer_GetShort(response, 5);
++ lkp->writeACL = CKYBuffer_GetShort(response, 7);
++ lkp->useACL = CKYBuffer_GetShort(response, 9);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_ListKeys(CKYCardConnection *conn, CKYByte seq,
++ CKYAppletRespListKeys *lkp, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ListKeys, &seq, NULL,
++ CKY_SIZE_LIST_KEYS, ckyAppletFill_ListKeys, lkp, apduRC);
++}
++
++/*
++ * Compute Crypt Cluster.
++ *
++ * Compute Crypt takes 3 types: Init, Process, Final.
++ *
++ */
++CKYStatus
++CKYApplet_ComputeCryptInit(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, CKYByte location,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgComputeCrypt ccd;
++ ccd.keyNumber = keyNumber;
++ ccd.mode = mode;
++ ccd.direction = direction;
++ ccd.location = location;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptInit, &ccd,
++ nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++CKYApplet_ComputeCryptProcess(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgComputeCrypt ccd;
++ ccd.keyNumber = keyNumber;
++ ccd.location = location;
++ ccd.data = data;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptProcess,
++ &ccd, nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++/* computeECCValue returns data in the form :
++ * len: short
++ * data: byte[len]
++ * This fill routine returns A buffer with a copy of data and a length of len */
++static CKYStatus
++ckyAppletFill_ComputeECCValueFinal(const CKYBuffer *response,
++ CKYSize size, void *param)
++{
++ CKYBuffer *cbuf = (CKYBuffer *)param;
++ CKYSize respSize = CKYBuffer_Size(response);
++ CKYSize dataLen;
++
++ if (cbuf == 0) {
++ return CKYSUCCESS; /* app didn't want the result */
++ }
++ /* data response code + length code */
++ if (respSize < 4) {
++ return CKYAPDUFAIL;
++ }
++ dataLen = CKYBuffer_GetShort(response, 0);
++ if (dataLen > (respSize-4)) {
++ return CKYAPDUFAIL;
++ }
++ return CKYBuffer_Replace(cbuf, 0, CKYBuffer_Data(response)+2, dataLen);
++}
++
++/* computeCrypt returns data in the form :
++ * len: short
++ * data: byte[len]
++ * This fill routine returns A buffer with a copy of data and a length of len */
++static CKYStatus
++ckyAppletFill_ComputeCryptFinal(const CKYBuffer *response,
++ CKYSize size, void *param)
++{
++ CKYBuffer *cbuf = (CKYBuffer *)param;
++ CKYSize respSize = CKYBuffer_Size(response);
++ CKYSize dataLen;
++
++ if (cbuf == 0) {
++ return CKYSUCCESS; /* app didn't want the result */
++ }
++ /* data response code + length code */
++ if (respSize < 4) {
++ return CKYAPDUFAIL;
++ }
++ dataLen = CKYBuffer_GetShort(response, 0);
++ if (dataLen > (respSize-4)) {
++ return CKYAPDUFAIL;
++ }
++ return CKYBuffer_Replace(cbuf, 0, CKYBuffer_Data(response)+2, dataLen);
++}
++
++CKYStatus
++CKYApplet_ComputeCryptFinal(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data, CKYBuffer *sig, CKYBuffer *result,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgComputeCrypt ccd;
++ ccd.keyNumber = keyNumber;
++ ccd.location = location;
++ ccd.data = data;
++ ccd.data = sig;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ComputeCryptFinal, &ccd,
++ nonce, CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal, result, apduRC);
++}
++
++/*
++ * do a complete ComputeCrypt operation
++ * ...look to data size to see if we should read/write the data to
++ * the on card buffer. (future)
++ */
++CKYStatus
++CKYApplet_ComputeCrypt(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, const CKYBuffer *data, CKYBuffer *sig,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYAppletArgComputeCrypt ccd;
++ CKYBuffer empty;
++ CKYISOStatus status;
++ short dataSize = 0;
++ int use2APDUs = 0;
++ int use_dl_object = CKYBuffer_Size(data) > 200 ;
++
++ CKYBuffer_InitEmpty(&empty);
++ ccd.keyNumber = keyNumber;
++ ccd.mode = mode;
++ ccd.direction = direction;
++ ccd.location = use_dl_object ? CKY_DL_OBJECT : CKY_DL_APDU;
++
++ if (!apduRC)
++ apduRC = &status;
++
++ if (use_dl_object) {
++ CKYBuffer sizeBuf;
++
++ CKYBuffer_InitEmpty(&sizeBuf);
++ CKYBuffer_AppendShort(&sizeBuf, CKYBuffer_Size(data));
++
++ ret = CKYApplet_WriteObjectFull(conn, 0xffffffff,
++ 0, CKYBuffer_Size(&sizeBuf), nonce,
++ &sizeBuf, apduRC);
++
++ CKYBuffer_FreeData(&sizeBuf);
++ if( ret != CKYSUCCESS)
++ goto fail;
++
++ ret = CKYApplet_WriteObjectFull(conn, 0xffffffff,
++ 2, CKYBuffer_Size(data), nonce,
++ data, apduRC);
++
++ if(ret != CKYSUCCESS)
++ goto fail;
++ }
++
++ if (mode == CKY_RSA_NO_PAD) {
++ ccd.data = use_dl_object ? &empty : data;
++ ccd.sig = sig;
++ ret = CKYApplet_HandleAPDU(conn,
++ CKYAppletFactory_ComputeCryptOneStep, &ccd, nonce,
++ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal,
++ use_dl_object ? NULL : result, apduRC);
++ if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
++ use2APDUs = 1; /* maybe it's an old applet */
++ }
++ } else {
++ use2APDUs = 1;
++ }
++ if (use2APDUs) {
++ /* future, if data is to big write it to the internal object
++ * and set location to DL_OBJECT */
++ ccd.data = ∅
++ ccd.sig = sig;
++
++ ret = CKYApplet_HandleAPDU(conn,
++ CKYAppletFactory_ComputeCryptInit, &ccd, nonce,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++ if (ret == CKYSUCCESS) {
++ ccd.data = use_dl_object ? &empty : data;
++ ret = CKYApplet_HandleAPDU(conn,
++ CKYAppletFactory_ComputeCryptFinal, &ccd, nonce,
++ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeCryptFinal,
++ use_dl_object ? NULL : result, apduRC);
++ }
++ }
++
++ if (use_dl_object && ret == CKYSUCCESS) {
++ CKYBuffer sizeOutBuf;
++ CKYBuffer_InitEmpty(&sizeOutBuf);
++
++ ret = CKYApplet_ReadObjectFull(conn,0xffffffff,
++ 0, 2,
++ nonce,&sizeOutBuf,apduRC);
++
++ if(ret != CKYSUCCESS) {
++ CKYBuffer_FreeData(&sizeOutBuf);
++ goto fail;
++ }
++
++ dataSize = CKYBuffer_GetShort(&sizeOutBuf, 0);
++
++ CKYBuffer_FreeData(&sizeOutBuf);
++
++ ret = CKYApplet_ReadObjectFull(conn,0xffffffff,
++ 2, dataSize,
++ nonce,result,apduRC);
++ }
++
++fail:
++
++ return ret;
++}
++
++CKYStatus
++CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
++ const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYStatus ret = CKYAPDUFAIL;
++ CKYAppletArgComputeECCKeyAgreement ccd;
++ CKYBuffer empty;
++ CKYISOStatus status;
++ /* Routine creates a sym key, should easily fit in one apdu */
++
++ CKYBuffer_InitEmpty(&empty);
++ ccd.keyNumber = keyNumber;
++ ccd.location = CKY_DL_APDU;
++
++ if (!apduRC)
++ apduRC = &status;
++
++ if (ccd.location == CKY_DL_APDU) {
++ ccd.publicValue = publicValue;
++ ccd.secretKey = sharedSecret;
++ ret = CKYApplet_HandleAPDU(conn,
++ CKYAppletFactory_ComputeECCKeyAgreementOneStep, &ccd,
nonce,
++ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
++ result, apduRC);
++ if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
++ return ret;
++ }
++ }
++
++ return ret;
++}
++
++CKYStatus
++CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
++ const CKYBuffer *data, CKYBuffer *sig,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYStatus ret = CKYAPDUFAIL;
++ CKYAppletArgComputeECCSignature ccd;
++ CKYBuffer empty;
++ CKYISOStatus status;
++
++ CKYBuffer_InitEmpty(&empty);
++ ccd.keyNumber = keyNumber;
++
++ /* Assume APDU, the signature can only get so big with our key sizes, ~ 130 for 521
bit key. */
++ ccd.location = CKY_DL_APDU;
++
++ if (!apduRC)
++ apduRC = &status;
++
++ if (ccd.location == CKY_DL_APDU) {
++ ccd.data = data;
++ ccd.sig = sig;
++ ret = CKYApplet_HandleAPDU(conn,
++ CKYAppletFactory_ComputeECCSignatureOneStep, &ccd,
nonce,
++ CKY_SIZE_UNKNOWN, ckyAppletFill_ComputeECCValueFinal,
++ result, apduRC);
++ if (ret == CKYAPDUFAIL && *apduRC == CKYISO_INCORRECT_P2) {
++ return ret;
++ }
++
++ }
++
++ return ret;
++}
++
++/*
++ * do a CAC Sign/Decrypt
++ */
++CKYStatus
++CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data,
++ CKYBuffer *result, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYSize dataSize = CKYBuffer_Size(data);
++ CKYOffset offset = 0;
++ CKYBuffer tmp;
++
++ CKYBuffer_InitEmpty(&tmp);
++
++ CKYBuffer_Resize(result, 0);
++ for(offset = 0; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE;
++ offset += CKY_MAX_WRITE_CHUNK_SIZE) {
++ CKYBuffer_Resize(&tmp,0);
++ CKYBuffer_AppendBuffer(&tmp, data, offset, CKY_MAX_WRITE_CHUNK_SIZE);
++ ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptStep,
++ &tmp, NULL, CKY_SIZE_UNKNOWN,
++ CKYAppletFill_AppendBuffer,
++ result, apduRC);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ }
++ CKYBuffer_Resize(&tmp,0);
++ CKYBuffer_AppendBuffer(&tmp, data, offset, dataSize - offset);
++ ret = CKYApplet_HandleAPDU(conn, CACAppletFactory_SignDecryptFinal,
++ &tmp, NULL, CKY_SIZE_UNKNOWN,
++ CKYAppletFill_AppendBuffer,
++ result, apduRC);
++
++ if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != dataSize)) {
++ /* RSA returns the same data size as input, didn't happen, so
++ * something is wrong. */
++ }
++
++done:
++ CKYBuffer_FreeData(&tmp);
++ return ret;
++}
++
++const P15PinInfo CACPinInfo =
++ { P15PinInitialized|P15PinNeedsPadding, P15PinUTF8, 0, 8, 8, 0, 0xff };
++const P15PinInfo PIVPinInfo =
++ { P15PinLocal|P15PinInitialized|P15PinNeedsPadding,
++ P15PinUTF8, 0, 8, 8, 0, 0xff };
++/*
++ * do a CAC VerifyPIN
++ */
++CKYStatus
++CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, int local,
++ CKYISOStatus *apduRC)
++{
++ return P15Applet_VerifyPIN(conn, pin,
++ local ? &PIVPinInfo: &CACPinInfo, apduRC);
++}
++
++
++/*
++ * Get a CAC Certificate
++ */
++CKYStatus
++CACApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYSize size = 100;
++
++ CKYBuffer_Resize(cert,0);
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_GetCertificate, &size, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++ while ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
++ size = *apduRC & ~CKYISO_MORE_MASK;
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_GetCertificate, &size, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++ }
++ return ret;
++}
++
++/*
++ * Read a CAC Tag/Value file
++ */
++CKYStatus
++CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type, CKYBuffer *buffer,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYByte maxtransfer;
++ unsigned short offset = 0;
++ unsigned short size;
++ CACAppletArgReadFile rfs;
++
++ CKYBuffer_Resize(buffer,0);
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++ rfs.offset = 0;
++ rfs.count = 2;
++ rfs.type = type;
++
++ /* APDU's are expensive, Grab a big chunk of the file first if possible */
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_ReadFile, &rfs, NULL,
++ rfs.count, CKYAppletFill_AppendBuffer,
++ buffer, apduRC);
++ /* file is probably smaller than 100 bytes, get the actual size first */
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ size = CKYBuffer_GetShortLE(buffer, 0) + 2 /* include the length itself */;
++ maxtransfer = CKY_MAX_READ_CHUNK_SIZE;
++ /* get the rest of the buffer if necessary */
++ for (offset = CKYBuffer_Size(buffer); size > offset;
++ offset = CKYBuffer_Size(buffer)) {
++ rfs.offset = offset;
++ rfs.count = MIN(size - offset, maxtransfer);
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_ReadFile, &rfs, NULL,
++ rfs.count, CKYAppletFill_AppendBuffer,
++ buffer, apduRC);
++ if (ret != CKYSUCCESS) {
++ if (*apduRC == CAC_INVALID_PARAMS) {
++ maxtransfer = maxtransfer/2;
++ if (maxtransfer == 0) {
++ return ret;
++ }
++ } else {
++ return ret;
++ }
++ }
++ }
++ return ret;
++}
++
++/*
++ * Select a EF
++ */
++CKYStatus
++P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer efBuf;
++ CKYBuffer_InitEmpty(&efBuf);
++ CKYBuffer_AppendShort(&efBuf, ef);
++ ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_SelectFile, &efBuf,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&efBuf);
++ return ret;
++}
++
++CKYStatus
++P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer efBuf;
++ CKYBuffer_InitEmpty(&efBuf);
++ CKYBuffer_AppendShort(&efBuf, ef);
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &efBuf,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ CKYBuffer_FreeData(&efBuf);
++ return ret;
++}
++
++CKYStatus
++P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin,
++ const P15PinInfo *pinInfo, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYSize size;
++ CKYBuffer encodedPin;
++ P15AppletArgVerifyPIN vps;
++
++ CKYBuffer_InitEmpty(&encodedPin);
++
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++
++ size = strlen(pin);
++ if (pinInfo->pinFlags & P15PinNeedsPadding) {
++ if (size > pinInfo->storedLength) {
++ size = pinInfo->storedLength;
++ }
++ ret=CKYBuffer_Reserve(&encodedPin, pinInfo->storedLength);
++ if (ret != CKYSUCCESS) { goto fail; }
++ }
++ /* This is where we would do upcase processing for the case insensitive
++ * flag. It's also where we would do mapping for bcd pins */
++ ret = CKYBuffer_Replace(&encodedPin, 0, (const CKYByte *)pin, size);
++ if (ret != CKYSUCCESS) { goto fail; }
++ if (pinInfo->pinFlags & P15PinNeedsPadding) {
++ int i;
++ int padSize = pinInfo->storedLength - size;
++ for (i=0; i < padSize; i++) {
++ CKYBuffer_AppendChar(&encodedPin, pinInfo->padChar);
++ }
++ }
++
++ vps.pinRef = pinInfo->pinRef |
++ ((pinInfo->pinFlags & P15PinLocal) ? ISO_LOGIN_LOCAL : ISO_LOGIN_GLOBAL);
++ vps.pinVal = &encodedPin;
++ ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_VerifyPIN, &vps, NULL,
++ 0, CKYAppletFill_Null,
++ NULL, apduRC);
++ /* it's unfortunate that the same code that means 'more data to follow'
for
++ * GetCertificate also means, auth failure, you only have N more attempts
++ * left in the verify PIN call */
++ if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
++ ret = CKYAPDUFAIL;
++ }
++fail:
++ CKYBuffer_FreeData(&encodedPin);
++ return ret;
++}
++
++
++/*
++ * Read Record
++ */
++CKYStatus
++P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record, CKYByte short_ef,
++ CKYByte flags, CKYByte size, CKYBuffer *data, CKYISOStatus *apduRC)
++{
++ P15AppletArgReadRecord rrd;
++
++ rrd.record = record;
++ rrd.short_ef = short_ef;
++ rrd.flags = flags;
++ rrd.size = size;
++ return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadRecord, &rrd, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, data, apduRC);
++}
++
++static CKYStatus
++P15Applet_ManageSecurityEnvironment(CKYCardConnection *conn, CKYByte key,
++ CKYByte direction, CKYByte p1,
++ CKYISOStatus *apduRC)
++{
++ P15AppletArgManageSecurityEnvironment mse;
++
++ mse.p1 = p1; /* this appears to be where most cards disagree */
++ mse.p2 = (direction == CKY_DIR_DECRYPT) ? ISO_MSE_KEA : ISO_MSE_SIGN;
++ mse.keyRef = key; /* should be CKYBuffer in the future? */
++ return CKYApplet_HandleAPDU(conn,
++ P15AppletFactory_ManageSecurityEnvironment, &mse, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
++ unsigned int keySize, CKYByte direction,
++ const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ P15AppletArgPerformSecurityOperation pso;
++ CKYSize dataSize = CKYBuffer_Size(data);
++ CKYOffset offset = 0;
++ CKYBuffer tmp;
++ int length = dataSize;
++ int appendLength = length;
++ int hasPad = 0;
++
++ /* Hack, lie and say we are always doing encipherment */
++ direction = CKY_DIR_DECRYPT;
++ CKYBuffer_Resize(result,0);
++ /*
++ * first set the security environment
++ */
++ ret = P15Applet_ManageSecurityEnvironment(conn, key, direction,
++ ISO_MSE_SET|ISO_MSE_QUAL_COMPUTE, apduRC);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++
++ CKYBuffer_InitEmpty(&tmp);
++
++ pso.data = &tmp;
++ pso.dir = direction;
++ if (direction == CKY_DIR_DECRYPT) {
++ length++;
++ CKYBuffer_AppendChar(&tmp, 0x00); /* pad byte */
++ hasPad = 1;
++ }
++ if (CKYCardConnection_GetProtocol(conn) == SCARD_PROTOCOL_T0) {
++ ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ for(offset = 0; length > CKY_MAX_WRITE_CHUNK_SIZE;
++ hasPad = 0,
++ offset += CKY_MAX_WRITE_CHUNK_SIZE,
++ length -= CKY_MAX_WRITE_CHUNK_SIZE) {
++ pso.chain = 1;
++ pso.retLen = 0;
++ CKYBuffer_AppendBuffer(&tmp, data, offset,
++ hasPad ? (CKY_MAX_WRITE_CHUNK_SIZE-1) : CKY_MAX_WRITE_CHUNK_SIZE);
++ ret = CKYApplet_HandleAPDU(conn,
++ P15AppletFactory_PerformSecurityOperation, &pso, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ CKYBuffer_Resize(&tmp, 0);
++ }
++ appendLength = length;
++ } else {
++ ret = CKYBuffer_Reserve(&tmp, length);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ }
++ CKYBuffer_AppendBuffer(&tmp, data, offset, appendLength);
++ pso.chain = 0;
++ pso.retLen = dataSize;
++
++ ret = CKYApplet_HandleAPDU(conn,
++ P15AppletFactory_PerformSecurityOperation, &pso, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, result, apduRC);
++
++done:
++ CKYBuffer_FreeData(&tmp);
++ return ret;
++}
++
++/*
++ * Read Binary
++ */
++CKYStatus
++P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset,
++ CKYByte short_ef, CKYByte flags, CKYByte size,
++ CKYBuffer *data, CKYISOStatus *apduRC)
++{
++ P15AppletArgReadBinary red;
++
++ red.offset = offset;
++ red.short_ef = short_ef;
++ red.flags = flags;
++ red.size = size;
++ return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadBinary, &red, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, data, apduRC);
++}
++
++CKYStatus
++CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert,
++ CKYSize *nextSize, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYSize size = 100;
++
++ CKYBuffer_Resize(cert,0);
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++ *nextSize = 0;
++
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_GetCertificate, &size, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++ if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
++ *nextSize = *apduRC & ~CKYISO_MORE_MASK;
++ }
++ return ret;
++}
++
++CKYStatus
++CACApplet_GetCertificateAppend(CKYCardConnection *conn, CKYBuffer *cert,
++ CKYSize nextSize, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYSize size = nextSize;
++
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_GetCertificate, &size, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++ while ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
++ size = *apduRC & ~CKYISO_MORE_MASK;
++ ret = CKYApplet_HandleAPDU(conn,
++ CACAppletFactory_GetCertificate, &size, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++ }
++ return ret;
++}
++
++/* Select the PIV applet */
++static CKYByte pivAid[] = {0xa0, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00,
++ 0x10, 0x00};
++CKYStatus
++PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYBuffer PIV_Applet_AID,return_AID;
++
++ CKYBuffer_InitEmpty(&return_AID);
++ CKYBuffer_InitFromData(&PIV_Applet_AID, pivAid, sizeof(pivAid));
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile,
++ &PIV_Applet_AID,
++ NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer,
++ &return_AID, apduRC);
++ /* Some cards return OK, but don't switch to our applet */
++ /* PIV has a well defined return for it's select, check to see if we have
++ * a PIV card here */
++ if (CKYBuffer_GetChar(&return_AID,0) != 0x61) {
++ /* not an application property template, so not a PIV. We could
++ * check that the aid tag (0x4f) and theallocation authority tag (0x79)
++ * are present, but what we are really avoiding is broken cards that
++ * lie about being able to switch to a particular applet, so the first
++ * tag should be sufficient */
++ ret = CKYAPDUFAIL; /* what we should have gotten */
++ }
++ CKYBuffer_FreeData(&PIV_Applet_AID);
++ CKYBuffer_FreeData(&return_AID);
++ return ret;
++}
++
++/*
++ * Get a PIV Certificate
++ */
++CKYStatus
++PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert, int tag,
++ CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYISOStatus status;
++ CKYBuffer tagBuf;
++
++ CKYBuffer_InitEmpty(&tagBuf);
++ CKYBuffer_Reserve(&tagBuf,4); /* can be up to 4 bytes */
++
++ CKYBuffer_Resize(cert,0);
++ if (apduRC == NULL) {
++ apduRC = &status;
++ }
++ if (tag >= 0x01000000) {
++ ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 24) & 0xff);
++ if (ret != CKYSUCCESS) { goto loser; }
++ }
++ if (tag >= 0x010000) {
++ ret = CKYBuffer_AppendChar(&tagBuf, (tag >> 16) & 0xff);
++ if (ret != CKYSUCCESS) { goto loser; }
++ }
++ if (tag >= 0x0100) {
++ ret =CKYBuffer_AppendChar(&tagBuf, (tag >> 8) & 0xff);
++ if (ret != CKYSUCCESS) { goto loser; }
++ }
++ ret = CKYBuffer_AppendChar(&tagBuf, tag & 0xff);
++ if (ret != CKYSUCCESS) { goto loser; }
++
++
++ ret = CKYApplet_HandleAPDU(conn,
++ PIVAppletFactory_GetCertificate, &tagBuf, NULL,
++ CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, cert,
++ apduRC);
++loser:
++ CKYBuffer_FreeData(&tagBuf);
++
++ return ret;
++}
++
++
++/*
++ * record the next ber tag and length. NOTE: this is a state machine.
++ * we can handle the case where we are passed the data just one byte
++ * at a time.
++ */
++static CKYStatus
++pivUnwrap(const CKYBuffer *buf, CKYOffset *offset,
++ CKYSize *dataSize, PIVUnwrapState *unwrap)
++{
++ if (unwrap->tag == 0) {
++ unwrap->tag = CKYBuffer_GetChar(buf, *offset);
++ if (unwrap->tag == 0) unwrap->tag = 0xff;
++ (*offset)++;
++ (*dataSize)--;
++ }
++ if (*dataSize == 0) {
++ return CKYSUCCESS;
++ }
++ if (unwrap->length_bytes != 0) {
++ int len;
++ if (unwrap->length_bytes == -1) {
++ len = CKYBuffer_GetChar(buf, *offset);
++ unwrap->length_bytes = 0;
++ unwrap->length = len;
++ (*offset)++;
++ (*dataSize)--;
++ if (len & 0x80) {
++ unwrap->length = 0;
++ unwrap->length_bytes = len & 0x7f;
++ }
++ }
++ while ((*dataSize != 0) && (unwrap->length_bytes != 0)) {
++ len = CKYBuffer_GetChar(buf, *offset);
++ (*offset) ++;
++ (*dataSize) --;
++ unwrap->length = ((unwrap->length) << 8 | len);
++ unwrap->length_bytes--;
++ }
++ }
++ return CKYSUCCESS;
++}
++
++/*
++ * Remove the BER wrapping first...
++ */
++static CKYStatus
++pivAppletFill_AppendUnwrapBuffer(const CKYBuffer *response,
++ CKYSize size, void *param)
++{
++ PIVAppletRespSignDecrypt *prsd = (PIVAppletRespSignDecrypt *)param;
++ CKYBuffer *buf = prsd->buf;
++ CKYSize dataSize = CKYBuffer_Size(response);
++ CKYOffset offset = 0;
++
++ if (dataSize <= 2) {
++ return CKYSUCCESS;
++ }
++ dataSize -= 2;
++ /* remove the first tag */
++ (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_1);
++ if (dataSize == 0) {
++ return CKYSUCCESS;
++ }
++ /* remove the second tag */
++ (void) pivUnwrap(response, &offset, &dataSize, &prsd->tag_2);
++ if (dataSize == 0) {
++ return CKYSUCCESS;
++ }
++ /* the rest is real data */
++ return CKYBuffer_AppendData(buf, CKYBuffer_Data(response) + offset,
++ dataSize);
++}
++
++static CKYStatus
++piv_wrapEncodeLength(CKYBuffer *buf, int length, int ber_len)
++{
++ if (ber_len== 1) {
++ CKYBuffer_AppendChar(buf,length);
++ } else {
++ ber_len--;
++ CKYBuffer_AppendChar(buf,0x80+ber_len);
++ while(ber_len--) {
++ CKYBuffer_AppendChar(buf,(length >> (8*ber_len)) & 0xff);
++ }
++ }
++ return CKYSUCCESS;
++}
++/*
++ * do a PIV Sign/Decrypt
++ */
++CKYStatus
++PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key, unsigned int keySize, int
derive,
++ const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC)
++{
++ CKYStatus ret;
++ CKYSize dataSize = CKYBuffer_Size(data);
++ CKYSize outputSize = keySize;
++ CKYOffset offset = 0;
++ CKYBuffer tmp;
++ CKYByte alg;
++ int ber_len_1;
++ int ber_len_2;
++ int length;
++ PIVAppletArgSignDecrypt pasd;
++ PIVAppletRespSignDecrypt prsd;
++
++ /* PIV only defines RSA 1024 and 2048, ECC 256 and ECC 384!!! */
++ if (keySize == 128) { /* 1024 bit == 128 bytes */
++ ber_len_2 = 2;
++ ber_len_1 = 2;
++ alg = 0x6;
++ } else if (keySize == 256) { /* 2048 bits == 256 bytes */
++ ber_len_2 = 3;
++ ber_len_1 = 3;
++ alg = 0x7;
++ } else if (keySize == 32) { /* 256 bits = 32 bytes */
++ ber_len_2 = 1;
++ ber_len_1 = 1;
++ alg = 0x11;
++ if (!derive) outputSize = keySize*2;
++ } else if (keySize == 48) { /* 384 bits = 48 bytes */
++ ber_len_2 = 1;
++ ber_len_1 = 1;
++ alg = 0x14;
++ if (!derive) outputSize = keySize*2;
++ } else {
++ return CKYINVALIDARGS;
++ }
++
++ CKYBuffer_InitEmpty(&tmp);
++ ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ CKYBuffer_AppendChar(&tmp,0x7c);
++ piv_wrapEncodeLength(&tmp,dataSize + ber_len_2 + 3,ber_len_1);
++ CKYBuffer_AppendChar(&tmp,0x82);
++ CKYBuffer_AppendChar(&tmp,0x0);
++ CKYBuffer_AppendChar(&tmp, derive ? 0x85 : 0x81);
++ piv_wrapEncodeLength(&tmp,dataSize,ber_len_2);
++
++ /* now length == header length from here to the end*/
++ length = CKYBuffer_Size(&tmp);
++
++ if (length + dataSize > CKY_MAX_WRITE_CHUNK_SIZE) {
++ CKYBuffer_AppendBuffer(&tmp, data, 0, CKY_MAX_WRITE_CHUNK_SIZE-length);
++ } else {
++ CKYBuffer_AppendBuffer(&tmp, data, 0, dataSize);
++ }
++
++ prsd.tag_1.tag = 0;
++ prsd.tag_1.length_bytes = -1;
++ prsd.tag_1.length = 0;
++ prsd.tag_2.tag = 0;
++ prsd.tag_2.length_bytes = -1;
++ prsd.tag_2.length = 0;
++ prsd.buf = result;
++ pasd.alg = alg;
++ pasd.key = key;
++ pasd.buf = &tmp;
++
++ CKYBuffer_Resize(result,0);
++ for(offset = -length; (dataSize-offset) > CKY_MAX_WRITE_CHUNK_SIZE; ) {
++ pasd.chain = 1;
++ pasd.len = 0;
++ ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt,
++ &pasd, NULL, CKY_SIZE_UNKNOWN,
++ pivAppletFill_AppendUnwrapBuffer,
++ &prsd, apduRC);
++ if (ret != CKYSUCCESS) {
++ goto done;
++ }
++ CKYBuffer_Resize(&tmp,0);
++ /* increment before we append the next tmp buffer */
++ offset += CKY_MAX_WRITE_CHUNK_SIZE;
++ CKYBuffer_AppendBuffer(&tmp, data, offset,
++ MIN(dataSize-offset, CKY_MAX_WRITE_CHUNK_SIZE));
++ }
++
++ pasd.chain = 0;
++ pasd.len = outputSize;
++
++ ret = CKYApplet_HandleAPDU(conn, PIVAppletFactory_SignDecrypt,
++ &pasd, NULL, CKY_SIZE_UNKNOWN,
++ pivAppletFill_AppendUnwrapBuffer,
++ &prsd, apduRC);
++
++ if ((ret == CKYSUCCESS) && (CKYBuffer_Size(result) != outputSize)) {
++ /* RSA returns the same data size as input, didn't happen, so
++ * something is wrong. */
++ }
++
++done:
++ CKYBuffer_FreeData(&tmp);
++ return ret;
++}
++
++/*
++ * PIN cluster
++ */
++CKYStatus
++CKYApplet_CreatePIN(CKYCardConnection *conn, CKYByte pinNumber,
++ CKYByte maxAttempts, const char *pinValue,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgCreatePIN cpd;
++ cpd.pinValue = pinValue;
++ cpd.maxAttempts = maxAttempts;
++ cpd.pinValue = pinValue;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_CreatePIN, &cpd, nonce,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++
++}
++
++CKYStatus
++CKYApplet_VerifyPIN(CKYCardConnection *conn, CKYByte pinNumber,
++ const char *pinValue, CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgVerifyPIN vpd;
++ vpd.pinValue = pinValue;
++ vpd.pinNumber = pinNumber;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_VerifyPIN, &vpd, NULL,
++ 8, CKYAppletFill_ReplaceBuffer, nonce, apduRC);
++}
++
++CKYStatus
++CKYApplet_ChangePIN(CKYCardConnection *conn, const char *oldPin,
++ const char *newPin, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgChangePIN cpd;
++ cpd.oldPin = oldPin;
++ cpd.newPin = newPin;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ChangePIN, &cpd, nonce,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++CKYApplet_ListPINs(CKYCardConnection *conn, unsigned short *pins,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ListPINs, NULL, NULL,
++ CKY_SIZE_LIST_PINS, CKYAppletFill_Short, pins, apduRC);
++}
++
++CKYStatus
++CKYApplet_Logout(CKYCardConnection *conn, CKYByte pinNumber,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_Logout, &pinNumber, nonce,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++CKYApplet_CreateObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYSize size, unsigned short readACL, unsigned short writeACL,
++ unsigned short deleteACL, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgCreateObject cod;
++ cod.objectID = objectID;
++ cod.size = size;
++ cod.readACL = readACL;
++ cod.writeACL = writeACL;
++ cod.deleteACL = deleteACL;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_CreateObject, &cod,
++ nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++CKYApplet_DeleteObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYByte zero, const CKYBuffer *nonce, CKYISOStatus *apduRC)
++{
++ CKYAppletArgDeleteObject dod;
++ dod.objectID = objectID;
++ dod.zero = zero;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_DeleteObject, &dod,
++ nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++/*
++ * Read Object cluster...
++ * This is the raw version that goes issues a single APDU.
++ */
++CKYStatus
++CKYApplet_ReadObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYOffset offset, CKYByte size, const CKYBuffer *nonce,
++ CKYBuffer *data, CKYISOStatus *apduRC)
++{
++ CKYAppletArgReadObject rod;
++
++ rod.objectID = objectID;
++ rod.offset = offset;
++ rod.size = size;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ReadObject, &rod, nonce,
++ size, CKYAppletFill_ReplaceBuffer, data, apduRC);
++}
++
++/*
++ * Read Object Append cluster...
++ * This is also issues a single APDU, but appends the resulting data
++ * to an existing buffer.
++ */
++
++CKYStatus
++CKYApplet_ReadObjectAppend(CKYCardConnection *conn, unsigned long objectID,
++ CKYOffset offset, CKYByte size, const CKYBuffer *nonce,
++ CKYBuffer *data, CKYISOStatus *apduRC)
++{
++ CKYAppletArgReadObject rod;
++
++ rod.objectID = objectID;
++ rod.offset = offset;
++ rod.size = size;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ReadObject, &rod, nonce,
++ size, CKYAppletFill_AppendBuffer, data, apduRC);
++}
++
++/*
++ * Read Object
++ * This is makes multiple APDU calls to read the entire object.
++ */
++CKYStatus
++CKYApplet_ReadObjectFull(CKYCardConnection *conn, unsigned long objectID,
++ CKYOffset offset, CKYSize size, const CKYBuffer *nonce,
++ CKYBuffer *data, CKYISOStatus *apduRC)
++{
++ CKYAppletArgReadObject rod;
++ CKYStatus ret = CKYSUCCESS;
++
++ rod.objectID = objectID;
++ rod.offset = offset;
++ do {
++ rod.size = (CKYByte) MIN(size, CKY_MAX_READ_CHUNK_SIZE);
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_ReadObject, &rod,
++ nonce, rod.size, CKYAppletFill_AppendBuffer, data, apduRC);
++ size -= rod.size;
++ rod.offset += rod.size;
++ } while ((size > 0) && (ret == CKYSUCCESS));
++
++ return ret;
++}
++
++
++/*
++ * Write Object
++ * This makes multiple APDU calls to write the entire object.
++ *
++ */
++
++CKYStatus
++CKYApplet_WriteObjectFull(CKYCardConnection *conn, unsigned long objectID,
++ CKYOffset offset, CKYSize size, const CKYBuffer *nonce,
++ const CKYBuffer *data, CKYISOStatus *apduRC)
++{
++
++ CKYBuffer chunk;
++ CKYOffset srcOffset = 0;
++ CKYAppletArgWriteObject wod;
++ CKYStatus ret = CKYSUCCESS;
++
++ wod.objectID = objectID;
++ wod.offset = offset;
++ do {
++ wod.size = (CKYByte) MIN(size, 220);
++ ret = CKYBuffer_InitFromBuffer(&chunk, data,
++ srcOffset, wod.size);
++ if(ret == CKYSUCCESS) {
++ wod.data = &chunk;
++ ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_WriteObject, &wod,
++ nonce, 0, CKYAppletFill_Null, NULL, apduRC);
++ size -= wod.size;
++ wod.offset += wod.size;
++ srcOffset += wod.size;
++ CKYBuffer_FreeData(&chunk);
++ }
++
++ } while ((size > 0) && (ret == CKYSUCCESS));
++
++ return ret;
++}
++
++/*
++ * List Object cluster
++ */
++static CKYStatus
++ckyAppletFill_ListObjects(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespListObjects *lop = (CKYAppletRespListObjects *)param;
++
++ lop->objectID = CKYBuffer_GetLong(response, 0);
++ lop->objectSize = CKYBuffer_GetLong(response, 4);
++ lop->readACL = CKYBuffer_GetShort(response, 8);
++ lop->writeACL = CKYBuffer_GetShort(response, 10);
++ lop->deleteACL = CKYBuffer_GetShort(response, 12);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_ListObjects(CKYCardConnection *conn, CKYByte seq,
++ CKYAppletRespListObjects *lop, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_ListObjects, &seq, NULL,
++ CKY_SIZE_LIST_OBJECTS, ckyAppletFill_ListObjects, lop, apduRC);
++}
++
++/*
++ * GetStatus cluster
++ */
++static CKYStatus
++ckyAppletFill_GetStatus(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespGetStatus *gsp = (CKYAppletRespGetStatus *)param;
++
++ gsp->protocolMajorVersion = CKYBuffer_GetChar(response, 0);
++ gsp->protocolMinorVersion = CKYBuffer_GetChar(response, 1);
++ gsp->appletMajorVersion = CKYBuffer_GetChar(response, 2);
++ gsp->appletMinorVersion = CKYBuffer_GetChar(response, 3);
++ gsp->totalObjectMemory = CKYBuffer_GetLong(response, 4);
++ gsp->freeObjectMemory = CKYBuffer_GetLong(response, 8);
++ gsp->numberPins = CKYBuffer_GetChar(response, 12);
++ gsp->numberKeys = CKYBuffer_GetChar(response, 13);
++ gsp->loggedInMask = CKYBuffer_GetShort(response, 14);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetStatus(CKYCardConnection *conn, CKYAppletRespGetStatus *status,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetStatus, NULL, NULL,
++ CKY_SIZE_GET_STATUS, ckyAppletFill_GetStatus, status, apduRC);
++}
++
++CKYStatus
++CKYApplet_Noop(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_Noop, NULL, NULL,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++CKYStatus
++CKYApplet_GetBuildID(CKYCardConnection *conn, unsigned long *buildID,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetBuildID, NULL, NULL,
++ CKY_SIZE_GET_BUILDID, CKYAppletFill_Long, buildID, apduRC);
++}
++
++/*
++ * GetLifeCycle cluster
++ */
++static CKYStatus
++ckyAppletFill_GetLifeCycle(const CKYBuffer *response, CKYSize size, void *param)
++{
++ *(CKYByte *)param= CKYBuffer_GetChar(response,0);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetLifeCycle(CKYCardConnection *conn, CKYByte *personalized,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetLifeCycle, NULL, NULL,
++ CKY_SIZE_GET_LIFE_CYCLE, ckyAppletFill_GetLifeCycle, personalized, apduRC);
++}
++
++static CKYStatus
++ckyAppletFill_GetLifeCycleV2(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespGetLifeCycleV2 *ext = (CKYAppletRespGetLifeCycleV2 *) param;
++ ext->lifeCycle = CKYBuffer_GetChar(response,0);
++ ext->pinCount = CKYBuffer_GetChar(response,1);
++ ext->protocolMajorVersion = CKYBuffer_GetChar(response,2);
++ ext->protocolMinorVersion = CKYBuffer_GetChar(response,3);
++ return CKYSUCCESS;
++}
++
++/*
++ * GetStatus cluster
++ */
++static CKYStatus
++ckyAppletFill_LifeCycleStatus(const CKYBuffer *response, CKYSize size, void *param)
++{
++ CKYAppletRespGetLifeCycleV2 *ext = (CKYAppletRespGetLifeCycleV2 *) param;
++ ext->pinCount = CKYBuffer_GetChar(response,12);
++ ext->protocolMajorVersion = CKYBuffer_GetChar(response,0);
++ ext->protocolMinorVersion = CKYBuffer_GetChar(response,1);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetLifeCycleV2(CKYCardConnection *conn,
++ CKYAppletRespGetLifeCycleV2 *ext, CKYISOStatus *apduRC)
++{
++ CKYStatus status;
++ status = CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetLifeCycleV2,
++ NULL,NULL, CKY_SIZE_GET_LIFE_CYCLE_V2, ckyAppletFill_GetLifeCycleV2,
++ ext, apduRC);
++
++ /* Get Life Cycle Version 2 is a new APDU with combines data from
++ * two other APDUs. Older tokens don't have this APDU, so use
++ * the old method to get the data */
++ if (status == CKYAPDUFAIL) {
++ status = CKYApplet_GetLifeCycle(conn,&ext->lifeCycle, apduRC);
++ if (status != CKYSUCCESS) {
++ return status;
++ }
++ status = CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetStatus, NULL,
++ NULL, CKY_SIZE_GET_STATUS, ckyAppletFill_LifeCycleStatus, ext, apduRC);
++ }
++ return status;
++}
++
++/*
++ * GetBuiltin cluster
++ */
++static CKYStatus
++ckyAppletFill_GetBuiltinACL(const CKYBuffer *response,CKYSize size,void *param)
++{
++ CKYAppletRespGetBuiltinACL *gba = (CKYAppletRespGetBuiltinACL *) param;
++ gba->create_object_ACL = CKYBuffer_GetShort(response,0);
++ gba->create_object_ACL = CKYBuffer_GetShort(response,2);
++ gba->create_object_ACL = CKYBuffer_GetShort(response,4);
++ gba->enable_ACL_change = CKYBuffer_GetChar(response,6);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYApplet_GetBuiltinACL(CKYCardConnection *conn,
++ CKYAppletRespGetBuiltinACL *gba, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetBuiltinACL, NULL,
++ NULL, CKY_SIZE_GET_BUILTIN_ACL, ckyAppletFill_GetBuiltinACL, gba,
++ apduRC);
++}
++
++CKYStatus
++CKYApplet_GetIssuerInfo(CKYCardConnection *conn, CKYBuffer *info,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetIssuerInfo, NULL,
++ NULL, CKY_SIZE_GET_ISSUER_INFO, CKYAppletFill_ReplaceBuffer,
++ info, apduRC);
++}
++
++CKYStatus
++CKYApplet_GetRandom(CKYCardConnection *conn, CKYBuffer *data, CKYByte len,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetRandom, &len,
++ NULL, len, CKYAppletFill_ReplaceBuffer, data, apduRC);
++}
++
++CKYStatus
++CKYApplet_GetRandomAppend(CKYCardConnection *conn, CKYBuffer *data, CKYByte len,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_GetRandom, &len,
++ NULL, len, CKYAppletFill_AppendBuffer, data, apduRC);
++}
++
++CKYStatus
++CKYApplet_SeedRandom(CKYCardConnection *conn, const CKYBuffer *data,
++ CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_SeedRandom, data,
++ NULL, 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++
++
++/*
++ * deprecates 0.x functions
++ */
++/* old applet verify pin call (no nonce returned) */
++CKYStatus
++CKYApplet_VerifyPinV0(CKYCardConnection *conn, CKYByte pinNumber,
++ const char *pinValue, CKYISOStatus *apduRC)
++{
++ CKYAppletArgVerifyPIN vpd;
++ vpd.pinValue = pinValue;
++ vpd.pinNumber = pinNumber;
++
++ vpd.pinValue = pinValue;
++ vpd.pinNumber = pinNumber;
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_VerifyPIN, &vpd, NULL,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++}
++
++/* logout all */
++CKYStatus
++CKYApplet_LogoutAllV0(CKYCardConnection *conn, CKYISOStatus *apduRC)
++{
++ return CKYApplet_HandleAPDU(conn, CKYAppletFactory_LogoutAllV0, NULL, NULL,
++ 0, CKYAppletFill_Null, NULL, apduRC);
++}
+diff -up ./esc/src/lib/coolkey/cky_applet.h.fix1 ./esc/src/lib/coolkey/cky_applet.h
+--- ./esc/src/lib/coolkey/cky_applet.h.fix1 2018-04-26 11:44:38.436986198 -0700
++++ ./esc/src/lib/coolkey/cky_applet.h 2018-04-26 11:44:38.436986198 -0700
+@@ -0,0 +1,680 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_APPLET_H
++#define CKY_APPLET_H 1
++
++#include "cky_base.h"
++#include "cky_card.h"
++#include "cky_factory.h"
++
++/*
++ * base typdefs
++ */
++/*
++ * ISO and applet response codes.
++ */
++typedef unsigned short CKYISOStatus; /* applet return status */
++/* Psuedo return codes created by the library software */
++#define CKYISO_INVRESPONSE 0xffff /* code returned by library to
++ * indicate no valid response
++ * received */
++#define CKYISO_NORESPONSE 0x0000 /* code returned by the library if
++ * operation failed before
++ * attempting to read a response */
++/* ISO defined Return codes */
++#define CKYISO_SUCCESS 0x9000 /* SUCCESS! */
++#define CKYISO_MORE_MASK 0xff00 /* More data mask */
++#define CKYISO_MORE 0x6300 /* More data available */
++#define CKYISO_DATA_INVALID 0x6984
++#define CKYISO_CONDITION_NOT_SATISFIED 0x6985 /* AKA not logged in (CAC)*/
++#define CKYISO_SECURITY_NOT_SATISFIED 0x6982 /* AKA not logged in (PIV)*/
++/* Applet Defined Return codes */
++#define CKYISO_NO_MEMORY_LEFT 0x9c01 /* There have been memory
++ * problems on the card */
++#define CKYISO_AUTH_FAILED 0x9c02 /* Entered PIN is not correct */
++#define CKYISO_OPERATION_NOT_ALLOWED 0x9c03 /* Required operation is not
++ * allowed in actual
++ * circumstances */
++#define CKYISO_UNSUPPORTED_FEATURE 0x9c05 /* Required feature is not (yet)
++ * supported */
++#define CKYISO_UNAUTHORIZED 0x9c06 /* Required operation was not
++ * authorized because of a lack of
++ * privileges */
++#define CKYISO_OBJECT_NOT_FOUND 0x9c07 /* Required object is missing */
++#define CKYISO_OBJECT_EXISTS 0x9c08 /* New object ID already in use */
++#define CKYISO_INCORRECT_ALG 0x9c09 /* Algorithm specified is not
++ * correct */
++#define CKYISO_SIGNATURE_INVALID 0x9c0b /* Verify operation detected an
++ * invalid signature */
++#define CKYISO_IDENTITY_BLOCKED 0x9c0c /* Operation has been blocked for
++ * security reason */
++#define CKYISO_INVALID_PARAMETER 0x9c0f /* Invalid input parameter to
++ * command */
++#define CKYISO_INCORRECT_P1 0x9c10 /* Incorrect P1 parameter */
++#define CKYISO_INCORRECT_P2 0x9c11 /* Incorrect P2 parameter */
++#define CKYISO_SEQUENCE_END 0x9c12 /* No more data available */
++#define CKYISO_INTERNAL_ERROR 0x9cff /* Reserved for debugging,
++ * shouldn't happen */
++
++#define CAC_INVALID_PARAMS 0x6a83
++#define CAC_TAG_FILE 1
++#define CAC_VALUE_FILE 2
++
++
++#define CAC_TAG_CARDURL 0xf3
++#define CAC_TAG_CERTIFICATE 0x70
++#define CAC_TAG_CERTINFO 0x71
++#define CAC_TLV_APP_PKI 0x04
++
++/*
++ * Pin Constants as used by our applet
++ */
++#define CKY_OLD_USER_PIN_NUM 1 /* version 0 and earlier */
++#define CKY_USER_PIN_NUM 0
++
++/*
++ * special size that tells the Verify Function not to verify the size because
++ * the ADPU can return variable size.
++ */
++#define CKY_SIZE_UNKNOWN 0xffffffff
++
++/*
++ * structures for returning Applet responses
++ */
++typedef struct _CKYAppletRespGetStatus {
++ CKYByte protocolMajorVersion;
++ CKYByte protocolMinorVersion;
++ CKYByte appletMajorVersion;
++ CKYByte appletMinorVersion;
++ unsigned long totalObjectMemory;
++ unsigned long freeObjectMemory;
++ CKYByte numberPins;
++ CKYByte numberKeys;
++ unsigned short loggedInMask;
++} CKYAppletRespGetStatus;
++
++typedef struct _CKYAppletRespGetLifeCycleV2 {
++ CKYByte lifeCycle;
++ CKYByte pinCount;
++ CKYByte protocolMajorVersion;
++ CKYByte protocolMinorVersion;
++} CKYAppletRespGetLifeCycleV2;
++
++typedef struct _CKYAppletRespGetBuiltinACL {
++ unsigned short create_object_ACL;
++ unsigned short create_key_ACL;
++ unsigned short create_pin_ACL;
++ CKYByte enable_ACL_change;
++} CKYAppletRespGetBuiltinACL;
++
++typedef struct _CKYAppletRespGetCPLCData {
++ unsigned short CPLCtag;
++ CKYByte length;
++ unsigned short fabricator;
++ unsigned short romType;
++ unsigned short romOSID;
++ unsigned short romOSDate;
++ unsigned short romOSLevel;
++ unsigned short eepromFabricationDate;
++ unsigned long eepromSerialNumber;
++ unsigned short eepromBatchID;
++ unsigned short eepromModuleFabricator;
++ unsigned short eepromModuleDate;
++ unsigned short eepromICManufacturer;
++ unsigned short eepromEmbeddingDate;
++ unsigned short eepromPrePersonalizer;
++ unsigned short eepromPrePersonalizeDate;
++ unsigned long eepromPrePersonalizeID;
++ unsigned short eepromPersonalizer;
++ unsigned short eepromPersonalizeDate;
++ unsigned long eepromPersonalizeID;
++} CKYAppletRespGetCPLCData;
++
++typedef struct _CKYAppletRespListObjects {
++ unsigned long objectID;
++ CKYSize objectSize;
++ unsigned short readACL;
++ unsigned short writeACL;
++ unsigned short deleteACL;
++} CKYAppletRespListObjects;
++
++typedef struct _CKYAppletRespListKeys {
++ CKYByte keyNum;
++ CKYByte keyType;
++ CKYByte keyPartner;
++ unsigned short keySize;
++ unsigned short readACL;
++ unsigned short writeACL;
++ unsigned short useACL;
++} CKYAppletRespListKeys;
++
++/*
++ * structures for the generic factories
++ */
++typedef struct _CKYAppletArgCreatePIN {
++ const char *pinValue;
++ CKYByte pinNumber;
++ CKYByte maxAttempts;
++} CKYAppletArgCreatePIN;
++
++typedef struct _CKYAppletArgVerifyPIN {
++ const char *pinValue;
++ CKYByte pinNumber;
++} CKYAppletArgVerifyPIN;
++
++typedef struct _CKYAppletArgChangePIN {
++ const char *oldPin;
++ const char *newPin;
++ CKYByte pinNumber;
++} CKYAppletArgChangePIN;
++
++typedef struct _CKYAppletArgCreateObject {
++ unsigned long objectID;
++ CKYSize size;
++ unsigned short readACL;
++ unsigned short writeACL;
++ unsigned short deleteACL;
++} CKYAppletArgCreateObject;
++
++typedef struct _CKYAppletArgDeleteObject {
++ unsigned long objectID;
++ CKYByte zero;
++} CKYAppletArgDeleteObject;
++
++typedef struct _CKYAppletArgReadObject {
++ unsigned long objectID;
++ CKYOffset offset;
++ CKYByte size;
++} CKYAppletArgReadObject;
++
++
++typedef struct _CKYAppletArgWriteObject {
++ unsigned long objectID;
++ CKYOffset offset;
++ CKYByte size;
++ CKYBuffer *data;
++
++} CKYAppletArgWriteObject;
++
++typedef struct _CKYAppletArgComputeCrypt {
++ CKYByte keyNumber;
++ CKYByte mode;
++ CKYByte direction;
++ CKYByte location;
++ const CKYBuffer *data;
++ const CKYBuffer *sig;
++} CKYAppletArgComputeCrypt;
++
++typedef struct _CKYAppletArgComputeECCSignature {
++ CKYByte keyNumber;
++ CKYByte location;
++ const CKYBuffer *data;
++ const CKYBuffer *sig;
++} CKYAppletArgComputeECCSignature;
++
++typedef struct _CKYAppletArgComputeECCKeyAgreement {
++ CKYByte keyNumber;
++ CKYByte location;
++ const CKYBuffer *publicValue;
++ const CKYBuffer *secretKey;
++} CKYAppletArgComputeECCKeyAgreement;
++
++
++typedef struct _CACAppletArgReadFile {
++ CKYByte type;
++ CKYByte count;
++ unsigned short offset;
++} CACAppletArgReadFile;
++
++typedef struct _PIVAppletArgSignDecrypt {
++ CKYByte alg;
++ CKYByte key;
++ CKYByte chain;
++ CKYSize len;
++ CKYBuffer *buf;
++} PIVAppletArgSignDecrypt;
++
++typedef struct _pivUnwrapState {
++ CKYByte tag;
++ CKYByte length;
++ int length_bytes;
++} PIVUnwrapState;
++
++typedef struct _PIVAppletRespSignDecrypt {
++ PIVUnwrapState tag_1;
++ PIVUnwrapState tag_2;
++ CKYBuffer *buf;
++} PIVAppletRespSignDecrypt;
++
++typedef struct _P15AppletArgReadRecord {
++ CKYByte record;
++ CKYByte short_ef;
++ CKYByte flags;
++ CKYByte size;
++} P15AppletArgReadRecord;
++
++typedef struct _P15AppletArgReadBinary {
++ unsigned short offset;
++ CKYByte short_ef;
++ CKYByte flags;
++ CKYByte size;
++} P15AppletArgReadBinary;
++
++typedef struct _P15AppletArgVerifyPIN {
++ const CKYBuffer *pinVal;
++ CKYByte pinRef;
++} P15AppletArgVerifyPIN;
++
++typedef struct _P15AppletArgManageSecurityEnvironment {
++ CKYByte p1;
++ CKYByte p2;
++ CKYByte keyRef;
++}
++ P15AppletArgManageSecurityEnvironment;
++
++typedef struct _P15AppletArgPerformSecurityOperation {
++ CKYByte dir;
++ int chain;
++ CKYSize retLen;
++ const CKYBuffer *data;
++} P15AppletArgPerformSecurityOperation;
++
++/* fills in an APDU from a structure -- form of all the generic factories*/
++typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param);
++/* fills in an a structure from a response -- form of all the fill structures*/
++typedef CKYStatus (*CKYFillFunction)(const CKYBuffer *response,
++ CKYSize size, void *param);
++
++CKY_BEGIN_PROTOS
++/*****************************************************************
++ *
++ * Generic factorys are used by the generic APDU processing
++ * to customize the formatting of APDU. The all have the same signature
++ * as CKYAppletFactory. Typically APDUs are formatted
++ * using parameterized calls of the form CKYAPDUFactory_ADPUNAME.
++ * The generic processing code, however needs calls with a common
++ * Signature. To accomplish the conversion, we build generic versions
++ * which take a void * parameter. Trivial APDU's can pass NULL or a pointer
++ * to the single parameter that they need. More complicated APDU's use
++ * CKYAppletArg* data structures defined above to pass more arguments.
++ *
++ * Generic factorys then call the standard CKYAPDUFactor_ADPUNAME() functions
++ * to build the APDUs. These functions are intended only as arguments
++ * to the generic ADPU calls, and not to be called directly.
++ *
++ *****************************************************************/
++/* param == CKYBuffer * (AID) */
++CKYStatus CKYAppletFactory_SelectFile(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_SelectCardManager(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetCPLCData(CKYAPDU *apdu, const void *param);
++/* param == CKYByte * (pointer to seq) */
++CKYStatus CKYAppletFactory_ListKeys(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgComputeCrypt */
++CKYStatus CKYAppletFactory_ComputeCryptInit(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgComputeCrypt */
++CKYStatus CKYAppletFactory_ComputeCryptProcess(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgComputeCrypt */
++CKYStatus CKYAppletFactory_ComputeCryptFinal(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgCreatePIN */
++CKYStatus CKYAppletFactory_CreatePIN(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgVeriryPIN */
++CKYStatus CKYAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgChangePIN */
++CKYStatus CKYAppletFactory_ChangePIN(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_ListPINs(CKYAPDU *apdu, const void *param);
++/* param == CKYByte * (pointer to pinNumber) */
++CKYStatus CKYAppletFactory_Logout(CKYAPDU *apdu, const void *param);
++/* Future add WriteObject */
++/* parm == CKYAppletArgWriteObject */
++CKYStatus CKYAppletFactory_WriteObject(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgCreateObject */
++CKYStatus CKYAppletFactory_CreateObject(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgDeleteObject */
++CKYStatus CKYAppletFactory_DeleteObject(CKYAPDU *apdu, const void *param);
++/* param == CKYAppletArgReadObject */
++CKYStatus CKYAppletFactory_ReadObject(CKYAPDU *apdu, const void *param);
++/* param == CKYByte * (pointer to seq) */
++CKYStatus CKYAppletFactory_ListObjects(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetStatus(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_Noop(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetBuildID(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetLifeCycle(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetLifeCycleV2(CKYAPDU *apdu, const void *param);
++/* param == CKYByte * */
++CKYStatus CKYAppletFactory_GetRandom(CKYAPDU *apdu, const void *param);
++/* param == CKY_Buffer */
++CKYStatus CKYAppletFactory_SeedRandom(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetIssuerInfo(CKYAPDU *apdu, const void *param);
++/* param == NULL */
++CKYStatus CKYAppletFactory_GetBuiltinACL(CKYAPDU *apdu, const void *param);
++/* deprecates 0.x functions */
++/* param == NULL */
++CKYStatus CKYAppletFactory_LogoutAllV0(CKYAPDU *apdu, const void *param);
++
++/*****************************************************************
++ *
++ * Generic Fill routines used by the generic APDU processing
++ * to customize how the response data is returned to the application.
++ * generally the param points to some structure which is filled in
++ * by the Fill function from the response data. Each APDU command
++ * can potentially have it's own fill function. Different appearent
++ * functions can be accomplished by calling the same APDU with a different
++ * fill function. The fill functions below are considered globally interesting
++ * to applications that wish to make custom APDU calls using the
++ * applet generic processing. Fill functions are never called directly,
++ * but through callback, and all have the same signature (CKYFillFunction)
++ *
++ *****************************************************************/
++/* a null fill function for those APDU's which do not return data */
++CKYStatus CKYAppletFill_Null(const CKYBuffer *response, CKYSize size, void *param);
++/* Buffer Fills: */
++/* Replace fill function for those APDU's which return raw data */
++/* param == CKYBuffer * */
++CKYStatus CKYAppletFill_ReplaceBuffer(const CKYBuffer *response, CKYSize size,
++ void *param);
++/* Append fill function can be used with any APDU that uses Buffer
++ * Replace. Repeated calls continuously adds more data to the buffer.
++ * Useful for repeated operations like read. */
++/* param == CKYBuffer * */
++CKYStatus CKYAppletFill_AppendBuffer(const CKYBuffer *response,
++ CKYSize size, void *param);
++/* Single value fills: Byte, Short, & Long */
++/* param == CKYByte * */
++CKYStatus CKYAppletFill_Byte(const CKYBuffer *response, CKYSize size, void *param);
++CKYStatus CKYAppletFill_Short(const CKYBuffer *response, CKYSize size, void *param);
++CKYStatus CKYAppletFill_Long(const CKYBuffer *response, CKYSize size, void *param);
++
++/*****************************************************************
++ *
++ * Utilities shared by all the fetch Cards.
++ *
++ *****************************************************************/
++/*
++ * verify the we got a successful response. Responses should include
++ * the expected data returned plus a 2 byte return code. This return
++ * code should be 0x9000 on success. The function copies the return code
++ * to apduRC if apduRC is not NULL.
++ */
++CKYBool CKYApplet_VerifyResponse(const CKYBuffer *response, CKYSize dataSize,
++ CKYISOStatus *apduRC);
++/*
++ * most commands have identical operations. This function
++ * handles these operations, isolating the differences in
++ * call back functions.
++ * It creates the ADPU using afFunc with afArg.
++ * Adds nonce if it exists.
++ * Sends the ADPU to the card through the connection conn.
++ * Checks that the response was valid (returning the responce code in apduRC.
++ * Formats the response data into fillArg with fillFunc
++ * nonce and apduRC can be NULL (no nonce is added, no status returned
++ * legal values for afArg are depened on afFunc.
++ * legal values for fillArg are depened on fillFunc.
++ */
++CKYStatus CKYApplet_HandleAPDU(CKYCardConnection *conn,
++ CKYAppletFactory afFunc, const void *afArg,
++ const CKYBuffer *nonce, CKYSize size,
++ CKYFillFunction fillFunc, void *fillArg, CKYISOStatus *apduRC);
++
++
++/*****************************************************************
++ *
++ * The following convience functions convert APDU calls
++ * into function calls, with input and output parameters.
++ * The application is still responsible for
++ * 1) creating a connection to the card,
++ * 2) Getting a transaction lock, then
++ * 3) selecting the appropriate applet (or Card manager).
++ * Except for those calls that have been noted, the appropriate applet
++ * is the CoolKey applet.
++ *
++ *****************************************************************/
++/* Select an applet. Can happen with either applet selected */
++CKYStatus CKYApplet_SelectFile(CKYCardConnection *conn, const CKYBuffer *AID,
++ CKYISOStatus *apduRC);
++
++/* Select the CoolKey applet. Special case of the above command */
++/* Can happen with either applet selected */
++CKYStatus CKYApplet_SelectCoolKeyManager(CKYCardConnection *conn,
++ CKYISOStatus *apduRC);
++
++/* Select the card manager. Can happen with either applet selected */
++CKYStatus CKYApplet_SelectCardManager(CKYCardConnection *conn,
++ CKYISOStatus *apduRC);
++/* GetCPLC data -- must be called with CM selected */
++/* fills in cplc */
++CKYStatus CKYApplet_GetCPLCData(CKYCardConnection *conn,
++ CKYAppletRespGetCPLCData *cplc, CKYISOStatus *apduRC);
++/* Get CUID. -- must be called with CM selected */
++/* special case of GetCPLCData */
++/* fills in cuid */
++CKYStatus CKYApplet_GetCUID(CKYCardConnection *conn,
++ CKYBuffer *cuid, CKYISOStatus *apduRC);
++/* Get MSN. -- must be called with CM selected */
++/* special case of GetCPLCData */
++/* returns msn */
++CKYStatus CKYApplet_GetMSN(CKYCardConnection *conn, unsigned long *msn,
++ CKYISOStatus *apduRC);
++
++/* List Keys -- see applet documentation */
++CKYStatus CKYApplet_ListKeys(CKYCardConnection *conn, CKYByte seq,
++ CKYAppletRespListKeys *lkp, CKYISOStatus *apduRC);
++/*
++ * Compute Crypt Cluster.
++ *
++ * Compute Crypt takes 3 phases: Init, Process, Final.
++ * Applications can call each phase separately using:
++ * CKYApplet_ComputeCryptInit
++ * CKYApplet_ComputeCryptProcess
++ * CKYApplet_ComputeCryptFinal
++ * or call all three in one set with:
++ * CKYApplet_ComputeCrypt
++ * Buffer values passed to Compute crypt should be raw data.
++ * The helper functions format the 2 byte length data required by the
++ * applet automatically.
++ */
++CKYStatus CKYApplet_ComputeCryptInit(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, CKYByte location,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_ComputeCryptProcess(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data, const CKYBuffer *nonce,
++ CKYISOStatus *apduRC);
++CKYStatus CKYApplet_ComputeCryptFinal(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data, CKYBuffer *sig, CKYBuffer *result,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC);
++/** ...look to data size to see if we should read/write the data to
++ * the on card buffer. (future) */
++CKYStatus CKYApplet_ComputeCrypt(CKYCardConnection *conn, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, const CKYBuffer *data, CKYBuffer *sig,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++/* Pin Command -- see applet documentation for use */
++CKYStatus CKYApplet_CreatePIN(CKYCardConnection *conn, CKYByte pinNumber,
++ CKYByte maxAttempts, const char *pinValue,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_VerifyPIN(CKYCardConnection *conn, CKYByte pinNumber,
++ const char *pinValue, CKYBuffer *nonce, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_ChangePIN(CKYCardConnection *conn, const char *oldPin,
++ const char *newPin, const CKYBuffer *nonce,
++ CKYISOStatus *apduRC);
++CKYStatus CKYApplet_ListPINs(CKYCardConnection *conn, unsigned short *pins,
++ CKYISOStatus *apduRC);
++CKYStatus CKYApplet_Logout(CKYCardConnection *conn, CKYByte pinNumber,
++ const CKYBuffer *nonce, CKYISOStatus *apduRC);
++/* Object Commands -- see applet documentation for use */
++CKYStatus CKYApplet_CreateObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYSize size, unsigned short readACL, unsigned short writeACL,
++ unsigned short deleteACL, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_DeleteObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYByte zero, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++
++/* CAC commands */
++/* Select one of the CAC PKI applets. Special case of CKYApplet_SelectFile */
++/* Select the CAC card manager. Can happen with either applet selected */
++CKYStatus CACApplet_SelectCardManager(CKYCardConnection *conn,
++ CKYISOStatus *apduRC);
++/* Select the CAC CC container. Can happen with either applet selected */
++CKYStatus CACApplet_SelectCCC(CKYCardConnection *conn, CKYISOStatus *apduRC);
++/* Select an old CAC applet and fill in the cardAID */
++CKYStatus CACApplet_SelectPKI(CKYCardConnection *conn, CKYBuffer *cardAid,
++ CKYByte instance, CKYISOStatus *apduRC);
++/* read a TLV file */
++CKYStatus CACApplet_ReadFile(CKYCardConnection *conn, CKYByte type,
++ CKYBuffer *buffer, CKYISOStatus *apduRC);
++CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC);
++
++
++/* must happen with PKI applet selected */
++CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data,
++ CKYBuffer *result, CKYISOStatus *apduRC);
++CKYStatus CACApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert,
++ CKYISOStatus *apduRC);
++CKYStatus CACApplet_GetCertificateFirst(CKYCardConnection *conn,
++ CKYBuffer *cert, CKYSize *nextSize,
++ CKYISOStatus *apduRC);
++CKYStatus CACApplet_GetCertificateAppend(CKYCardConnection *conn,
++ CKYBuffer *cert, CKYSize nextSize,
++ CKYISOStatus *apduRC);
++
++/*CKYStatus CACApplet_GetProperties(); */
++CKYStatus CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin,
++ int local, CKYISOStatus *apduRC);
++
++/* Select a PIV applet */
++CKYStatus PIVApplet_Select(CKYCardConnection *conn, CKYISOStatus *apduRC);
++
++CKYStatus PIVApplet_GetCertificate(CKYCardConnection *conn, CKYBuffer *cert,
++ int tag, CKYISOStatus *apduRC);
++CKYStatus PIVApplet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
++ unsigned int keySize, int derive,
++ const CKYBuffer *data, CKYBuffer *result,
++ CKYISOStatus *apduRC);
++
++/* PKCS Commands 15 */
++CKYStatus P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC);
++CKYStatus P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef,
++ CKYISOStatus *apduRC);
++CKYStatus P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record,
++ CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data,
++ CKYISOStatus *apduRC);
++CKYStatus P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset,
++ CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data,
++ CKYISOStatus *apduRC);
++CKYStatus P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin,
++ const P15PinInfo *pinInfo, CKYISOStatus *apduRC);
++
++CKYStatus P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
++ unsigned int keySize, CKYByte direction,
++ const CKYBuffer *data, CKYBuffer *result,
++ CKYISOStatus *apduRC);
++
++/*
++ * There are 3 read commands:
++ *
++ * CKYApplet_ReadObject issues a single Read APDU call. Supplied data buffer
++ * is overwritten. This function is limited to reading 240 bytes.
++ * CKYApplet_ReadObjectAppend also issues a single Read APDU call. However,
++ * the result is appended to the data buffer. Again, this function is limited
++ * to reading 240 bytes.
++ * CKYApplet_ReadObjectFull can read an entire data object. It makes multiple
++ * apdu calls in order to read the full amount into the buffer. The buffer
++ * is overwriten.
++ */
++CKYStatus CKYApplet_ReadObject(CKYCardConnection *conn, unsigned long objectID,
++ CKYOffset offset, CKYByte size, const CKYBuffer *nonce,
++ CKYBuffer *data, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_ReadObjectAppend(CKYCardConnection *conn,
++ unsigned long objectID, CKYOffset offset, CKYByte size,
++ const CKYBuffer *nonce, CKYBuffer *data, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_ReadObjectFull(CKYCardConnection *conn,
++ unsigned long objectID, CKYOffset offset, CKYSize size,
++ const CKYBuffer *nonce, CKYBuffer *data, CKYISOStatus *apduRC);
++/*
++ * There is 1 write command:
++ * CKYApplet_WriteObjectFull can write an entire data object. It makes multiple
++ * apdu calls in order to write the full amount into the buffer. The buffer is
++ * overwritten.
++*/
++
++CKYStatus CKYApplet_WriteObjectFull(CKYCardConnection *conn,
++ unsigned long objectID, CKYOffset offset, CKYSize size,
++ const CKYBuffer *nonce, const CKYBuffer *data, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_ListObjects(CKYCardConnection *conn, CKYByte seq,
++ CKYAppletRespListObjects *lop, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_GetStatus(CKYCardConnection *conn,
++ CKYAppletRespGetStatus *status, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_Noop(CKYCardConnection *conn, CKYISOStatus *apduRC);
++CKYStatus CKYApplet_GetBuildID(CKYCardConnection *conn, unsigned long *buildID,
++ CKYISOStatus *apduRC);
++CKYStatus CKYApplet_GetLifeCycle(CKYCardConnection *conn, CKYByte *personalized,
++ CKYISOStatus *apduRC);
++CKYStatus CKYApplet_GetLifeCycleV2(CKYCardConnection *conn,
++ CKYAppletRespGetLifeCycleV2 *ext, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_GetRandom(CKYCardConnection *conn,
++ CKYBuffer *buf, CKYByte len, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_GetRandomAppend(CKYCardConnection *conn,
++ CKYBuffer *buf, CKYByte len, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_SeedRandom(CKYCardConnection *conn,
++ const CKYBuffer *buf, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_GetIssuerInfo(CKYCardConnection *conn,
++ CKYBuffer *buf, CKYISOStatus *apduRC);
++
++CKYStatus CKYApplet_GetBuiltinACL(CKYCardConnection *conn,
++ CKYAppletRespGetBuiltinACL *gba, CKYISOStatus *apduRC);
++
++/** ECC commands
++ * * */
++
++CKYStatus CKYApplet_ComputeECCSignature(CKYCardConnection *conn, CKYByte keyNumber,
++ const CKYBuffer *data, CKYBuffer *sig,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++
++CKYStatus
++CKYApplet_ComputeECCKeyAgreement(CKYCardConnection *conn, CKYByte keyNumber,
++ const CKYBuffer *publicValue, CKYBuffer *sharedSecret,
++ CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC);
++
++
++/*
++ * deprecates 0.x functions
++ */
++/* old applet verify pin call (no nonce returned) */
++CKYStatus CKYApplet_VerifyPinV0(CKYCardConnection *conn, CKYByte pinNumber,
++ const char *pinValue, CKYISOStatus *apduRC);
++/* logout all */
++CKYStatus CKYApplet_LogoutAllV0(CKYCardConnection *conn, CKYISOStatus *apduRC);
++
++CKY_END_PROTOS
++#endif /* CKY_APPLET_H */
+diff -up ./esc/src/lib/coolkey/cky_base.c.fix1 ./esc/src/lib/coolkey/cky_base.c
+--- ./esc/src/lib/coolkey/cky_base.c.fix1 2018-04-26 11:44:38.436986198 -0700
++++ ./esc/src/lib/coolkey/cky_base.c 2018-04-26 11:44:38.436986198 -0700
+@@ -0,0 +1,835 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include <string.h>
++#include <stdlib.h>
++#include <assert.h>
++#include "cky_basei.h"
++#include "cky_base.h"
++
++/*
++ * generic buffer management functions
++ *
++ * These functions allow simple buffer management used in the CoolKey
++ * library and it's clients.
++ */
++
++/* initialize a new buffer to a known state */
++static void
++ckyBuffer_initBuffer(CKYBuffer *buf)
++{
++#ifdef DEBUG
++ assert(sizeof(CKYBuffer) == sizeof(CKYBufferPublic));
++#endif
++ buf->data = NULL;
++ buf->size = 0;
++ buf->len = 0;
++ buf->reserved = NULL; /* make coverity happy */
++}
++
++/*
++ * Init functions clobbers the current contents and allocates the required
++ * space. Active buffers should call CKYBuffer_FreerData before
++ * calling an init function. All init functions copies the supplied data
++ * into newly allocated space.
++ */
++/* init an empty buffer that will later be filled in. */
++CKYStatus
++CKYBuffer_InitEmpty(CKYBuffer *buf)
++{
++ ckyBuffer_initBuffer(buf);
++ return CKYSUCCESS;
++}
++
++/* Create a buffer of length len all initialized to '0' */
++CKYStatus
++CKYBuffer_InitFromLen(CKYBuffer *buf, CKYSize len)
++{
++ CKYStatus ret;
++
++ ckyBuffer_initBuffer(buf);
++ ret = CKYBuffer_Reserve(buf, len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->len = len;
++ memset(buf->data, 0, buf->len);
++ return CKYSUCCESS;
++}
++
++static CKYByte
++fromHex(const char *cp)
++{
++ if (*cp >= '0' && *cp <= '9') {
++ return (CKYByte) *cp - '0';
++ }
++ if (*cp >= 'a' && *cp <= 'f') {
++ return (CKYByte) *cp - 'a' + 0xa;
++ }
++ if (*cp >= 'A' && *cp <= 'F') {
++ return (CKYByte) *cp - 'A' + 0xA;
++ }
++ return 0;
++}
++
++/* Create a buffer by decoding a hex string. hexString is NULL terminated. */
++CKYStatus
++CKYBuffer_InitFromHex(CKYBuffer *buf, const char *hexString)
++{
++ int len = strlen(hexString);
++ int dataHalf = 0;
++ CKYByte lastDigit = 0;
++ CKYByte digit;
++ const char *cp;
++ CKYByte *bp;
++ CKYStatus ret;
++
++ if (len & 1) {
++ len++;
++ dataHalf++;
++ }
++ ckyBuffer_initBuffer(buf);
++ ret = CKYBuffer_Reserve(buf, len/2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->len = len/2;
++ bp = buf->data;
++ for (cp = hexString; *cp; cp++) {
++ digit = fromHex(cp);
++ /* check for error? */
++ if (dataHalf) {
++ *bp++= lastDigit << 4 | digit;
++ }
++ dataHalf ^= 1;
++ lastDigit = digit;
++ }
++ return CKYSUCCESS;
++}
++
++/* Create a buffer from data */
++CKYStatus
++CKYBuffer_InitFromData(CKYBuffer *buf, const CKYByte *data, CKYSize len)
++{
++ CKYStatus ret;
++
++ ckyBuffer_initBuffer(buf);
++ ret = CKYBuffer_Reserve(buf, len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->len = len;
++ memcpy(buf->data, data, buf->len);
++ return CKYSUCCESS;
++}
++
++
++/* Create a buffer from part of another buffer. Start indicates the
++ * offset in the old buffer to start in, and len specifies how many bytes
++ * to copy */
++CKYStatus
++CKYBuffer_InitFromBuffer(CKYBuffer *buf,
++ const CKYBuffer *src, CKYOffset start, CKYSize len)
++{
++ CKYStatus ret;
++
++ ckyBuffer_initBuffer(buf);
++ if (src->len < start) {
++ len = 0;
++ } else if (src->len < start+len) {
++ len = src->len -start;
++ }
++ ret = CKYBuffer_Reserve(buf, len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->len = len;
++ if (len == 0) {
++ return CKYSUCCESS;
++ }
++ memcpy(buf->data, src->data+start, buf->len);
++ return CKYSUCCESS;
++}
++
++/* Create a buffer from and exact copy of another buffer. */
++CKYStatus
++CKYBuffer_InitFromCopy(CKYBuffer *buf, const CKYBuffer *src)
++{
++ CKYStatus ret;
++
++ ckyBuffer_initBuffer(buf);
++ /* src buffer has no length, make sure the dest is empty */
++ if (src->len == 0) {
++ return CKYSUCCESS;
++ }
++ ret = CKYBuffer_Reserve(buf, src->len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->len = src->len;
++ memcpy(buf->data, src->data, buf->len);
++ return CKYSUCCESS;
++}
++
++/*
++ * append functions increase the buffer size if necessary
++ */
++CKYStatus
++CKYBuffer_AppendChar(CKYBuffer *buf, CKYByte val)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + 1);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->data[buf->len] = val;
++ buf->len += 1;
++ return CKYSUCCESS;
++}
++
++/* append a short in network order */
++CKYStatus
++CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + 2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->data[buf->len+0] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[buf->len+1] = (CKYByte) ((val >> 0) & 0xff);
++ buf->len += 2;
++ return CKYSUCCESS;
++}
++
++/* append a short in network order */
++CKYStatus
++CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + 2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff);
++ buf->len += 2;
++ return CKYSUCCESS;
++}
++
++/* append a long in applet order */
++CKYStatus
++CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + 4);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->data[buf->len+0] = (CKYByte) ((val >> 24) & 0xff);
++ buf->data[buf->len+1] = (CKYByte) ((val >> 16) & 0xff);
++ buf->data[buf->len+2] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[buf->len+3] = (CKYByte) ((val >> 0) & 0xff);
++ buf->len += 4;
++ return CKYSUCCESS;
++}
++
++/* append a long in applet order */
++CKYStatus
++CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + 4);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ buf->data[buf->len+3] = (CKYByte) ((val >> 24) & 0xff);
++ buf->data[buf->len+2] = (CKYByte) ((val >> 16) & 0xff);
++ buf->data[buf->len+1] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[buf->len+0] = (CKYByte) ((val >> 0) & 0xff);
++ buf->len += 4;
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data, CKYSize len)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, offset+len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ if (buf->len < offset + len) {
++ buf->len = offset + len;
++ }
++ memcpy(buf->data+offset, data, len);
++ return CKYSUCCESS;
++}
++
++/* append data with length of len bytes */
++CKYStatus
++CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Reserve(buf, buf->len + len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ memcpy(buf->data+buf->len, data, len);
++ buf->len += len;
++ return CKYSUCCESS;
++}
++
++/* append data with length of len bytes */
++CKYStatus
++CKYBuffer_AppendBuffer(CKYBuffer *buf, const CKYBuffer *src,
++ CKYOffset offset, CKYSize len)
++{
++ unsigned long maxlen = src->len - offset;
++ if ((maxlen < len) || (src->len < offset)) {
++ return CKYDATATOOLONG;
++ }
++ return CKYBuffer_AppendData(buf, src->data+offset, len);
++}
++
++/* append data with length of len bytes */
++CKYStatus
++CKYBuffer_AppendCopy(CKYBuffer *buf, const CKYBuffer *src)
++{
++ return CKYBuffer_AppendData(buf, src->data, src->len);
++}
++
++CKYStatus
++CKYBuffer_Reserve(CKYBuffer *buf, CKYSize newSize)
++{
++ if (buf->size >= newSize) {
++ return CKYSUCCESS;
++ }
++ buf->data = (CKYByte *)realloc(buf->data, newSize);
++ if (buf->data == NULL) {
++ buf->size = 0;
++ buf->len = 0;
++ return CKYNOMEM;
++ }
++ buf->size = newSize;
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetChar(CKYBuffer *buf, CKYOffset offset, CKYByte val)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+1) {
++ ret = CKYBuffer_Resize(buf,offset+1);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ buf->data[offset] = val;
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetChars(CKYBuffer *buf, CKYOffset offset, CKYByte val, CKYSize len)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+len) {
++ ret = CKYBuffer_Resize(buf,offset+len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ memset(buf->data+offset,val, len);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+2) {
++ ret = CKYBuffer_Resize(buf,offset+2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ buf->data[offset+0] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[offset+1] = (CKYByte) ((val >> 0) & 0xff);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+2) {
++ ret = CKYBuffer_Resize(buf,offset+2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+4) {
++ ret = CKYBuffer_Resize(buf,offset+4);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ buf->data[offset+0] = (CKYByte) ((val >> 24) & 0xff);
++ buf->data[offset+1] = (CKYByte) ((val >> 16) & 0xff);
++ buf->data[offset+2] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[offset+3] = (CKYByte) ((val >> 0) & 0xff);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val)
++{
++ CKYStatus ret;
++
++ if (buf->len < offset+4) {
++ ret = CKYBuffer_Resize(buf,offset+4);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ buf->data[offset+3] = (CKYByte) ((val >> 24) & 0xff);
++ buf->data[offset+2] = (CKYByte) ((val >> 16) & 0xff);
++ buf->data[offset+1] = (CKYByte) ((val >> 8) & 0xff);
++ buf->data[offset+0] = (CKYByte) ((val >> 0) & 0xff);
++ return CKYSUCCESS;
++}
++
++CKYByte
++CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset)
++{
++ if (buf->len < offset+1) {
++ return 0;
++ }
++ return buf->data[offset];
++}
++
++unsigned short
++CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset)
++{
++ unsigned short val;
++ if (buf->len < offset+2) {
++ return 0;
++ }
++ val = ((unsigned short)buf->data[offset+0]) << 8;
++ val |= ((unsigned short)buf->data[offset+1]) << 0;
++ return val;
++}
++
++unsigned short
++CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset)
++{
++ unsigned short val;
++ if (buf->len < offset+2) {
++ return 0;
++ }
++ val = ((unsigned short)buf->data[offset+1]) << 8;
++ val |= ((unsigned short)buf->data[offset+0]) << 0;
++ return val;
++}
++
++unsigned long
++CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset)
++{
++ unsigned long val;
++ if (buf->len < offset+4) {
++ return 0;
++ }
++ val = ((unsigned long)buf->data[offset+0]) << 24;
++ val |= ((unsigned long)buf->data[offset+1]) << 16;
++ val |= ((unsigned long)buf->data[offset+2]) << 8;
++ val |= ((unsigned long)buf->data[offset+3]) << 0;
++ return val;
++}
++
++unsigned long
++CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset)
++{
++ unsigned long val;
++ if (buf->len < offset+4) {
++ return 0;
++ }
++ val = ((unsigned long)buf->data[offset+3]) << 24;
++ val |= ((unsigned long)buf->data[offset+2]) << 16;
++ val |= ((unsigned long)buf->data[offset+1]) << 8;
++ val |= ((unsigned long)buf->data[offset+0]) << 0;
++ return val;
++}
++
++CKYStatus
++CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen)
++{
++ CKYStatus ret;
++
++ if (buf->len < newLen) {
++ ret = CKYBuffer_Reserve(buf, newLen);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ memset(buf->data+buf->len, 0, newLen - buf->len);
++ }
++ buf->len = newLen;
++ return CKYSUCCESS;
++}
++
++/* clear out a memory buffer... including unallocated space, then
++ * set the buffer length to '0' */
++void
++CKYBuffer_Zero(CKYBuffer *buf)
++{
++ if (buf->size != 0) {
++ memset(buf->data, 0, buf->size);
++ }
++ buf->len = 0;;
++}
++
++CKYSize
++CKYBuffer_Size(const CKYBuffer *buf)
++{
++ return buf->len;
++}
++
++const CKYByte *
++CKYBuffer_Data(const CKYBuffer *buf)
++{
++ return buf->data;
++}
++
++CKYBool
++CKYBuffer_DataIsEqual(const CKYBuffer *buf1, const CKYByte *buf2, CKYSize buf2Len)
++{
++ if (buf1->len != buf2Len) {
++ return 0;
++ }
++
++ /* all zero length buffers are equal, whether or not they have pointers
++ * allocated */
++ if (buf1->len == 0) {
++ return 1;
++ }
++
++ return memcmp(buf1->data, buf2, buf1->len) == 0;
++}
++
++CKYBool
++CKYBuffer_IsEqual(const CKYBuffer *buf1, const CKYBuffer *buf2)
++{
++ return CKYBuffer_DataIsEqual(buf1, buf2->data, buf2->len);
++}
++
++CKYStatus
++CKYBuffer_FreeData(CKYBuffer *buf)
++{
++ free(buf->data);
++ ckyBuffer_initBuffer(buf);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYAPDU_Init(CKYAPDU *apdu)
++{
++#ifdef DEBUG
++ assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
++#endif
++ ckyBuffer_initBuffer(&apdu->apduBuf);
++ apdu->reserved = NULL;
++ return CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_MIN_LEN);
++}
++
++CKYStatus
++CKYAPDU_InitFromData(CKYAPDU *apdu, const CKYByte *data, CKYSize len)
++{
++#ifdef DEBUG
++ assert(sizeof(CKYAPDU) == sizeof(CKYAPDUPublic));
++#endif
++ ckyBuffer_initBuffer(&apdu->apduBuf);
++ apdu->reserved = NULL;
++ if (len > CKYAPDU_MAX_DATA_LEN) {
++ return CKYDATATOOLONG;
++ }
++ return CKYBuffer_InitFromData(&apdu->apduBuf, data, len);
++}
++
++CKYStatus
++CKYAPDU_FreeData(CKYAPDU *apdu)
++{
++ return CKYBuffer_FreeData(&apdu->apduBuf);
++}
++
++
++CKYByte
++CKYAPDU_GetCLA(const CKYAPDU *apdu)
++{
++ return CKYBuffer_GetChar(&apdu->apduBuf, CKY_CLA_OFFSET);
++}
++
++CKYStatus
++CKYAPDU_SetCLA(CKYAPDU *apdu, CKYByte b)
++{
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_CLA_OFFSET, b);
++}
++
++CKYByte
++CKYAPDU_GetINS(const CKYAPDU *apdu)
++{
++ return CKYBuffer_GetChar(&apdu->apduBuf, CKY_INS_OFFSET);
++}
++
++CKYStatus
++CKYAPDU_SetINS(CKYAPDU *apdu, CKYByte b)
++{
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_INS_OFFSET, b);
++}
++
++CKYByte
++CKYAPDU_GetP1(const CKYAPDU *apdu)
++{
++ return CKYBuffer_GetChar(&apdu->apduBuf, CKY_P1_OFFSET);
++}
++
++CKYStatus
++CKYAPDU_SetP1(CKYAPDU *apdu, CKYByte b)
++{
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_P1_OFFSET, b);
++}
++
++CKYByte
++CKYAPDU_GetP2(const CKYAPDU *apdu)
++{
++ return CKYBuffer_GetChar(&apdu->apduBuf, CKY_P2_OFFSET);
++}
++
++CKYStatus
++CKYAPDU_SetP2(CKYAPDU *apdu, CKYByte b)
++{
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_P2_OFFSET, b);
++}
++
++CKYStatus
++CKYAPDU_SetSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len)
++{
++ CKYStatus ret;
++ CKYOffset offset = 0;
++
++ /* Encode with T1 if necessary */
++
++ if (len < CKYAPDU_MAX_DATA_LEN) {
++ offset = 0;
++ ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN);
++ if (ret != CKYSUCCESS ) {
++ return ret;
++ }
++ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) len);
++ } else if (len < CKYAPDU_MAX_T1_DATA_LEN) {
++ offset = 2;
++ ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN);
++ if (ret != CKYSUCCESS ) {
++ return ret;
++ }
++ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) 0);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ ret = CKYBuffer_SetShort(&apdu->apduBuf,CKY_LC_OFFSET+1,
++ (unsigned short)len);
++ } else {
++ return CKYDATATOOLONG;
++ }
++
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ return CKYBuffer_Replace(&apdu->apduBuf,
++ CKYAPDU_HEADER_LEN + offset , data, len);
++}
++
++CKYStatus
++CKYAPDU_SetSendDataBuffer(CKYAPDU *apdu, const CKYBuffer *buf)
++{
++ return CKYAPDU_SetSendData(apdu, buf->data, buf->len);
++}
++
++CKYStatus
++CKYAPDU_AppendSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len)
++{
++ CKYStatus ret;
++ CKYSize dataLen;
++
++ if (CKYBuffer_Size(&apdu->apduBuf) <= CKYAPDU_MIN_LEN) {
++ return CKYAPDU_SetSendData(apdu,data, len);
++ }
++
++ dataLen = CKYBuffer_Size(&apdu->apduBuf) + len - CKYAPDU_HEADER_LEN;
++ /* only handles T0 encoding, not T1 encoding */
++ if (dataLen >= CKYAPDU_MAX_DATA_LEN) {
++ return CKYDATATOOLONG;
++ }
++ ret = CKYBuffer_AppendData(&apdu->apduBuf, data, len);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) dataLen);
++}
++
++CKYStatus
++CKYAPDU_AppendSendDataBuffer(CKYAPDU *apdu, const CKYBuffer *buf)
++{
++ return CKYAPDU_AppendSendData(apdu, buf->data, buf->len);
++}
++
++CKYStatus
++CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKYByte recvlen)
++{
++ CKYStatus ret;
++ ret = CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_HEADER_LEN);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, recvlen);
++}
++
++CKYStatus
++CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen)
++{
++ CKYStatus ret;
++
++ if (recvlen <= CKYAPDU_MAX_DATA_LEN) {
++ return CKYAPDU_SetReceiveLen(apdu, (CKYByte)(recvlen & 0xff));
++ }
++ ret = CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_HEADER_LEN+2);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, 0);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ return CKYBuffer_SetShort(&apdu->apduBuf, CKY_LE_OFFSET+1, recvlen);
++}
++
++CKYStatus
++CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen)
++{
++ if (recvlen <= CKYAPDU_MAX_T1_DATA_LEN) {
++ return CKYAPDU_SetShortReceiveLen(apdu, (unsigned short)
++ (recvlen & 0xffff));
++ }
++ return CKYDATATOOLONG;
++}
++
++/*
++ * Append Le, If Le=0, treat it as 256 (CKYAPD_MAX_DATA_LEN)
++ */
++CKYStatus
++CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen)
++{
++ /* If we already have a data buffer, make sure that we aren't already
++ * using T1 encoding */
++ if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) {
++ if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) == 0) {
++ /* we are using T1 encoding, use AppendShort*/
++ return CKYBuffer_AppendShort(&apdu->apduBuf,
++ recvlen ? (unsigned short) recvlen: CKYAPDU_MAX_DATA_LEN);
++ }
++ }
++ return CKYBuffer_AppendChar(&apdu->apduBuf, recvlen);
++}
++
++/*
++ * Append a short Le. If Le be encoded with just T0, do so. If Le=0 treat
++ * it as 65536 (CKYAPDU_MAX_T1_DATA_LEN)
++ */
++CKYStatus
++CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen)
++{
++ CKYStatus ret;
++ /* If we already have a data buffer, it's encoding affects ours */
++ if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) {
++ /* CKY_LC_OFFSET == 0 means T1, otherwise it's T0 */
++ if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) != 0) {
++ /* remember 0 is 65536 here */
++ if ((recvlen == 0) || (recvlen > CKYAPDU_MAX_DATA_LEN)) {
++ /* we can't a encode T1 receive length if we already have a
++ * T0 encoded buffer data */
++ return CKYDATATOOLONG;
++ }
++ /* T0 encoding */
++ return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff);
++ }
++ /* T1 encoding */
++ return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen);
++ }
++ /* if length fits in a bit and we aren't forced into T1 encoding, use
++ * T0 */
++ if ((recvlen != 0) && (recvlen <= CKYAPDU_MAX_DATA_LEN)) {
++ return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff);
++ }
++ /* write the T1 encoding marker */
++ ret = CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)0);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ /* T1 encoded length */
++ return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen);
++}
++
++CKYStatus
++CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen)
++{
++ if (recvlen > CKYAPDU_MAX_T1_DATA_LEN) {
++ return CKYDATATOOLONG;
++ }
++ return CKYAPDU_AppendShortReceiveLen(apdu,
++ (unsigned short)(recvlen & 0xffff));
++}
++
++
++void
++CKY_SetName(const char *p)
++{
++}
++
++
++
++
+diff -up ./esc/src/lib/coolkey/cky_base.h.fix1 ./esc/src/lib/coolkey/cky_base.h
+--- ./esc/src/lib/coolkey/cky_base.h.fix1 2018-04-26 11:44:38.437986192 -0700
++++ ./esc/src/lib/coolkey/cky_base.h 2018-04-26 11:44:38.437986192 -0700
+@@ -0,0 +1,340 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_BASE_H
++#define CKY_BASE_H 1
++
++/*
++ * Common types and structs
++ */
++/* buffer sizes */
++typedef unsigned long CKYSize;
++/* offsets into buffers are data */
++typedef unsigned long CKYOffset;
++/* bytes, buffers */
++typedef unsigned char CKYByte;
++/* Bool type */
++typedef unsigned char CKYBool;
++
++typedef unsigned long CKYBitFlags;
++
++#define CKYBUFFER_PUBLIC \
++ unsigned long reserved1;\
++ unsigned long reserved2;\
++ void *reserved3;\
++ void *reserved4;
++
++#define CKYAPDU_PUBLIC \
++ unsigned long reserved1;\
++ unsigned long reserved2;\
++ void *reserved3;\
++ void *reserved4; \
++ void *reserved5;
++
++
++typedef struct _CKYBuffer {
++#ifdef CKYBUFFER_PRIVATE
++ CKYBUFFER_PRIVATE
++#else
++ CKYBUFFER_PUBLIC
++#endif
++} CKYBuffer;
++
++typedef struct _CKYAPDU {
++#ifdef CKYAPDU_PRIVATE
++ CKYAPDU_PRIVATE
++#else
++ CKYAPDU_PUBLIC
++#endif
++} CKYAPDU;
++
++/*
++ * the following is just to make sure the sizes match
++ */
++#ifdef DEBUG
++#ifdef CKYBUFFER_PRIVATE
++typedef struct _CKYBufferPublic {
++ CKYBUFFER_PUBLIC
++} CKYBufferPublic;
++
++typedef struct _CKYAPDUPublic {
++ CKYAPDU_PUBLIC
++} CKYAPDUPublic;
++#endif
++#endif
++
++typedef enum {
++ CKYSUCCESS, /* operation completed successfully */
++ CKYNOMEM, /* failed to allocate memory */
++ CKYDATATOOLONG, /* index or length exceeded a buffer or device size */
++ CKYNOSCARD, /* Scard library does not exist */
++ CKYSCARDERR, /* I/O Error in the SCard interface level. */
++ /* more specific error values can be queried from
++ * the context or connection with the
++ * GetLastError() call */
++ CKYLIBFAIL, /* error is shared library. no additional
++ * error is available. Only returned from internal
++ * SHlib calls (not surfaced in public APIs */
++ CKYAPDUFAIL, /* processing worked, but applet rejected the APDU
++ * (command) sent. ADPUIOStatus has more info on
++ * why the APDU failed */
++ CKYINVALIDARGS, /* Caller passed in bad args */
++ CKYINVALIDDATA, /* Data supplied was invalid */
++ CKYUNSUPPORTED, /* Requested Operation or feature is not supported */
++} CKYStatus;
++
++/*
++ * defines related to APDU's
++ */
++#define CKY_CLA_OFFSET 0
++#define CKY_INS_OFFSET 1
++#define CKY_P1_OFFSET 2
++#define CKY_P2_OFFSET 3
++#define CKY_P3_OFFSET 4 /* P3 is P3, LC, and LE depending on usage */
++#define CKY_LC_OFFSET 4
++#define CKY_LE_OFFSET 4
++
++#define CKYAPDU_MAX_DATA_LEN 256
++#define CKYAPDU_MAX_T1_DATA_LEN 65536
++#define CKYAPDU_MIN_LEN 4
++#define CKYAPDU_HEADER_LEN 5
++#define CKYAPDU_MAX_LEN (CKYAPDU_HEADER_LEN+CKYAPDU_MAX_DATA_LEN)
++#define CKY_MAX_ATR_LEN 32
++#define CKY_OUTRAGEOUS_MALLOC_SIZE (1024*1024)
++
++#define P15FlagsPrivate 0x00000001
++#define P15FlagsModifiable 0x00000002
++
++#define P15UsageEncrypt 0x00000001
++#define P15UsageDecrypt 0x00000002
++#define P15UsageSign 0x00000004
++#define P15UsageSignRecover 0x00000008
++#define P15UsageWrap 0x00000010
++#define P15UsageUnwrap 0x00000020
++#define P15UsageVerify 0x00000040
++#define P15UsageVerifyRecover 0x00000080
++#define P15UsageDerive 0x00000100
++#define P15UsageNonRepudiation 0x00000200
++
++#define P15AccessSensitive 0x00000001
++#define P15AccessExtractable 0x00000002
++#define P15AccessAlwaysSenstive 0x00000004
++#define P15AccessNeverExtractable 0x00000008
++#define P15AccessLocal 0x00000010
++
++#define P15PinCaseSensitive 0x00000001
++#define P15PinLocal 0x00000002
++#define P15PinChangeDisabled 0x00000004
++#define P15PinUnblockDisabled 0x00000008
++#define P15PinInitialized 0x00000010
++#define P15PinNeedsPadding 0x00000020
++#define P15PinUnblockingPin 0x00000040
++#define P15PinSOPin 0x00000080
++#define P15PinDisableAllowed 0x00000100
++
++typedef enum {P15PinBCD=0, P15PinASCIINum=1, P15PinUTF8=2} P15PinType;
++
++typedef struct _P15PinInfo {
++ CKYBitFlags pinFlags;
++ P15PinType pinType;
++ CKYByte minLength;
++ CKYByte storedLength;
++ unsigned long maxLength;
++ CKYByte pinRef;
++ CKYByte padChar;
++} P15PinInfo;
++
++
++/*
++ * allow direct inclusion in C++ files
++ */
++#ifdef __cplusplus
++#define CKY_BEGIN_PROTOS extern "C" {
++#define CKY_END_PROTOS }
++#else
++#define CKY_BEGIN_PROTOS
++#define CKY_END_PROTOS
++#endif
++
++CKY_BEGIN_PROTOS
++/*
++ * generic buffer management functions
++ *
++ * These functions allow simple buffer management used in the CoolKey
++ * library and it's clients.
++ */
++
++/*
++ * Init functions clobbers the current contents and allocates the required
++ * space.
++ * - Active buffers should call CKYBuffer_FreeData before calling an init
++ * function.
++ * - New buffers should call some CKYBuffer_Init function before any use.
++ * - All init functions copies the supplied data into newly allocated space.
++ */
++/* Create an empty buffer with no memory allocated to it. This is sufficient
++ * to begin using a buffer. Note that new calls will probably allocate memory.
++ * It is safe to free an empty buffer. */
++CKYStatus CKYBuffer_InitEmpty(CKYBuffer *buf);
++
++/* Create a buffer of length len all initialized to '0' */
++CKYStatus CKYBuffer_InitFromLen(CKYBuffer *buf, CKYSize len);
++
++/* Create a buffer by decoding a hex string. hexString is NULL terminated. */
++CKYStatus CKYBuffer_InitFromHex(CKYBuffer *buf, const char *hexString);
++
++/* Create a buffer from data */
++CKYStatus CKYBuffer_InitFromData(CKYBuffer *buf, const CKYByte *data, CKYSize len);
++
++/* Create a buffer from part of another buffer. Start indicates the
++ * offset in the old buffer to start in, and len specifies how many bytes
++ * to copy */
++CKYStatus CKYBuffer_InitFromBuffer(CKYBuffer *buf, const CKYBuffer *src,
++ CKYOffset start, CKYSize len);
++/* Create a buffer from an exact copy of another buffer */
++CKYStatus CKYBuffer_InitFromCopy(CKYBuffer *buf, const CKYBuffer *src);
++/*
++ * append functions increase the buffer size if necessary
++ */
++/* append a short in applet order */
++CKYStatus CKYBuffer_AppendChar(CKYBuffer *buf, CKYByte b);
++
++/* append a short in applet order */
++CKYStatus CKYBuffer_AppendShort(CKYBuffer *buf, unsigned short val);
++
++/* append a short in little endian order */
++CKYStatus CKYBuffer_AppendShortLE(CKYBuffer *buf, unsigned short val);
++
++/* append a long in applet order */
++CKYStatus CKYBuffer_AppendLong(CKYBuffer *buf, unsigned long val);
++
++/* append a long in little endian order */
++CKYStatus CKYBuffer_AppendLongLE(CKYBuffer *buf, unsigned long val);
++
++/* append data. the data starts at data and extends len bytes */
++CKYStatus CKYBuffer_AppendData(CKYBuffer *buf, const CKYByte *data, CKYSize len);
++
++/* append buffer fragment. the data starts at buffer[offset]
++ * and extends len bytes */
++CKYStatus CKYBuffer_AppendBuffer(CKYBuffer *buf, const CKYBuffer *src,
++ CKYOffset offset, CKYSize len);
++
++/* append a full buffer */
++CKYStatus CKYBuffer_AppendCopy(CKYBuffer *buf, const CKYBuffer *src );
++
++/* reserve increases the space allocated for the buffer, but does not
++ * increase the actual buffer size. If the buffer already newSize or more
++ * space allocated, Reserve is a no op.
++ */
++CKYStatus CKYBuffer_Reserve(CKYBuffer *buf, CKYSize newSize) ;
++
++/* resize affects the buffer's size. If the buffer len increases,
++ * the new date will be zero'ed out. If the buffer shrinks, the buffer
++ * is truncated, but the space is not removed.
++ */
++CKYStatus CKYBuffer_Resize(CKYBuffer *buf, CKYSize newLen);
++
++/* replace bytes starting at 'offset'. If the buffer needs to be extended,
++ * it will be automatically */
++CKYStatus CKYBuffer_Replace(CKYBuffer *buf, CKYOffset offset, const CKYByte *data,
++ CKYSize len);
++
++/* set byte at ofset. The buffer is extended to offset if necessary */
++CKYStatus CKYBuffer_SetChar(CKYBuffer *buf, CKYOffset offset, CKYByte c);
++/* set several copies of 'c' at from offset to offset+ len */
++CKYStatus CKYBuffer_SetChars(CKYBuffer *buf, CKYOffset offset,
++ CKYByte c, CKYSize len);
++/* These functions work in applet order */
++CKYStatus CKYBuffer_SetShort(CKYBuffer *buf, CKYOffset offset, unsigned short val);
++CKYStatus CKYBuffer_SetLong(CKYBuffer *buf, CKYOffset offset, unsigned long val);
++
++/* These functions work in little endian order */
++CKYStatus CKYBuffer_SetShortLE(CKYBuffer *buf, CKYOffset offset, unsigned short val);
++CKYStatus CKYBuffer_SetLongLE(CKYBuffer *buf, CKYOffset offset, unsigned long val);
++/* read a character from offset. If offset is beyond the end of the buffer,
++ * then the function returns '0' */
++CKYByte CKYBuffer_GetChar(const CKYBuffer *buf, CKYOffset offset);
++/* These functions work in applet order */
++unsigned short CKYBuffer_GetShort(const CKYBuffer *buf, CKYOffset offset);
++unsigned long CKYBuffer_GetLong(const CKYBuffer *buf, CKYOffset offset);
++/* These functions work in little endian order */
++unsigned short CKYBuffer_GetShortLE(const CKYBuffer *buf, CKYOffset offset);
++unsigned long CKYBuffer_GetLongLE(const CKYBuffer *buf, CKYOffset offset);
++
++/* clear out all the data in a buffer */
++void CKYBuffer_Zero(CKYBuffer *buf);
++
++/* return the size (length) of a buffer. This is only the portion of the
++ * buffer that has valid data set. */
++CKYSize CKYBuffer_Size(const CKYBuffer *buf);
++
++/* return a pointer to the data buffer */
++const CKYByte *CKYBuffer_Data(const CKYBuffer *buf);
++
++/* compare two buffers return :
++ * 1 if the two buffers are equal,
++ * 0 if they are not */
++CKYBool CKYBuffer_IsEqual(const CKYBuffer *buf1, const CKYBuffer *buf2);
++/* compares raw data with a buffer or equality */
++CKYBool CKYBuffer_DataIsEqual(const CKYBuffer *buf1,
++ const CKYByte *buf2, CKYSize buf2Len);
++
++/* free all the data associated with a buffer and initialize the buffer */
++CKYStatus CKYBuffer_FreeData(CKYBuffer *buf);
++
++/*
++ * APDU's are buffers that know about the APDU structure
++ */
++CKYStatus CKYAPDU_Init(CKYAPDU *apdu);
++CKYStatus CKYAPDU_InitFromData(CKYAPDU *apdu, const CKYByte *data, CKYSize size);
++CKYStatus CKYAPDU_FreeData(CKYAPDU *apdu);
++
++/* Access APDU header bytes */
++CKYByte CKYAPDU_GetCLA(const CKYAPDU *apdu);
++CKYStatus CKYAPDU_SetCLA(CKYAPDU *apdu, CKYByte b);
++CKYByte CKYAPDU_GetINS(const CKYAPDU *apdu);
++CKYStatus CKYAPDU_SetINS(CKYAPDU *apdu, CKYByte b);
++CKYByte CKYAPDU_GetP1(const CKYAPDU *apdu);
++CKYStatus CKYAPDU_SetP1(CKYAPDU *apdu, CKYByte b);
++CKYByte CKYAPDU_GetP2(const CKYAPDU *apdu);
++CKYStatus CKYAPDU_SetP2(CKYAPDU *apdu, CKYByte b);
++
++/* add sending date to the APDU */
++/* Set resets the buffer, append, adds the data to the end. Lc in
++ * the APDU header is automaticallu updated */
++CKYStatus CKYAPDU_SetSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len);
++CKYStatus CKYAPDU_SetSendDataBuffer(CKYAPDU *apdu, const CKYBuffer *buf);
++CKYStatus CKYAPDU_AppendSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len);
++CKYStatus CKYAPDU_AppendSendDataBuffer(CKYAPDU *apdu, const CKYBuffer *buf);
++
++/* set Le in the APDU header to the amount of bytes expected to be
++ * returned. */
++CKYStatus CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
++CKYStatus CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen);
++CKYStatus CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen);
++CKYStatus CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
++CKYStatus CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen);
++CKYStatus CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen);
++
++/* set the parent loadmodule name */
++void CKY_SetName(const char *name);
++
++CKY_END_PROTOS
++
++#endif /* CKY_BASE_H */
+diff -up ./esc/src/lib/coolkey/cky_basei.h.fix1 ./esc/src/lib/coolkey/cky_basei.h
+--- ./esc/src/lib/coolkey/cky_basei.h.fix1 2018-04-26 11:44:38.437986192 -0700
++++ ./esc/src/lib/coolkey/cky_basei.h 2018-04-26 11:44:38.437986192 -0700
+@@ -0,0 +1,35 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_BASE_H
++#ifndef CKY_BASEI_H
++#define CKY_BASEI_H 1
++
++#define CKYBUFFER_PRIVATE \
++ CKYSize len; \
++ CKYSize size; \
++ CKYByte *data; \
++ void *reserved;
++
++#define CKYAPDU_PRIVATE \
++ CKYBuffer apduBuf; \
++ void *reserved;
++
++#endif /* CKY_BASE_H */
++#endif /* CKY_BASEI_H */
+diff -up ./esc/src/lib/coolkey/cky_card.c.fix1 ./esc/src/lib/coolkey/cky_card.c
+--- ./esc/src/lib/coolkey/cky_card.c.fix1 2018-04-26 11:44:38.437986192 -0700
++++ ./esc/src/lib/coolkey/cky_card.c 2018-04-26 11:44:38.437986192 -0700
+@@ -0,0 +1,1226 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include <winscard.h>
++#include <stdlib.h>
++#include <string.h>
++#include "cky_basei.h" /* friend class */
++#include "cky_base.h"
++#include "cky_card.h"
++#include "dynlink.h"
++
++#ifndef WINAPI
++#define WINAPI
++typedef SCARD_READERSTATE *LPSCARD_READERSTATE;
++#endif
++
++#ifndef SCARD_E_NO_READERS_AVAILABLE
++#define SCARD_E_NO_READERS_AVAILABLE ((unsigned long)0x8010002EL)
++#endif
++
++#define NEW(type,count) (type *)malloc((count)*sizeof(type))
++
++/*
++ * protect against scard API not being installed.
++ */
++
++typedef long (WINAPI * SCardEstablishContextFn) (
++ unsigned long dwScope,
++ const void * pvReserved1,
++ const void * pvReserved2,
++ LPSCARDCONTEXT phContext);
++
++typedef long (WINAPI * SCardReleaseContextFn) (
++ SCARDCONTEXT hContext);
++
++typedef long (WINAPI * SCardBeginTransactionFn) (
++ long hCard);
++
++typedef long (WINAPI * SCardEndTransactionFn) (
++ long hCard,
++ unsigned long dwDisposition);
++
++typedef long (WINAPI * SCardConnectFn) (
++ SCARDCONTEXT hContext,
++ const char *szReader,
++ unsigned long dwShareMode,
++ unsigned long dwPreferredProtocols,
++ long *phCard,
++ unsigned long *pdwActiveProtocol);
++
++typedef long (WINAPI * SCardDisconnectFn) (
++ long hCard,
++ unsigned long dwDisposition);
++
++typedef long (WINAPI * SCardTransmitFn) (
++ long hCard,
++ LPCSCARD_IO_REQUEST pioSendPci,
++ const unsigned char *pbSendBuffer,
++ unsigned long cbSendLength,
++ LPSCARD_IO_REQUEST pioRecvPci,
++ unsigned char *pbRecvBuffer,
++ unsigned long *pcbRecvLength);
++
++typedef long (WINAPI * SCardReconnectFn) (
++ long hCard,
++ unsigned long dwShareMode,
++ unsigned long dwPreferredProtocols,
++ unsigned long dwInitialization,
++ unsigned long *pdwActiveProtocol);
++
++typedef long (WINAPI * SCardListReadersFn) (
++ SCARDCONTEXT hContext,
++ const char *mszGroups,
++ char *mszReaders,
++ unsigned long *pcchReaders);
++
++typedef long (WINAPI * SCardStatusFn) (
++ long hCard,
++ char *mszReaderNames,
++ unsigned long *pcchReaderLen,
++ unsigned long *pdwState,
++ unsigned long *pdwProtocol,
++ unsigned char *pbAtr,
++ unsigned long *pcbAtrLen);
++
++typedef long (WINAPI * SCardGetAttribFn) (
++ long hCard,
++ unsigned long dwAttId,
++ char *pbAttr,
++ unsigned long *pchAttrLen);
++
++typedef long (WINAPI * SCardGetStatusChangeFn) (
++ SCARDCONTEXT hContext,
++ unsigned long dwTimeout,
++ LPSCARD_READERSTATE rgReaderStates,
++ unsigned long cReaders);
++
++typedef long (WINAPI * SCardCancelFn) (
++ SCARDCONTEXT hContext);
++
++typedef struct _SCard {
++ SCardEstablishContextFn SCardEstablishContext;
++ SCardReleaseContextFn SCardReleaseContext;
++ SCardBeginTransactionFn SCardBeginTransaction;
++ SCardEndTransactionFn SCardEndTransaction;
++ SCardConnectFn SCardConnect;
++ SCardDisconnectFn SCardDisconnect;
++ SCardTransmitFn SCardTransmit;
++ SCardReconnectFn SCardReconnect;
++ SCardListReadersFn SCardListReaders;
++ SCardStatusFn SCardStatus;
++ SCardGetAttribFn SCardGetAttrib;
++ SCardGetStatusChangeFn SCardGetStatusChange;
++ SCardCancelFn SCardCancel;
++ SCARD_IO_REQUEST *SCARD_PCI_T0_;
++ SCARD_IO_REQUEST *SCARD_PCI_T1_;
++} SCard;
++
++#define GET_ADDRESS(library, scard, name) \
++ status= ckyShLibrary_getAddress(library, \
++ (void**) &scard->name, MAKE_DLL_SYMBOL(name)); \
++ if (status != CKYSUCCESS) { \
++ goto fail; \
++ }
++
++#ifdef WIN32
++#define SCARD_LIB_NAME "winscard.dll"
++#else
++#ifdef MAC
++#define SCARD_LIB_NAME "PCSC.Framework/PCSC"
++#else
++#ifdef LINUX
++#define SCARD_LIB_NAME "libpcsclite.so"
++#else
++#ifndef SCARD_LIB_NAME
++#error "define wincard library for this platform"
++#endif
++#endif
++#endif
++#endif
++
++static SCard *
++ckySCard_Init(void)
++{
++ ckyShLibrary library;
++ CKYStatus status;
++ SCard *scard = NEW(SCard, 1);
++
++ if (!scard) {
++ return NULL;
++ }
++
++ library = ckyShLibrary_open(SCARD_LIB_NAME);
++ if (!library) {
++ goto fail;
++ }
++
++ GET_ADDRESS(library, scard, SCardEstablishContext);
++ GET_ADDRESS(library, scard, SCardReleaseContext);
++ GET_ADDRESS(library, scard, SCardBeginTransaction);
++ GET_ADDRESS(library, scard, SCardEndTransaction);
++ /* expands to SCardConnectA on Windows */
++ GET_ADDRESS(library, scard, SCardConnect);
++ GET_ADDRESS(library, scard, SCardDisconnect);
++ GET_ADDRESS(library, scard, SCardTransmit);
++ GET_ADDRESS(library, scard, SCardReconnect);
++ /* expands to SCardListReadersA on Windows */
++ GET_ADDRESS(library, scard, SCardListReaders);
++ /* expands to SCardStatusA on Windows */
++ GET_ADDRESS(library, scard, SCardStatus);
++#ifdef WIN32
++ GET_ADDRESS(library, scard, SCardGetAttrib);
++#endif
++ /* SCardGetStatusChangeA */
++ GET_ADDRESS(library, scard, SCardGetStatusChange);
++ GET_ADDRESS(library, scard, SCardCancel);
++
++ status = ckyShLibrary_getAddress( library,
++ (void**) &scard->SCARD_PCI_T0_, MAKE_DLL_SYMBOL(g_rgSCardT0Pci));
++ if( status != CKYSUCCESS ) {
++ goto fail;
++ }
++
++ status = ckyShLibrary_getAddress( library,
++ (void**) &scard->SCARD_PCI_T1_, MAKE_DLL_SYMBOL(g_rgSCardT1Pci));
++ if( status != CKYSUCCESS ) {
++ goto fail;
++ }
++ return scard;
++
++fail:
++ if (library) {
++ ckyShLibrary_close(library);
++ }
++ free(scard);
++ return NULL;
++}
++/*
++ * Implement CKYReaderNameLists and CKYCardConnectionLists
++ */
++/* make the list code happy */
++static void
++CKYReaderName_Destroy(char *data) {
++ free(data);
++}
++
++#include "cky_list.i" /* implemnentation of the lists define by cky_list.h
*/
++CKYLIST_IMPLEMENT(CKYReaderName, char *)
++CKYLIST_IMPLEMENT(CKYCardConnection, CKYCardConnection *)
++
++
++/*
++ * CKReader objects represent Readers attached to the system.
++ * The objects themselves are really SCard SCARD_READERSTATE objects.
++ * These objects are used in 2 ways:
++ * 1) the application creates static SCARD_READERSTATE's and use
++ * CKYReader_Init() to initialize the structure. In this case
++ * the application can call any of the reader 'methods' (functions
++ * starting with CKReader) on these objects. When finished the
++ * application is responsible for calling CKYReader_FreeData() to free
++ * any data held by the reader object.
++ * 2) Acquire an array of readers with CKYReader_CreateArray(). In this
++ * case the application can call any method on any particular array member
++ * In the end the Application is responsible for calling
++ * CKYReader_DestroyArray() to free the entire array.
++ */
++
++void
++CKYReader_Init(SCARD_READERSTATE *reader)
++{
++ reader->szReader = NULL;
++ reader->pvUserData = 0;
++ reader->cbAtr = 0;
++ reader->dwCurrentState = SCARD_STATE_UNAWARE;
++}
++
++void
++CKYReader_FreeData(SCARD_READERSTATE *reader)
++{
++ if (reader->szReader) {
++ free((void *)reader->szReader);
++ }
++ CKYReader_Init(reader);
++}
++
++CKYStatus
++CKYReader_SetReaderName(SCARD_READERSTATE *reader, const char *name)
++{
++ free((void *)reader->szReader);
++ reader->szReader = strdup(name);
++ return (reader->szReader)? CKYSUCCESS: CKYNOMEM;
++}
++
++const char *
++CKYReader_GetReaderName(const SCARD_READERSTATE *reader)
++{
++ return reader->szReader;
++}
++
++/* see openSC or PCSC for the semantics of Known State and Event States */
++CKYStatus
++CKYReader_SetKnownState(SCARD_READERSTATE *reader, unsigned long state)
++{
++ reader->dwCurrentState = state;
++ return CKYSUCCESS;
++}
++
++unsigned long
++CKYReader_GetKnownState(const SCARD_READERSTATE *reader)
++{
++ return reader->dwCurrentState;
++}
++
++unsigned long
++CKYReader_GetEventState(const SCARD_READERSTATE *reader)
++{
++ return reader->dwEventState;
++}
++
++/* Caller must have init'ed the buffer before calling
++ * any data in the existing buffer is overwritten */
++CKYStatus
++CKYReader_GetATR(const SCARD_READERSTATE *reader, CKYBuffer *buf)
++{
++ CKYStatus ret;
++
++ ret = CKYBuffer_Resize(buf, reader->cbAtr);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ return CKYBuffer_Replace(buf, 0, reader->rgbAtr, reader->cbAtr);
++}
++
++SCARD_READERSTATE *
++CKYReader_CreateArray(const CKYReaderNameList readerNames,
++ unsigned long *returnReaderCount)
++{
++ unsigned long i,j;
++ unsigned long readerCount;
++ SCARD_READERSTATE *readers;
++ CKYStatus ret;
++
++ readerCount=CKYReaderNameList_GetCount(readerNames);
++ if (readerCount == 0) {
++ return NULL;
++ }
++ readers = NEW(SCARD_READERSTATE, readerCount);
++ if (readers == NULL) {
++ return NULL;
++ }
++
++ for (i=0; i < readerCount; i++) {
++ CKYReader_Init(&readers[i]);
++ ret = CKYReader_SetReaderName(&readers[i],
++ CKYReaderNameList_GetValue(readerNames,i));
++ if (ret != CKYSUCCESS) {
++ break;
++ }
++ }
++ if (ret != CKYSUCCESS) {
++ for (j=0; j < i; j++) {
++ CKYReader_FreeData(&readers[j]);
++ }
++ free(readers);
++ return NULL;
++ }
++ if (returnReaderCount) {
++ *returnReaderCount=readerCount;
++ }
++
++ return readers;
++}
++
++/*
++ * add more reader states to an existing reader state array.
++ * The existing reader will have a new pointer, which will be updated only
++ * after the new one is complete, and before the old one is freed. The 'add'
++ * array is not modified or freed.
++ */
++CKYStatus
++CKYReader_AppendArray(SCARD_READERSTATE **array, unsigned long arraySize,
++ const char **readerNames, unsigned long numReaderNames)
++{
++ unsigned long i,j;
++ SCARD_READERSTATE *readers;
++ SCARD_READERSTATE *old;
++ CKYStatus ret = CKYSUCCESS;
++
++ readers = NEW(SCARD_READERSTATE, arraySize+numReaderNames);
++ if (readers == NULL) {
++ return CKYNOMEM;
++ }
++ /* copy the original readers, inheriting all the pointer memory */
++ memcpy(readers, *array, arraySize*sizeof(SCARD_READERSTATE));
++
++ /* initialize and add the new reader states. */
++ for (i=0; i < numReaderNames; i++) {
++ CKYReader_Init(&readers[i+arraySize]);
++ ret = CKYReader_SetReaderName(&readers[i+arraySize],readerNames[i]);
++ if (ret != CKYSUCCESS) {
++ break;
++ }
++ }
++
++ /* we failed, only free the new reader states, ownership of the new
++ * ones will revert back to the original */
++ if (ret != CKYSUCCESS) {
++ for (j=0; j < i; j++) {
++ CKYReader_FreeData(&readers[j+arraySize]);
++ }
++ free(readers);
++ return ret;
++ }
++
++ /* Now we swap the readers states */
++ old = *array;
++ *array = readers;
++ /* it's now safe to free the old one */
++ free(old);
++
++ return CKYSUCCESS;
++}
++
++void
++CKYReader_DestroyArray(SCARD_READERSTATE *reader, unsigned long readerCount)
++{
++ unsigned long i;
++
++ for (i=0; i < readerCount; i++) {
++ CKYReader_FreeData(&reader[i]);
++ }
++ free(reader);
++}
++
++/*
++ * CKYCardContexts are wrapped access to the SCard Context, which is
++ * part of the openSC/ Microsoft PCSC interface. Applications will
++ * typically open one context to get access to the SCard Subsystem.
++ *
++ * To protect ourselves from systems without the SCard library installed,
++ * the SCard calls are looked up from the library and called through
++ * a function pointer.
++ */
++struct _CKYCardContext {
++ SCARDCONTEXT context;
++ SCard *scard;
++ unsigned long scope;
++ unsigned long lastError;
++};
++
++
++static CKYStatus
++ckyCardContext_init(CKYCardContext *ctx)
++{
++ static SCard *scard;
++
++ ctx->lastError = 0;
++ ctx->context = 0;
++ if (!scard) {
++ scard = ckySCard_Init();
++ if (!scard) {
++ return CKYNOSCARD;
++ }
++ }
++ ctx->scard = scard;
++ return CKYSUCCESS;
++}
++
++static CKYStatus
++ckyCardContext_release(CKYCardContext *ctx)
++{
++ unsigned long rv = ctx->scard->SCardReleaseContext(ctx->context);
++ ctx->context = 0;
++ if (rv != SCARD_S_SUCCESS) {
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++static CKYStatus
++ckyCardContext_establish(CKYCardContext *ctx, unsigned long scope)
++{
++ unsigned long rv;
++
++ if (ctx->context) {
++ ckyCardContext_release(ctx);
++ }
++ rv = ctx->scard->SCardEstablishContext(scope, NULL, NULL,
&ctx->context);
++ if (rv != SCARD_S_SUCCESS) {
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYCardContext *
++CKYCardContext_Create(unsigned long scope)
++{
++ CKYCardContext *ctx;
++ CKYStatus ret;
++
++ ctx = NEW(CKYCardContext, 1);
++ if (ctx == NULL) {
++ return NULL;
++ }
++ ret = ckyCardContext_init(ctx);
++ if (ret != CKYSUCCESS) {
++ CKYCardContext_Destroy(ctx);
++ return NULL;
++ }
++ ctx->scope = scope;
++ ret = ckyCardContext_establish(ctx, scope);
++#ifdef MAC
++/* Apple won't establish a connnection if pcscd is not running. Because of
++ * the way securityd controls pcscd, this may not necessarily be an error
++ * condition. Detect this case and continue. We'll establish the connection
++ * later..
++ */
++ if (ctx->lastError == SCARD_F_INTERNAL_ERROR) {
++ ctx->context = 0; /* make sure it's not established */
++ return ctx;
++ }
++#endif
++ if (ret != CKYSUCCESS) {
++ CKYCardContext_Destroy(ctx);
++ return NULL;
++ }
++ return ctx;
++}
++
++CKYStatus
++CKYCardContext_Destroy(CKYCardContext *ctx)
++{
++ CKYStatus ret = CKYSUCCESS;
++ if (ctx == NULL) {
++ return CKYSUCCESS;
++ }
++ if (ctx->context) {
++ ret = ckyCardContext_release(ctx);
++ }
++ free(ctx);
++ return ret;
++}
++
++SCARDCONTEXT
++CKYCardContext_GetContext(const CKYCardContext *ctx)
++{
++ return ctx->context;
++}
++
++CKYStatus
++CKYCardContext_ListReaders(CKYCardContext *ctx, CKYReaderNameList *readerNames)
++{
++ unsigned long readerLen;
++ unsigned long rv;
++ char * readerStr = NULL;
++ char *cur;
++ char ** readerList;
++ int count,i;
++
++
++ /* return NULL in the case nothing is found, or there is an error */
++ *readerNames = NULL;
++
++ /* if we aren't established yet, do so now */
++ if (!ctx->context) {
++ CKYStatus ret = ckyCardContext_establish(ctx, ctx->scope);
++ if (ret != CKYSUCCESS) {
++
++#ifdef MAC
++ if (ctx->lastError == SCARD_F_INTERNAL_ERROR) {
++ /* Still can't establish, just treat it as 'zero' readers */
++ return CKYSUCCESS;
++ }
++#endif
++ return ret;
++ }
++ }
++
++ /* get the initial length */
++ readerLen = 0;
++ rv = ctx->scard->SCardListReaders(ctx->context, NULL /*groups*/,
++ NULL, &readerLen);
++ /* handle the other errors from SCardListReaders */
++ if (rv == SCARD_E_NO_READERS_AVAILABLE) {
++ /* not really an error: there are no readers */
++ return CKYSUCCESS;
++ }
++
++ if( rv != SCARD_S_SUCCESS ) {
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++
++ /* if no readers, return OK and a NULL list */
++ if (readerLen == 0) {
++ return CKYSUCCESS;
++ }
++
++ /*
++ * Keep trying to read in the buffer, allowing that the required buffer
++ * length may change between calls to SCardListReaders.
++ */
++ do {
++ if (readerLen < 1 || readerLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
++ return CKYNOMEM;
++ }
++ readerStr = NEW(char,readerLen);
++ if (readerStr == NULL) {
++ return CKYNOMEM;
++ }
++
++ rv = ctx->scard->SCardListReaders(ctx->context, NULL /*groups*/,
++ readerStr, &readerLen);
++
++ /* we've found it, pop out with readerStr allocated */
++ if (rv == SCARD_S_SUCCESS) {
++ break;
++ }
++
++ /* Nope, free the reader we allocated */
++ free(readerStr);
++ readerStr = NULL;
++
++ } while( rv == SCARD_E_INSUFFICIENT_BUFFER );
++
++ /* handle the other errors from SCardListReaders */
++ if (rv == SCARD_E_NO_READERS_AVAILABLE) {
++ /* not really an error: there are no readers */
++ ctx->lastError = SCARD_E_NO_READERS_AVAILABLE;
++ return CKYSUCCESS;
++ }
++ if (rv != SCARD_S_SUCCESS) {
++ /* stash the error and fail */
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++
++ /*
++ * Windows returns the list of readers as a series of null terminated
++ * strings, terminated with an additional NULL. For example, if there
++ * are three readers name "Reader 1", "Reader 2", "Reader
3", the returned
++ * readerStr would look like: "Reader 1\0Reader 2\0Reader N\0\0".
++ *
++ * We need to return a list of ReaderNames. This is currently a pointer
++ * to an array of string pointers, terminated by a NULL.
++ *
++ * +--------------+
++ * | Reader 1 ptr | -> "Reader 1"
++ * +--------------+
++ * | Reader 2 ptr | -> "Reader 2"
++ * +--------------+
++ * | Reader N ptr | -> "Reader N"
++ * +--------------+
++ * | NULL |
++ * +--------------+
++ *
++ * NOTE: This code explicitly knows the underlying format for
++ * CKYReaderNameLists defined in cky_list.i. If cky_list.i is changes,
++ * this code will need to be changed as well.
++ */
++ /* find the count of readers */
++ for (cur = readerStr, count = 0; *cur; cur += strlen(cur)+1, count++ )
++ /* Empty */ ;
++ readerList = NEW(char *,count+1);
++ if (readerList == NULL) {
++ goto fail;
++ }
++
++ /* now copy the readers into the array */
++ for (i=0, cur=readerStr; i < count ; cur+=strlen(cur) +1, i++) {
++ readerList[i] = strdup(cur);
++ if (readerList[i] == NULL) {
++ goto fail;
++ }
++ }
++ readerList[count] = NULL;
++ free(readerStr);;
++ *readerNames = (CKYReaderNameList) readerList;
++ return CKYSUCCESS;
++
++fail:
++ if (readerStr) {
++ free(readerStr);
++ }
++ if (readerList) {
++ CKYReaderNameList_Destroy((CKYReaderNameList) readerList);
++ }
++ return CKYNOMEM;
++}
++
++/*
++ * The original C++ API had to very similiar functions that returned
++ * either reader names or connections based on ATR. This is a single
++ * function that can return both. The exported interface calls this
++ * one with one of the lists set to NULL.
++ *
++ * NOTE: this function "knows" the underlying format for lists and
++ * hand builds the related lists.
++ */
++CKYStatus
++ckyCardContext_findReadersByATR(CKYCardContext *ctx,
++ CKYReaderNameList *returnReaders,
++ CKYCardConnectionList *returnConn,
++ const CKYBuffer *targetATR)
++{
++ CKYReaderNameList readerNames;
++ CKYBuffer ATR;
++ CKYCardConnection **connList = NULL;
++ CKYCardConnection **connPtr = NULL;
++ char **readerList = NULL;
++ char **readerPtr = NULL;
++ int readerCount, i;
++ CKYStatus ret;
++
++ CKYBuffer_InitEmpty(&ATR);
++
++ /* if we aren't established yet, do so now */
++ if (!ctx->context) {
++ ret = ckyCardContext_establish(ctx, ctx->scope);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++
++ /* initialize our returned values to empty */
++ if (returnReaders) {
++ *returnReaders = NULL;
++ }
++ if (returnConn) {
++ *returnConn = NULL;
++ }
++
++ ret = CKYCardContext_ListReaders(ctx, &readerNames);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++
++ readerCount = CKYReaderNameList_GetCount(readerNames);
++
++ /* none found, return success */
++ if (readerCount == 0) {
++ CKYReaderNameList_Destroy(readerNames);
++ return CKYSUCCESS;
++ }
++
++ /* now initialize our name and connection lists */
++ if (returnConn) {
++ connList = NEW(CKYCardConnection *, readerCount);
++ connPtr = connList;
++ if (connList == NULL) {
++ goto fail;
++ }
++ }
++ if (returnReaders) {
++ readerList = NEW(char *, readerCount);
++ readerPtr = readerList;
++ if (readerList == NULL) {
++ goto fail;
++ }
++ }
++
++ ret = CKYBuffer_Resize(&ATR, CKY_MAX_ATR_LEN);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++
++ /* now walk the reader list trying to get connections */
++ for (i=0; i < readerCount ; i++) {
++ CKYCardConnection * conn = CKYCardConnection_Create(ctx);
++ unsigned long state;
++ const char *thisReader = CKYReaderNameList_GetValue(readerNames, i);
++
++
++ if (!conn) {
++ goto loop;
++ }
++ ret = CKYCardConnection_Connect(conn, thisReader);
++ if (ret != CKYSUCCESS) {
++ goto loop;
++ }
++ ret = CKYCardConnection_GetStatus(conn, &state, &ATR);
++ if (ret != CKYSUCCESS) {
++ goto loop;
++ }
++ if (CKYBuffer_IsEqual(targetATR, &ATR)) {
++ if (connPtr) {
++ *connPtr++ = conn; /* adopt */
++ conn = NULL;
++ }
++ if (readerPtr) {
++ *readerPtr++ = strdup(thisReader);
++ }
++ }
++
++loop:
++ /* must happen each time through the loop */
++ if (conn) {
++ CKYCardConnection_Destroy(conn);
++ }
++ }
++
++ /* done with the reader names now */
++ CKYReaderNameList_Destroy(readerNames);
++ /* and the ATR buffer */
++ CKYBuffer_FreeData(&ATR);
++
++ /* terminate out lists and return them */
++ if (readerPtr) {
++ *readerPtr = NULL;
++ *returnReaders = (CKYReaderNameList) readerList;
++ }
++ if (connPtr) {
++ *connPtr = NULL;
++ *returnConn = (CKYCardConnectionList) connList;
++ }
++ return CKYSUCCESS;
++
++fail:
++ if (readerNames) {
++ CKYReaderNameList_Destroy(readerNames);
++ }
++ if (connList) {
++ free(connList);
++ }
++ if (readerList) {
++ free(readerList);
++ }
++ CKYBuffer_FreeData(&ATR);
++ return CKYNOMEM;
++}
++
++CKYStatus
++CKYCardContext_FindCardsByATR(CKYCardContext *ctx,
++ CKYCardConnectionList *cardList, const CKYBuffer *targetATR)
++{
++ return ckyCardContext_findReadersByATR(ctx, NULL, cardList, targetATR);
++}
++
++CKYStatus
++CKYCardContext_FindReadersByATR(CKYCardContext *ctx,
++ CKYReaderNameList *readerNames, const CKYBuffer *targetATR)
++{
++ return ckyCardContext_findReadersByATR(ctx, readerNames, NULL, targetATR);
++}
++
++CKYCardConnection *
++CKYCardContext_CreateConnection(CKYCardContext *ctx)
++{
++ return CKYCardConnection_Create(ctx);
++}
++
++CKYStatus
++CKYCardContext_WaitForStatusChange(CKYCardContext *ctx,
++ SCARD_READERSTATE *readers, unsigned long readerCount,
++ unsigned long timeout)
++{
++ unsigned long rv;
++
++ /* if we aren't established yet, do so now */
++ if (!ctx->context) {
++ CKYStatus ret = ckyCardContext_establish(ctx, ctx->scope);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ }
++ rv = ctx->scard->SCardGetStatusChange(ctx->context, timeout,
++ readers, readerCount);
++ if (rv != SCARD_S_SUCCESS) {
++ if ((rv == SCARD_E_NO_SERVICE) || (rv == SCARD_E_SERVICE_STOPPED)) {
++ /* if we were stopped, don't reuse the old context,
++ * pcsc-lite hangs */
++ ckyCardContext_release(ctx);
++ }
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardContext_Cancel(CKYCardContext *ctx)
++{
++ unsigned long rv;
++
++ /* if we aren't established yet, we can't be in change status then */
++ if (!ctx->context) {
++ return CKYSUCCESS;
++ }
++ rv = ctx->scard->SCardCancel(ctx->context);
++
++ if (rv != SCARD_S_SUCCESS) {
++ ctx->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++unsigned long
++CKYCardContext_GetLastError(const CKYCardContext *ctx)
++{
++ return ctx->lastError;
++}
++
++/*
++ * Connections represent the connection to the actual smart cards.
++ * Applications usually has one of these for each card inserted in
++ * the system. Connections are where we can get information about
++ * each card, as well as transmit commands (APDU's) to the card.
++ */
++/* In the originaly C++ library, lastError was set to the last return
++ * code from any SCARD call. In this C version of the library, lastError
++ * is the last non-successful SCARD call. lastError will be set
++ * if the function returns CKYSCARDERR.
++ */
++struct _CKYCardConnection {
++ const CKYCardContext *ctx;
++ SCard *scard; /* cache a copy from the context */
++ SCARDHANDLE cardHandle;
++ unsigned long lastError;
++ CKYBool inTransaction;
++ unsigned long protocol;
++};
++
++static void
++ckyCardConnection_init(CKYCardConnection *conn, const CKYCardContext *ctx)
++{
++ conn->ctx = ctx;
++ conn->scard = ctx->scard;
++ conn->cardHandle = 0;
++ conn->lastError = 0;
++ conn->inTransaction = 0;
++ conn->protocol = SCARD_PROTOCOL_T0;
++}
++
++
++CKYCardConnection *
++CKYCardConnection_Create(const CKYCardContext *ctx)
++{
++ CKYCardConnection *conn;
++
++ /* don't even try if we don't have a Card Context */
++ if (ctx == NULL) {
++ return NULL;
++ }
++
++ conn = NEW(CKYCardConnection, 1);
++ if (conn == NULL) {
++ return NULL;
++ }
++ ckyCardConnection_init(conn, ctx);
++ return conn;
++}
++
++
++CKYStatus
++CKYCardConnection_Destroy(CKYCardConnection *conn)
++{
++ if (conn == NULL) {
++ return CKYSUCCESS;
++ }
++ if (conn->inTransaction) {
++ CKYCardConnection_EndTransaction(conn);
++ }
++ CKYCardConnection_Disconnect(conn);
++ free(conn);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_Connect(CKYCardConnection *conn, const char *readerName)
++{
++ CKYStatus ret;
++ unsigned long rv;
++
++ ret = CKYCardConnection_Disconnect(conn);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ rv = conn->scard->SCardConnect( conn->ctx->context, readerName,
++ SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &conn->cardHandle,
&conn->protocol);
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_Disconnect(CKYCardConnection *conn)
++{
++ unsigned long rv;
++ if (conn->cardHandle == 0) {
++ return CKYSUCCESS;
++ }
++ rv = conn->scard->SCardDisconnect( conn->cardHandle, SCARD_LEAVE_CARD);
++ conn->cardHandle = 0;
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYBool
++CKYCardConnection_IsConnected(const CKYCardConnection *conn)
++{
++ return (conn->cardHandle != 0);
++}
++
++unsigned long
++CKYCardConnection_GetProtocol(const CKYCardConnection *conn)
++{
++ return conn->protocol;
++}
++
++CKYStatus
++ckyCardConnection_reconnectRaw(CKYCardConnection *conn, unsigned long init)
++{
++ unsigned long rv;
++ unsigned long protocol;
++
++ rv = conn->scard->SCardReconnect(conn->cardHandle,
++ SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 , init, &protocol);
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ conn->protocol = protocol;
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_Reconnect(CKYCardConnection *conn)
++{
++ return ckyCardConnection_reconnectRaw(conn, SCARD_LEAVE_CARD);
++}
++
++CKYStatus CKYCardConnection_Reset(CKYCardConnection *conn)
++{
++ return ckyCardConnection_reconnectRaw(conn, SCARD_RESET_CARD);
++}
++
++CKYStatus
++CKYCardConnection_BeginTransaction(CKYCardConnection *conn)
++{
++ unsigned long rv;
++ rv = conn->scard->SCardBeginTransaction(conn->cardHandle);
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ conn->inTransaction = 1;
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_EndTransaction(CKYCardConnection *conn)
++{
++ unsigned long rv;
++ if (!conn->inTransaction) {
++ return CKYSUCCESS; /* C++ library returns success in this case, but
++ * it may be better to return an error ? */
++ }
++ rv = conn->scard->SCardEndTransaction(conn->cardHandle, SCARD_LEAVE_CARD);
++ conn->inTransaction = 0;
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_TransmitAPDU(CKYCardConnection *conn, CKYAPDU *apdu,
++ CKYBuffer *response)
++{
++ CKYStatus ret;
++ unsigned long rv;
++
++ ret = CKYBuffer_Resize(response, CKYAPDU_MAX_LEN);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++
++ if( conn->protocol == SCARD_PROTOCOL_T0 ) {
++ rv = conn->scard->SCardTransmit(conn->cardHandle,
++ conn->scard->SCARD_PCI_T0_,
++ CKYBuffer_Data(&apdu->apduBuf), CKYBuffer_Size(&apdu->apduBuf),
++ NULL, response->data, &response->len);
++ } else {
++ rv = conn->scard->SCardTransmit(conn->cardHandle,
++ conn->scard->SCARD_PCI_T1_,
++ CKYBuffer_Data(&apdu->apduBuf),
CKYBuffer_Size(&apdu->apduBuf),
++ NULL, response->data, &response->len);
++ }
++
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError =rv;
++ return CKYSCARDERR;
++ }
++
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_ExchangeAPDU(CKYCardConnection *conn, CKYAPDU *apdu,
++ CKYBuffer *response)
++{
++ CKYStatus ret;
++ CKYBuffer getResponse;
++ CKYSize size = 0;
++
++ ret = CKYCardConnection_TransmitAPDU(conn, apdu, response);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ CKYBuffer_InitEmpty(&getResponse);
++
++ /* automatically handle the response data protocol */
++ while ((ret == CKYSUCCESS) &&
++ (size = CKYBuffer_Size(response)) >= 2 &&
++ (CKYBuffer_GetChar(response,size-2) == 0x61)) {
++ /* get the response */
++ CKYAPDU getResponseAPDU;
++
++ CKYBuffer_Zero(&getResponse);
++ CKYAPDU_Init(&getResponseAPDU);
++ CKYAPDU_SetCLA(&getResponseAPDU, 0x00);
++ CKYAPDU_SetINS(&getResponseAPDU, 0xc0);
++ CKYAPDU_SetP1(&getResponseAPDU, 0x00);
++ CKYAPDU_SetP2(&getResponseAPDU, 0x00);
++ CKYAPDU_SetReceiveLen(&getResponseAPDU,
++ CKYBuffer_GetChar(response,size-1));
++ ret = CKYCardConnection_TransmitAPDU(conn, &getResponseAPDU,
++ &getResponse);
++ CKYAPDU_FreeData(&getResponseAPDU);
++ if ((ret == CKYSUCCESS) && (CKYBuffer_Size(&getResponse) >= 2)) {
++ CKYBuffer_Resize(response, size-2);
++ CKYBuffer_AppendCopy(response,&getResponse);
++ }
++ }
++ CKYBuffer_FreeData(&getResponse);
++ return ret;
++}
++
++CKYStatus
++CKYCardConnection_GetStatus(CKYCardConnection *conn,
++ unsigned long *state, CKYBuffer *ATR)
++{
++ unsigned long readerLen = 0;
++ unsigned long protocol;
++ unsigned long rv;
++ CKYSize atrLen;
++ char *readerStr;
++ CKYStatus ret;
++
++
++ /*
++ * Get initial length. We have to do all this because the Muscle
++ * implementation of PCSC requires us to supply a non-NULL argument
++ * for readerName before it will tell us the ATR, which is all we really
++ * care about.
++ */
++ rv = conn->scard->SCardStatus(conn->cardHandle,
++ NULL /*readerName*/, &readerLen, state, &protocol, NULL, &atrLen);
++ if ( rv != SCARD_S_SUCCESS ) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++
++ do {
++ if (readerLen < 1 || readerLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
++ return CKYNOMEM;
++ }
++ /* Mac & Linux return '0' or ATR length, just use the max value */
++ if (atrLen == 0) {
++ atrLen = CKY_MAX_ATR_LEN;
++ }
++ if (atrLen < 1 || atrLen > CKY_OUTRAGEOUS_MALLOC_SIZE) {
++ return CKYNOMEM;
++ }
++ ret = CKYBuffer_Resize(ATR, atrLen);
++ if (ret != CKYSUCCESS) {
++ return ret;
++ }
++ readerStr = NEW(char, readerLen);
++ if (readerStr == NULL) {
++ return CKYNOMEM;
++ }
++
++ rv = conn->scard->SCardStatus(conn->cardHandle, readerStr, &readerLen,
++ state, &protocol, ATR->data, &atrLen);
++ ATR->len = atrLen;
++ free(readerStr);
++ } while (rv == SCARD_E_INSUFFICIENT_BUFFER);
++
++ if (rv != SCARD_S_SUCCESS) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYCardConnection_GetAttribute(CKYCardConnection *conn,
++ unsigned long attrID, CKYBuffer *attrBuf)
++{
++#ifdef WIN32
++ unsigned long len = 0;
++ unsigned long rv;
++
++ /*
++ * Get initial length. We have to do all this because the Muscle
++ * implementation of PCSC requires us to supply a non-NULL argument
++ * for readerName before it will tell us the ATR, which is all we really
++ * care about.
++ */
++ rv = conn->scard->SCardGetAttrib(conn->cardHandle, attrID, NULL,
&len);
++ if ( rv != SCARD_S_SUCCESS ) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ CKYBuffer_Resize(attrBuf, len);
++
++ rv = conn->scard->SCardGetAttrib(conn->cardHandle, attrID,
++ attrBuf->data, &attrBuf->len);
++ if( rv != SCARD_S_SUCCESS ) {
++ conn->lastError = rv;
++ return CKYSCARDERR;
++ }
++ return CKYSUCCESS;
++#else
++ conn->lastError = -1;
++ return CKYSCARDERR;
++#endif
++}
++
++const CKYCardContext *
++CKYCardConnection_GetContext(const CKYCardConnection *conn)
++{
++ return conn->ctx;
++}
++
++unsigned long
++CKYCardConnection_GetLastError(const CKYCardConnection *conn)
++{
++ return conn->lastError;
++}
+diff -up ./esc/src/lib/coolkey/cky_card.h.fix1 ./esc/src/lib/coolkey/cky_card.h
+--- ./esc/src/lib/coolkey/cky_card.h.fix1 2018-04-26 11:44:38.439986181 -0700
++++ ./esc/src/lib/coolkey/cky_card.h 2018-04-26 11:44:38.439986181 -0700
+@@ -0,0 +1,132 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_CARD_H
++#define CKY_CARD_H 1
++
++#include <winscard.h>
++
++#include "cky_base.h"
++#include "cky_list.h"
++
++/*
++ * hide the structure of CardConnections and CardContexts
++ */
++typedef struct _CKYCardContext CKYCardContext;
++typedef struct _CKYCardConnection CKYCardConnection;
++
++/*
++ * define CKYReaderNameList, CKYReaderNameIterator, CKYCardConnectionList, and
++ * CKYCardConnectionIterator, and their associated functions.
++ * See cky_list.h for these functions .
++ */
++
++CKYLIST_DECLARE(CKYReaderName, char *)
++CKYLIST_DECLARE(CKYCardConnection, CKYCardConnection *)
++
++CKY_BEGIN_PROTOS
++void CKYReader_Init(SCARD_READERSTATE *reader);
++void CKYReader_FreeData(SCARD_READERSTATE *reader);
++
++/*
++ * "Accessors": for SCARD_READERSTATE structure as a class.
++ * These functions take an SCARD_READERSTATE which can also be referenced
++ * directly.
++ */
++CKYStatus CKYReader_SetReaderName(SCARD_READERSTATE *reader, const char *name);
++const char *CKYReader_GetReaderName(const SCARD_READERSTATE *reader);
++CKYStatus CKYReader_SetKnownState(SCARD_READERSTATE *reader,
++ unsigned long state);
++unsigned long CKYReader_GetKnownState(const SCARD_READERSTATE *reader);
++unsigned long CKYReader_GetEventState(const SCARD_READERSTATE *reader);
++CKYStatus CKYReader_GetATR(const SCARD_READERSTATE *reader, CKYBuffer *buf);
++/* create an array of READERSTATEs from a LIST of Readers */
++SCARD_READERSTATE *CKYReader_CreateArray(const CKYReaderNameList readerNames,
++ unsigned long *readerCount);
++/* frees the reader, then the full array */
++void CKYReader_DestroyArray(SCARD_READERSTATE *reader, unsigned long count);
++/* add more elements to a ReaderState array*/
++CKYStatus
++CKYReader_AppendArray(SCARD_READERSTATE **array, unsigned long arraySize,
++ const char **readerNames, unsigned long numReaderNames);
++
++/*
++ * card contexts wrap Microsoft's SCARDCONTEXT.
++ */
++/* create a new one. SCOPE must be SCOPE_USER */
++CKYCardContext *CKYCardContext_Create(unsigned long scope);
++/* destroy an existing one */
++CKYStatus CKYCardContext_Destroy(CKYCardContext *context);
++/* get the Windows handle associated with this context */
++SCARDCONTEXT CKYCardContext_GetContext(const CKYCardContext *context);
++/* Get a list of the installed readers */
++CKYStatus CKYCardContext_ListReaders(CKYCardContext *context,
++ CKYReaderNameList *readerNames);
++/* get a list of card connections for cards matching our target ATR */
++CKYStatus CKYCardContext_FindCardsByATR(CKYCardContext *context,
++ CKYCardConnectionList *cardList,
++ const CKYBuffer *targetATR);
++/* get a list of readers with attached cards that match our target ATR */
++CKYStatus CKYCardContext_FindReadersByATR(CKYCardContext *context,
++ CKYReaderNameList *readerNames,
++ const CKYBuffer *targetATR);
++/* return if any of the readers in our array has changed in status */
++CKYStatus CKYCardContext_WaitForStatusChange(CKYCardContext *context,
++ SCARD_READERSTATE *readers,
++ unsigned long readerCount,
++ unsigned long timeout);
++/* cancel any current operation (such as wait for status change) on this
++ * context */
++CKYStatus CKYCardContext_Cancel(CKYCardContext *context);
++/* get the last underlying Windows SCARD error */
++unsigned long CKYCardContext_GetLastError(const CKYCardContext *context);
++
++/*
++ * manage the actual connection to a card.
++ */
++/* create a connection. A connection is not associated with a reader
++ * until CKYCardConnection_Connect() is called.
++ */
++CKYCardConnection *CKYCardConnection_Create(const CKYCardContext *context);
++CKYStatus CKYCardConnection_Destroy(CKYCardConnection *connection);
++CKYStatus CKYCardConnection_BeginTransaction(CKYCardConnection *connection);
++CKYStatus CKYCardConnection_EndTransaction(CKYCardConnection *connection);
++CKYStatus CKYCardConnection_TransmitAPDU(CKYCardConnection *connection,
++ CKYAPDU *apdu,
++ CKYBuffer *response);
++CKYStatus CKYCardConnection_ExchangeAPDU(CKYCardConnection *connection,
++ CKYAPDU *apdu,
++ CKYBuffer *response);
++CKYStatus CKYCardConnection_Connect(CKYCardConnection *connection,
++ const char *readerName);
++CKYStatus CKYCardConnection_Disconnect(CKYCardConnection *connection);
++unsigned long CKYCardConnection_GetProtocol(const CKYCardConnection *conn);
++CKYBool CKYCardConnection_IsConnected(const CKYCardConnection *connection);
++CKYStatus CKYCardConnection_Reconnect(CKYCardConnection *connection);
++CKYStatus CKYCardConnection_GetStatus(CKYCardConnection *connection,
++ unsigned long *state, CKYBuffer *ATR);
++CKYStatus CKYCardConnection_GetAttribute(CKYCardConnection *connection,
++ unsigned long attrID, CKYBuffer *attrBuf);
++CKYStatus CKYCardConnection_Reset(CKYCardConnection *connection);
++const CKYCardContext *CKYCardConnection_GetContext(const CKYCardConnection *cxt);
++unsigned long CKYCardConnection_GetLastError(const CKYCardConnection *context);
++
++CKY_END_PROTOS
++
++#endif /* CKY_CARD_H */
+diff -up ./esc/src/lib/coolkey/cky_factory.c.fix1 ./esc/src/lib/coolkey/cky_factory.c
+--- ./esc/src/lib/coolkey/cky_factory.c.fix1 2018-04-26 11:44:38.439986181 -0700
++++ ./esc/src/lib/coolkey/cky_factory.c 2018-04-26 11:44:38.439986181 -0700
+@@ -0,0 +1,885 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include "string.h"
++#include "cky_base.h"
++#include "cky_factory.h"
++
++/*
++ * special commands can be issued at any time
++ */
++CKYStatus
++CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
++ const CKYBuffer *AID)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE);
++ CKYAPDU_SetP1(apdu, p1);
++ CKYAPDU_SetP2(apdu, p2);
++ return CKYAPDU_SetSendDataBuffer(apdu, AID);
++}
++
++CKYStatus
++CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu)
++{
++ CKYByte c = 0;
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE);
++ CKYAPDU_SetP1(apdu, 0x04);
++ CKYAPDU_SetP2(apdu, 0x00);
++ /* I can't find the documentation for this, but if you pass an empty
++ * AID to SelectFile on the Cyberflex Access 32k, it selects the
++ * CardManager applet. Good thing, because I couldn't find any other
++ * way to accomplish this without knowing the AID of the CardManager. */
++ return CKYAPDU_SetSendData(apdu,&c,0);
++}
++
++/*
++ * card manager commands must be issued with the card manager selected.
++ */
++CKYStatus
++CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM);
++ CKYAPDU_SetINS(apdu, ISO_INS_GET_DATA);
++ CKYAPDU_SetP1(apdu, 0x9f);
++ CKYAPDU_SetP2(apdu, 0x7f);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_CPLCDATA);
++}
++/*
++ * applet commands must be issued with the appplet selected.
++ */
++CKYStatus
++CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_LIST_KEYS);
++ CKYAPDU_SetP1(apdu, sequence);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_LIST_KEYS);
++}
++
++CKYStatus
++CKYAPDUFactory_ComputeCryptInit(CKYAPDU *apdu, CKYByte keyNumber, CKYByte mode,
++ CKYByte direction, CKYByte location)
++{
++ CKYByte data[5];
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_INIT);
++ data[0] = mode;
++ data[1] = direction;
++ data[2] = location;
++ data[3] = 0; /* future provide for init data */
++ data[4] = 0;
++ return CKYAPDU_SetSendData(apdu, data, sizeof(data));
++}
++
++CKYStatus
++CKYAPDUFactory_ComputeCryptProcess(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data)
++{
++ CKYStatus ret;
++ CKYBuffer buf;
++
++ CKYBuffer_InitEmpty(&buf);
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_PROCESS);
++ if (data) {
++ ret = CKYBuffer_Reserve(&buf, 3);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, location);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)CKYBuffer_Size(data));
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, data);
++ } else {
++ ret = CKYAPDU_SetSendData(apdu, &location, 1);
++ }
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++
++CKYStatus
++CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data, const CKYBuffer *sig)
++{
++ CKYStatus ret;
++ CKYBuffer buf;
++
++ CKYBuffer_InitEmpty(&buf);
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_FINAL);
++ if (data) {
++ ret = CKYBuffer_Reserve(&buf, 3);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, location);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)CKYBuffer_Size(data));
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, data);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ if (sig) {
++ CKYBuffer_Resize(&buf,2);
++ CKYBuffer_SetShort(&buf, 0, (unsigned short)CKYBuffer_Size(sig));
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, sig);
++ }
++ } else {
++ ret = CKYAPDU_SetSendData(apdu, &location, 1);
++ }
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location,
++ const CKYBuffer *publicData, const CKYBuffer *secretKey)
++{
++ CKYStatus ret = CKYINVALIDARGS;
++ CKYSize len;
++ CKYBuffer buf;
++
++ if (!publicData)
++ return ret;
++
++ if (!(len = CKYBuffer_Size(publicData)))
++ return ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_KEY_AGREEMENT);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
++
++ CKYBuffer_InitEmpty(&buf);
++
++ ret = CKYBuffer_Reserve(&buf, 3);
++
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendChar(&buf, location);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, publicData);
++ if (ret == CKYSUCCESS && secretKey && 0 < (len =
CKYBuffer_Size(secretKey))) {
++ CKYBuffer_Resize(&buf,2);
++ CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, secretKey);
++ }
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber, CKYByte mode,
++ CKYByte direction, CKYByte location,
++ const CKYBuffer *idata, const CKYBuffer *sig)
++{
++ CKYStatus ret = CKYINVALIDARGS;
++ CKYSize len;
++ CKYBuffer buf;
++
++ if (!idata)
++ return ret;
++
++ if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT)
++ return ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_CRYPT);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
++
++ CKYBuffer_InitEmpty(&buf);
++
++ ret = CKYBuffer_Reserve(&buf, 5);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendChar(&buf, mode);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendChar(&buf, direction);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendChar(&buf, location);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, idata);
++ if (ret == CKYSUCCESS && sig && 0 < (len = CKYBuffer_Size(sig)))
{
++ CKYBuffer_Resize(&buf,2);
++ CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, sig);
++ }
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CKYAPDUFactory_CreatePIN(CKYAPDU *apdu, CKYByte pinNumber, CKYByte maxAttempts,
++ const char *pinValue)
++{
++ CKYSize len;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_CREATE_PIN);
++ CKYAPDU_SetP1(apdu, pinNumber);
++ CKYAPDU_SetP2(apdu, maxAttempts);
++ len = strlen(pinValue);
++ return CKYAPDU_SetSendData(apdu, (unsigned char *)pinValue, len);
++}
++
++CKYStatus
++CKYAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte pinNumber, const char *pinValue)
++{
++ CKYSize len;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_VERIFY_PIN);
++ CKYAPDU_SetP1(apdu, pinNumber);
++ CKYAPDU_SetP2(apdu, 0x00);
++ len = strlen(pinValue);
++ return CKYAPDU_SetSendData(apdu, (unsigned char *)pinValue, len);
++}
++
++CKYStatus
++CKYAPDUFactory_ChangePIN(CKYAPDU *apdu, CKYByte pinNumber, const char *oldPin,
++ const char *newPin)
++{
++ CKYSize oldLen, newLen;
++ CKYBuffer buf;
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_CHANGE_PIN);
++ CKYAPDU_SetP1(apdu, pinNumber);
++ CKYAPDU_SetP2(apdu, 0x00);
++
++ CKYBuffer_InitEmpty(&buf);
++ oldLen = strlen(oldPin);
++ newLen = strlen(newPin);
++ /* optimization, do a single malloc for the whole block */
++ ret = CKYBuffer_Reserve(&buf, oldLen+newLen+4);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)oldLen);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendData(&buf, (unsigned char *)oldPin, oldLen);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)newLen);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendData(&buf, (unsigned char *)newPin, newLen);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CKYAPDUFactory_ListPINs(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_LIST_PINS);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_LIST_PINS);
++}
++
++CKYStatus
++CKYAPDUFactory_Logout(CKYAPDU *apdu, CKYByte pinNumber)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_LOGOUT);
++ CKYAPDU_SetP1(apdu, pinNumber);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID, CKYSize size,
++ unsigned short readACL, unsigned short writeACL, unsigned short deleteACL)
++{
++ CKYBuffer buf;
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_CREATE_OBJ);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ CKYBuffer_InitEmpty(&buf);
++ /* optimization, do a single malloc for the whole block */
++ ret = CKYBuffer_Reserve(&buf,0x0e);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendLong(&buf,objectID);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendLong(&buf,size);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf,readACL);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf,writeACL);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendShort(&buf,deleteACL);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++
++}
++
++CKYStatus
++CKYAPDUFactory_DeleteObject(CKYAPDU *apdu, unsigned long objectID, CKYByte zero)
++{
++ CKYBuffer buf;
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_DELETE_OBJ);
++ CKYAPDU_SetP1(apdu, zero);
++ CKYAPDU_SetP2(apdu, 0x00);
++ CKYBuffer_InitEmpty(&buf);
++ ret = CKYBuffer_AppendLong(&buf,objectID);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++
++}
++
++CKYStatus
++CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location,
++ const CKYBuffer *idata, const CKYBuffer *sig)
++{
++ CKYStatus ret = CKYINVALIDARGS;
++ CKYSize len;
++ CKYBuffer buf;
++
++ if (!idata)
++ return ret;
++
++ if (!(len = CKYBuffer_Size(idata)) && location != CKY_DL_OBJECT)
++ return ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_COMPUTE_ECC_SIGNATURE);
++ CKYAPDU_SetP1(apdu, keyNumber);
++ CKYAPDU_SetP2(apdu, CKY_CIPHER_ONE_STEP);
++
++ CKYBuffer_InitEmpty(&buf);
++
++ ret = CKYBuffer_Reserve(&buf, 3);
++
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendChar(&buf, location);
++ if (ret == CKYSUCCESS)
++ ret = CKYBuffer_AppendShort(&buf, (unsigned short)len);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, idata);
++ if (ret == CKYSUCCESS && sig && 0 < (len = CKYBuffer_Size(sig)))
{
++ CKYBuffer_Resize(&buf,2);
++ CKYBuffer_SetShort(&buf, 0, (unsigned short)len);
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, &buf);
++ if (ret == CKYSUCCESS)
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, sig);
++ }
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CKYAPDUFactory_ReadObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYOffset offset, CKYByte size)
++{
++ CKYBuffer buf;
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_READ_OBJ);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ CKYBuffer_InitEmpty(&buf);
++ /* optimization, do a single malloc for the whole block */
++ ret = CKYBuffer_Reserve(&buf,0x09);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendLong(&buf,objectID);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendLong(&buf,offset);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, size);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++
++}
++
++CKYStatus
++CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYOffset offset,CKYSize size,CKYBuffer *data)
++{
++ CKYBuffer buf;
++ CKYStatus ret = CKYSUCCESS;
++ unsigned short dataSize = 0;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_WRITE_OBJ);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ CKYBuffer_InitEmpty(&buf);
++
++ dataSize = (unsigned short) CKYBuffer_Size(data);
++
++ if(!dataSize) {
++ ret = CKYINVALIDARGS;
++ goto fail;
++ }
++
++ ret = CKYBuffer_AppendLong(&buf,objectID);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendLong(&buf,offset);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, size);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++
++ ret = CKYAPDU_SetSendDataBuffer(apdu,&buf);
++
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++
++ ret = CKYAPDU_AppendSendDataBuffer(apdu, data);
++
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++
++}
++
++CKYStatus
++CKYAPDUFactory_ListObjects(CKYAPDU *apdu, CKYByte sequence)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_LIST_OBJECTS);
++ CKYAPDU_SetP1(apdu, sequence);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_LIST_OBJECTS);
++}
++
++CKYStatus
++CKYAPDUFactory_GetStatus(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_STATUS);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_STATUS);
++}
++
++CKYStatus
++CKYAPDUFactory_Noop(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_NOP);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYSUCCESS;
++}
++
++CKYStatus
++CKYAPDUFactory_GetBuildID(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_BUILDID);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_BUILDID);
++}
++
++CKYStatus
++CKYAPDUFactory_GetLifeCycle(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_LIFECYCLE);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_LIFE_CYCLE);
++}
++
++CKYStatus
++CKYAPDUFactory_GetLifeCycleV2(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_LIFECYCLE);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_LIFE_CYCLE_V2);
++}
++
++CKYStatus
++CKYAPDUFactory_GetRandom(CKYAPDU *apdu, CKYByte len)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_RANDOM);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, len);
++}
++
++CKYStatus
++CKYAPDUFactory_SeedRandom(CKYAPDU *apdu, const CKYBuffer *data)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_SEED_RANDOM);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetSendDataBuffer(apdu, data);
++}
++
++CKYStatus
++CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_ISSUER_INFO);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_ISSUER_INFO);
++}
++
++CKYStatus
++CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_COOLKEY);
++ CKYAPDU_SetINS(apdu, CKY_INS_GET_BUILTIN_ACL);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_BUILTIN_ACL);
++}
++
++CKYStatus
++CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, const CKYBuffer *data)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, CAC_INS_SIGN_DECRYPT);
++ CKYAPDU_SetP1(apdu, type);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetSendDataBuffer(apdu, data);
++}
++
++CKYStatus
++CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, CAC_INS_GET_CERTIFICATE);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, size);
++}
++
++CKYStatus
++CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset,
++ CKYByte type, CKYByte count)
++{
++ CKYStatus ret;
++ CKYBuffer buf;
++
++ CKYBuffer_InitEmpty(&buf);
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM);
++ CKYAPDU_SetINS(apdu, CAC_INS_READ_FILE);
++ CKYAPDU_SetP1(apdu, (offset >> 8) & 0xff);
++ CKYAPDU_SetP2(apdu, offset & 0xff);
++ ret = CKYBuffer_Reserve(&buf, 2);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, type);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, count);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++CACAPDUFactory_GetProperties(CKYAPDU *apdu)
++{
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, CAC_INS_GET_PROPERTIES);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, 0x00);
++ return CKYAPDU_SetReceiveLen(apdu, CAC_SIZE_GET_PROPERTIES);
++}
++
++CKYStatus
++PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg,
++ CKYByte key, int len, const CKYBuffer *data)
++{
++ CKYStatus ret;
++ CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN :
++ CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, PIV_INS_GEN_AUTHENTICATE);
++ CKYAPDU_SetP1(apdu, alg);
++ CKYAPDU_SetP2(apdu, key);
++ ret = CKYAPDU_SetSendDataBuffer(apdu, data);
++ if (ret == CKYSUCCESS && chain == 0 && len != 0) {
++ if (len >= 256) len = 0;
++ ret = CKYAPDU_AppendReceiveLen(apdu, len);
++ }
++ return ret;
++}
++
++CKYStatus
++PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object, CKYByte count)
++{
++ CKYStatus ret;
++ CKYBuffer buf;
++ CKYByte objectSize;
++
++ CKYBuffer_InitEmpty(&buf);
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, 0xcb);
++ CKYAPDU_SetP1(apdu, 0x3f);
++ CKYAPDU_SetP2(apdu, 0xff);
++
++ objectSize = CKYBuffer_Size(object);
++
++ ret = CKYBuffer_Reserve(&buf, 2+objectSize);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, 0x5c);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendChar(&buf, objectSize);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYBuffer_AppendCopy(&buf, object);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_SetSendDataBuffer(apdu, &buf);
++ if (ret != CKYSUCCESS) {
++ goto fail;
++ }
++ ret = CKYAPDU_AppendReceiveLen(apdu, count);
++fail:
++ CKYBuffer_FreeData(&buf);
++ return ret;
++}
++
++CKYStatus
++P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const CKYBuffer *pin)
++{
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN);
++ CKYAPDU_SetP1(apdu, 0x00);
++ CKYAPDU_SetP2(apdu, keyRef);
++ /* no pin, send an empty buffer */
++ if (CKYBuffer_Size(pin) == 0) {
++ return CKYAPDU_SetReceiveLen(apdu, 0);
++ }
++
++ /* all CAC pins are 8 bytes exactly. If to long, truncate it */
++ ret = CKYAPDU_SetSendDataBuffer(apdu, pin);
++ return ret;
++
++}
++
++CKYStatus
++P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record, CKYByte short_ef,
++ CKYByte flags, CKYByte count)
++{
++ CKYByte control;
++
++ control = (short_ef << 3) & 0xf8;
++ control |= flags & 0x07;
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_READ_RECORD);
++ CKYAPDU_SetP1(apdu, record);
++ CKYAPDU_SetP2(apdu, control);
++ return CKYAPDU_SetReceiveLen(apdu, count);
++}
++
++CKYStatus
++P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset,
++ CKYByte short_ef, CKYByte flags, CKYByte count)
++{
++ CKYByte p1 = 0,p2 = 0;
++ unsigned short max_offset = 0;
++
++ if (flags & P15_USE_SHORT_EF) {
++ max_offset = 0xff;
++ p1 = P15_USE_SHORT_EF | (short_ef & 0x7);
++ p2 = offset & 0xff;
++ } else {
++ max_offset = 0x7fff;
++ p1 = (offset >> 8) & 0x7f;
++ p2 = offset & 0xff;
++ }
++ if (offset > max_offset) {
++ return CKYINVALIDARGS;
++ }
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_READ_BINARY);
++ CKYAPDU_SetP1(apdu, p1);
++ CKYAPDU_SetP2(apdu, p2);
++ return CKYAPDU_SetReceiveLen(apdu, count);
++}
++
++CKYStatus
++P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
++ CKYByte keyRef)
++{
++ CKYByte param[3];
++
++ CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_MANAGE_SECURITY_ENVIRONMENT);
++ CKYAPDU_SetP1(apdu, p1);
++ CKYAPDU_SetP2(apdu, p2);
++ param[0] = 0x83;
++ param[1] = 1;
++ param[2] = keyRef;
++ return CKYAPDU_SetSendData(apdu, param, sizeof param);
++}
++
++CKYStatus
++P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir,
++ int chain, CKYSize retLen, const CKYBuffer *data)
++{
++ CKYByte p1,p2;
++ CKYStatus ret;
++
++ CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN :
++ CKY_CLASS_ISO7816);
++ CKYAPDU_SetINS(apdu, ISO_INS_PERFORM_SECURITY_OPERATION);
++ if (dir == CKY_DIR_DECRYPT) {
++ p1 = ISO_PSO_DECRYPT_P1;
++ p2 = ISO_PSO_DECRYPT_P2;
++ } else {
++ p1 = ISO_PSO_SIGN_P1;
++ p2 = ISO_PSO_SIGN_P2;
++ }
++ CKYAPDU_SetP1(apdu, p1);
++ CKYAPDU_SetP2(apdu, p2);
++ ret = CKYAPDU_SetSendDataBuffer(apdu, data);
++ if (ret == CKYSUCCESS && (chain == 0) && retLen != 0) {
++ ret = CKYAPDU_AppendReceiveLength(apdu, retLen);
++ }
++ return ret;
++}
++
++
+diff -up ./esc/src/lib/coolkey/cky_factory.h.fix1 ./esc/src/lib/coolkey/cky_factory.h
+--- ./esc/src/lib/coolkey/cky_factory.h.fix1 2018-04-26 11:44:38.442986163 -0700
++++ ./esc/src/lib/coolkey/cky_factory.h 2018-04-26 11:44:38.441986169 -0700
+@@ -0,0 +1,294 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_FACTORY_H
++#define CKY_FACTORY_H 1
++
++#include "cky_base.h"
++
++/*
++ * Various Class bytes
++ */
++#define CKY_CLASS_ISO7816 0x00
++#define CKY_CLASS_ISO7816_CHAIN 0x10
++#define CKY_CLASS_GLOBAL_PLATFORM 0x80
++#define CKY_CLASS_SECURE 0x84
++#define CKY_CLASS_COOLKEY 0xb0
++
++/*
++ * Applet Instruction Bytes
++ */
++/* Card Manager */
++#define ISO_INS_SELECT_FILE 0xa4
++#define ISO_INS_GET_DATA 0xca
++#define ISO_INS_READ_BINARY 0xb0
++#define ISO_INS_READ_RECORD 0xb2
++#define ISO_INS_MANAGE_SECURITY_ENVIRONMENT 0x22
++#define ISO_INS_PERFORM_SECURITY_OPERATION 0x2a
++
++/* ISO Parameters: */
++#define ISO_LOGIN_LOCAL 0x80
++#define ISO_LOGIN_GLOBAL 0x00
++#define ISO_MSE_SET 0x01
++#define ISO_MSE_STORE 0xf2
++#define ISO_MSE_RESTORE 0xf3
++#define ISO_MSE_ERASE 0xf4
++#define ISO_MSE_QUAL_VERIFY 0x80
++#define ISO_MSE_QUAL_COMPUTE 0x40
++#define ISO_MSE_AUTH 0xa4
++#define ISO_MSE_SIGN 0xb6
++#define ISO_MSE_KEA 0xb8
++#define ISO_PSO_SIGN_P1 0x9e
++#define ISO_PSO_SIGN_P2 0x9a
++#define ISO_PSO_ENCRYPT_P1 0x86
++#define ISO_PSO_ENCRYPT_P2 0x80
++#define ISO_PSO_DECRYPT_P1 0x80
++#define ISO_PSO_DECRYPT_P2 0x86
++
++/* deprecated */
++#define CKY_INS_SETUP 0x2A
++#define CKY_INS_GEN_KEYPAIR 0x30
++#define CKY_INS_EXPORT_KEY 0x34
++#define CKY_INS_UNBLOCK_PIN 0x46
++#define CKY_INS_GET_CHALLENGE 0x62
++#define CKY_INS_CAC_EXT_AUTH 0x38
++#define CKY_INS_LOGOUT_ALL 0x60
++
++/* public */
++#define CKY_INS_VERIFY_PIN 0x42
++#define CKY_INS_LIST_OBJECTS 0x58
++#define CKY_INS_LIST_KEYS 0x3A
++#define CKY_INS_LIST_PINS 0x48
++#define CKY_INS_GET_STATUS 0x3C
++#define CKY_INS_GET_LIFECYCLE 0xF2
++#define CKY_INS_GET_ISSUER_INFO 0xF6
++#define CKY_INS_GET_BUILTIN_ACL 0xFA
++#define CKY_INS_GET_BUILDID 0x70
++#define CKY_INS_GET_RANDOM 0x72
++#define CKY_INS_SEED_RANDOM 0x73
++#define CKY_INS_NOP 0x71
++
++/* nonce validated only */
++#define CKY_INS_LOGOUT 0x61
++
++/* nonce validated & Secure Channel */
++#define CKY_INS_IMPORT_KEY 0x32
++#define CKY_INS_COMPUTE_CRYPT 0x36
++#define CKY_INS_COMPUTE_ECC_SIGNATURE 0x37
++#define CKY_INS_COMPUTE_ECC_KEY_AGREEMENT 0x38
++#define CKY_INS_CREATE_PIN 0x40
++#define CKY_INS_CHANGE_PIN 0x44
++#define CKY_INS_CREATE_OBJ 0x5A
++#define CKY_INS_DELETE_OBJ 0x52
++#define CKY_INS_READ_OBJ 0x56
++#define CKY_INS_WRITE_OBJ 0x54
++
++/* Secure channel only */
++#define CKY_INS_INIT_UPDATE 0x50
++#define CKY_INS_SEC_EXT_AUTH 0x82
++#define CKY_INS_SEC_SET_LIFECYCLE 0xF0
++#define CKY_INS_SEC_SET_PIN 0x04
++#define CKY_INS_SEC_READ_IOBUF 0x08
++#define CKY_INS_SEC_START_ENROLLMENT 0x0C
++
++
++/* CAC */
++#define CAC_INS_GET_CERTIFICATE 0x36
++#define CAC_INS_SIGN_DECRYPT 0x42
++#define CAC_INS_VERIFY_PIN 0x20
++#define CAC_INS_GET_PROPERTIES 0x56
++#define CAC_INS_READ_FILE 0x52
++
++#define CAC_SIZE_GET_PROPERTIES 48
++#define CAC_P1_STEP 0x80
++#define CAC_P1_FINAL 0x00
++
++/* PIV */
++#define PIV_INS_GEN_AUTHENTICATE 0x87
++
++/*
++ * Fixed return sized from various commands
++ */
++#define CKY_SIZE_GET_CPLCDATA 45
++#define CKY_SIZE_LIST_KEYS 11
++#define CKY_SIZE_LIST_PINS 2
++#define CKY_SIZE_LIST_OBJECTS 14
++#define CKY_SIZE_GET_STATUS 16
++#define CKY_SIZE_GET_LIFE_CYCLE 1
++#define CKY_SIZE_GET_LIFE_CYCLE_V2 4
++#define CKY_SIZE_GET_BUILDID 4
++#define CKY_SIZE_GET_ISSUER_INFO 0xe0
++#define CKY_SIZE_GET_BUILTIN_ACL 7
++
++/*
++ * Crypt functions
++ */
++/* functions */
++#define CKY_CIPHER_INIT 1
++#define CKY_CIPHER_PROCESS 2
++#define CKY_CIPHER_FINAL 3
++#define CKY_CIPHER_ONE_STEP 4 /* init and final in one APDU */
++
++/* modes */
++#define CKY_RSA_NO_PAD 0x00
++#define CKY_RSA_PAD_PKCS1 0x01
++#define CKY_DSA_SHA 0x10
++#define CKY_DES_CBC_NOPAD 0x20
++#define CKY_DES_ECB_NOPAD 0x21
++
++/* operations (Cipher Direction) */
++#define CKY_DIR_NONE 0x00
++#define CKY_DIR_SIGN 0x01
++#define CKY_DIR_VERIFY 0x02
++#define CKY_DIR_ENCRYPT 0x03
++#define CKY_DIR_DECRYPT 0x04
++
++/* Data Location */
++#define CKY_DL_APDU 0x01
++#define CKY_DL_OBJECT 0x02
++
++/* Key Types */
++#define CKY_KEY_RSA_PUBLIC 0x01
++#define CKY_KEY_RSA_PRIVATE 0x02
++#define CKY_KEY_RSA_PRIVATE_CRT 0x03
++#define CKY_KEY_DSA_PUBLIC 0x04
++#define CKY_KEY_DSA_PRIVATE 0x05
++#define CKY_KEY_DES 0x06
++#define CKY_KEY_3DES 0x07
++#define CKY_KEY_3DES3 0x08
++
++/* List Operators */
++#define CKY_LIST_RESET 0x00
++#define CKY_LIST_NEXT 0x01
++
++/* Max Size for a read block */
++#define CKY_MAX_READ_CHUNK_SIZE 255
++#define CKY_MAX_WRITE_CHUNK_SIZE 240
++
++/* Life Cycle State */
++#define CKY_APPLICATION_LOGICALLY_DELETED 0x00
++#define CKY_APPLICATION_INSTALLED 0x03
++#define CKY_APPLICATION_SELECTABLE 0x07
++#define CKY_APPLICATION_PERSONALIZED 0x0f
++#define CKY_APPLICATION_BLOCKED 0x7f
++#define CKY_APPLICATION_LOCKED 0xff
++#define CKY_CARDM_MANAGER_OP_READER 0x01
++#define CKY_CARDM_MANAGER_INITIALIZED 0x03
++#define CKY_CARDM_MANAGER_SECURED 0x0f
++#define CKY_CARDM_MANAGER_LOCKED 0x7f
++#define CKY_CARDM_MANAGER_TERMINATED 0xff
++
++/* Read Record Flags */
++#define P15_READ_P1 0x4
++#define P15_READ_P1_TO_LAST 0x5
++#define P15_READ_LAST_TO_P1 0x6
++#define P15_READ_FIRST 0x0
++#define P15_READ_LAST 0x1
++#define P15_READ_NEXT 0x2
++#define P15_READ_PREV 0x3
++
++/* Read Binary Flags */
++#define P15_USE_SHORT_EF 0x80
++
++/*
++ * The following factories 'Fill in' APDUs for each of the
++ * functions described below. Nonces are not automatically added.
++ * APDU's are for COOLKEY version 1.0 protocol. Callers should pass
++ * in Already inited apdu's . Callers are responsible for freeing.
++ * the APDU data, even in event of failure.
++ */
++CKY_BEGIN_PROTOS
++
++/* function based factorys */
++CKYStatus CKYAPDUFactory_SelectFile(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
++ const CKYBuffer *AID);
++CKYStatus CKYAPDUFactory_SelectCardManager(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_ListKeys(CKYAPDU *apdu, CKYByte sequence);
++CKYStatus CKYAPDUFactory_ComputeCryptInit(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, CKYByte location);
++CKYStatus CKYAPDUFactory_ComputeCryptProcess(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data);
++CKYStatus CKYAPDUFactory_ComputeCryptFinal(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location, const CKYBuffer *data, const CKYBuffer *sig);
++CKYStatus CKYAPDUFactory_ComputeCryptOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte mode, CKYByte direction, CKYByte location,
++ const CKYBuffer *data, const CKYBuffer *sig);
++CKYStatus CKYAPDUFactory_ComputeECCSignatureOneStep(CKYAPDU *apdu, CKYByte keyNumber,
++ CKYByte location,
++ const CKYBuffer *data, const CKYBuffer *sig);
++CKYStatus CKYAPDUFactory_ComputeECCKeyAgreementOneStep(CKYAPDU *apdu, CKYByte
keyNumber,
++ CKYByte location,
++ const CKYBuffer *publicData, const CKYBuffer *secretKey);
++CKYStatus CKYAPDUFactory_CreatePIN(CKYAPDU *apdu, CKYByte pinNumber,
++ CKYByte maxAttempts, const char *pinValue);
++CKYStatus CKYAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte pinNumber,
++ const char *pinValue);
++CKYStatus CKYAPDUFactory_ChangePIN(CKYAPDU *apdu, CKYByte pinNUmber,
++ const char *oldPin, const char *newPin);
++CKYStatus CKYAPDUFactory_ListPINs(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_Logout(CKYAPDU *apdu, CKYByte pinNumber);
++CKYStatus CKYAPDUFactory_WriteObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYOffset offset,CKYSize size,CKYBuffer *data);
++/* Future add WriteObject */
++CKYStatus CKYAPDUFactory_CreateObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYSize size, unsigned short readACL, unsigned short writeACL,
++ unsigned short deleteACL);
++CKYStatus CKYAPDUFactory_DeleteObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYByte zero);
++CKYStatus CKYAPDUFactory_ReadObject(CKYAPDU *apdu, unsigned long objectID,
++ CKYOffset offset, CKYByte size);
++CKYStatus CKYAPDUFactory_ListObjects(CKYAPDU *apdu, CKYByte sequence);
++CKYStatus CKYAPDUFactory_GetStatus(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_Noop(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetBuildID(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetLifeCycle(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetLifeCycleV2(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetRandom(CKYAPDU *apdu, CKYByte len);
++CKYStatus CKYAPDUFactory_SeedRandom(CKYAPDU *apdu, const CKYBuffer *data);
++CKYStatus CKYAPDUFactory_GetIssuerInfo(CKYAPDU *apdu);
++CKYStatus CKYAPDUFactory_GetBuiltinACL(CKYAPDU *apdu);
++
++CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type,
++ const CKYBuffer *data);
++CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size);
++CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset,
++ CKYByte type, CKYByte count);
++CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu);
++
++CKYStatus PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object,
++ CKYByte count);
++CKYStatus PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg,
++ CKYByte key, int len, const CKYBuffer *data);
++
++CKYStatus P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef,
++ const CKYBuffer *pin);
++CKYStatus P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record,
++ CKYByte short_ef, CKYByte flags, CKYByte count);
++CKYStatus P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset,
++ CKYByte short_ef, CKYByte flags, CKYByte count);
++CKYStatus P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu,
++ CKYByte p1, CKYByte p2, CKYByte key);
++CKYStatus P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir,
++ int chain, CKYSize retLen, const CKYBuffer *data);
++
++
++CKY_END_PROTOS
++
++#endif /* CKY_FACTORY_H */
+diff -up ./esc/src/lib/coolkey/cky_list.h.fix1 ./esc/src/lib/coolkey/cky_list.h
+--- ./esc/src/lib/coolkey/cky_list.h.fix1 2018-04-26 11:44:38.442986163 -0700
++++ ./esc/src/lib/coolkey/cky_list.h 2018-04-26 11:44:38.442986163 -0700
+@@ -0,0 +1,75 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_LIST_H
++#define CKY_LIST_H 1
++/*
++ * Macro to declare methods and types for CoolKey Lists.
++ */
++#define CKYLIST_DECLARE(name, type) \
++typedef void *name##List; \
++typedef void *name##Iterator; \
++ \
++CKY_BEGIN_PROTOS \
++/* get the number of elements in the name##List */ \
++unsigned long name##List_GetCount(name##List list); \
++ \
++/* returns the 'index'th element of the list. \
++ * This provides one way of walking the list... \
++ * \
++ * // acquire name##List list \
++ * int count; \
++ * int i; \
++ * \
++ * count = name##List_GetCount(list); \
++ * for (i=0; i < count; i++) { \
++ * const type value = name##List_GetValue(list, i); \
++ * \
++ * // Process value \
++ * } \
++ */ \
++const type name##List_GetValue(name##List list, unsigned long index); \
++ \
++/* * Destroy a list */ \
++void name##List_Destroy(name##List list); \
++ \
++/* \
++ * The following iterators allows someone to easily walk the list using \
++ * the following sample code. These functions hide the underlying \
++ * implementation. \
++ * \
++ * // acquire name##List list \
++ * name##Iterator iter; \
++ * \
++ * for (iter = name##List_GetIterator(list); !name##Iterator_End(inter); \
++ * iter = name##Interator_Next(iter) ) { \
++ * const type value = name##Interator_GetValue(iter); \
++ * \
++ * // Process value \
++ * } \
++ * \
++ */ \
++name##Iterator name##List_GetIterator(name##List list); \
++CKYBool name##Iterator_End(name##Iterator iter); \
++name##Iterator name##Iterator_Next(name##Iterator iter); \
++const type name##Iterator_GetValue(name##Iterator iter); \
++CKY_END_PROTOS \
++/* end of Declarations */
++
++#endif /* CKY_LIST_H */
+diff -up ./esc/src/lib/coolkey/cky_list.i.fix1 ./esc/src/lib/coolkey/cky_list.i
+--- ./esc/src/lib/coolkey/cky_list.i.fix1 2018-04-26 11:44:38.442986163 -0700
++++ ./esc/src/lib/coolkey/cky_list.i 2018-04-26 11:44:38.442986163 -0700
+@@ -0,0 +1,145 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifndef CKY_LIST_I
++#define CKY_LIST_I 1
++
++#define CKYLIST_IMPLEMENT(name,type) \
++ \
++/* \
++ * name##List is implemented as a pointer to a NULL terminated array of \
++ * type##s. A NULL name##List is valid and means a list with '0' elements \
++ * The actual type is a void * and the follow functions are designed to \
++ * hide the underlying structure of name##List. \
++ */ \
++ \
++/* get the number of elements in the reader List */ \
++unsigned long \
++name##List_GetCount(name##List list) \
++{ \
++ type *current; \
++ int count; \
++ \
++ if (list == NULL) { \
++ return 0; \
++ } \
++ \
++ for (count=0, current = (type *)list; *current; current++, count++) { \
++ /* EMPTY */ ; \
++ } \
++ \
++ return count; \
++} \
++ \
++ \
++/* returns the 'index'th element of the list. \
++ * index is not checked for overruns in this implementation. \
++ * \
++ * This provides one way of walking the list... \
++ * \
++ * // acquire name##List list \
++ * int count; \
++ * int i; \
++ * \
++ * count = name##List_GetCount(list); \
++ * for (i=0; i < count; i++) { \
++ * const type value = name##List_GetValue(list, i); \
++ * \
++ * // Process value \
++ * } \
++ */ \
++const type \
++name##List_GetValue(name##List list, unsigned long index) \
++{ \
++ type *array = (type *)list; \
++ \
++ /* should probably be an assert */ \
++ if (list == NULL) { \
++ return NULL; \
++ } \
++ return array[index]; \
++} \
++ \
++/* Destroy a list */ \
++void \
++name##List_Destroy(name##List list) \
++{ \
++ type *cur; \
++ if (list == NULL) { \
++ return ; \
++ } \
++ \
++ for (cur =(type *)list; *cur; cur++) { \
++ name##_Destroy(*cur); \
++ } \
++ free(list); \
++} \
++ \
++/* \
++ * The following iterators allows someone to easily walk the list using \
++ * the following sample code. These functions hide the underlying \
++ * implementation. \
++ * \
++ * // acquire name##List list \
++ * name##Iterator iter; \
++ * \
++ * for (iter = name##List_GetIterator(list); !name##Iterator_End(inter); \
++ * iter = name##Iterator_Next(iter) ) { \
++ * const type value = name##Iterator_GetValue(iter); \
++ * // process value \
++ * } \
++ * \
++ */ \
++name##Iterator \
++name##List_GetIterator(name##List list) \
++{ \
++ return (name##Iterator) list; \
++} \
++ \
++CKYBool \
++name##Iterator_End(name##Iterator iter) \
++{ \
++ if (iter == NULL) { \
++ return 1; \
++ } \
++ return *(type *)iter == NULL; \
++} \
++ \
++name##Iterator \
++name##Iterator_Next(name##Iterator iter) \
++{ \
++ if (iter == NULL) { \
++ return NULL; \
++ } \
++ return (name##Iterator) (((type *)iter)+1); \
++} \
++ \
++const type \
++name##Iterator_GetValue(name##Iterator iter) \
++{ \
++ /* assert(iter != NULL); */ \
++ return *(type *)iter; \
++} \
++ \
++/* \
++ * add functions to create lists, & add elements to lists \
++ */ \
++
++
++#endif /* CKY_LIST_I */
+diff -up ./esc/src/lib/coolkey/CoolKey.cpp.fix1 ./esc/src/lib/coolkey/CoolKey.cpp
+--- ./esc/src/lib/coolkey/CoolKey.cpp.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/CoolKey.cpp 2018-04-26 11:44:38.443986158 -0700
+@@ -22,8 +22,6 @@
+
+ #include "prthread.h"
+ #include "pk11func.h"
+-#include "cky_base.h"
+-#include "cky_applet.h"
+
+ #include "NSSManager.h"
+ #include "CoolKeyHandler.h"
+@@ -475,6 +473,268 @@ HRESULT CoolKeyNotify(const CoolKey *aKe
+ return S_OK;
+ }
+
++HRESULT CoolKeyGetCUIDDirectly(char *aBuff, int aBuffLen, const char *readerName) {
++
++ CKYBuffer cuid;
++ CKYBuffer_InitEmpty(&cuid);
++ CKYCardConnection *conn = NULL;
++ CKYStatus status;
++ HRESULT result = E_FAIL;
++ CKYCardContext *cardCtxt = NULL;
++ CKYISOStatus apduRC = 0;
++
++ const CKYByte * cuidBytes = NULL;
++
++
++ if ( !aBuff || aBuffLen < 25 || !readerName)
++ {
++ goto done;
++ }
++
++ cardCtxt = CKYCardContext_Create(SCARD_SCOPE_USER);
++ assert(cardCtxt);
++ if (!cardCtxt) {
++ goto done;
++ }
++
++ conn = CKYCardConnection_Create(cardCtxt);
++ assert(conn);
++ if (!conn) {
++ goto done;
++ }
++
++ status = CKYCardConnection_Connect(conn, readerName);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ CKYCardConnection_BeginTransaction(conn);
++
++ status = CKYApplet_GetCUID(conn, &cuid, &apduRC);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ cuidBytes = CKYBuffer_Data(&cuid);
++
++ result = CoolKeyBinToHex(cuidBytes,
++ CKYBuffer_Size(&cuid),
++ (unsigned char *) aBuff,
++ aBuffLen,
++ 1);
++
++ result = S_OK;
++done:
++
++ if (conn) {
++ CKYCardConnection_EndTransaction(conn);
++ CKYCardConnection_Disconnect(conn);
++ CKYCardConnection_Destroy(conn);
++ }
++ if (cardCtxt) {
++ CKYCardContext_Destroy(cardCtxt);
++ }
++
++ CKYBuffer_FreeData(&cuid);
++
++ return result;
++
++
++}
++
++HRESULT CoolKeyGetATRDirectly(char *aBuff, int aBuffLen,const char *readerName) {
++
++ CKYBuffer ATR;
++ CKYBuffer_InitEmpty(&ATR);
++ CKYCardConnection *conn = NULL;
++ CKYStatus status;
++ HRESULT result = E_FAIL;
++ CKYCardContext *cardCtxt = NULL;
++
++ const CKYByte * atrBytes = NULL;
++
++ if ( !aBuff || aBuffLen < 25 || !readerName)
++ {
++ goto done;
++ }
++
++ cardCtxt = CKYCardContext_Create(SCARD_SCOPE_USER);
++ assert(cardCtxt);
++ if (!cardCtxt) {
++ goto done;
++ }
++
++ conn = CKYCardConnection_Create(cardCtxt);
++ assert(conn);
++ if (!conn) {
++ goto done;
++ }
++
++ status = CKYCardConnection_Connect(conn, readerName);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ CKYCardConnection_BeginTransaction(conn);
++ unsigned long state;
++
++ status = CKYCardConnection_GetStatus(conn, &state, &ATR);
++ if (status != CKYSUCCESS) {
++ result = E_FAIL;
++ goto done;
++ }
++
++ atrBytes = CKYBuffer_Data(&ATR);
++
++ result = CoolKeyBinToHex(atrBytes,
++ CKYBuffer_Size(&ATR),
++ (unsigned char *) aBuff,
++ aBuffLen,
++ 1);
++
++
++ if(result != CKYSUCCESS) {
++ goto done;
++ }
++
++ result = S_OK;
++ done:
++
++ if (conn) {
++ CKYCardConnection_EndTransaction(conn);
++ CKYCardConnection_Disconnect(conn);
++ CKYCardConnection_Destroy(conn);
++ }
++ if (cardCtxt) {
++ CKYCardContext_Destroy(cardCtxt);
++ }
++
++ CKYBuffer_FreeData(&ATR);
++
++ return result;
++}
++
++HRESULT CoolKeyGetLifeCycleDirectly(CKYByte *personalized,const char *readerName) {
++ CKYCardConnection *conn = NULL;
++ CKYStatus status;
++ HRESULT result = E_FAIL;
++
++ CKYISOStatus apduRC = 0;
++
++ CKYCardContext *cardCtxt = NULL;
++
++ if ( personalized == NULL || !readerName)
++ {
++ goto done;
++ }
++
++ cardCtxt = CKYCardContext_Create(SCARD_SCOPE_USER);
++ assert(cardCtxt);
++ if (!cardCtxt) {
++ goto done;
++ }
++
++ conn = CKYCardConnection_Create(cardCtxt);
++ assert(conn);
++ if (!conn) {
++ goto done;
++ }
++
++ status = CKYCardConnection_Connect(conn, readerName);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ CKYCardConnection_BeginTransaction(conn);
++ unsigned long state;
++ status = CKYApplet_SelectCoolKeyManager(conn, &apduRC);
++ if (status != CKYSUCCESS) {
++ *personalized = 0xff;
++ goto done;
++ }
++
++ //We know we have selected the applet, even if the subsequent
++ // LifeCycle call fails.
++ *personalized = 0x7;
++ status = CKYApplet_GetLifeCycle(conn, personalized,&apduRC);
++
++ if(result != CKYSUCCESS) {
++ goto done;
++ }
++
++ result = S_OK;
++ done:
++
++ if (conn) {
++ CKYCardConnection_EndTransaction(conn);
++ CKYCardConnection_Disconnect(conn);
++ CKYCardConnection_Destroy(conn);
++ }
++ if (cardCtxt) {
++ CKYCardContext_Destroy(cardCtxt);
++ }
++
++ return result;
++}
++
++HRESULT CoolKeyGetCPLCDataDirectly(CKYAppletRespGetCPLCData *cplc,const char
*readerName) {
++
++ CKYCardConnection *conn = NULL;
++ CKYStatus status;
++ HRESULT result = E_FAIL;
++ CKYISOStatus apduRC = 0;
++ CKYCardContext *cardCtxt = NULL;
++
++ if ( cplc == NULL || !readerName)
++ {
++ goto done;
++ }
++
++ cardCtxt = CKYCardContext_Create(SCARD_SCOPE_USER);
++ assert(cardCtxt);
++ if (!cardCtxt) {
++ goto done;
++ }
++
++ conn = CKYCardConnection_Create(cardCtxt);
++ assert(conn);
++ if (!conn) {
++ goto done;
++ }
++
++ status = CKYCardConnection_Connect(conn, readerName);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ CKYCardConnection_BeginTransaction(conn);
++ unsigned long state;
++
++ status = CKYApplet_SelectCardManager(conn, &apduRC);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ status = CKYApplet_GetCPLCData(conn, cplc,
++ &apduRC);
++ if (status != CKYSUCCESS) {
++ goto done;
++ }
++
++ result = S_OK;
++ done:
++
++ if (conn) {
++ CKYCardConnection_EndTransaction(conn);
++ CKYCardConnection_Disconnect(conn);
++ CKYCardConnection_Destroy(conn);
++ }
++ if (cardCtxt) {
++ CKYCardContext_Destroy(cardCtxt);
++ }
++
++ return result;
++}
+
+
+ static std::list<ActiveKeyNode *> g_ActiveKeyList;
+diff -up ./esc/src/lib/coolkey/CoolKeyHandler.cpp.fix1
./esc/src/lib/coolkey/CoolKeyHandler.cpp
+--- ./esc/src/lib/coolkey/CoolKeyHandler.cpp.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/CoolKeyHandler.cpp 2018-04-26 11:44:38.445986146 -0700
+@@ -44,6 +44,8 @@
+ #include "CoolKeyHandler.h"
+ #include "SlotUtils.h"
+
++static const char *cac_manu_id= "Common Access Card";
++static const char *piv_manu_id= "piv II ";
+
+ //static char *test_extended_login =
"s=325&msg_type=13&invalid_login=0&blocked=0&error=&required_parameter0=id%3DUSER%5FID%26name%3DUser+ID%26desc%3DUser+ID%26type%3Dstring%26option%3Doption1%2Coption2%2Coption3&required_parameter1=id%3DUSER%5FPWD%26name%3DUser+Password%26desc%3DUser+Password%26type%3Dpassword%26option%3D&required_parameter2=id%3DUSER%5FPIN%26name%3DPIN%26desc%3DOne+time+PIN+received+via+mail%26type%3Dpassword%26option%3D";
+
+@@ -1141,12 +1143,10 @@ HRESULT CoolKeyHandler::HttpBeginOpReque
+ const char *atr = GetATRForKeyID(&mKey);
+ if (!atr )
+ {
+- HttpDisconnect();
+- RemoveKeyFromActiveKeyList(&mKey);
+- return E_FAIL;
++ sprintf(buffer,"tokenATR=%s","unknown-atr");
++ } else {
++ sprintf(buffer,"tokenATR=%s",atr);
+ }
+-
+- sprintf(buffer,"tokenATR=%s",atr);
+
+ ext_buffer = buffer;
+
+@@ -1190,6 +1190,41 @@ HRESULT CoolKeyHandler::HttpBeginOpReque
+ }
+ }
+
++CKYBuffer *CoolKeyHandler::processTokenPDU(CoolKeyHandler *context, CKYAPDU *apdu)
++{
++ char tBuff[56];
++ CKYStatus status = CKYSUCCESS;
++ PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s
CoolKeyHandler::processTokenPDU:\n",GetTStamp(tBuff,56)));
++ if(!apdu || !context)
++ {
++ CoolKeyLogMsg( PR_LOG_ERROR, "%s apdu message. Bad input data.
\n",GetTStamp(tBuff,56));
++ return NULL;
++ }
++
++ CKYBuffer *response = NULL;
++ status = CKYBuffer_InitEmpty(response);
++
++ if(status != CKYSUCCESS) {
++ CoolKeyLogMsg( PR_LOG_ERROR, "%s apdu message. Out of memory.
\n",GetTStamp(tBuff,56));
++ return NULL;
++ }
++
++ status = CKYCardConnection_ExchangeAPDU(context->GetCardConnection(),
++ apdu, response);
++
++ if (status != CKYSUCCESS) {
++ CoolKeyLogMsg( PR_LOG_ERROR,
++ "%s Processing apdu message. Can't write apdu to card! status %d
response[0] %x response[1] %x error %d \n"
++ ,GetTStamp(tBuff,56)
,status,CKYBuffer_GetChar(response,0),CKYBuffer_GetChar(response,1),
++ CKYCardConnection_GetLastError(context->GetCardConnection()));
++
++ return response;
++ }
++
++ return response;
++
++}
++
+ void CoolKeyHandler::HttpProcessTokenPDU(CoolKeyHandler
*context,eCKMessage_TOKEN_PDU_REQUEST *req)
+ {
+ char tBuff[56];
+@@ -1606,7 +1641,12 @@ void CoolKeyHandler::HttpProcessEndOp(Co
+ void NotifyEndResult(CoolKeyHandler* context, int operation, int result, int
description)
+ {
+ char tBuff[56];
+- RefreshInfoFlagsForKeyID(context->GetAutoCoolKey());
++
++ CoolKeyInfo *info = GetCoolKeyInfoByKeyID(context->GetAutoCoolKey());
++ CKHGetCoolKeyInfo(info->mSlot,info);
++
++
++ //RefreshInfoFlagsForKeyID(context->GetAutoCoolKey());
+
+ PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CoolKeyHandler::NotifyEndResult
context %p op %d result %d description
%d:\n",GetTStamp(tBuff,56),context,operation,result,description));
+
+@@ -2024,14 +2064,14 @@ getCUIDFromTokenInfo(CK_TOKEN_INFO *toke
+ isxdigit(tokenInfo->manufacturerID[3]) ) {
+ // one format has top 2 bytes of CUID (4 hex digits) in manufacturer,
+ // and the rest in the module
+- cp = copySerialNumber(cp, (const char *)tokenInfo->manufacturerID, 4);
+- cp = copySerialNumber(cp,(const char *)tokenInfo->model,
+- sizeof(tokenInfo->model));
++ cp = copySerialNumber(cp, (const char *)tokenInfo->manufacturerID, 2);
++ cp = copySerialNumber(cp,(const char *)tokenInfo->serialNumber,
++ sizeof(tokenInfo->serialNumber));
+ } else {
+ // otherwise it's just the concatenation of the model and serial
+ // fields
+ cp = copySerialNumber(cp, (const char *)tokenInfo->model,
+- sizeof(tokenInfo->model));
++ 2);
+ cp = copySerialNumber(cp, (const char *)tokenInfo->serialNumber,
+ sizeof(tokenInfo->serialNumber));
+ }
+@@ -2055,126 +2095,155 @@ CKHGetInfoFlags(PK11SlotInfo *aSlot)
+ }
+
+ CoolKeyInfo *
+-CKHGetCoolKeyInfo(PK11SlotInfo *aSlot)
++CKHGetCoolKeyInfo(PK11SlotInfo *aSlot,CoolKeyInfo *currentInfo)
+ {
+ char tBuff[56];
+ PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s
CKHGetCoolKeyInfo:\n",GetTStamp(tBuff,56)));
+- PK11GenericObject *obj = NULL;
+ SECItem label, ATR;
+ CK_TOKEN_INFO tokenInfo;
+ CoolKeyInfo *info = NULL;
+ SECStatus status;
+- HRESULT hres;
+- int atrSize;
+- char *atrString;
+- SECItem isCOOLKey;
++ HRESULT hres,atrRes,cuidRes,cycleRes;
+
++ CKYBuffer cardATR;
++ CKYBuffer_InitEmpty(&cardATR);
++ char *readerName = PK11_GetSlotName(aSlot);
++
+ memset((void *) &tokenInfo,0,sizeof(tokenInfo));
+ ATR.data = NULL; // initialize for error processing
+ label.data = NULL; // initialize for error processing
+- isCOOLKey.data = NULL;
+
+
+ int isACOOLKey = 0;
++ int isACAC = 0;
++ int isAPIV = 0;
+
+- /* if it's one of "ours" it'll have a reader object */
+- obj = PK11_FindGenericObjects(aSlot, CKO_MOZILLA_READER);
+- if (obj == NULL) {
+- goto failed;
+- }
++ int hasApplet = 0;
++ int isPersonalized = 0;
+
+- // get the reader name (though we probably don't need it anymore
+- status = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_LABEL, &label);
+- if (status != SECSuccess) {
+- goto failed;
+- }
++ CKYByte lifeCycle = 0;
++
++ char atrChar[100];
++ memset((void*) atrChar,0,sizeof(atrChar));
++
++ char cuidChar[100];
++ memset((void*) cuidChar,0 ,sizeof(cuidChar));
+
+- // get the ATR (though, again, we probably don't need it
+- status = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_MOZILLA_ATR, &ATR);
+- // PK11_DestroyGenericObjects(obj);
+- if (status != SECSuccess) {
+- goto failed;
+- }
+ // get the CUID/Serial number (we *WILL* continue to need it )
+ status = PK11_GetTokenInfo(aSlot,&tokenInfo);
+ if (status != SECSuccess) {
+ goto failed;
+ }
+
+- //get the are we a CoolKey value
++ tokenInfo.flags=0; //Ignore what opensc says, get the info ourselves later.
++ //Get the life cycle state:
+
+- status = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_MOZILLA_IS_COOL_KEY,
&isCOOLKey);
++ cycleRes = CoolKeyGetLifeCycleDirectly(&lifeCycle,readerName);
+
+- PK11_DestroyGenericObjects(obj);
+- obj = NULL;
++ if(lifeCycle == 0x7) { // applet only
++ hasApplet = 1;
++ }
+
+- if (status != SECSuccess) {
+- goto failed;
++ if(lifeCycle == 0xF) { //personalized
++ hasApplet = 1;
++ isPersonalized = 1;
+ }
+
+- if(isCOOLKey.len == 1)
+- {
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo:
CKA_MOZILLA_IS_COOL_KEY %d.\n",GetTStamp(tBuff,56),(int) isCOOLKey.data[0]));
++ //Let's see if we can get the ATR by force explicitly
++
++ atrRes = CoolKeyGetATRDirectly(atrChar,100,readerName);
+
+- isACOOLKey=(int) isCOOLKey.data[0];
+- }
++ if(atrRes == E_FAIL) {
++ goto failed;
++ }
+
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo: info->flags
%u.\n",GetTStamp(tBuff,56),tokenInfo.flags));
+-
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo: info->label
%s.\n",GetTStamp(tBuff,56),(char *)tokenInfo.label));
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo:
info->manufacturerID %s.\n",GetTStamp(tBuff,56),(char
*)tokenInfo.manufacturerID));
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo: info->model
%s.\n",GetTStamp(tBuff,56),(char *)tokenInfo.model));
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo:
info->serialNumber %s.\n",GetTStamp(tBuff,56),(char *)tokenInfo.serialNumber));
++ // Figure out the token type by process of elimination
++ // CAC has a manu id of "Common Access Card" and
++ // PIV has a manu id of "piv II "
++
++ // Since we are configured to only be notified of coolkey's, cac's and
piv's
++ // non blank coolkeys will be identified by NOT being cac or piv in the manu id
field.
++
++ if(!strcmp((const char *) tokenInfo.manufacturerID,cac_manu_id)) {
++ isACAC = 1;
++ } else if(!strcmp((const char *) tokenInfo.manufacturerID, piv_manu_id)) {
++ isAPIV = 1;
++ } else {
++ isACOOLKey = 1;
++ }
+
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo:
info->firmwareVersion.major %d info->firmwareVersion.minor %d
\n",GetTStamp(tBuff,56),(int)tokenInfo.firmwareVersion.major,(int)
tokenInfo.firmwareVersion.minor));
++ // OK, we have everything we need, now build the COOLKEYInfo structure.
++ // either create a new one or use the one we have already and refresh it
++ if(currentInfo == NULL) {
++ info = new CoolKeyInfo();
++ } else {
++ info = currentInfo;
+
++ if(info->mReaderName) {
++ free(info->mReaderName);
++ }
++ if(info->mCUID) {
++ free(info->mCUID);
++ }
++ if(info->mATR) {
++ free(info->mATR);
++ }
++ info->mInfoFlags = 0;
++ }
+
+- // OK, we have everything we need, now build the COOLKEYInfo structure.
+- info = new CoolKeyInfo();
+ if (!info) {
+ goto failed;
+ }
+
+- atrSize = ATR.len*2+5;
+- atrString = (char *)malloc(atrSize);
+- hres = CoolKeyBinToHex(ATR.data, ATR.len,
+- (unsigned char *) atrString, atrSize, true);
+- /* shouldn't the be != S_SUCCESS? */
+- if (hres == E_FAIL) {
+- free(atrString);
+- goto failed;
++ //Massage the tokenInfo so it adhered to when coolkey was doing it.
++ if(hasApplet) {
++ tokenInfo.firmwareVersion.major = 1;
+ }
+- SECITEM_FreeItem(&ATR,PR_FALSE);
+- ATR.data = NULL;
+
++ if(isPersonalized) {
++ tokenInfo.flags |= CKF_TOKEN_INITIALIZED;
++ }
+
+- PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo: info->atr
%s.\n",GetTStamp(tBuff,56),(char *)atrString));
++ info->mInfoFlags = MapGetFlags(&tokenInfo);
+
++ info->mReaderName = strdup(readerName);
+
+- info->mATR = atrString;
+- info->mReaderName= (char *)malloc(label.len+1);
+- if (!info->mReaderName) {
+- goto failed;
++ info->mCUID = (char *)malloc(35); /* should be a define ! */
++
++ if(strlen(atrChar) > 0) {
++ info->mATR = strdup(atrChar);
+ }
+- memcpy(info->mReaderName, label.data, label.len);
+- info->mReaderName[label.len] = 0;
+- info->mInfoFlags = MapGetFlags(&tokenInfo);
+
+- info->mCUID = (char *)malloc(35); /* should be a define ! */
+ if (!info->mCUID) {
+ goto failed;
+ }
++
+ hres = getCUIDFromTokenInfo(&tokenInfo, info->mCUID);
+ /* shouldn't the be != S_SUCCESS? */
+ if (hres == E_FAIL) {
+ goto failed;
+ }
+
++ //Check for blank cuid and put something there
++
++ if(isACOOLKey && strlen(info->mCUID) == 0 )
++ {
++ //Let's try to get the cuid directly from the token.
++
++ cuidRes = CoolKeyGetCUIDDirectly(cuidChar, 100, readerName);
++
++ if(cuidRes != S_OK) {
++ strcpy(info->mCUID, "blank-token");
++ } else {
++ strcpy(info->mCUID, cuidChar);
++ }
++ }
++
+ PR_LOG( coolKeyLogHN, PR_LOG_DEBUG, ("%s CKHGetCoolKeyInfo: tokenInfo.label
length %d.\n",GetTStamp(tBuff,56),strlen((char *) tokenInfo.label)));
+
+ // Give the CAC card some sort of unique key ID
+
+- if(strlen(info->mCUID) == 0)
++ if(isACAC && strlen(info->mCUID) == 0)
+ {
+ strncpy(info->mCUID,(char *)tokenInfo.label,35);
+ info->mCUID[34] = 0;
+@@ -2186,26 +2255,20 @@ CKHGetCoolKeyInfo(PK11SlotInfo *aSlot)
+ info->mInfoFlags |= COOLKEY_INFO_IS_REALLY_A_COOLKEY_MASK;
+ }
+
+- SECITEM_FreeItem(&ATR,PR_FALSE);
+ SECITEM_FreeItem(&label,PR_FALSE);
+- SECITEM_FreeItem(&isCOOLKey,PR_FALSE);
+
+ info->mSlot = PK11_ReferenceSlot(aSlot);
+ info->mSeries = PK11_GetSlotSeries(aSlot);
+ return info;
+
+ failed:
+- if (ATR.data) {
+- SECITEM_FreeItem(&ATR,PR_FALSE);
+- }
+ if (label.data) {
+ SECITEM_FreeItem(&label,PR_FALSE);
+ }
+- if (obj) {
+- PK11_DestroyGenericObjects(obj);
+- }
+ if (info) {
+ delete info;
+ }
++
++ CKYBuffer_FreeData(&cardATR);
+ return NULL;
+ }
+diff -up ./esc/src/lib/coolkey/CoolKeyHandler.h.fix1
./esc/src/lib/coolkey/CoolKeyHandler.h
+--- ./esc/src/lib/coolkey/CoolKeyHandler.h.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/CoolKeyHandler.h 2018-04-26 11:44:38.445986146 -0700
+@@ -115,7 +115,10 @@ class CoolKeyHandler
+ HRESULT Renew(void);
+ HRESULT Format(const char *aTokenType);
+ HRESULT Disconnect();
+-
++
++ //APDU related
++
++ CKYBuffer *processTokenPDU(CoolKeyHandler *context, CKYAPDU *apdu);
+
+ //Http Related
+
+@@ -259,7 +262,7 @@ eCKMessage *AllocateMessage(eCKMessage::
+
+
+ void DisplayEndDialog(int operation, int result, int description);
+-CoolKeyInfo *CKHGetCoolKeyInfo(PK11SlotInfo *aSlot);
++CoolKeyInfo *CKHGetCoolKeyInfo(PK11SlotInfo *aSlot,CoolKeyInfo *currentInfo);
+ unsigned int CKHGetInfoFlags(PK11SlotInfo *aSlot);
+
+ #endif /* CoolKeyHandler.h__ */
+diff -up ./esc/src/lib/coolkey/CoolKey.h.fix1 ./esc/src/lib/coolkey/CoolKey.h
+--- ./esc/src/lib/coolkey/CoolKey.h.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/CoolKey.h 2018-04-26 11:44:38.446986140 -0700
+@@ -32,6 +32,9 @@
+ #include <vector>
+ #include <string>
+
++#include "cky_base.h"
++#include "cky_applet.h"
++
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Public Structures and Functions:
+@@ -185,7 +188,6 @@ COOLKEY_API HRESULT CoolKeyInitializeLog
+ COOLKEY_API HRESULT CoolKeyLogMsg(int logLevel, const char *fmt, ...);
+
+ COOLKEY_API HRESULT CoolKeyLogNSSStatus();
+-
+ //Utility time function
+ char *GetTStamp(char *aTime,int aSize);
+ }
+@@ -262,8 +264,10 @@ const char *CoolKeyGetKeyID(const char *
+ const char *CoolKeyGetConfig(const char *aName);
+ HRESULT CoolKeySetConfig(const char *aName,const char *aValue);
+ CoolKeyBadCertHandler CoolKeyGetBadCertHandler();
+-
+-
++HRESULT CoolKeyGetATRDirectly(char *aBuff, int aBuffLen, const char *readerName);
++HRESULT CoolKeyGetCUIDDirectly(char *aBuff, int aBuffLen, const char *readerName);
++HRESULT CoolKeyGetCPLCDataDirectly(CKYAppletRespGetCPLCData *cplc,const char
*readerName);
++HRESULT CoolKeyGetLifeCycleDirectly(CKYByte *personalized,const char *readerName);
+
+ }
+
+diff -up ./esc/src/lib/coolkey/CoolKey_Message.cpp.fix1
./esc/src/lib/coolkey/CoolKey_Message.cpp
+--- ./esc/src/lib/coolkey/CoolKey_Message.cpp.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/CoolKey_Message.cpp 2018-04-26 11:44:38.446986140 -0700
+@@ -941,7 +941,7 @@ void eCKMessage_BEGIN_OP::encode(string
+
+ int size = extensions.length();
+
+- if(aOutputVal[size -1 ] == '&')
++ if(extensions[size -1 ] == '&')
+ {
+ extensions.erase(size -1);
+ }
+diff -up ./esc/src/lib/coolkey/dynlink.c.fix1 ./esc/src/lib/coolkey/dynlink.c
+--- ./esc/src/lib/coolkey/dynlink.c.fix1 2018-04-26 11:44:38.447986134 -0700
++++ ./esc/src/lib/coolkey/dynlink.c 2018-04-26 11:44:38.447986134 -0700
+@@ -0,0 +1,37 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#ifdef WIN32
++#include "dynlink_win.c"
++#else
++#ifdef MAC
++#include "dynlink_mac.c"
++#else
++#ifdef HAVE_DLFCN_H
++#include "dynlink_unix.c"
++#else
++#error "Platform not supported... add dynlink_PLAT.c and update dynlink.c"
++#endif
++#endif
++#endif
++
+diff -up ./esc/src/lib/coolkey/dynlink.h.fix1 ./esc/src/lib/coolkey/dynlink.h
+--- ./esc/src/lib/coolkey/dynlink.h.fix1 2018-04-26 11:44:38.447986134 -0700
++++ ./esc/src/lib/coolkey/dynlink.h 2018-04-26 11:44:38.447986134 -0700
+@@ -0,0 +1,54 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++/*
++ * the following header file is private to the CoolKey library.
++ * This is because CoolKey library is supposed to operate in the PKCS #11
++ * module which needs to be independent of runtimes like NSPR. Longer term
++ * there should be a generic version of this which uses the application
++ * runtime, and pkcs #11 supplies it's only copy of these functions.
++ */
++#ifndef CKY_SHLIB_H
++#define CKY_SHLIB_H 1
++
++#undef QUOTE
++#undef QUOTE_MACRO
++#define QUOTE(arg) #arg
++#define QUOTE_MACRO(arg) QUOTE(arg)
++
++/* Hmmm maybe this should be hidden in getAddress? */
++#ifdef MAC
++#define DLL_SYM_PREFIX "_"
++#else
++#define DLL_SYM_PREFIX
++#endif
++
++#define MAKE_DLL_SYMBOL(name) DLL_SYM_PREFIX QUOTE(name)
++
++typedef void *ckyShLibrary;
++
++ckyShLibrary ckyShLibrary_open(const char *libname);
++CKYStatus ckyShLibrary_close(ckyShLibrary libHandle);
++CKYStatus ckyShLibrary_getAddress(ckyShLibrary libHandle,
++ void **func, const char *funcName);
++
++#ifdef MAC
++void ckyShLibrary_setParent(char *name);
++#endif
++#endif
+diff -up ./esc/src/lib/coolkey/dynlink_mac.c.fix1 ./esc/src/lib/coolkey/dynlink_mac.c
+--- ./esc/src/lib/coolkey/dynlink_mac.c.fix1 2018-04-26 11:44:38.447986134 -0700
++++ ./esc/src/lib/coolkey/dynlink_mac.c 2018-04-26 11:44:38.447986134 -0700
+@@ -0,0 +1,147 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ ***** END COPYRIGHT BLOCK *****/
++
++#include <mach-o/dyld.h>
++#include <stdio.h>
++#include "cky_base.h"
++#include "dynlink.h"
++#include "string.h"
++#include "stdlib.h"
++
++#define EXEPATH "@executable_path/"
++#define SYSPATH "/System/Library/Frameworks/"
++
++static char *ckyShLibrary_parent = NULL;
++
++/* allow the parent library to set our name */
++void
++ckyShLibrary_setParent(char *p)
++{
++ ckyShLibrary_parent = p;
++}
++
++#ifdef nodef
++/* get the parent librarie's path */
++char *
++ckyShLibrary_getParentPath()
++{
++ char *result;
++ char *image_name;
++ int i, count = _dyld_image_count();
++
++ if (ckyShLibrary_parent == NULL) {
++ return NULL;
++ }
++
++ for (i = 0; i < count; i++) {
++ image_name = _dyld_get_image_name(i);
++ if (strstr(image_name, ckyShLibrary_parent) != NULL) {
++ result = malloc(strlen(image_name)+1);
++ if (result != NULL) {
++ char *truncate;
++ strcpy(result, image_name);
++ truncate = strrchr(result,'/');
++ if (truncate) {
++ *(truncate+1) = 0;
++ }
++ }
++ return result;
++ }
++ }
++ return NULL;
++}
++#endif
++
++ckyShLibrary
++ckyShLibrary_open(const char *libname)
++{
++ const struct mach_header *library;
++ /*char *parentPath = ckyShLibrary_getParentPath(); */
++ char *libPath = NULL;
++ int len = sizeof(SYSPATH);
++
++#ifdef notdef
++ if (parentPath) {
++ int pLen = strlen(parentPath)+1;
++ if (pLen > len) {
++ len = pLen;
++ }
++ }
++#endif
++
++ libPath = malloc(len+strlen(libname)+1);
++ /* if we couldn't get the space, just use the LD_LIBPATH */
++ if (libPath) {
++#ifdef notdef
++ /* first try the parent DLL path if known */
++ if (parentPath) {
++ /* then try the path of the shared library */
++ strcpy(libPath,parentPath);
++ strcat(libPath,libname);
++ free(parentPath);
++ library = NSAddImage(libPath,
++ NSADDIMAGE_OPTION_RETURN_ON_ERROR |
++ NSADDIMAGE_OPTION_WITH_SEARCHING);
++ if (library) {
++ free(libPath);
++ return (ckyShLibrary)library;
++ }
++ }
++#endif
++ /* the try the executable's lib path */
++ strcpy(libPath,SYSPATH);
++ strcat(libPath,libname);
++ library = NSAddImage(libPath,
++ NSADDIMAGE_OPTION_RETURN_ON_ERROR |
++ NSADDIMAGE_OPTION_WITH_SEARCHING);
++ free(libPath);
++ if (library) {
++ return (ckyShLibrary)library;
++ }
++ }
++
++ /* finally grab it from the system libpath */
++ library = NSAddImage(libname,
++ NSADDIMAGE_OPTION_RETURN_ON_ERROR |
++ NSADDIMAGE_OPTION_WITH_SEARCHING);
++ return (ckyShLibrary)library;
++}
++
++CKYStatus
++ckyShLibrary_close(ckyShLibrary _lib)
++{
++ // Can't unload an image on Mac OS X.
++ return CKYSUCCESS;
++}
++
++CKYStatus
++ckyShLibrary_getAddress(const ckyShLibrary _lib, void ** func,
++ const char *funcName)
++{
++ const struct mach_header *library = (const struct mach_header *)_lib;
++ NSSymbol symbol;
++ symbol = NSLookupSymbolInImage(library, funcName,
++ NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
++ NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
++ if( symbol == NULL ) {
++ return CKYLIBFAIL;
++ }
++ *func = NSAddressOfSymbol(symbol);
++ return CKYSUCCESS;
++}
+diff -up ./esc/src/lib/coolkey/dynlink_unix.c.fix1 ./esc/src/lib/coolkey/dynlink_unix.c
+--- ./esc/src/lib/coolkey/dynlink_unix.c.fix1 2018-04-26 11:44:38.447986134 -0700
++++ ./esc/src/lib/coolkey/dynlink_unix.c 2018-04-26 11:44:38.447986134 -0700
+@@ -0,0 +1,66 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include <dlfcn.h>
++#include <unistd.h>
++#if !defined(MAC) && !defined(HPUX)
++#include <link.h>
++#endif
++#include <assert.h>
++
++#include "cky_base.h"
++#include "dynlink.h"
++
++ckyShLibrary
++ckyShLibrary_open(const char *libname)
++{
++ void *library;
++
++ library = dlopen(libname, RTLD_LAZY);
++ return library;
++}
++
++CKYStatus
++ckyShLibrary_close(ckyShLibrary library)
++{
++ int rv;
++
++ if (library == NULL) {
++ return CKYSUCCESS;
++ }
++
++ rv = dlclose(library);
++ if( rv != 0 ) {
++ return CKYLIBFAIL;
++ }
++ return CKYSUCCESS;
++}
++
++CKYStatus
++ckyShLibrary_getAddress(const ckyShLibrary library, void **func,
++ const char *funcName)
++{
++ assert(library);
++ void* f = dlsym(library, funcName);
++ if( f == NULL ) {
++ return CKYLIBFAIL;
++ }
++ *func = f;
++ return CKYSUCCESS;
++}
+diff -up ./esc/src/lib/coolkey/dynlink_win.c.fix1 ./esc/src/lib/coolkey/dynlink_win.c
+--- ./esc/src/lib/coolkey/dynlink_win.c.fix1 2018-04-26 11:44:38.447986134 -0700
++++ ./esc/src/lib/coolkey/dynlink_win.c 2018-04-26 11:44:38.447986134 -0700
+@@ -0,0 +1,66 @@
++/* ***** BEGIN COPYRIGHT BLOCK *****
++ * Copyright (C) 2005 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation version
++ * 2.1 of the License.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ * ***** END COPYRIGHT BLOCK ***** */
++
++#include <Windows.h>
++#include "cky_base.h"
++#include "dynlink.h"
++
++
++ckyShLibrary
++ckyShLibrary_open(const char *libname)
++{
++ HMODULE library;
++ library = LoadLibrary(libname);
++
++ return (ckyShLibrary) library;
++}
++
++CKYStatus
++ckyShLibrary_close(ckyShLibrary _lib)
++{
++ HMODULE library = (HMODULE) _lib;
++ BOOL ret;
++
++ if( library == NULL ) {
++ return CKYSUCCESS;
++ }
++
++ ret = FreeLibrary(library);
++ library = NULL;
++
++ if (!ret) {
++ return CKYLIBFAIL;
++ }
++
++ return CKYSUCCESS;
++}
++
++CKYStatus
++ckyShLibrary_getAddress(const ckyShLibrary _lib, void **func,
++ const char *funcName)
++{
++ const HMODULE library = (const HMODULE) _lib;
++
++ *func = (void *)GetProcAddress(library, funcName);
++ if (*func == NULL) {
++ return CKYLIBFAIL;
++ }
++
++ return CKYSUCCESS;
++}
+diff -up ./esc/src/lib/coolkey/manifest.mn.fix1 ./esc/src/lib/coolkey/manifest.mn
+--- ./esc/src/lib/coolkey/manifest.mn.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/manifest.mn 2018-04-26 11:44:38.448986129 -0700
+@@ -22,14 +22,13 @@ XULRUNNER_BASE=$(CORE_DEPTH)/dist/$(OBJD
+ SYS_INC = /usr/include
+ MODULE = ckymanager
+ LIBRARY_NAME = $(MODULE)
+-REQUIRES = httpchunked nss nspr ckyapplet
++REQUIRES = httpchunked nss nspr
+ ifndef MOZ_OFFSET
+ MOZ_OFFSET = mozilla-1.7.13
+ endif
+ DEFINES += -I$(CORE_DEPTH)/esc/app/xpcom -I$(SYS_INC)/nspr4 -I$(SYS_INC)/nss3
-I$(SYS_INC)/PCSC -I$(SYS_INC)/$(MOZ_OFFSET)/nspr -I$(SYS_INC)/$(MOZ_OFFSET)/nss
-I$(XULRUNNER_BASE)/dist/public/nss -I$(XULRUNNER_BASE)/dist/include/nspr
-I$(GECKO_SDK_PATH)/include/nspr -I$(GECKO_SDK_PATH)/include/nss -fno-strict-aliasing
+ MAPFILE = $(OBJDIR)/ckymanager.def
+
+-#EXTRA_LIBS += -L$(DIST)/lib -lckyapplet
+
+ CPPSRCS = \
+ NSSManager.cpp \
+@@ -39,7 +38,13 @@ CPPSRCS = \
+ CoolKey.cpp \
+ SmartCardMonitoringThread.cpp \
+ $(NULL)
+-
++CSRCS =\
++ cky_applet.c \
++ cky_base.c \
++ cky_card.c \
++ cky_factory.c \
++ dynlink_unix.c \
++ $(NULL)
+ EXPORTS = \
+ CoolKey.h \
+ $(NULL)
+diff -up ./esc/src/lib/coolkey/NSSManager.cpp.fix1 ./esc/src/lib/coolkey/NSSManager.cpp
+--- ./esc/src/lib/coolkey/NSSManager.cpp.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/NSSManager.cpp 2018-04-26 11:44:38.448986129 -0700
+@@ -102,7 +102,7 @@ HRESULT NSSManager::InitNSS(const char *
+
+ char modSpec[512];
+
+- sprintf(modSpec,"library=\"%s\" name=\"%s\"
parameters=\"%s\"
NSS=\"slotParams={0x00000002=[slotFlags='PublicCerts']}\"\n",COOLKEY_PKCS11_LIBRARY,COOLKEY_NAME,PROMISCUOUS_PARAMETER);
++ sprintf(modSpec,"library=\"%s\" name=\"%s\"
NSS=\"slotParams={0x00000002=[slotFlags='PublicCerts']}\"\n",COOLKEY_PKCS11_LIBRARY,COOLKEY_NAME,PROMISCUOUS_PARAMETER);
+
+ PR_LOG( coolKeyLogNSS, PR_LOG_DEBUG, ("%s InitNSS: modSpec
%s\n",GetTStamp(tBuff,56),modSpec));
+
+diff -up ./esc/src/lib/coolkey/NSSManager.h.fix1 ./esc/src/lib/coolkey/NSSManager.h
+--- ./esc/src/lib/coolkey/NSSManager.h.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/NSSManager.h 2018-04-26 11:44:38.458986071 -0700
+@@ -18,7 +18,7 @@
+ #ifdef DARWIN
+ #define COOLKEY_PKCS11_LIBRARY "/Library/Application
Support/CoolKey/PKCS11/libcoolkeypk11.dylib"
+ #else
+-#define COOLKEY_PKCS11_LIBRARY DLL_PREFIX"coolkeypk11."DLL_SUFFIX
++#define COOLKEY_PKCS11_LIBRARY "onepin-opensc-pkcs11."DLL_SUFFIX
+ #endif
+
+ #define COOLKEY_NAME "COOL Key Module"
+diff -up ./esc/src/lib/coolkey/SmartCardMonitoringThread.cpp.fix1
./esc/src/lib/coolkey/SmartCardMonitoringThread.cpp
+--- ./esc/src/lib/coolkey/SmartCardMonitoringThread.cpp.fix1 2017-07-24
16:46:36.000000000 -0700
++++ ./esc/src/lib/coolkey/SmartCardMonitoringThread.cpp 2018-04-26 11:44:38.460986059
-0700
+@@ -81,7 +81,7 @@ void SmartCardMonitoringThread::Insert(P
+ PR_LOG( coolKeyLogSC, PR_LOG_DEBUG,
+ ("%s SmartCardMonitoringThread::Insert Key.
\n",GetTStamp(tBuff,56)));
+
+- CoolKeyInfo *info = CKHGetCoolKeyInfo(aSlot);
++ CoolKeyInfo *info = CKHGetCoolKeyInfo(aSlot,NULL);
+ if (info) {
+ if (!InsertCoolKeyInfoIntoCoolKeyList(info)) {
+ AutoCoolKey key(eCKType_CoolKey, info->mCUID);
+diff -up ./esc/src/lib/NssHttpClient/manifest.mn.fix1
./esc/src/lib/NssHttpClient/manifest.mn
+--- ./esc/src/lib/NssHttpClient/manifest.mn.fix1 2017-07-24 16:46:36.000000000 -0700
++++ ./esc/src/lib/NssHttpClient/manifest.mn 2018-04-26 11:44:38.462986047 -0700
+@@ -31,7 +31,7 @@ endif
+
+
+ MAPFILE = $(OBJDIR)/httpchunked.def
+-DEFINES = -I$(SYS_INC)/nspr4 -I$(SYS_INC)/nss3 -I$(SYS_INC)/$(MOZ_OFFSET)/nspr
-I$(SYS_INC)/$(MOZ_OFFSET)/nss -I$(XULRUNNER_BASE)/dist/public/nss
-I$(XULRUNNER_BASE)/dist/include/nspr -I$(GECKO_SDK_PATH)/include/nspr
-I$(GECKO_SDK_PATH)/include/nss
++DEFINES = -I$(SYS_INC)/nspr4 -I$(SYS_INC)/nss3 -I$(SYS_INC)/$(MOZ_OFFSET)/nspr
-I$(SYS_INC)/$(MOZ_OFFSET)/nss -I$(XULRUNNER_BASE)/dist/public/nss
-I$(XULRUNNER_BASE)/dist/include/nspr -I$(GECKO_SDK_PATH)/include/nspr
-I$(GECKO_SDK_PATH)/include/nss -I$(SYS_INC)/PCSC -I$(CORE_DEPTH)/src/lib/coolkey
+
+ CPPSRCS = \
+ Cache.cpp \
diff --git a/esc-1.1.1-fix2.patch b/esc-1.1.1-fix2.patch
new file mode 100644
index 0000000..95c2642
--- /dev/null
+++ b/esc-1.1.1-fix2.patch
@@ -0,0 +1,11 @@
+diff -up ./esc/src/xulrunner/xulrunner-mozconfig.fix2
./esc/src/xulrunner/xulrunner-mozconfig
+--- ./esc/src/xulrunner/xulrunner-mozconfig.fix2 2018-04-30 13:48:53.944086197 -0700
++++ ./esc/src/xulrunner/xulrunner-mozconfig 2018-04-30 13:49:22.804921349 -0700
+@@ -37,6 +37,7 @@ ac_add_options --disable-skia
+ ac_add_options --with-system-nspr
+ ac_add_options --with-system-nss
+ ac_add_options --disable-crashreporter
++ac_add_options --disable-startupcache
+
+ export BUILD_OFFICIAL=1
+ export MOZILLA_OFFICIAL=1
diff --git a/esc.spec b/esc.spec
index 3fea7ec..1dbd84d 100644
--- a/esc.spec
+++ b/esc.spec
@@ -1,6 +1,6 @@
Name: esc
Version: 1.1.1
-Release: 3%{?dist}
+Release: 4%{?dist}
Summary: Enterprise Security Client Smart Card Client
License: GPL+
URL:
http://directory.fedora.redhat.com/wiki/CoolKey
@@ -10,6 +10,8 @@ Group: Applications/Internet
%global libnotify_version 0.7.0
%global libvpx_version 1.0.0
+Patch1: esc-1.1.1-fix1.patch
+Patch2: esc-1.1.1-fix2.patch
BuildRequires: doxygen fontconfig-devel
BuildRequires: glib2-devel atk-devel
@@ -17,7 +19,7 @@ BuildRequires: pkgconfig
BuildRequires: nspr-devel nss-devel nss-static
BuildRequires: libX11-devel libXt-devel
-BuildRequires: pcsc-lite-devel coolkey-devel
+BuildRequires: pcsc-lite-devel
BuildRequires: desktop-file-utils zip binutils
BuildRequires: libnotify-devel >= %{libnotify_version}
BuildRequires: dbus-devel
@@ -46,10 +48,11 @@ BuildRequires: yasm
BuildRequires: dbus-glib-devel
BuildRequires: libffi-devel
BuildRequires: sqlite-devel
+BuildRequires: opensc
Requires: sqlite
-Requires: pcsc-lite coolkey nss nspr
+Requires: pcsc-lite nss nspr
Requires: zip dbus >= 0.90 libnotify >= 0.4.2
Requires: mozilla-filesystem
Requires: nspr-devel
@@ -72,12 +75,14 @@ Requires: alsa-lib-devel
Requires: libnotify-devel
Requires: mesa-libGL-devel
Requires: libvpx-devel >= %{libvpx_version}
+Requires: opensc
-# 390 does not have coolkey or smartCards
+# 390 does not have smartCards
ExcludeArch: s390 s390x
-#xulrunner doesn't seem to support this one
-ExcludeArch: aarch64
+#xulrunner doesn't seem to support these right now
+#Temporary anyway, since xulrunner is going away soon.
+ExcludeArch: aarch64 i686
# We can't allow the internal xulrunner to leak out
AutoReqProv: 0
@@ -116,6 +121,9 @@ cryptographic smartcards.
#patch esc
+%patch1 -p1 -b .fix1
+%patch2 -p1 -b .fix2
+
r=$(uname -r | sed -e 's/\(^[^.]*\.[^.]*\).*/\1/')
[ -f esc/coreconf/Linux$r.mk ] || ln -s Linux3.5.mk esc/coreconf/Linux$r.mk
@@ -210,10 +218,13 @@ chmod 755 $RPM_BUILD_ROOT/%{escdir}/application.ini
%license %{docdir}/LICENSE
%{escdir}/esc
+%attr(755, root, root) %{escdir}/esc
%{escdir}/escd
%{escbindir}/esc
%{escdir}/application.ini
-
+%{escdir}/opensc.esc.conf
+%dir %{escdir}/chrome
+%dir %{escdir}/defaults
%{escdir}/chrome.manifest
%{escdir}/chrome/chrome.manifest
@@ -236,6 +247,8 @@ killall --exact -q escd
exit 0
%changelog
+* Mon Apr 23 2018 Jack Magne <jmagne(a)redhat.com> - 1.1.1-4
+- Remove coolkey dependencies, replace with opensc.
* Wed Feb 07 2018 Fedora Release Engineering <releng(a)fedoraproject.org> - 1.1.1-3
- Rebuilt for
https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild