#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mypkcs11.h"
#include "cackey-chrome.h"
struct cackey_chrome_id {
void *id;
size_t idLen;
int initialized;
};
static CK_FUNCTION_LIST_PTR moduleFunctionList = NULL;
static CK_RV cackey_chrome_init(void) {
CK_C_INITIALIZE_ARGS initargs;
CK_RV chk_rv;
if (moduleFunctionList != NULL) {
return(CKR_OK);
}
chk_rv = C_GetFunctionList(&moduleFunctionList);
if (chk_rv != CKR_OK) {
return(chk_rv);
}
initargs.CreateMutex = NULL;
initargs.DestroyMutex = NULL;
initargs.LockMutex = NULL;
initargs.UnlockMutex = NULL;
initargs.flags = CKF_OS_LOCKING_OK;
initargs.pReserved = NULL;
chk_rv = moduleFunctionList->C_Initialize(&initargs);
if (chk_rv != CKR_OK) {
return(chk_rv);
}
return(CKR_OK);
}
void cackey_chrome_terminate(void) {
if (!moduleFunctionList) {
return;
}
moduleFunctionList->C_Finalize(NULL);
free(moduleFunctionList);
moduleFunctionList = NULL;
return;
}
static CK_RV cackey_chrome_GetAttributesFromTemplate(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE *attrTemplate, CK_ULONG attrTemplateCount) {
CK_RV chk_rv;
CK_ATTRIBUTE *currAttr;
CK_ULONG currAttrIndex;
for (currAttrIndex = 0; currAttrIndex < attrTemplateCount; currAttrIndex++) {
currAttr = &attrTemplate[currAttrIndex];
currAttr->pValue = NULL;
currAttr->ulValueLen = 0;
}
chk_rv = moduleFunctionList->C_GetAttributeValue(hSession, hObject, attrTemplate, attrTemplateCount);
if (chk_rv == CKR_ATTRIBUTE_TYPE_INVALID || chk_rv == CKR_ATTRIBUTE_SENSITIVE || chk_rv == CKR_BUFFER_TOO_SMALL) {
chk_rv = CKR_OK;
}
if (chk_rv != CKR_OK) {
return(chk_rv);
}
for (currAttrIndex = 0; currAttrIndex < attrTemplateCount; currAttrIndex++) {
currAttr = &attrTemplate[currAttrIndex];
if (currAttr->ulValueLen == 0) {
continue;
}
if (((CK_LONG) currAttr->ulValueLen) == ((CK_LONG) -1)) {
continue;
}
currAttr->pValue = malloc(currAttr->ulValueLen);
}
chk_rv = moduleFunctionList->C_GetAttributeValue(hSession, hObject, attrTemplate, attrTemplateCount);
if (chk_rv != CKR_OK) {
free(currAttr->pValue);
return(chk_rv);
}
return(CKR_OK);
}
int cackey_chrome_listCertificates(struct cackey_certificate **certificates) {
CK_RV chk_rv;
CK_ULONG numSlots, currSlot;
CK_SLOT_ID_PTR slots;
CK_SLOT_INFO slotInfo;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hObject;
CK_ULONG ulObjectCount;
CK_ATTRIBUTE searchTemplatePrivateKeys[] = {
{CKA_CLASS, NULL, sizeof(CK_OBJECT_CLASS)}
};
CK_ATTRIBUTE searchTemplateCertificates[] = {
{CKA_CLASS, NULL, sizeof(CK_OBJECT_CLASS)},
{CKA_ID, NULL, 0}
};
CK_ATTRIBUTE attrTemplatePrivateKey[] = {
{CKA_ID, NULL, 0}
};
CK_ATTRIBUTE attrTemplateCertificate[] = {
{CKA_VALUE, NULL, 0}
};
CK_OBJECT_CLASS objectClassPrivateKey = CKO_PRIVATE_KEY;
CK_OBJECT_CLASS objectClassCertificate = CKO_CERTIFICATE;
struct cackey_chrome_id *ids;
int idsCount, currId;
int foundCertificates, certificatesCount;
*certificates = NULL;
chk_rv = cackey_chrome_init();
if (chk_rv != CKR_OK) {
return(0);
}
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, NULL, &numSlots);
if (chk_rv != CKR_OK) {
return(0);
}
slots = malloc(sizeof(*slots) * numSlots);
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, slots, &numSlots);
if (chk_rv != CKR_OK) {
free(slots);
return(0);
}
searchTemplatePrivateKeys[0].pValue = &objectClassPrivateKey;
searchTemplateCertificates[0].pValue = &objectClassCertificate;
foundCertificates = 0;
certificatesCount = 10;
*certificates = malloc(sizeof(**certificates) * certificatesCount);
idsCount = 10;
ids = malloc(sizeof(*ids) * idsCount);
for (currId = 0; currId < idsCount; currId++) {
ids[currId].initialized = 0;
}
for (currSlot = 0; currSlot < numSlots; currSlot++) {
chk_rv = moduleFunctionList->C_GetSlotInfo(slots[currSlot], &slotInfo);
if (chk_rv != CKR_OK) {
continue;
}
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != CKF_TOKEN_PRESENT) {
continue;
}
chk_rv = moduleFunctionList->C_OpenSession(slots[currSlot], CKF_SERIAL_SESSION, NULL, NULL, &hSession);
if (chk_rv != CKR_OK) {
continue;
}
chk_rv = moduleFunctionList->C_FindObjectsInit(hSession, searchTemplatePrivateKeys, sizeof(searchTemplatePrivateKeys) / sizeof(searchTemplatePrivateKeys[0]));
if (chk_rv != CKR_OK) {
moduleFunctionList->C_CloseSession(hSession);
continue;
}
for (currId = 0; currId < idsCount; currId++) {
if (!ids[currId].initialized) {
continue;
}
free(ids[currId].id);
ids[currId].initialized = 0;
}
currId = 0;
while (1) {
chk_rv = moduleFunctionList->C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
if (chk_rv != CKR_OK) {
break;
}
if (ulObjectCount == 0) {
break;
}
if (ulObjectCount != 1) {
break;
}
chk_rv = cackey_chrome_GetAttributesFromTemplate(hSession, hObject, attrTemplatePrivateKey, sizeof(attrTemplatePrivateKey) / sizeof(attrTemplatePrivateKey[0]));
if (chk_rv != CKR_OK) {
continue;
}
if (currId >= idsCount) {
idsCount *= 2;
ids = realloc(ids, sizeof(*ids) * idsCount);
}
ids[currId].idLen = attrTemplatePrivateKey[0].ulValueLen;
ids[currId].id = attrTemplatePrivateKey[0].pValue;
ids[currId].initialized = 1;
currId++;
}
moduleFunctionList->C_FindObjectsFinal(hSession);
for (currId = 0; currId < idsCount; currId++) {
if (!ids[currId].initialized) {
continue;
}
searchTemplateCertificates[1].pValue = ids[currId].id;
searchTemplateCertificates[1].ulValueLen = ids[currId].idLen;
chk_rv = moduleFunctionList->C_FindObjectsInit(hSession, searchTemplateCertificates, sizeof(searchTemplateCertificates) / sizeof(searchTemplateCertificates[0]));
if (chk_rv != CKR_OK) {
free(ids[currId].id);
ids[currId].initialized = 0;
continue;
}
while (1) {
chk_rv = moduleFunctionList->C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
if (chk_rv != CKR_OK) {
break;
}
if (ulObjectCount == 0) {
break;
}
if (ulObjectCount != 1) {
break;
}
chk_rv = cackey_chrome_GetAttributesFromTemplate(hSession, hObject, attrTemplateCertificate, sizeof(attrTemplateCertificate) / sizeof(attrTemplateCertificate[0]));
if (chk_rv != CKR_OK) {
continue;
}
if (foundCertificates >= certificatesCount) {
certificatesCount *= 2;
*certificates = realloc(*certificates, sizeof(**certificates) * certificatesCount);
}
(*certificates)[foundCertificates].certificate = malloc(attrTemplateCertificate[0].ulValueLen);
memcpy((*certificates)[foundCertificates].certificate, attrTemplateCertificate[0].pValue, attrTemplateCertificate[0].ulValueLen);
(*certificates)[foundCertificates].certificate_len = attrTemplateCertificate[0].ulValueLen;
free(attrTemplateCertificate[0].pValue);
foundCertificates++;
}
moduleFunctionList->C_FindObjectsFinal(hSession);
free(ids[currId].id);
ids[currId].initialized = 0;
}
moduleFunctionList->C_CloseSession(hSession);
}
for (currId = 0; currId < idsCount; currId++) {
if (!ids[currId].initialized) {
continue;
}
free(ids[currId].id);
ids[currId].initialized = 0;
}
free(ids);
free(slots);
return(foundCertificates);
}
void cackey_chrome_freeCertificates(struct cackey_certificate *certificates, int certificatesCount) {
int idx;
if (certificates == NULL) {
return;
}
for (idx = 0; idx < certificatesCount; idx++) {
if (certificates[idx].certificate) {
free(certificates[idx].certificate);
}
}
free(certificates);
return;
}
int cackey_chrome_listReaders(struct cackey_reader **readers) {
CK_RV chk_rv;
CK_ULONG numSlots, currSlot;
CK_SLOT_ID_PTR slots;
CK_SLOT_INFO slotInfo;
chk_rv = cackey_chrome_init();
if (chk_rv != CKR_OK) {
return(0);
}
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, NULL, &numSlots);
if (chk_rv != CKR_OK) {
return(0);
}
slots = malloc(sizeof(*slots) * numSlots);
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, slots, &numSlots);
if (chk_rv != CKR_OK) {
free(slots);
return(0);
}
*readers = malloc(sizeof(**readers) * numSlots);
for (currSlot = 0; currSlot < numSlots; currSlot++) {
chk_rv = moduleFunctionList->C_GetSlotInfo(slots[currSlot], &slotInfo);
if (chk_rv != CKR_OK) {
continue;
}
(*readers)[currSlot].reader = malloc(sizeof(slotInfo.slotDescription) + 1);
memcpy((*readers)[currSlot].reader, slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
(*readers)[currSlot].reader[sizeof(slotInfo.slotDescription)] = '\0';
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != CKF_TOKEN_PRESENT) {
(*readers)[currSlot].cardInserted = false;
} else {
(*readers)[currSlot].cardInserted = true;
}
}
free(slots);
return(numSlots);
}
void cackey_chrome_freeReaders(struct cackey_reader *readers, int readersCount) {
int idx;
if (readers == NULL) {
return;
}
for (idx = 0; idx < readersCount; idx++) {
if (readers[idx].reader) {
free(readers[idx].reader);
}
}
free(readers);
return;
}
cackey_chrome_returnType cackey_chrome_signMessage(struct cackey_certificate *certificate, void *data, unsigned long dataLength, void *destination, unsigned long *destinationLength, char **pinPrompt, const char *pin) {
CK_RV chk_rv;
CK_ULONG numSlots, currSlot;
CK_SLOT_ID_PTR slots;
CK_SLOT_INFO slotInfo;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hObject, hKey;
CK_ULONG ulObjectCount;
CK_ATTRIBUTE searchTemplateCertificates[] = {
{CKA_CLASS, NULL, sizeof(CK_OBJECT_CLASS)},
{CKA_VALUE, NULL, 0}
};
CK_ATTRIBUTE searchTemplatePrivateKeys[] = {
{CKA_CLASS, NULL, sizeof(CK_OBJECT_CLASS)},
{CKA_ID, NULL, 0}
};
CK_ATTRIBUTE attrTemplateCertificate[] = {
{CKA_ID, NULL, 0},
{CKA_LABEL, NULL, 0}
};
CK_MECHANISM signMechanism = {CKM_RSA_PKCS, NULL, 0};
CK_OBJECT_CLASS objectClassPrivateKey = CKO_PRIVATE_KEY;
CK_OBJECT_CLASS objectClassCertificate = CKO_CERTIFICATE;
CK_TOKEN_INFO tokenInfo;
CK_ULONG tmpDestinationLength;
char *certificateLabel;
int foundPrivateKeyObject;
cackey_chrome_returnType retval;
*pinPrompt = NULL;
retval = CACKEY_CHROME_ERROR;
chk_rv = cackey_chrome_init();
if (chk_rv != CKR_OK) {
return(retval);
}
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, NULL, &numSlots);
if (chk_rv != CKR_OK) {
return(retval);
}
slots = malloc(sizeof(*slots) * numSlots);
chk_rv = moduleFunctionList->C_GetSlotList(FALSE, slots, &numSlots);
if (chk_rv != CKR_OK) {
free(slots);
return(retval);
}
searchTemplateCertificates[0].pValue = &objectClassCertificate;
searchTemplatePrivateKeys[0].pValue = &objectClassPrivateKey;
searchTemplateCertificates[1].pValue = certificate->certificate;
searchTemplateCertificates[1].ulValueLen = certificate->certificate_len;
foundPrivateKeyObject = 0;
certificateLabel = NULL;
for (currSlot = 0; currSlot < numSlots; currSlot++) {
chk_rv = moduleFunctionList->C_GetSlotInfo(slots[currSlot], &slotInfo);
if (chk_rv != CKR_OK) {
continue;
}
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != CKF_TOKEN_PRESENT) {
continue;
}
chk_rv = moduleFunctionList->C_OpenSession(slots[currSlot], CKF_SERIAL_SESSION, NULL, NULL, &hSession);
if (chk_rv != CKR_OK) {
continue;
}
chk_rv = moduleFunctionList->C_FindObjectsInit(hSession, searchTemplateCertificates, sizeof(searchTemplateCertificates) / sizeof(searchTemplateCertificates[0]));
if (chk_rv != CKR_OK) {
moduleFunctionList->C_CloseSession(hSession);
continue;
}
while (1) {
chk_rv = moduleFunctionList->C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
if (chk_rv != CKR_OK) {
break;
}
if (ulObjectCount == 0) {
break;
}
if (ulObjectCount != 1) {
break;
}
chk_rv = cackey_chrome_GetAttributesFromTemplate(hSession, hObject, attrTemplateCertificate, sizeof(attrTemplateCertificate) / sizeof(attrTemplateCertificate[0]));
if (chk_rv != CKR_OK) {
continue;
}
searchTemplatePrivateKeys[1].pValue = attrTemplateCertificate[0].pValue;
searchTemplatePrivateKeys[1].ulValueLen = attrTemplateCertificate[0].ulValueLen;
if (attrTemplateCertificate[1].ulValueLen > 0 && attrTemplateCertificate[1].pValue != NULL) {
certificateLabel = malloc(attrTemplateCertificate[1].ulValueLen + 1);
memcpy(certificateLabel, attrTemplateCertificate[1].pValue, attrTemplateCertificate[1].ulValueLen);
certificateLabel[attrTemplateCertificate[1].ulValueLen] = '\0';
}
break;
}
moduleFunctionList->C_FindObjectsFinal(hSession);
if (searchTemplatePrivateKeys[1].pValue != NULL) {
chk_rv = moduleFunctionList->C_FindObjectsInit(hSession, searchTemplateCertificates, sizeof(searchTemplateCertificates) / sizeof(searchTemplateCertificates[0]));
if (chk_rv == CKR_OK) {
while (1) {
chk_rv = moduleFunctionList->C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
if (chk_rv != CKR_OK) {
break;
}
if (ulObjectCount == 0) {
break;
}
if (ulObjectCount != 1) {
break;
}
hKey = hObject;
foundPrivateKeyObject = 1;
break;
}
moduleFunctionList->C_FindObjectsFinal(hSession);
}
free(searchTemplatePrivateKeys[1].pValue);
}
if (foundPrivateKeyObject) {
chk_rv = moduleFunctionList->C_SignInit(hSession, &signMechanism, hKey);
if (chk_rv != CKR_OK) {
break;
}
tmpDestinationLength = *destinationLength;
chk_rv = moduleFunctionList->C_Sign(hSession, data, dataLength, destination, &tmpDestinationLength);
switch (chk_rv) {
case CKR_OK:
*destinationLength = tmpDestinationLength;
retval = CACKEY_CHROME_OK;
break;
case CKR_USER_NOT_LOGGED_IN:
chk_rv = moduleFunctionList->C_GetTokenInfo(slots[currSlot], &tokenInfo);
if (chk_rv == CKR_OK) {
if ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == CKF_PROTECTED_AUTHENTICATION_PATH) {
retval = CACKEY_CHROME_NEEDPROTECTEDLOGIN;
} else {
retval = CACKEY_CHROME_NEEDLOGIN;
*pinPrompt = malloc(1024);
if (certificateLabel) {
snprintf(*pinPrompt, 1024, "Please enter the PIN for %s:%s", tokenInfo.label, certificateLabel);
} else {
snprintf(*pinPrompt, 1024, "Please enter the PIN for %s", tokenInfo.label);
}
}
} else {
retval = CACKEY_CHROME_NEEDLOGIN;
*pinPrompt = strdup("Please enter your Smartcard PIN");
}
if (retval == CACKEY_CHROME_NEEDPROTECTEDLOGIN) {
retval = CACKEY_CHROME_ERROR;
chk_rv = moduleFunctionList->C_Login(hSession, CKU_USER, NULL, 0);
} else {
if (pin) {
retval = CACKEY_CHROME_ERROR;
free(*pinPrompt);
*pinPrompt = NULL;
chk_rv = moduleFunctionList->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR) pin, strlen(pin));
} else {
chk_rv = CKR_GENERAL_ERROR;
}
}
if (chk_rv == CKR_OK && retval == CACKEY_CHROME_ERROR) {
chk_rv = moduleFunctionList->C_SignInit(hSession, &signMechanism, hKey);
if (chk_rv != CKR_OK) {
break;
}
tmpDestinationLength = *destinationLength;
chk_rv = moduleFunctionList->C_Sign(hSession, data, dataLength, destination, &tmpDestinationLength);
switch (chk_rv) {
case CKR_OK:
*destinationLength = tmpDestinationLength;
retval = CACKEY_CHROME_OK;
break;
case CKR_USER_NOT_LOGGED_IN:
retval = CACKEY_CHROME_NEEDLOGIN;
break;
default:
retval = CACKEY_CHROME_ERROR;
break;
}
}
break;
default:
retval = CACKEY_CHROME_ERROR;
break;
}
break;
}
moduleFunctionList->C_CloseSession(hSession);
}
free(slots);
if (certificateLabel) {
free(certificateLabel);
}
return(retval);
}
#ifdef __cplusplus
}
#endif