コード例 #1
0
ファイル: esteid_sign.c プロジェクト: Krabi/idkaart_public
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;
}
コード例 #2
0
ファイル: dialogs-gtk.c プロジェクト: Krabi/idkaart_public
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);
}
コード例 #3
0
ファイル: esteid_sign.c プロジェクト: Krabi/idkaart_public
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;
}
コード例 #4
0
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;
}
コード例 #5
0
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;
}
コード例 #6
0
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;
}
コード例 #7
0
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);
}
コード例 #8
0
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;
}
コード例 #9
0
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);

}
コード例 #10
0
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;
}
コード例 #11
0
ファイル: esteid_sign.c プロジェクト: Krabi/idkaart_public
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);
}
コード例 #12
0
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++;
	}
}
コード例 #13
0
ファイル: esteid_sign.c プロジェクト: Krabi/idkaart_public
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;
}
コード例 #14
0
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;
	}
}