summaryrefslogtreecommitdiff
path: root/libdigidoc/DigiDocPKCS11.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdigidoc/DigiDocPKCS11.c')
-rw-r--r--libdigidoc/DigiDocPKCS11.c956
1 files changed, 956 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocPKCS11.c b/libdigidoc/DigiDocPKCS11.c
new file mode 100644
index 0000000..158c63d
--- /dev/null
+++ b/libdigidoc/DigiDocPKCS11.c
@@ -0,0 +1,956 @@
+//==================================================
+// FILE: DigiDocPKCS11.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for signing using PKCS#11 API
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// 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; either
+// version 2.1 of the License, or (at your option) any later version.
+// 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.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.02.2004 Integrated
+// 26.01.2004 Aare
+// Removed function signOCSPRequestWithPKCS11onWin
+// 13.01.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include "DigiDocPKCS11.h"
+#include "DigiDocConfig.h"
+#include "DigiDocDebug.h"
+#include "DigiDocCert.h"
+#include "DigiDocGen.h"
+#include "DigiDocConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+
+static CK_FUNCTION_LIST_PTR ckFunc = 0;
+
+//AA 04/01/26
+extern X509_ALGOR* setSignAlgorithm(const EVP_MD * type);
+
+// I suppose there won't be so many slots
+
+#define INVALID_SLOTIID 1000
+
+//============================================================
+// Attempts to load and initialize on PKCS#11 driver DLL.
+//============================================================
+EXP_OPTION LIBHANDLE initPKCS11Library(const char* libName)
+{
+ LIBHANDLE pLibrary = 0;
+ CK_C_GetFunctionList pC_GetFunctionList;
+ CK_RV rv;
+
+ // load PKCS#11 driver
+ ddocDebug(3, "initPKCS11Library", "Loading driver: %s", libName);
+#ifdef WIN32
+ pLibrary = LoadLibrary((LPCSTR)libName);
+#else
+ pLibrary = dlopen(libName, RTLD_NOW);
+#endif
+ if(pLibrary != NULL) {
+ // printf("Resolve PKCS#11 function index!\n");
+ // Get function pointer to C_GetFunctionList
+#ifdef WIN32
+ pC_GetFunctionList = (CK_C_GetFunctionList)GetProcAddress(/*(HINSTANCE__*)*/pLibrary, "C_GetFunctionList");
+#else
+ pC_GetFunctionList = (CK_C_GetFunctionList)dlsym(pLibrary, "C_GetFunctionList");
+#endif
+ if(pC_GetFunctionList != NULL) {
+ ddocDebug(3, "initPKCS11Library", "Getting PKCS#11 func!");
+ // Get function pointers to all PKCS #11 functions
+ rv = (*pC_GetFunctionList)(&ckFunc);
+ if(rv == CKR_OK) {
+ ddocDebug(3, "initPKCS11Library", "Initializing PKCS#11 library:");
+ // Initalize Cryptoki
+ rv = (*ckFunc->C_Initialize)(0);
+ ddocDebug(3, "initPKCS11Library", "Initlialized: %d", (int)rv);
+ if(rv != CKR_OK) {
+ ddocDebug(2, "initPKCS11Library", "Error initializing library!");
+ pLibrary = NULL; // error initializing the library
+ }
+ } else {
+ ddocDebug(2, "initPKCS11Library", "Error getting PKCS#11 func!");
+ pLibrary = NULL; // error getting function pointers
+ }
+ } else {
+ ddocDebug(2, "initPKCS11Library", "Error resolving PKCS#11 function index!");
+ pLibrary = NULL; // error getting function list function
+ }
+ } else {
+#ifdef WIN32
+ ddocDebug(2, "initPKCS11Library", "Error loading driver : %s", libName);
+#else
+ ddocDebug(2, "initPKCS11Library", "Error loading driver : %s", dlerror());
+#endif
+ }
+ return pLibrary;
+}
+
+//============================================================
+// Cleanup PKCS#11 library session
+//============================================================
+EXP_OPTION void closePKCS11Library(LIBHANDLE pLibrary, CK_SESSION_HANDLE hSession)
+{
+ CK_RV rv;
+
+ // close session
+ if(hSession > 0) {
+ ddocDebug(3, "closePKCS11Library", "Closing PKCS#11 session!");
+ rv = (*ckFunc->C_CloseSession)(hSession);
+ }
+ // finalize library
+ rv = (*ckFunc->C_Finalize)(0);
+ // remove .so from memory
+ ddocDebug(3, "closePKCS11Library", "Closing PKCS#11 library!\n");
+ if(pLibrary)
+#ifdef WIN32
+ FreeLibrary(/*(HINSTANCE__*)*/pLibrary);
+#else
+ dlclose(pLibrary);
+#endif
+}
+
+//============================================================
+// Retrieves the slotid list
+//============================================================
+EXP_OPTION CK_RV GetSlotIds(CK_SLOT_ID_PTR pSlotids, CK_ULONG_PTR pLen)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetSlotList)(TRUE, pSlotids, pLen);
+ return rv;
+}
+
+//============================================================
+// Retrieves one tokens info
+//============================================================
+EXP_OPTION CK_RV GetTokenInfo(CK_TOKEN_INFO_PTR pTokInfo, CK_SLOT_ID id)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetTokenInfo)(id, pTokInfo);
+ return rv;
+}
+
+//============================================================
+// Retrieves one slots info
+//============================================================
+EXP_OPTION CK_RV GetSlotInfo(CK_SLOT_INFO_PTR pSlotInfo, CK_SLOT_ID id)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetSlotInfo)(id, pSlotInfo);
+ return rv;
+}
+
+//============================================================
+// Loads the PKCS#11 driver and
+// tests if the driver loaded correctly
+// Returns 0 for ok otherwise error code
+//============================================================
+int loadAndTestDriver(const char* driver, LIBHANDLE* pLibrary, CK_SLOT_ID* slotids, int slots, CK_ULONG slot)
+{
+ CK_TOKEN_INFO tokinfo;
+ CK_SLOT_INFO slotinfo;
+ CK_ULONG idlen, i, ok;
+ CK_RV rv;
+ int err = ERR_OK;
+
+ // initialize
+ *pLibrary = NULL;
+ memset(slotids, 0, sizeof(CK_SLOT_ID) * slots);
+ // try to load the driver
+ *pLibrary = initPKCS11Library(driver);
+ if(!(*pLibrary))
+ SET_LAST_ERROR_RETURN_CODE(ERR_PKCS_LIB_LOAD);
+ idlen = slots;
+ rv = GetSlotIds(slotids, &idlen);
+ ddocDebug(3, "loadAndTestDriver", "RV: %d slots: %ld", (int)rv, (long)idlen);
+ if (rv != CKR_OK) {
+ err = ERR_PKCS_SLOT_LIST;
+ SET_LAST_ERROR(err);
+ }
+ if ((slot < 0) || (slot >= (int)idlen)) {
+ err = ERR_PKCS_WRONG_SLOT;
+ SET_LAST_ERROR(err);
+ }
+ // it's useful to test DLL load status this way:
+ ok = 0;
+ for(i = 0; i < (int)idlen; i++) {
+ rv = GetSlotInfo(&slotinfo, slotids[i]);
+ if(slotinfo.flags & CKF_TOKEN_PRESENT) {
+ ddocDebug(3, "loadAndTestDriver", "Read Token: %ld", (long)i);
+ rv = GetTokenInfo(&tokinfo, slotids[i]); // if !CKR_OK test
+ tokinfo.label[31] = 0;
+ ddocDebug(3, "loadAndTestDriver", "RV: %d Token: %s", (int)rv, tokinfo.label);
+ if(rv != CKR_OK)
+ slotids[i] = INVALID_SLOTIID; // set bad slotids to 0
+ else
+ ok++; // count the good slots
+ } else {
+ slotids[i] = INVALID_SLOTIID; // no tokne in this slot
+ }
+ }
+ // fill other slotid's with invalid slotid
+ for(i = idlen; i < (CK_ULONG)slots; i++)
+ slotids[i] = INVALID_SLOTIID;
+ if(ok < slot) {
+ err = ERR_PKCS_CARD_READ; // if not enough good slots
+ SET_LAST_ERROR(err);
+ }
+ // in case of error try to unload the module and notify caller
+ if (err) {
+ if (*pLibrary)
+ closePKCS11Library(*pLibrary, 0);
+ *pLibrary = NULL;
+ }
+ return err;
+}
+
+//============================================================
+// Opens smart card session.
+// slotId - id of the sert slot
+// pin - card pin
+// return session id or -1 for failure
+//============================================================
+CK_SESSION_HANDLE OpenSession(CK_SLOT_ID slotId, const char *pin)
+{
+ CK_SESSION_HANDLE hSession = 0;
+ /*
+ Ainult SERIAL_SESSION toetatud, Digiallkirja andvat privaatvo~tit kasutav sessioon
+ on initsialiseeritud CKS_RO_USER_FUNCTIONS staatusesse, seda on tehtud Netscape lolli-
+ tamiseks, et see igal vo~imalikul ja vo~imatul juhul ei ku"siks pin'i vo~tme jaoks
+ mida ta niiehknii kasutada ei oska. Selle jaoks tuleb vajaduse korral ikka C_Login
+ va"lja kutsuda.
+ */
+ CK_RV rv = (*ckFunc->C_OpenSession)(slotId, CKF_SERIAL_SESSION,0,0,&hSession);
+ ddocDebug(3, "OpenSession", "Open sess for slot id: %u - sess: %uld RV = %u", slotId, hSession, rv);
+ if(rv == CKR_OK && pin) { // don't login if pin is null. Session can be used also to read certs.
+ /* Kommentaar: Ainult CKU_USER toetatud. */
+ rv = (*ckFunc->C_Login)(hSession, CKU_USER, (unsigned char*)pin, strlen(pin));
+ ddocDebug(3, "OpenSession", "Login for slot id: %u - sess: %uld RV = %u", slotId, hSession, rv);
+ if(rv != CKR_OK)
+ hSession = CK_INVALID_HANDLE; // mark session bad!
+ }
+ // Return the session handle and exit
+ return hSession;
+}
+
+//============================================================
+// Sign a string using a private key referred by the supplied handle.
+// hSession - card session handle
+// hPrivateKey - private key handle
+// Signature - buffer for signature
+// ulSignatureLen - signature buffer length
+// sigData - data to be signed
+//============================================================
+CK_RV SignData(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPrivateKey,
+ CK_BYTE* Signature, CK_ULONG* ulSignatureLen,
+ CK_BYTE* sigData, CK_ULONG dataLen)
+{
+ // Set up mechanism for PKCS #1 signing
+ CK_MECHANISM Mechanism = { CKM_RSA_PKCS, 0, 0 };
+ // Initiate the signature operation
+ CK_RV rv = (*ckFunc->C_SignInit)(hSession,&Mechanism,hPrivateKey);
+ if(rv == CKR_OK) {
+ // Kommentaar: Realiseeritud meetodi CKM_RSA_PKCS jaoks.
+ rv = (*ckFunc->C_Sign)(hSession, sigData, dataLen,
+ Signature, ulSignatureLen);
+ if(rv != CKR_OK)
+ ddocDebug(1, "SignData", "Error signing - sess: %u pkey: %uld slen: %uld dlen: %uld. RV = %u",
+ hSession, hPrivateKey, ulSignatureLen, dataLen, rv);
+ } // if C_SignInit
+ else
+ ddocDebug(1, "SignData", "Error initing sign session. RV = %ld", rv);
+ ddocDebug(3, "SignData", "RV = %ld", rv);
+ return rv;
+}
+
+
+//============================================================
+// Locates a certificate on the token on basis of its CKA_LABEL attribute.
+// hSession - card session handle
+// label - key label
+// return objects handle or -1 for failure
+//============================================================
+CK_OBJECT_HANDLE LocateCertificate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR certData, CK_ULONG_PTR certLen,
+ char idData[20][20], CK_ULONG idLen[20],
+ int* pSelKey)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i, j;
+ CK_BYTE buf1[20];
+ CK_OBJECT_HANDLE hCert = CK_INVALID_HANDLE;
+ CK_RV rv;
+
+ // Set up a template to search for Certificate token objects
+ // in the given session and thus slot
+ CK_OBJECT_CLASS ObjClass = CKO_CERTIFICATE;
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ { CKA_ID, (void*)0, 0 }
+ };
+ CK_ATTRIBUTE Template3[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_VALUE, (void*)0, *certLen },
+ { CKA_ID, (void*)0, 0 }
+ };
+ CK_ULONG ulCount = 0;
+
+ if(idLen)
+ ulCount = sizeof(Template1)/sizeof(CK_ATTRIBUTE);
+ else
+ ulCount = sizeof(Template3)/sizeof(CK_ATTRIBUTE);
+ *certLen = 0;
+ /*
+ ** Initiate the object search
+ C_FindObjectsInit initializes a search for token and session objects that match a template.
+ hSession is the sessions handle; pTemplate points to a search template that specifies the
+ attribute values to match; ulCount is the number of attributes in the search template. The
+ matching criterion is an exact byte-for-byte match with all attributes in the template.
+ To find all objects, set ulCount to 0.
+ */
+
+ for(j = 0; j < 20 && !(*certLen); j++) {
+ if(idLen && idLen[j]) {
+ memset(buf1, 0, sizeof(buf1));
+ memcpy(buf1, idData[j], idLen[j]);
+ Template1[1].pValue = buf1;
+ Template1[1].ulValueLen = idLen[j];
+ }
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, (idLen ? Template1 : Template3), 1); //ulCount);
+ if(rv==CKR_OK) {
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocateCertificate", "search key-id: %s, found: %ld rv: %ld", buf1, ulObjectCount, rv);
+ if(rv==CKR_OK) {
+ // pick the first cert that is valid
+ // list and ignore any other
+ for(i = 0; i < ulObjectCount; i++) {
+ hCert = Objects[i];
+ memset(certData, 0, *certLen);
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ // get cert length
+ *certLen = 0;
+ Template2[1].pValue = buf1;
+ Template2[1].ulValueLen = sizeof(buf1);
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hCert, Template2, ulCount);
+ ddocDebug(3, "LocateCertificate", "cert-id: %s", buf1);
+ if(rv == CKR_OK && (!idLen ||
+ (idLen && !memcmp(idData[j], buf1, idLen[1])))) {
+ *certLen = Template2[0].ulValueLen;
+ // now get cert data
+ Template2[0].pValue = certData;
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hCert, Template2, ulCount);
+ ddocDebug(3, "LocateCertificate", "cert-len: %ld", *certLen);
+ if(*certLen > 0 && pSelKey) {
+ *pSelKey = j;
+ break; // found it
+ }
+
+ } // if rv == CKR_OK
+ } // for i < ulObjectCount
+ } // if rv
+ } // if rv
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ } // for j
+ //if(hCert == CK_INVALID_HANDLE)
+ // *certLen = 0;
+ return hCert;
+}
+
+//============================================================
+// Locates a private key on the token on basis of its CKA_LABEL attribute.
+// hSession - card session handle
+// idData - address of an array of label buffers
+// idlen - array of label lengths
+// return objects handle or -1 for failure
+//============================================================
+CK_RV LocatePrivateKey(CK_SESSION_HANDLE hSession, char idData[20][20], CK_ULONG idLen[20], CK_OBJECT_HANDLE_PTR hKeys)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_RV rv;
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i;
+ // Set up a template to search for all Private Key tokens
+ // Given the session context, that is associated with
+ // one slot we will find only one object
+ CK_OBJECT_CLASS ObjClass = CKO_PRIVATE_KEY;
+ char buf1[20];
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) }
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_ID, (void*)0, idLen[0] }
+ };
+ CK_ULONG ulCount = sizeof(Template1) / sizeof(CK_ATTRIBUTE);
+
+ /*
+ ** Initiate the object search
+ C_FindObjectsInit initializes a search for token and session objects that match a template.
+ hSession is the sessions handle; pTemplate points to a search template that specifies the
+ attribute values to match; ulCount is the number of attributes in the search template. The
+ matching criterion is an exact byte-for-byte match with all attributes in the template.
+ To find all objects, set ulCount to 0.
+ */
+ ddocDebug(3, "LocatePrivateKey", "LocatePrivateKey");
+ rv = (*ckFunc->C_FindObjectsInit)(hSession,Template1,ulCount);
+ if(rv==CKR_OK) {
+ // Get list of object handles
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocatePrivateKey", "Find: %d count: %ld", rv, ulObjectCount);
+ if(rv==CKR_OK) {
+ // get labels of all possible private keys
+ for(i = 0; i < ulObjectCount; i++) {
+ hKeys[i] = Objects[i];
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ // get key id length
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hKeys[i], Template2, ulCount);
+ if(rv == CKR_OK) {
+ idLen[i] = Template2[0].ulValueLen;
+ // now get key id data
+ Template2[0].pValue = buf1;
+ memset(buf1, 0, sizeof(buf1));
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hKeys[i], Template2, ulCount);
+ ddocDebug(3, "LocatePrivateKey", "key: %d id %s len: %ld", i, buf1, idLen[i]);
+ memcpy(idData[i], buf1, idLen[i]);
+ }
+ } // for i < ulObjectsCount
+ }
+ }
+ // Remember to call C_FindObjectsFinal to terminate the search
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ return rv;
+}
+
+//============================================================
+// Locates a private key on the token on basis of its CKA_ID attribute.
+// hSession - card session handle
+// idData - id value
+// idLen - length of id value
+// hKey - address of key handle to be returned
+// return objects handle or -1 for failure
+//============================================================
+CK_RV LocatePrivateKeyWithId(CK_SESSION_HANDLE hSession, CK_BYTE_PTR idData, CK_ULONG idLen, CK_OBJECT_HANDLE_PTR hKey)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_RV rv;
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i;
+ CK_OBJECT_CLASS ObjClass = CKO_PRIVATE_KEY;
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ { CKA_ID, (void*)idData, idLen }
+ };
+ CK_ULONG ulCount = sizeof(Template1) / sizeof(CK_ATTRIBUTE);
+ char buf2[40];
+ int l2;
+
+ l2 = sizeof(buf2);
+ bin2hex((const byte*)idData, idLen, (char*)buf2, &l2);
+ ddocDebug(3, "LocatePrivateKeyWithId", "LocatePrivateKey with id: %s", buf2);
+ //Template1[1].pValue = idData;
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, Template1, ulCount);
+ if(rv==CKR_OK) {
+ // Get list of object handles
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocatePrivateKeyWithId", "Find: %d count: %ld", rv, ulObjectCount);
+ if(rv==CKR_OK) {
+ // get labels of all possible private keys
+ for(i = 0; i < ulObjectCount; i++) {
+ ddocDebug(3, "LocatePrivateKeyWithId", "Key handle: %d", Objects[i]);
+ *hKey = Objects[i];
+ } // for i < ulObjectsCount
+ }
+ }
+ // Remember to call C_FindObjectsFinal to terminate the search
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ return rv;
+}
+
+
+
+int ddocLocateSlotWithSignatureCert(LIBHANDLE pLibrary, CK_SLOT_ID* slotids,
+ CK_SLOT_ID* pSlotId, X509** ppCert,
+ char idData[20], int* pIdLen, int nSlot, int* pIdx)
+{
+ int err = ERR_PRIVKEY_READ, i, j, nMatch, l3;
+ CK_RV rv;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE objects[10];
+ CK_BYTE buf2[20], buf3[40];
+ CK_ULONG ulObjectCount = sizeof(objects)/sizeof(CK_OBJECT_HANDLE), ulCount = 0, l1 = 0, l2 = 0;
+ CK_OBJECT_CLASS ObjClass = CKO_CERTIFICATE;
+
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) }
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_VALUE, (void*)0, l1 },
+ { CKA_ID, (void*)0, sizeof(buf2)}
+ };
+ char buf1[3000], buf4[64];
+ X509* pCert = 0;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(pLibrary);
+ RETURN_IF_NULL_PARAM(pSlotId);
+ RETURN_IF_NULL_PARAM(slotids);
+ RETURN_IF_NULL_PARAM(idData);
+ RETURN_IF_NULL_PARAM(ppCert);
+ // mark as not found
+ memset(idData, 0, *pIdLen);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Driver handle: %d err = %d", pLibrary, err);
+ // now check every slot
+ for(i = 0, nMatch = 0; (i < 20) && !(*ppCert); i++) {
+ if(slotids[i] != INVALID_SLOTIID) {
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Checking slot nr: %d id: %d", i, slotids[i]);
+ // open session to slot but no login since we just need the cert
+ rv = (*ckFunc->C_OpenSession)(slotids[i], CKF_SERIAL_SESSION,0,0,&hSession);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Login rv: %ld session: %ld", rv, hSession);
+ if(rv == CKR_OK) {
+ ulCount = sizeof(Template1)/sizeof(CK_ATTRIBUTE);
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, Template1, ulCount);
+ if(rv == CKR_OK) {
+ rv = (*ckFunc->C_FindObjects)(hSession, objects, ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, objects: %ld",
+ slotids[i], ulObjectCount);
+ if(rv == CKR_OK && ulObjectCount > 0) {
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ for(j = 0; j < (int)ulObjectCount; j++) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ Template2[0].pValue = 0; // check length first
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, objects[j], Template2, ulCount);
+ if(rv == CKR_OK && Template2[0].ulValueLen < sizeof(buf1)) {
+ l1 = Template2[0].ulValueLen;
+ // now get cert data
+ Template2[0].pValue = buf1;
+ Template2[1].pValue = buf2;
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, objects[j], Template2, ulCount);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, object: %ld cert-len: %ld rv: %ld",
+ slotids[i], j, l1, rv);
+ pCert = 0;
+ err = ddocDecodeX509Data(&pCert, (const byte*)buf1, l1);
+ if(pCert) {
+ // debug
+ memset(buf4, 0, sizeof(buf4));
+ ReadCertSerialNumber(buf4, sizeof(buf4), pCert);
+ ddocCertGetSubjectCN(pCert, &mbuf1);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, object: %ld cert-serial: %s CN: %s",
+ slotids[i], j, buf4, (char*)mbuf1.pMem);
+ if(ddocCertCheckKeyUsage(pCert, KUIDX_NON_REPUDIATION)) {
+ if((!nSlot || nSlot == nMatch) && !(*ppCert)) {
+ l3 = sizeof(buf3);
+ memset(buf3, 0, l3);
+ bin2hex((const byte*)buf2, (int)Template2[1].ulValueLen, (char*)buf3, &l3);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Selecting slot: %d id: %d key-id %s", i, slotids[i], buf3);
+ *pSlotId = slotids[i];
+ *pIdx = i;
+ // keep this cert for signing
+ if(*ppCert)
+ X509_free(*ppCert);
+ (*ppCert) = pCert;
+ pCert = NULL; // mark as used
+ memcpy(idData, buf2, Template2[1].ulValueLen);
+ *pIdLen = Template2[1].ulValueLen;
+ err = ERR_OK; // found it
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Selected key/cert: %s - %s", buf4, (char*)mbuf1.pMem);
+ } else { // useable slot but not a match by slot id
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Useable slot: %d but search: %d", nMatch, nSlot);
+ nMatch++;
+ }
+ } // if non-repu cert
+ ddocMemBuf_free(&mbuf1);
+ } // if pCert
+ if(pCert)
+ X509_free(pCert);
+ pCert = 0;
+
+ } // if get-attribute ok
+ } // for j < ulObjectCount
+ } // if found any certs
+ } // if find-init ok
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ } // if login ok
+ rv = (*ckFunc->C_CloseSession)(hSession);
+ } // if slotid
+ } // for i
+
+ return err;
+}
+
+extern void dumpInFile(const char* fileName, const char* data);
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// Uses EstEID card to sign the info
+// pSigInfo - signature info object
+// nSigType - signature type code
+// keyfile - RSA key file
+// passwd - key password
+// certfile - certificate file
+//============================================================
+EXP_OPTION int calculateSignatureWithEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ int slot, const char* passwd)
+{
+ int err = ERR_OK, nKey;
+ LIBHANDLE pLibrary = 0;
+ CK_ULONG certLen, sigLen, padDigLen;
+ CK_RV rv;
+ CK_SLOT_ID slotids[20], slId = 0;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE hPrivateKey = 0, hKeys[20], hCert;
+ char keyId[20][20], kId[20];
+ CK_ULONG keyIdLen[20];
+ CK_BYTE certData[2048];
+ CK_BYTE sigDig[100], padDig[130];
+ CK_BYTE signature[256];
+ CK_BYTE padding[] = { 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20 };
+ //CK_BYTE padding256[] = { 48, 49, 48, 13, 6, 9, 96, 134, 72, 1 ,101, 3, 4, 2, 1, 5, 0, 4, 32};
+ //CK_BYTE padding256[] = { 48, 33, 48, 13, 6, 9, 96, 134, 72, 1 ,101, 3, 4, 2, 1, 5, 0, 4, 32};
+ char* buf1;
+ int l1, l2, kILen;
+ X509* x509 = 0;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ // try active driver driver first
+ snprintf((char*)signature, sizeof(signature), "DIGIDOC_DRIVER_%d_FILE",
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ for(l1 = 0; l1 < 20; l1++)
+ slotids[l1] = INVALID_SLOTIID; // initialize
+ err = loadAndTestDriver(ConfigItem_lookup((const char*)signature),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ ddocDebug(3, "calculateSignatureWithEstID", "Driver handle: %d err = %d slot: %d",
+ pLibrary, err, slot);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // inittialize
+ slId = INVALID_SLOTIID; // not found yet
+ // try key-usage check
+ if(ConfigItem_lookup_int("KEY_USAGE_CHECK", 1)) {
+ kILen = sizeof(kId);
+ ddocDebug(3, "calculateSignatureWithEstID", "Find slot by key-usage, slot: %d", slot);
+ err = ddocLocateSlotWithSignatureCert(pLibrary, slotids, &slId, &x509, kId, &kILen, slot, &l1);
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select by key-usage slot idx: %d = %d err: %d key-id: %s, kid-len: %d", l1, slId, err, kId, kILen);
+ if(err != ERR_OK || l1 < 0 || l1 >= 20) {
+ SET_LAST_ERROR(ERR_SIGNERS_CERT_NON_REPU);
+ return ERR_SIGNERS_CERT_NON_REPU;
+ }
+ } else {
+ ddocDebug(3, "calculateSignatureWithEstID", "Find slot by slot idx: %d", slot);
+ for(l1 = 0; (l1 < 20) && (slId == INVALID_SLOTIID); l1++) {
+ if(slotids[l1] != INVALID_SLOTIID)
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Slot idx: %d = %d", l1, slotids[l1]);
+ if(slotids[l1] != INVALID_SLOTIID && l1 == slot) {
+ slId = slotids[l1];
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select idx: %d slot: %d", l1, slId);
+ } // if slotid
+ } // for
+ }
+ // use default if not found by key-id or direct
+ if(slId == INVALID_SLOTIID) {
+ l1 = ConfigItem_lookup_int("DIGIDOC_SIGNATURE_SLOT", 0);
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select default slot idx: %d = %d", l1, slotids[l1]);
+ slId = slotids[l1];
+ }
+ }
+
+ // open session
+ if(slId != INVALID_SLOTIID) {
+ hSession = OpenSession(slId, passwd);
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Open sess for slot: %d sess = %d", slId, hSession);
+ if (hSession == CK_INVALID_HANDLE) { err = ERR_PKCS_LOGIN; SET_LAST_ERROR(err); return err; }
+ ddocDebug(3, "calculateSignatureWithEstID", "OpenSession ok, hSession1 = %d", (int)hSession);
+
+ if(!x509) {
+ ddocDebug(3, "calculateSignatureWithEstID", "Cert ok");
+ // get private key
+ for(l1 = 0; l1 < 20; l1++) {
+ memset(keyId[l1], 0, 20);
+ keyIdLen[l1] = 0;
+ }
+ err = LocatePrivateKey(hSession, keyId, keyIdLen, hKeys);
+ //ddocDebug(3, "calculateSignatureWithEstID", "Priv key: %s", keyId);
+ //
+
+ // get cert
+ memset(certData, 0, sizeof(certData));
+ certLen = sizeof(certData);
+ hCert = LocateCertificate(hSession, certData, &certLen, keyId, keyIdLen, &nKey);
+ hPrivateKey = hKeys[nKey];
+ ddocDebug(3, "calculateSignatureWithEstID", "selected priv-key: %ld pos %d id: %s", hPrivateKey, nKey, keyId[nKey]);
+ ddocDebug(3, "calculateSignatureWithEstID", "Cert-len: %ld", certLen);
+ //printf("Cert: %s", certData);
+ if (hCert == (CK_OBJECT_HANDLE)-1) { err = ERR_PKCS_CERT_LOC; SET_LAST_ERROR(err); return err; }
+
+ // set cert data
+ err = ddocDecodeX509Data(&x509, certData, certLen);
+
+
+ } else { // cert already found
+ //kILen = sizeof(kId);
+ ddocDebug(3, "calculateSignatureWithEstID", "Locate priv key2 id: %s, len: %d, hkey: %d", kId, kILen, hPrivateKey);
+ err = LocatePrivateKeyWithId(hSession, (CK_BYTE_PTR)kId, kILen, &hPrivateKey);
+ ddocDebug(3, "calculateSignatureWithEstID", "Priv key-id: %s len: %d hkey: %d err: %d", kId, kILen, hPrivateKey, err);
+ }
+ ddocDebug(3, "calculateSignatureWithEstID", "Priv key: %d err: %d", hPrivateKey, err);
+ if (hPrivateKey == CK_INVALID_HANDLE) { err = ERR_PKCS_PK; SET_LAST_ERROR(err); return err; }
+ if (!x509) { err = ERR_PKCS_CERT_DECODE; }
+
+ // save cert in file
+ if(ConfigItem_lookup_int("DEBUG_LEVEL", 1) > 3)
+ saveCert(x509, "signer.pem", FILE_FORMAT_PEM);
+ setSignatureCert(pSigInfo, x509);
+
+ // FIXME
+ createTimestamp(pSigDoc, (char*)sigDig, sizeof(sigDig));
+ setString((char**)&(pSigInfo->szTimeStamp), (const char*)sigDig, -1);
+
+ // Signed properties digest
+ buf1 = createXMLSignedProperties(pSigDoc, pSigInfo, 0);
+ //dumpInFile("sigprop-sign1.txt", buf1);
+ if (!buf1) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ mbuf1.pMem = canonicalizeXML((char*)buf1, strlen(buf1));
+ mbuf1.nLen = strlen((const char*)mbuf1.pMem);
+ ddocDebugWriteFile(4, "sigprop-signed.txt", &mbuf1);
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)mbuf1.pMem, mbuf1.nLen, DIGEST_SHA1, sigDig, &l2);
+ free(buf1);
+ ddocMemBuf_free(&mbuf1);
+ if (err != ERR_OK) {
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigPropDigest(pSigInfo, (const char*)sigDig, l2);
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // create signed info
+ buf1 = createXMLSignedInfo(pSigDoc, pSigInfo);
+ if (!buf1) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err ;
+ }
+ // get digest
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)buf1, strlen(buf1), DIGEST_SHA1, sigDig, &l2);
+ free(buf1);
+ if (err != ERR_OK) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigInfoRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // sign data
+ sigLen = sizeof(signature);
+ memset(signature, 0, sizeof(signature));
+ // pad PKCS#1 ver 1
+ padDigLen = 35;
+ memset(padDig, 0, sizeof(padDig));
+ memcpy(padDig, padding, 15);
+ memcpy(padDig + 15, sigDig, l2);
+ //rv = RSA_padding_add_PKCS1_type_1(padDig, padDigLen, sigDig, l2);
+ //rv = RSA_padding_check_PKCS1_type_1(sigDig, l2, padDig, padDigLen, padDigLen+1);
+ // checkErrors();
+ // sign data
+ rv = SignData(hSession, hPrivateKey,
+ signature, &sigLen, padDig, padDigLen);
+ if (rv != CKR_OK) {
+ err = ERR_PKCS_SIGN_DATA;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+
+ // set signature value
+ ddocSigInfo_SetSignatureValue(pSigInfo, (const char*)signature, (int)sigLen);
+ ddocDebug(3, "calculateSignatureWithEstID", "Sig-len: %ld", sigLen);
+
+ } // if slotid found
+
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+ return err;
+}
+
+//============================================================
+// Loads the PKCS#11 driver and
+// tests if the driver loaded correctly
+// Returns 0 for ok otherwise error code
+//============================================================
+EXP_OPTION CK_RV getDriverInfo(CK_INFO_PTR pInfo)
+{
+ return (*ckFunc->C_GetInfo)(pInfo);
+}
+
+//============================================================
+// Decrypts RSA encrypted data with the private key
+// slot - number of the slot for decryption key. On ID card allways 0
+// pin - corresponding pin for the key. On ID card - PIN1
+// encData - encrypted data
+// encLen - length of encrypted data
+// decData - buffer for decrypted data
+// encLen - length of buffer. Will be modified by amount of decrypted data
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int decryptWithEstID(int slot, const char* pin,
+ const char* encData, int encLen,
+ char* decData, int *decLen)
+{
+ int err = ERR_OK, l1, l2;
+ LIBHANDLE pLibrary = 0;
+ CK_ULONG keyIdLen[20];
+ CK_RV rv;
+ CK_SLOT_ID slotids[20], slId;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE hPrivateKey, hKeys[20];
+ char keyId[20][20];
+ char driver[100];
+ CK_MECHANISM Mechanism = { CKM_RSA_PKCS, 0, 0 };
+ CK_ULONG outlen;
+
+ ddocDebug(3, "decryptWithEstID", "slot: %d enc-data: %d bytes buffer size: %d", slot, encLen, *decLen);
+ snprintf(driver, sizeof(driver), "DIGIDOC_DRIVER_%d_FILE", ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ ddocDebug(3, "decryptWithEstID", "Driver nr: %d - %s",
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1),
+ ConfigItem_lookup(driver));
+ err = loadAndTestDriver(ConfigItem_lookup(driver),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ if(err) return err;
+
+ // find the right slotid
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ if(l2 == slot)
+ slId = slotids[l1];
+ l2++;
+ }
+ }
+ // open session
+ //ddocDebug(3, "decryptWithEstID", "OpenSession id = %d, pin: %s", (int)slId, pin);
+ hSession = OpenSession(slId, pin);
+ if (hSession == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_LOGIN); return ERR_PKCS_LOGIN; }
+ ddocDebug(3, "decryptWithEstID", "OpenSession ok, hSession = %d", (int)hSession);
+
+ // get private key
+ for(l1 = 0; l1 < 20; l1++) {
+ memset(keyId[l1], 0, 20);
+ keyIdLen[l1] = 0;
+ }
+ err = LocatePrivateKey(hSession, keyId, keyIdLen, hKeys);
+ hPrivateKey = hKeys[0]; //???
+ //ddocDebug(3, "decryptWithEstID", "Priv key: %s", keyId);
+ //if (hPrivateKey == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_PK); return ERR_PKCS_PK; }
+ // init decrypt
+ rv = (*ckFunc->C_DecryptInit)(hSession, &Mechanism, hPrivateKey);
+ ddocDebug(3, "decryptWithEstID", "DecryptInit: %d", (int)rv);
+ if(rv != CKR_OK) SET_LAST_ERROR_RETURN(ERR_DENC_DECRYPT, ERR_DENC_DECRYPT)
+ // decrypt data
+ outlen = *decLen;
+ rv = (*ckFunc->C_Decrypt)(hSession, (CK_BYTE_PTR)encData, (CK_ULONG)encLen, (CK_BYTE_PTR)decData, (CK_ULONG_PTR)&outlen);
+ *decLen = outlen;
+ ddocDebug(3, "decryptWithEstID", "RV: %d, dec-len: %d", (int)rv, *decLen);
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+ if(rv != CKR_OK)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DECRYPT, ERR_DENC_DECRYPT)
+ return err;
+}
+
+
+//============================================================
+// Locates and reads users certificate from smartcard
+// slot - number of the slot for decryption key. On ID card allways 0
+// ppCert - address for newly allocated certificate pointer
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int findUsersCertificate(int slot, X509** ppCert)
+{
+ int err = ERR_OK, l1, l2;
+ LIBHANDLE pLibrary = 0;
+ CK_RV rv = 0;
+ CK_SLOT_ID slotids[20], slId;
+ CK_OBJECT_HANDLE hCert;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_ULONG certLen;
+ CK_BYTE certData[2048];
+ char driver[100];
+
+
+ *ppCert = 0;
+ snprintf(driver, sizeof(driver), "DIGIDOC_DRIVER_%d_FILE", ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ ddocDebug(3, "findUsersCertificate", "Slot: %d Driver nr: %d - %s", slot,
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1),
+ ConfigItem_lookup(driver));
+ err = loadAndTestDriver(ConfigItem_lookup(driver),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ if(err) return err;
+ //debug
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "findUsersCertificate", "Slot1: %d, id %d", l1, slotids[l1]);
+ }
+ }
+ // find the right slotid
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "findUsersCertificate", "Slot2: %d, id %d", l1, slotids[l1]);
+ if(l2 == slot)
+ slId = slotids[l1];
+ l2++;
+ }
+ }
+ // open session
+ ddocDebug(3, "findUsersCertificate", "OpenSession slotid %d", slId);
+ hSession = OpenSession(slId, NULL);
+ if (hSession == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_LOGIN); return ERR_PKCS_LOGIN; }
+ ddocDebug(3, "findUsersCertificate", "OpenSession ok, hSession = %d", (int)hSession);
+
+ // get cert
+ memset(certData, 0, sizeof(certData));
+ certLen = sizeof(certData);
+ hCert = LocateCertificate(hSession, certData, &certLen, 0, 0, 0);
+ ddocDebug(3, "findUsersCertificate", "hCert = %d, len: %d", (int)hCert, certLen);
+ if (hCert == (CK_OBJECT_HANDLE)-1) { err = ERR_PKCS_CERT_LOC; SET_LAST_ERROR(err); }
+
+ // set cert data
+ if(certLen)
+ err = ddocDecodeX509Data(ppCert, certData, certLen);
+
+
+ ddocDebug(3, "findUsersCertificate", "RV: %d, cert: %s", (int)rv, (*ppCert ? "OK" : "NULL"));
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+
+ return err;
+}
+
+