char* EstEID_getFullNameWithPersonalCode(EstEID_Map cert) { const char *surname; const char *personalID; const char *givenName; char *name; int nameSize = 0; givenName = EstEID_mapGet(cert, "givenName"); if (!givenName) givenName = ""; surname = EstEID_mapGet(cert, "surname"); if (!surname) surname = ""; personalID = EstEID_mapGet(cert, "serialNumber"); if (!personalID) personalID = ""; nameSize = strlen(givenName) + strlen(surname) + strlen(personalID) + 4; name = (char *)malloc(nameSize); sprintf(name,"%s %s", givenName, surname); if(strlen(personalID)) { strcat(name, ", "); strcat(name, personalID); } return name; }
static GtkTreeModel* createAndFillModel() { GtkListStore *certificatesList = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); GtkTreeIter iterator; char *validTo = NULL; EstEID_Certs *certs = EstEID_loadCerts(); EstEID_log("%i certificates found", certs->count); for(int i = 0; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if (!EstEID_mapGet(cert, "usageNonRepudiation")) continue; validTo = getDateFromDateTime(EstEID_mapGet(cert, "validTo")); gtk_list_store_append(certificatesList, &iterator); gtk_list_store_set(certificatesList, &iterator, 0, EstEID_mapGet(cert, "commonName"), 1, EstEID_mapGet(cert, "organizationName"), 2, validTo, 3, EstEID_mapGet(cert, "certHash"), -1); if(validTo) { free(validTo); validTo = NULL; } } return GTK_TREE_MODEL(certificatesList); }
int EstEID_findNonRepuditionCert(EstEID_Certs *certs, const char *certId) { for (unsigned int i = 0; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if (EstEID_mapGet(cert, "usageNonRepudiation") && !strcmp(certId, EstEID_mapGet(cert, "certHash"))) { return i; } } return NOT_FOUND; }
EstEID_Map EstEID_getNonRepudiationCertById(char* certID) { if (!EstEID_loadCerts()) return NULL; for (unsigned int i = 0; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if(EstEID_mapGet(cert, "certHash") && !strcmp(certID, EstEID_mapGet(cert, "certHash"))) { return cert; } } sprintf(EstEID_error, "non-repudiation certificate not found"); EstEID_errorCode = ESTEID_CERT_NOT_FOUND_ERROR; return NULL; }
bool doGetCertificates(PluginInstance *obj, NPVariant *result) { LOG_LOCATION; EstEID_log("obj=%p, name=doGetCertificates", obj); NPObject *windowObject = NULL; browserFunctions->getvalue(obj->npp, NPNVWindowNPObject, &windowObject); NPVariant array; browserFunctions->invoke(obj->npp, windowObject, browserFunctions->getstringidentifier("Array"), NULL, 0, &array); EstEID_Certs *certs = EstEID_loadCerts(); for (unsigned i = 0u; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if (!EstEID_mapGet(cert, "usageNonRepudiation")) continue; CertInstance *certInstance = (CertInstance *)browserFunctions->createobject(obj->npp, certClass()); certInstance->npp = obj->npp; certInstance->certInfo = EstEID_mapClone(cert); browserFunctions->retainobject((NPObject *)certInstance); EstEID_log("certObject=%p", certInstance); NPVariant *arg = (NPVariant *)browserFunctions->memalloc(sizeof(NPVariant)); OBJECT_TO_NPVARIANT((NPObject *)certInstance, *arg); NPVariant ret; browserFunctions->invoke(obj->npp, array.value.objectValue, browserFunctions->getstringidentifier("push"), arg, 1, &ret); } browserFunctions->retainobject(array.value.objectValue); OBJECT_TO_NPVARIANT(array.value.objectValue, *result); return true; }
bool certGetProperty(CertInstance *obj, NPIdentifier name, NPVariant *variant) { NPUTF8* nameString = browserFunctions->utf8fromidentifier(name); EstEID_log("name=%s", (char *)nameString); const char *result = EstEID_mapGet(obj->certInfo, EstEID_getCertPropertyName(nameString)); browserFunctions->memfree(nameString); if (result) return copyStringToNPVariant(result, variant); return false; }
const char *EstEID_mapGet(EstEID_Map map, const char *key) { if (!map) { return NULL; } if (!strcmp(map->key, key)) { return map->value; } return EstEID_mapGet(map->next, key); }
EstEID_Map EstEID_getNonRepudiationCert() { if (!EstEID_loadCerts()) return NULL; for (unsigned int i = 0; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if (EstEID_mapGet(cert, "usageNonRepudiation")) return cert; } sprintf(EstEID_error, "non-repudiation certificate not found"); EstEID_errorCode = ESTEID_CERT_NOT_FOUND_ERROR; return NULL; }
int main(void) { EstEID_Map map = NULL; assertIntEquals(0, EstEID_mapSize(map)); map = EstEID_mapPut(map, "foo", "bar"); assertNotNull(map); assertIntEquals(1, EstEID_mapSize(map)); map = EstEID_mapPut(map, "foo", "FOO"); assertIntEquals(1, EstEID_mapSize(map)); char *k = strdup("key"); char *v = strdup("value"); map = EstEID_mapPut(map, k, v); free(k); free(v); assertIntEquals(2, EstEID_mapSize(map)); assertStringEquals("value", EstEID_mapGet(map, "key")); assertNull(EstEID_mapGet(map, "xyz")); EstEID_mapFree(map); EstEID_Map m = EstEID_mapPut(NULL, "a", "A"); EstEID_mapPut(m, "b", "B"); EstEID_mapPut(m, "c", "C"); printf("map:\n"); EstEID_mapPrint(stdout, m); EstEID_Map c = EstEID_mapClone(m); EstEID_mapFree(m); printf("clone:\n"); EstEID_mapPrint(stdout, c); EstEID_mapFree(c); }
BOOL CEstEidPin2Dlg::OnInitDialog() { LOG_LOCATION; CDialog::OnInitDialog(); WCHAR label[512]; int certIndex; EstEID_Certs *certs = EstEID_loadCerts(); if (!certs) { EstEID_log("no certs found"); } else if ((certIndex = EstEID_findNonRepuditionCert(certs, ATL::CW2A(this->certId))) == NOT_FOUND) { EstEID_log("card is changed"); } EstEID_Map cert = certs->certs[certIndex]; char* name = EstEID_getFullNameWithPersonalCode(cert); MultiByteToWideChar(CP_UTF8, 0, name, -1, label, sizeof(label) / sizeof(WCHAR)); this->SetWindowText(label); SetDlgItemText(IDC_NAME, label); this->pin2MinLen = (unsigned)atoi(EstEID_mapGet(cert, "minPinLen")); free(name); MultiByteToWideChar(CP_UTF8, 0, l10n("For signing enter PIN2:"), -1, label, sizeof(label) / sizeof(WCHAR)); SetDlgItemText(IDC_PIN2_LABEL, label); MultiByteToWideChar(CP_UTF8, 0, l10n("Sign"), -1, label, sizeof(label) / sizeof(WCHAR)); SetDlgItemText(IDOK, label); MultiByteToWideChar(CP_UTF8, 0, l10n("Cancel"), -1, label, sizeof(label) / sizeof(WCHAR)); SetDlgItemText(IDCANCEL, label); SetDlgItemText(IDC_ERROR, L""); EndDialogIfPIN2Blocked(SetUpPin2Dialog()); return TRUE; }
int EstEID_signHash(char **signature, unsigned int *signatureLength, CK_SLOT_ID slotID, EstEID_Map cert, const char *hash, unsigned int hashLength, EstEID_PINPromptData pinPromptData) { CK_SESSION_HANDLE session = 0L; LOG_LOCATION; if (EstEID_CK_failure("C_OpenSession", fl->C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session))) return FAILURE; char *name = EstEID_getFullNameWithPersonalCode(cert); for (int attempt = 0, blocked = FALSE;; attempt++) { char message[1024]; int remainingTries = EstEID_getRemainingTries(slotID); if (remainingTries == -1) CLOSE_SESSION_AND_RETURN(FAILURE); if (!remainingTries || blocked) { sprintf(EstEID_error, "C_Login error: %s (%li)", pkcs11_error_message(CKR_PIN_LOCKED), CKR_PIN_LOCKED); pinPromptData.alertFunction(pinPromptData.nativeWindowHandle, l10n("PIN2 blocked, can not sign!")); CLOSE_SESSION_AND_RETURN(FAILURE); } if (remainingTries < 3 || attempt) { sprintf(message, "%s%s %i", (attempt ? l10n("Incorrect PIN2! ") : ""), l10n("Tries left:"), remainingTries); } else { message[0] = 0; } int isPinPad = EstEID_isPinPad(slotID); CK_RV loginResult = CKR_FUNCTION_CANCELED; if(!isPinPad) { // Simple card reader char *pin = pinPromptData.promptFunction(pinPromptData.nativeWindowHandle, name, message, (unsigned)atoi(EstEID_mapGet(cert, "minPinLen")), isPinPad); if (!pin || strlen(pin) == 0) { if (pin) free(pin); setUserCancelErrorCodeAndMessage(); CLOSE_SESSION_AND_RETURN(FAILURE); } loginResult = fl->C_Login(session, CKU_USER, (unsigned char *)pin, strlen(pin)); free(pin); } else { // PIN pad #ifdef _WIN32 EstEID_log("creating pinpad dialog UI thread"); pinpad_thread_result = -1; FAIL_IF_THREAD_ERROR("CreateMutex", (pinpad_thread_mutex = CreateMutex(NULL, FALSE, NULL))); #else EstEID_log("creating pinpad worker thread"); pinpad_thread_result = -1; FAIL_IF_PTHREAD_ERROR("pthread_mutex_init", pthread_mutex_init(&pinpad_thread_mutex, NULL)); FAIL_IF_PTHREAD_ERROR("pthread_cond_init", pthread_cond_init(&pinpad_thread_condition, NULL)); pthread_t pinpad_thread; EstEID_PINPadThreadData threadData; threadData.session = session; threadData.result = CKR_OK; #endif EstEID_log("thread launched"); #ifdef _WIN32 /* NB! Due to Firefox for Windows specific behaviour C_Login() is launched from main thread and UI code is running in separate thread if running on Windows. */ EstEID_PINPromptDataEx pinPromptDataEx; pinPromptDataEx.pinPromptData = pinPromptData; pinPromptDataEx.message = message; pinPromptDataEx.name = name; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&EstEID_pinPadLogin, (LPVOID)&pinPromptDataEx, 0, NULL); loginResult = fl->C_Login(session, CKU_USER, NULL, 0); closePinPadModalSheet(); #else FAIL_IF_PTHREAD_ERROR("pthread_create", pthread_create(&pinpad_thread, NULL, EstEID_pinPadLogin, (void*)&threadData)); pinPromptData.promptFunction(pinPromptData.nativeWindowHandle, name, message, 0, isPinPad); loginResult = threadData.result; #endif EstEID_log("pinpad sheet/dialog closed"); if (loginResult == CKR_FUNCTION_CANCELED) { setUserCancelErrorCodeAndMessage(); CLOSE_SESSION_AND_RETURN(FAILURE); } } EstEID_log("loginResult = %s", pkcs11_error_message(loginResult)); switch (loginResult) { case CKR_PIN_LOCKED: blocked = TRUE; case CKR_PIN_INCORRECT: case CKR_PIN_INVALID: case CKR_PIN_LEN_RANGE: EstEID_log("this was attempt %i, loginResult causes to run next round", attempt); continue; default: if (EstEID_CK_failure("C_Login", loginResult)) CLOSE_SESSION_AND_RETURN(FAILURE); } break; // Login successful - correct PIN supplied } return EstEID_RealSign(session, signature, signatureLength, hash, hashLength, name); }
void buildCertificatesList(HWND hwnd) { RECT rect; HWND certificatesList; LV_COLUMN lvC; certificatesList = GetDlgItem(hwnd, IDC_CERTIFICATESLIST); ListView_SetUnicodeFormat(certificatesList, true); GetClientRect(certificatesList, &rect); int rectWidth = rect.right - rect.left; int colSize = rectWidth/6; int colWidths[] = {3 * colSize, 2 * colSize, colSize + (rectWidth - (6*colSize)), 0}; int colTitles[] = {IDS_CERTIFICATEHEADER, IDS_TYPEHEADER, IDS_VALIDUNTILHEADER, IDS_EMPTY}; ListView_SetExtendedListViewStyle(certificatesList, LVS_EX_FULLROWSELECT); lvC.mask = LVCF_WIDTH | LVCF_TEXT; lvC.fmt = LVCFMT_LEFT; TCHAR header[32]; for(int index = 0; index < 4; index++) { lvC.iSubItem = index; lvC.cx = colWidths[index]; LoadString(pluginInstance, colTitles[index], header, sizeof(header)/sizeof(TCHAR)); lvC.pszText = header;//colTitles[index]; ListView_InsertColumn(certificatesList, index, &lvC); } LV_ITEM lv; lv.mask = LVIF_TEXT; EstEID_Certs *certs = EstEID_loadCerts(); EstEID_log("reading certs @ %p, certs->count = %u ", certs, certs->count); TCHAR unicodeBuf[512]; int currentCertIndex = 0; for (int i = 0; i < certs->count; i++) { EstEID_Map cert = certs->certs[i]; if (!EstEID_mapGet(cert, "usageNonRepudiation")) { continue; } lv.iSubItem = 0; lv.iItem = currentCertIndex; MultiByteToWideChar(CP_UTF8, 0, EstEID_mapGet(cert, "commonName"), -1, unicodeBuf, sizeof(unicodeBuf) / sizeof(TCHAR)); lv.pszText = (LPWSTR)unicodeBuf; ListView_InsertItem(certificatesList, &lv); MultiByteToWideChar(CP_UTF8, 0, EstEID_mapGet(cert, "organizationName"), -1, unicodeBuf, sizeof(unicodeBuf) / sizeof(TCHAR)); ListView_SetItemText(certificatesList, currentCertIndex, 1, unicodeBuf); char* validTo = getDateFromDateTime(EstEID_mapGet(cert, "validTo")); MultiByteToWideChar(CP_UTF8, 0, validTo, -1, unicodeBuf, sizeof(unicodeBuf) / sizeof(TCHAR)); ListView_SetItemText(certificatesList, currentCertIndex, 2, unicodeBuf); free(validTo); MultiByteToWideChar(CP_UTF8, 0, EstEID_mapGet(cert, "certHash"), -1, unicodeBuf, sizeof(unicodeBuf) / sizeof(TCHAR)); ListView_SetItemText(certificatesList, currentCertIndex, 3, unicodeBuf); currentCertIndex++; } }
int EstEID_signHash(char **signature, unsigned int *signatureLength, CK_SLOT_ID slotID, EstEID_Map cert, const char *hash, unsigned int hashLength, EstEID_PINPromptData pinPromptData) { CK_SESSION_HANDLE session = 0L; if (EstEID_CK_failure("C_OpenSession", fl->C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session))) return FAILURE; const char *givenName = EstEID_mapGet(cert, "givenName"); if (!givenName) givenName = ""; const char *surname = EstEID_mapGet(cert, "surname"); if (!surname) surname = ""; const char *personalID = EstEID_mapGet(cert, "serialNumber"); if (!personalID) personalID = ""; char *name = (char *)malloc(strlen(givenName) + strlen(surname) + strlen(personalID) + 4); sprintf(name, "%s %s", givenName, surname); if(strlen(personalID)) { strcat(name, ", "); strcat(name, personalID); } for (int attempt = 0, blocked = FALSE;; attempt++) { char message[1024]; int remainingTries = EstEID_getRemainingTries(slotID); if (remainingTries == -1) CLOSE_SESSION_AND_FAIL; if (!remainingTries || blocked) { sprintf(EstEID_error, "C_Login error: %s (%li)", pkcs11_error_message(CKR_PIN_LOCKED), CKR_PIN_LOCKED); pinPromptData.alertFunction(pinPromptData.nativeWindowHandle, l10n("PIN2 blocked, cannot sign!")); CLOSE_SESSION_AND_FAIL; } if (remainingTries < 3 || attempt) { sprintf(message, "%s%s %i", (attempt ? l10n("Incorrect PIN2! ") : ""), l10n("Tries left:"), remainingTries); } else { message[0] = 0; } int isPinPad = EstEID_isPinPad(slotID); CK_RV loginResult = CKR_FUNCTION_CANCELED; if(!isPinPad) { // Simple card reader char *pin = pinPromptData.promptFunction(pinPromptData.nativeWindowHandle, name, message, (unsigned)atoi(EstEID_mapGet(cert, "minPinLen")), isPinPad); if (!pin || strlen(pin) == 0) { if (pin) free(pin); setUserCancelErrorCodeAndMessage(); CLOSE_SESSION_AND_FAIL; } loginResult = fl->C_Login(session, CKU_USER, (unsigned char *)pin, strlen(pin)); free(pin); } else { // PIN pad #ifdef _WIN32 EstEID_log("creating pinpad dialog UI thread"); pinpad_thread_result = -1; FAIL_IF_THREAD_ERROR("CreateMutex", (pinpad_thread_mutex = CreateMutex(NULL, FALSE, NULL))); #else EstEID_log("creating pinpad worker thread"); pinpad_thread_result = -1; FAIL_IF_PTHREAD_ERROR("pthread_mutex_init", pthread_mutex_init(&pinpad_thread_mutex, NULL)); FAIL_IF_PTHREAD_ERROR("pthread_cond_init", pthread_cond_init(&pinpad_thread_condition, NULL)); pthread_t pinpad_thread; EstEID_PINPadThreadData threadData; threadData.session = session; threadData.result = CKR_OK; #endif EstEID_log("thread launched"); #ifdef _WIN32 /* NB! Due to Firefox for Windows specific behaviour C_Login() is launched from main thread and UI code is running in separate thread if running on Windows. */ EstEID_PINPromptDataEx pinPromptDataEx; pinPromptDataEx.pinPromptData = pinPromptData; pinPromptDataEx.message = message; pinPromptDataEx.name = name; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&EstEID_pinPadLogin, (LPVOID)&pinPromptDataEx, 0, NULL); loginResult = fl->C_Login(session, CKU_USER, NULL, 0); closePinPadModalSheet(); #else FAIL_IF_PTHREAD_ERROR("pthread_create", pthread_create(&pinpad_thread, NULL, EstEID_pinPadLogin, (void*)&threadData)); pinPromptData.promptFunction(pinPromptData.nativeWindowHandle, name, message, 0, isPinPad); loginResult = threadData.result; #endif EstEID_log("pinpad sheet/dialog closed"); if (loginResult == CKR_FUNCTION_CANCELED) { setUserCancelErrorCodeAndMessage(); CLOSE_SESSION_AND_FAIL; } } EstEID_log("loginResult = %s", pkcs11_error_message(loginResult)); switch (loginResult) { case CKR_PIN_LOCKED: blocked = TRUE; case CKR_PIN_INCORRECT: case CKR_PIN_INVALID: case CKR_PIN_LEN_RANGE: EstEID_log("this was attempt %i, loginResult causes to run next round", attempt); continue; default: if (EstEID_CK_failure("C_Login", loginResult)) CLOSE_SESSION_AND_FAIL; } break; // Login successful - correct PIN supplied } if (name){ free(name); name = NULL; } CK_OBJECT_CLASS objectClass = CKO_PRIVATE_KEY; CK_ATTRIBUTE searchAttribute = {CKA_CLASS, &objectClass, sizeof(objectClass)}; if (EstEID_CK_failure("C_FindObjectsInit", fl->C_FindObjectsInit(session, &searchAttribute, 1))) CLOSE_SESSION_AND_FAIL; CK_OBJECT_HANDLE privateKeyHandle; CK_ULONG objectCount; if (EstEID_CK_failure("C_FindObjects", fl->C_FindObjects(session, &privateKeyHandle, 1, &objectCount))) CLOSE_SESSION_AND_FAIL; if (EstEID_CK_failure("C_FindObjectsFinal", fl->C_FindObjectsFinal(session))) CLOSE_SESSION_AND_FAIL; if (objectCount == 0) CLOSE_SESSION_AND_FAIL; // todo ?? set error message CK_MECHANISM mechanism = {CKM_RSA_PKCS, 0, 0}; if (EstEID_CK_failure("C_SignInit", fl->C_SignInit(session, &mechanism, privateKeyHandle))) CLOSE_SESSION_AND_FAIL; unsigned int hashWithPaddingLength; char *hashWithPadding = EstEID_addPadding(hash, hashLength, &hashWithPaddingLength); CK_ULONG len; if (EstEID_CK_failure("C_Sign", fl->C_Sign(session, (CK_BYTE_PTR)hashWithPadding, hashWithPaddingLength, NULL, &len))) { free(hashWithPadding); CLOSE_SESSION_AND_FAIL; } *signature = (char *)malloc(len); if (EstEID_CK_failure("C_Sign", fl->C_Sign(session, (CK_BYTE_PTR)hashWithPadding, hashWithPaddingLength, (CK_BYTE_PTR) * signature, &len))) { free(hashWithPadding); CLOSE_SESSION_AND_FAIL; } *signatureLength = len; free(hashWithPadding); if (session) { if (EstEID_CK_failure("C_CloseSession", fl->C_CloseSession(session))) { return FAILURE; } } EstEID_log("successfully signed"); return SUCCESS; }
bool doSign(PluginInstance *obj, NPVariant *args, unsigned argCount, NPVariant *result) { EstEID_log("obj=%p, name=sign argCount=%u", obj, argCount); FAIL_IF_NOT_ALLOWED_SITE; if (argCount < 2) { browserFunctions->setexception(&obj->header, "Missing arguments"); return false; } if(argCount > 2 && NPVARIANT_IS_OBJECT(args[2])){ strncpy(pluginLanguage, getLanguageFromOptions(obj, args[2]), 2); } EstEID_setLocale(pluginLanguage); void* wnd = getNativeWindowHandle(obj); EstEID_PINPromptData pinPromptData = {promptForPIN, showAlert, wnd, NULL, NULL}; NPUTF8* certId = createStringFromNPVariant(&args[0]); NPUTF8* hash = createStringFromNPVariant(&args[1]); char *signature = NULL; #ifdef _WIN32 DialogData dialogData; dialogData.pin2[0] = '\0'; dialogData.minPin2Length = 5; dialogData.certId = certId; dialogData.hash = hash; dialogData.signature[0] = '\0'; CK_SLOT_ID slotId; if(EstEID_getSlotId(certId, &slotId)){ if(EstEID_isPinPad(slotId)) { signature = EstEID_sign(certId, hash, pinPromptData); } else { dialogData.pinName = EstEID_mapGet(EstEID_getNonRepudiationCertById(certId), "pinName"); DialogBoxParam(pluginInstance, MAKEINTRESOURCEW(IDD_PIN_DIALOG), (HWND)wnd, Pin2DialogProc, (LPARAM)&dialogData); LOG_LOCATION; EstEID_log("Signature lenght: %i" , strlen(dialogData.signature)); if (strlen(dialogData.signature) != 0) { signature = (char*)malloc(SIGNATURE_BUFFER_SIZE); // check? strcpy(signature, dialogData.signature); } else { sprintf(EstEID_error, "User canceled"); EstEID_errorCode = ESTEID_USER_CANCEL; EstEID_log("EstEID_error = %s", EstEID_error); } } } else { return false; } #else signature = EstEID_sign(certId, hash, pinPromptData); #endif LOG_LOCATION if (signature) { //EstEID_log("Signature %s", signature); copyStringToNPVariant(signature, result); free(signature); return true; }else { browserFunctions->setexception(&obj->header, EstEID_error); return false; } }