1 | /* |
---|
2 | * Estonian ID card plugin for web browsers |
---|
3 | * |
---|
4 | * Copyright (C) 2010-2011 Codeborne <info@codeborne.com> |
---|
5 | * |
---|
6 | * This is free software; you can redistribute it and/or |
---|
7 | * modify it under the terms of the GNU Lesser General Public |
---|
8 | * License as published by the Free Software Foundation; either |
---|
9 | * version 2.1 of the License, or (at your option) any later version. |
---|
10 | * |
---|
11 | * This software is distributed in the hope that it will be useful, |
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | * Lesser General Public License for more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU Lesser General Public |
---|
17 | * License along with this library; if not, write to the Free Software |
---|
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
---|
19 | * |
---|
20 | */ |
---|
21 | |
---|
22 | #include <stdlib.h> |
---|
23 | #include <stdio.h> |
---|
24 | #include <string.h> |
---|
25 | |
---|
26 | #ifndef _WIN32 |
---|
27 | #include <unistd.h> |
---|
28 | #include <pthread.h> |
---|
29 | #endif |
---|
30 | |
---|
31 | #include <openssl/x509.h> |
---|
32 | #include <openssl/pem.h> |
---|
33 | #include <openssl/md5.h> |
---|
34 | |
---|
35 | #include "esteid_certinfo.h" |
---|
36 | #include "esteid_log.h" |
---|
37 | #include "esteid_timer.h" |
---|
38 | #include "pkcs11_errors.h" |
---|
39 | #include "esteid_map.h" |
---|
40 | #include "esteid_error.h" |
---|
41 | |
---|
42 | #ifdef _WIN32 |
---|
43 | #include <windows.h> |
---|
44 | #define LOAD_LIBRARY HMODULE handle = LoadLibrary(L"opensc-pkcs11.dll") |
---|
45 | #define GET_FUNCTION_PTR GetProcAddress |
---|
46 | char error_buffer[32]; |
---|
47 | |
---|
48 | char *library_error() { |
---|
49 | sprintf(error_buffer, "code %lu", GetLastError()); |
---|
50 | return error_buffer; |
---|
51 | } |
---|
52 | #else |
---|
53 | #include <dlfcn.h> |
---|
54 | #ifdef __APPLE__ |
---|
55 | #define LOAD_LIBRARY void *handle = dlopen("/Library/EstonianIDCard/lib/esteid-pkcs11.so", RTLD_NOW) |
---|
56 | #else |
---|
57 | #define LOAD_LIBRARY void *handle = dlopen("opensc-pkcs11.so", RTLD_NOW) |
---|
58 | #endif |
---|
59 | #define GET_FUNCTION_PTR dlsym |
---|
60 | char *library_error() { |
---|
61 | return dlerror(); |
---|
62 | } |
---|
63 | #endif |
---|
64 | |
---|
65 | // on Windows it is important that openssl is included _after_ windows.h |
---|
66 | #include <openssl/x509.h> |
---|
67 | #include <openssl/pem.h> |
---|
68 | |
---|
69 | #define FAILURE 0 |
---|
70 | #define SUCCESS 1 |
---|
71 | |
---|
72 | #define FAIL_IF(failure) if (failure) { EstEID_freeCerts(); return FAILURE; } |
---|
73 | #define FAIL_UNLESS(success) if (!success) { EstEID_freeCerts(); return FAILURE; } |
---|
74 | |
---|
75 | CK_FUNCTION_LIST_PTR fl = NULL; |
---|
76 | |
---|
77 | static EstEID_Certs *certs = NULL; |
---|
78 | |
---|
79 | char EstEID_error[ESTEID_ERROR_SIZE]; |
---|
80 | int EstEID_errorCode; |
---|
81 | |
---|
82 | void EstEID_clear_error(void) { |
---|
83 | EstEID_error[0] = 0; |
---|
84 | EstEID_errorCode = ESTEID_NO_ERROR; |
---|
85 | } |
---|
86 | |
---|
87 | int EstEID_CK_failure(const char *name, CK_RV result) { |
---|
88 | EstEID_clear_error(); |
---|
89 | if (result == CKR_OK || result == CKR_CRYPTOKI_ALREADY_INITIALIZED) return FAILURE; |
---|
90 | sprintf(EstEID_error, "%s error: %s (%li)", name, pkcs11_error_message(result), result); |
---|
91 | EstEID_errorCode = ESTEID_PKCS11_ERROR; |
---|
92 | EstEID_log("cryptoki error: %s", EstEID_error); |
---|
93 | return SUCCESS; |
---|
94 | } |
---|
95 | |
---|
96 | int EstEID_dl_failure(const char *name, void *ptr) { |
---|
97 | EstEID_clear_error(); |
---|
98 | if (ptr) return FALSE; |
---|
99 | snprintf(EstEID_error, sizeof(EstEID_error) - 1, "%s failed: %s", name, library_error()); |
---|
100 | EstEID_errorCode = ESTEID_LIBRARY_LOAD_ERROR; |
---|
101 | EstEID_error[sizeof(EstEID_error) - 1] = 0; |
---|
102 | EstEID_log("dl error: %s", EstEID_error); |
---|
103 | return TRUE; |
---|
104 | } |
---|
105 | |
---|
106 | int EstEID_md5_failure(void *ptr) { |
---|
107 | EstEID_clear_error(); |
---|
108 | if (ptr) return FALSE; |
---|
109 | snprintf(EstEID_error, sizeof(EstEID_error) - 1, "Cert id creation failed"); |
---|
110 | EstEID_errorCode = ESTEID_MD5_ERROR; |
---|
111 | EstEID_error[sizeof(EstEID_error) - 1] = 0; |
---|
112 | EstEID_log("%s", EstEID_error); |
---|
113 | return TRUE; |
---|
114 | } |
---|
115 | |
---|
116 | char *EstEID_createString(CK_UTF8CHAR *padded, int length) { |
---|
117 | int i = 0; |
---|
118 | char *result = (char *)malloc(sizeof(char)* (length + 1)); |
---|
119 | |
---|
120 | strncpy(result, (char *)padded, length); |
---|
121 | result[length] = ' '; |
---|
122 | for (i = length; i >= 0 && result[i] == ' '; i--) result[i] = 0; |
---|
123 | return result; |
---|
124 | } |
---|
125 | |
---|
126 | void EstEID_logInitInfo(CK_INFO info) { |
---|
127 | char *libraryDescription = EstEID_createString(info.libraryDescription, 32); |
---|
128 | char *manufacturerID = EstEID_createString(info.manufacturerID, 32); |
---|
129 | EstEID_log("cryptoki %i.%i, library %i.%i %s, %s", info.cryptokiVersion.major, info.cryptokiVersion.minor, info.libraryVersion.major, info.libraryVersion.minor, libraryDescription, manufacturerID); |
---|
130 | free(libraryDescription); |
---|
131 | free(manufacturerID); |
---|
132 | } |
---|
133 | |
---|
134 | #ifdef _WIN32 |
---|
135 | #define pthread_mutex_t HANDLE |
---|
136 | #define pthread_cond_t HANDLE |
---|
137 | #endif |
---|
138 | |
---|
139 | pthread_mutex_t initialization_mutex; |
---|
140 | pthread_cond_t initialization_condition; |
---|
141 | //pthread_t initialization_thread; |
---|
142 | int initialization_result; |
---|
143 | int initialization_completed = FALSE; |
---|
144 | |
---|
145 | THREAD_RETURN_TYPE EstEID_initializeCryptokiThread(void *v) { |
---|
146 | CK_C_INITIALIZE_ARGS init_args; |
---|
147 | struct timeval start; |
---|
148 | |
---|
149 | LOG_LOCATION; |
---|
150 | #ifdef _WIN32 |
---|
151 | WaitForSingleObject(initialization_mutex, INFINITE); |
---|
152 | #else |
---|
153 | pthread_mutex_lock(&initialization_mutex); |
---|
154 | #endif |
---|
155 | memset( &init_args, 0x0, sizeof(init_args) ); |
---|
156 | init_args.flags = CKF_OS_LOCKING_OK; |
---|
157 | |
---|
158 | start = EstEID_startTimer(); |
---|
159 | initialization_result = fl->C_Initialize(&init_args); |
---|
160 | EstEID_log("C_Initialize: %s (%li)", pkcs11_error_message(initialization_result), initialization_result); |
---|
161 | EstEID_stopTimerAndLog(start, "C_Initialize:"); |
---|
162 | |
---|
163 | if (initialization_result == CKR_CRYPTOKI_ALREADY_INITIALIZED) { |
---|
164 | EstEID_log("initialization_result == CKR_CRYPTOKI_ALREADY_INITIALIZED"); |
---|
165 | } |
---|
166 | |
---|
167 | if (initialization_result == CKR_OK) { |
---|
168 | CK_INFO info; |
---|
169 | EstEID_log("initialization_result == CKR_OK"); |
---|
170 | if (!EstEID_CK_failure("C_GetInfo", fl->C_GetInfo(&info))) { |
---|
171 | EstEID_logInitInfo(info); |
---|
172 | }; |
---|
173 | } |
---|
174 | initialization_completed = TRUE; |
---|
175 | #ifdef _WIN32 |
---|
176 | ReleaseMutex(initialization_mutex); |
---|
177 | return TRUE; |
---|
178 | #else |
---|
179 | pthread_cond_broadcast(&initialization_condition); |
---|
180 | pthread_mutex_unlock(&initialization_mutex); |
---|
181 | pthread_exit(NULL); |
---|
182 | #endif |
---|
183 | } |
---|
184 | |
---|
185 | #ifdef _WIN32 |
---|
186 | |
---|
187 | int EstEID_startInitializeCryptokiThread() { |
---|
188 | DWORD threadId; |
---|
189 | |
---|
190 | LOG_LOCATION; |
---|
191 | |
---|
192 | initialization_result = -1; |
---|
193 | FAIL_IF_THREAD_ERROR("CreateMutex", (initialization_mutex = CreateMutex(NULL, FALSE, NULL))); |
---|
194 | EstEID_log("initialization_mutex = %p", initialization_mutex); |
---|
195 | FAIL_IF_THREAD_ERROR("CreateThread", CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&EstEID_initializeCryptokiThread, NULL, 0, &threadId)); |
---|
196 | |
---|
197 | return SUCCESS; |
---|
198 | } |
---|
199 | |
---|
200 | #else |
---|
201 | |
---|
202 | int EstEID_startInitializeCryptokiThread() { |
---|
203 | initialization_result = -1; |
---|
204 | FAIL_IF_PTHREAD_ERROR("pthread_mutex_init", pthread_mutex_init(&initialization_mutex, NULL)); |
---|
205 | FAIL_IF_PTHREAD_ERROR("pthread_cond_init", pthread_cond_init(&initialization_condition, NULL)); |
---|
206 | pthread_t initialization_thread; |
---|
207 | FAIL_IF_PTHREAD_ERROR("pthread_create", pthread_create(&initialization_thread, NULL, EstEID_initializeCryptokiThread, NULL)); |
---|
208 | return SUCCESS; |
---|
209 | } |
---|
210 | |
---|
211 | #endif |
---|
212 | |
---|
213 | int EstEID_loadLibrary() { |
---|
214 | CK_C_GetFunctionList GetFunctionList; |
---|
215 | LOAD_LIBRARY; |
---|
216 | |
---|
217 | LOG_LOCATION; |
---|
218 | if (fl) return SUCCESS; |
---|
219 | |
---|
220 | if (EstEID_dl_failure("dlopen", handle)) return FAILURE; |
---|
221 | GetFunctionList = (CK_C_GetFunctionList)GET_FUNCTION_PTR(handle, "C_GetFunctionList"); |
---|
222 | if (EstEID_dl_failure("dlsym", GetFunctionList)) return FAILURE; |
---|
223 | if (EstEID_CK_failure("GetFunctionList", GetFunctionList(&fl))) return FAILURE; |
---|
224 | if (!EstEID_startInitializeCryptokiThread()) return FAILURE; |
---|
225 | |
---|
226 | EstEID_log("successful"); |
---|
227 | |
---|
228 | return SUCCESS; |
---|
229 | } |
---|
230 | |
---|
231 | int EstEID_initializeCryptoki() { |
---|
232 | LOG_LOCATION; |
---|
233 | if (!EstEID_loadLibrary()) return FAILURE; |
---|
234 | #ifdef _WIN32 |
---|
235 | if (WAIT_OBJECT_0 != WaitForSingleObject(initialization_mutex, 0)) { |
---|
236 | EstEID_log("waiting for C_Initialize to complete"); |
---|
237 | WaitForSingleObject(initialization_mutex, INFINITE); |
---|
238 | } |
---|
239 | while (!initialization_completed) { |
---|
240 | ReleaseMutex(initialization_mutex); |
---|
241 | EstEID_log("waiting for C_Initialize to complete"); |
---|
242 | WaitForSingleObject(initialization_mutex, INFINITE); |
---|
243 | } |
---|
244 | ReleaseMutex(initialization_mutex); |
---|
245 | #else |
---|
246 | if (0 != pthread_mutex_trylock(&initialization_mutex)) { |
---|
247 | EstEID_log("waiting for C_Initialize to complete"); |
---|
248 | pthread_mutex_lock(&initialization_mutex); |
---|
249 | } |
---|
250 | while (!initialization_completed) { |
---|
251 | EstEID_log("waiting for C_Initialize to complete"); |
---|
252 | pthread_cond_wait(&initialization_condition, &initialization_mutex); |
---|
253 | } |
---|
254 | pthread_mutex_unlock(&initialization_mutex); |
---|
255 | #endif |
---|
256 | if (EstEID_CK_failure("C_Initialize", initialization_result)) return FAILURE; |
---|
257 | return SUCCESS; |
---|
258 | } |
---|
259 | |
---|
260 | int EstEID_loadSlotIDs(EstEID_Certs *certs) { |
---|
261 | CK_ULONG slotCount; |
---|
262 | EstEID_log("+++++++++++++++++++++++++++++++++++++ slotCount = %i", slotCount); |
---|
263 | |
---|
264 | FAIL_IF(EstEID_CK_failure("C_GetSlotList", fl->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount))); |
---|
265 | |
---|
266 | EstEID_log("+++++++++++++++++++++++++++++++++++++ slotCount = %i", slotCount); |
---|
267 | certs->count = slotCount; |
---|
268 | certs->slotIDs = (CK_SLOT_ID_PTR)malloc(sizeof(CK_SLOT_ID) * slotCount); |
---|
269 | certs->certs = (EstEID_Map *)malloc(sizeof(EstEID_Map) * slotCount); |
---|
270 | |
---|
271 | FAIL_IF(EstEID_CK_failure("C_GetSlotList", fl->C_GetSlotList(CK_TRUE, certs->slotIDs, &slotCount))); |
---|
272 | |
---|
273 | return SUCCESS; |
---|
274 | } |
---|
275 | |
---|
276 | //int EstEID_loadCertEntries(EstEID_Map cert, char *prefix, X509_NAME *x509Name) { |
---|
277 | int EstEID_loadCertEntries(EstEID_Map cert, char *prefix, struct X509_name_st *x509Name) { |
---|
278 | unsigned int i; |
---|
279 | // todo: error handling of all openssl functions |
---|
280 | unsigned int count = X509_NAME_entry_count(x509Name); |
---|
281 | for (i = 0; i < count; i++) { |
---|
282 | char *value; |
---|
283 | char name[1024]; |
---|
284 | X509_NAME_ENTRY *entry = X509_NAME_get_entry(x509Name, i); |
---|
285 | |
---|
286 | strcpy(name, prefix); |
---|
287 | OBJ_obj2txt(name + strlen(prefix), sizeof(name) - strlen(prefix), entry->object, 0); |
---|
288 | |
---|
289 | ASN1_STRING_to_UTF8((unsigned char **)&value, entry->value); |
---|
290 | |
---|
291 | EstEID_mapPutNoAlloc(cert, strdup(name), value); |
---|
292 | } |
---|
293 | return SUCCESS; |
---|
294 | } |
---|
295 | |
---|
296 | char *EstEID_getCertHash(char *certificate) { |
---|
297 | unsigned char certMD5[MD5_DIGEST_LENGTH]; |
---|
298 | char result[2 * MD5_DIGEST_LENGTH + 1] = ""; |
---|
299 | char chunk[3]; |
---|
300 | int i; |
---|
301 | |
---|
302 | MD5((unsigned char*)certificate, strlen(certificate), certMD5); |
---|
303 | |
---|
304 | for(i = 0; i < MD5_DIGEST_LENGTH; i++){ |
---|
305 | sprintf(chunk, "%02X", certMD5[i]); |
---|
306 | strcat(result, chunk); |
---|
307 | } |
---|
308 | |
---|
309 | EstEID_log("cert hash as HEX string: %s", result); |
---|
310 | return strdup(result); |
---|
311 | } |
---|
312 | |
---|
313 | char *EstEID_ASN1_TIME_toString(ASN1_TIME *time) { |
---|
314 | // ASN1_GENERALIZEDTIME.data format: yyyyMMddHHmmssZ |
---|
315 | ASN1_GENERALIZEDTIME *gt = ASN1_TIME_to_generalizedtime(time, NULL); |
---|
316 | char *data = (char *)gt->data; |
---|
317 | // result format dd.MM.yyyy HH:mm:ss |
---|
318 | // todo maybe: ASN1_GENERALIZEDTIME is in GMT -> should we adjust it? |
---|
319 | char *result = (char *)malloc(20); |
---|
320 | |
---|
321 | LOG_LOCATION; |
---|
322 | |
---|
323 | strncpy(result, data + 6, 2); |
---|
324 | strncpy(result + 3, data + 4, 2); |
---|
325 | strncpy(result + 6, data, 4); |
---|
326 | strncpy(result + 11, data + 8, 2); |
---|
327 | strncpy(result + 14, data + 10, 2); |
---|
328 | strncpy(result + 17, data + 12, 2); |
---|
329 | result[2] = result[5] = '.'; |
---|
330 | result[10] = ' '; |
---|
331 | result[13] = result[16] = ':'; |
---|
332 | result[19] = 0; |
---|
333 | ASN1_GENERALIZEDTIME_free(gt); |
---|
334 | return result; |
---|
335 | } |
---|
336 | |
---|
337 | int EstEID_loadCertInfoEntries(EstEID_Certs *certs, int index) { |
---|
338 | EstEID_Map cert = certs->certs[index]; |
---|
339 | CK_SLOT_ID slotID = certs->slotIDs[index]; |
---|
340 | CK_SESSION_HANDLE session; |
---|
341 | CK_OBJECT_CLASS objectClass = CKO_CERTIFICATE; |
---|
342 | CK_OBJECT_HANDLE objectHandle; |
---|
343 | CK_ULONG objectCount; |
---|
344 | CK_ATTRIBUTE searchAttribute ={CKA_CLASS, &objectClass, sizeof(objectClass)}; |
---|
345 | CK_ATTRIBUTE attribute = {CKA_VALUE, NULL_PTR, 0}; |
---|
346 | CK_ULONG certificateLength; |
---|
347 | CK_BYTE_PTR certificate; |
---|
348 | char *certMD5, *certSerialNumber, *b, *pem; |
---|
349 | const unsigned char *p; |
---|
350 | X509 *x509 ; |
---|
351 | unsigned long keyUsage; |
---|
352 | ASN1_BIT_STRING *usage; |
---|
353 | BIO *bio; |
---|
354 | int len; |
---|
355 | |
---|
356 | LOG_LOCATION; |
---|
357 | |
---|
358 | FAIL_IF(EstEID_CK_failure("C_OpenSession", fl->C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session))); |
---|
359 | |
---|
360 | if (EstEID_CK_failure("C_FindObjectsInit", fl->C_FindObjectsInit(session, &searchAttribute, 1))) return FAILURE; |
---|
361 | |
---|
362 | if (EstEID_CK_failure("C_FindObjects", fl->C_FindObjects(session, &objectHandle, 1, &objectCount))) return FAILURE; |
---|
363 | |
---|
364 | if (objectCount == 0) return SUCCESS; |
---|
365 | |
---|
366 | if (EstEID_CK_failure("C_GetAttributeValue", fl->C_GetAttributeValue(session, objectHandle, &attribute, 1))) return FAILURE; |
---|
367 | |
---|
368 | certificateLength = attribute.ulValueLen; |
---|
369 | certificate = (CK_BYTE_PTR)malloc(certificateLength); |
---|
370 | attribute.pValue = certificate; |
---|
371 | if (EstEID_CK_failure("C_GetAttributeValue", fl->C_GetAttributeValue(session, objectHandle, &attribute, 1))) return FAILURE; |
---|
372 | |
---|
373 | EstEID_log("cert = %p, certificate = %p, certificateLength = %i", cert, certificate, certificateLength); |
---|
374 | EstEID_mapPutNoAlloc(cert, strdup("certificateAsHex"), EstEID_bin2hex((char *)certificate, certificateLength)); |
---|
375 | |
---|
376 | p = certificate; |
---|
377 | x509 = d2i_X509(NULL, &p, certificateLength); |
---|
378 | |
---|
379 | certMD5 = EstEID_getCertHash((char*)certificate); |
---|
380 | FAIL_IF(EstEID_md5_failure(certMD5)); |
---|
381 | EstEID_mapPutNoAlloc(cert, strdup("certHash"), certMD5); |
---|
382 | free(certificate); |
---|
383 | |
---|
384 | // todo: error handling of all openssl functions |
---|
385 | |
---|
386 | EstEID_mapPutNoAlloc(cert, strdup("validTo"), EstEID_ASN1_TIME_toString(X509_get_notAfter(x509))); |
---|
387 | EstEID_mapPutNoAlloc(cert, strdup("validFrom"), EstEID_ASN1_TIME_toString(X509_get_notBefore(x509))); |
---|
388 | |
---|
389 | usage = (ASN1_BIT_STRING *)X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL); |
---|
390 | if (usage->length > 0) keyUsage = usage->data[0]; |
---|
391 | ASN1_BIT_STRING_free(usage); |
---|
392 | |
---|
393 | if (keyUsage & X509v3_KU_DIGITAL_SIGNATURE) EstEID_mapPut(cert, "usageDigitalSignature", "TRUE"); |
---|
394 | if (keyUsage & X509v3_KU_NON_REPUDIATION) { |
---|
395 | EstEID_mapPut(cert, "usageNonRepudiation", "TRUE"); |
---|
396 | EstEID_mapPut(cert, "keyUsage", "Non-Repudiation"); // for compatibility with older plugin |
---|
397 | } |
---|
398 | |
---|
399 | EstEID_loadCertEntries(cert, "", X509_get_subject_name(x509)); |
---|
400 | |
---|
401 | certSerialNumber = (char*)malloc(33); |
---|
402 | snprintf(certSerialNumber, 32, "%lX", ASN1_INTEGER_get(X509_get_serialNumber(x509))); |
---|
403 | EstEID_mapPutNoAlloc(cert, strdup("certSerialNumber"), certSerialNumber); |
---|
404 | EstEID_loadCertEntries(cert, "issuer.", X509_get_issuer_name(x509)); |
---|
405 | |
---|
406 | bio = BIO_new(BIO_s_mem()); |
---|
407 | if (!PEM_write_bio_X509(bio, x509)) printf("Cannot create PEM\n"); |
---|
408 | len = BIO_get_mem_data(bio, &b); |
---|
409 | pem = (char *)malloc(len + 1); |
---|
410 | strncpy(pem, b, len); |
---|
411 | pem[len] = 0; |
---|
412 | BIO_free(bio); |
---|
413 | EstEID_mapPutNoAlloc(cert, strdup("certificateAsPEM"), pem); |
---|
414 | |
---|
415 | FAIL_IF(EstEID_CK_failure("C_CloseSession", fl->C_CloseSession(session))); |
---|
416 | return SUCCESS; |
---|
417 | } |
---|
418 | |
---|
419 | EstEID_Map EstEID_createCertMap(CK_TOKEN_INFO tokenInfo) { |
---|
420 | char *label = EstEID_createString(tokenInfo.label, sizeof(tokenInfo.label)); |
---|
421 | EstEID_Map cert = EstEID_mapPutNoAlloc(NULL, strdup("label"), label); |
---|
422 | |
---|
423 | char pinLen[8]; |
---|
424 | memset(pinLen, 0x0, 8); |
---|
425 | sprintf(pinLen, "%lu", tokenInfo.ulMinPinLen); |
---|
426 | EstEID_mapPut(cert, "minPinLen", pinLen); |
---|
427 | |
---|
428 | return cert; |
---|
429 | } |
---|
430 | |
---|
431 | int EstEID_loadCertInfo(EstEID_Certs *certs, int index) { |
---|
432 | CK_TOKEN_INFO tokenInfo; |
---|
433 | CK_SLOT_ID slotID = certs->slotIDs[index]; |
---|
434 | CK_SLOT_INFO slotInfo; |
---|
435 | |
---|
436 | LOG_LOCATION; |
---|
437 | EstEID_log("---------------------- index = %i", index); |
---|
438 | |
---|
439 | FAIL_IF(EstEID_CK_failure("C_GetSlotInfo", fl->C_GetSlotInfo(slotID, &slotInfo))); |
---|
440 | |
---|
441 | if (!(slotInfo.flags & CKF_TOKEN_PRESENT)) return SUCCESS; |
---|
442 | |
---|
443 | FAIL_IF(EstEID_CK_failure("C_GetTokenInfo", fl->C_GetTokenInfo(slotID, &tokenInfo))); |
---|
444 | |
---|
445 | certs->certs[index] = EstEID_createCertMap(tokenInfo); |
---|
446 | |
---|
447 | FAIL_UNLESS(EstEID_loadCertInfoEntries(certs, index)); |
---|
448 | |
---|
449 | return SUCCESS; |
---|
450 | } |
---|
451 | |
---|
452 | void EstEID_waitForSlotEvent() { |
---|
453 | CK_SLOT_ID slotID = 0; |
---|
454 | CK_RV result = fl->C_WaitForSlotEvent(0, &slotID, NULL_PTR); |
---|
455 | printf("result: %s, slotID: %lu\n", pkcs11_error_message(result), slotID); |
---|
456 | } |
---|
457 | |
---|
458 | int EstEID_tokensChanged() { |
---|
459 | CK_SLOT_ID slotID; |
---|
460 | int changed = FALSE; |
---|
461 | |
---|
462 | LOG_LOCATION; |
---|
463 | |
---|
464 | while (fl->C_WaitForSlotEvent(CKF_DONT_BLOCK, &slotID, NULL_PTR) == CKR_OK) { |
---|
465 | EstEID_log("C_WaitForSlotEvent() pass cycle 1"); |
---|
466 | changed = TRUE; |
---|
467 | } |
---|
468 | if (!changed) { |
---|
469 | while (fl->C_WaitForSlotEvent(CKF_DONT_BLOCK, &slotID, NULL_PTR) == CKR_OK) { |
---|
470 | EstEID_log("C_WaitForSlotEvent() pass cycle 2"); |
---|
471 | changed = TRUE; |
---|
472 | } |
---|
473 | } |
---|
474 | EstEID_log("tokens change %sdetected", changed ? "" : "not "); |
---|
475 | return changed; |
---|
476 | } |
---|
477 | |
---|
478 | EstEID_Certs *EstEID_loadCerts() { |
---|
479 | unsigned int i; |
---|
480 | LOG_LOCATION; |
---|
481 | if (!EstEID_initializeCryptoki()) { |
---|
482 | EstEID_log("cryptoki initialization result forces to return NULL"); |
---|
483 | return NULL; |
---|
484 | } |
---|
485 | if (certs && !EstEID_tokensChanged()){ |
---|
486 | EstEID_log("tokens not changed, returning existing certs"); |
---|
487 | return certs; |
---|
488 | } |
---|
489 | if (certs) EstEID_freeCerts(); |
---|
490 | |
---|
491 | certs = (EstEID_Certs *)malloc(sizeof(EstEID_Certs)); |
---|
492 | if (!EstEID_loadSlotIDs(certs)) return NULL; |
---|
493 | EstEID_log("Certs count=%lu", certs->count); |
---|
494 | for (i = 0; i < certs->count; i++) { |
---|
495 | if (!EstEID_loadCertInfo(certs, i)) return NULL; |
---|
496 | EstEID_log("slotID=%lu", certs->slotIDs[i]); |
---|
497 | EstEID_logMap(certs->certs[i]); |
---|
498 | } |
---|
499 | EstEID_log("returning %u fresh cert(s)", certs->count); |
---|
500 | return certs; |
---|
501 | } |
---|
502 | |
---|
503 | void EstEID_printCerts() { |
---|
504 | unsigned int i; |
---|
505 | if (!EstEID_loadCerts()) { |
---|
506 | printf("%s\n", EstEID_error); |
---|
507 | return; |
---|
508 | } |
---|
509 | for (i = 0; i < certs->count; i++) { |
---|
510 | EstEID_Map cert = certs->certs[i]; |
---|
511 | fprintf(stdout, "Slot: %lu\n", certs->slotIDs[i]); |
---|
512 | EstEID_mapPrint(stdout, cert); |
---|
513 | } |
---|
514 | } |
---|
515 | |
---|
516 | void EstEID_freeCerts() { |
---|
517 | unsigned int i; |
---|
518 | if (certs == NULL) return; |
---|
519 | for (i = 0; i < certs->count; i++) { |
---|
520 | EstEID_mapFree(certs->certs[i]); |
---|
521 | } |
---|
522 | if (certs->certs) free(certs->certs); |
---|
523 | if (certs->slotIDs) free(certs->slotIDs); |
---|
524 | free(certs); |
---|
525 | certs = NULL; |
---|
526 | } |
---|
527 | |
---|
528 | EstEID_Map EstEID_getNonRepudiationCert() { |
---|
529 | unsigned int i; |
---|
530 | if (!EstEID_loadCerts()) return NULL; |
---|
531 | for (i = 0; i < certs->count; i++) { |
---|
532 | EstEID_Map cert = certs->certs[i]; |
---|
533 | if (EstEID_mapGet(cert, "usageNonRepudiation")) return cert; |
---|
534 | } |
---|
535 | sprintf(EstEID_error, "non-repudiation certificate not found"); |
---|
536 | EstEID_errorCode = ESTEID_CERT_NOT_FOUND_ERROR; |
---|
537 | return NULL; |
---|
538 | } |
---|
539 | |
---|
540 | EstEID_Map EstEID_getNonRepudiationCertById(char* certID) { |
---|
541 | unsigned int i; |
---|
542 | if (!EstEID_loadCerts()) return NULL; |
---|
543 | for (i = 0; i < certs->count; i++) { |
---|
544 | EstEID_Map cert = certs->certs[i]; |
---|
545 | if(EstEID_mapGet(cert, "certHash") && !strcmp(certID, EstEID_mapGet(cert, "certHash"))) { |
---|
546 | return cert; |
---|
547 | } |
---|
548 | } |
---|
549 | sprintf(EstEID_error, "non-repudiation certificate not found"); |
---|
550 | EstEID_errorCode = ESTEID_CERT_NOT_FOUND_ERROR; |
---|
551 | return NULL; |
---|
552 | } |
---|
553 | |
---|
554 | const char *EstEID_getCertPropertyName(const char *name) { |
---|
555 | char *realName = (char *)name; |
---|
556 | if (!strcmp("CN", name)) realName = "commonName"; |
---|
557 | else if (!strcmp("id", name)) realName = "certHash"; |
---|
558 | else if (!strcmp("issuerCN", name)) realName = "issuer.commonName"; |
---|
559 | else if (!strcmp("cert", name)) realName = "certificateAsHex"; |
---|
560 | return realName; |
---|
561 | } |
---|
562 | |
---|
563 | char *EstEID_bin2hex(const char *bin, const int binLength) { |
---|
564 | int j; |
---|
565 | char *hex = (char *)malloc(binLength * 2 + 1); |
---|
566 | LOG_LOCATION; |
---|
567 | for (j = 0; j < binLength; j++) sprintf(hex + (j * 2), "%02X", (unsigned char)bin[j]); |
---|
568 | hex[binLength * 2] = '\0'; |
---|
569 | return hex; |
---|
570 | } |
---|
571 | |
---|