1 /*
2  * Copyright (c) 2009 .SE (The Internet Infrastructure Foundation).
3  * Copyright (c) 2009 NLNet Labs.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <dlfcn.h>
36 #include <ldns/ldns.h>
37 #include <ldns/util.h>
38 
39 #include <libxml/tree.h>
40 #include <libxml/parser.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/relaxng.h>
44 
45 #include "libhsm.h"
46 #include "libhsmdns.h"
47 #include "compat.h"
48 #include "duration.h"
49 
50 #include <pkcs11.h>
51 #include <pthread.h>
52 
53 /*! Fixed length from PKCS#11 specification */
54 #define HSM_TOKEN_LABEL_LENGTH 32
55 
56 /*! Global (initial) context, with mutex to serialize access to it */
57 hsm_ctx_t *_hsm_ctx;
58 pthread_mutex_t _hsm_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
59 
60 /*! General PKCS11 helper functions */
61 static char const *
ldns_pkcs11_rv_str(CK_RV rv)62 ldns_pkcs11_rv_str(CK_RV rv)
63 {
64     switch (rv)
65         {
66         case CKR_OK:
67             return "CKR_OK";
68         case CKR_CANCEL:
69             return "CKR_CANCEL";
70         case CKR_HOST_MEMORY:
71             return "CKR_HOST_MEMORY";
72         case CKR_GENERAL_ERROR:
73             return "CKR_GENERAL_ERROR";
74         case CKR_FUNCTION_FAILED:
75             return "CKR_FUNCTION_FAILED";
76         case CKR_SLOT_ID_INVALID:
77             return "CKR_SLOT_ID_INVALID";
78         case CKR_ATTRIBUTE_READ_ONLY:
79             return "CKR_ATTRIBUTE_READ_ONLY";
80         case CKR_ATTRIBUTE_SENSITIVE:
81             return "CKR_ATTRIBUTE_SENSITIVE";
82         case CKR_ATTRIBUTE_TYPE_INVALID:
83             return "CKR_ATTRIBUTE_TYPE_INVALID";
84         case CKR_ATTRIBUTE_VALUE_INVALID:
85             return "CKR_ATTRIBUTE_VALUE_INVALID";
86         case CKR_DATA_INVALID:
87             return "CKR_DATA_INVALID";
88         case CKR_DATA_LEN_RANGE:
89             return "CKR_DATA_LEN_RANGE";
90         case CKR_DEVICE_ERROR:
91             return "CKR_DEVICE_ERROR";
92         case CKR_DEVICE_MEMORY:
93             return "CKR_DEVICE_MEMORY";
94         case CKR_DEVICE_REMOVED:
95             return "CKR_DEVICE_REMOVED";
96         case CKR_ENCRYPTED_DATA_INVALID:
97             return "CKR_ENCRYPTED_DATA_INVALID";
98         case CKR_ENCRYPTED_DATA_LEN_RANGE:
99             return "CKR_ENCRYPTED_DATA_LEN_RANGE";
100         case CKR_FUNCTION_CANCELED:
101             return "CKR_FUNCTION_CANCELED";
102         case CKR_FUNCTION_NOT_PARALLEL:
103             return "CKR_FUNCTION_NOT_PARALLEL";
104         case CKR_FUNCTION_NOT_SUPPORTED:
105             return "CKR_FUNCTION_NOT_SUPPORTED";
106         case CKR_KEY_HANDLE_INVALID:
107             return "CKR_KEY_HANDLE_INVALID";
108         case CKR_KEY_SIZE_RANGE:
109             return "CKR_KEY_SIZE_RANGE";
110         case CKR_KEY_TYPE_INCONSISTENT:
111             return "CKR_KEY_TYPE_INCONSISTENT";
112         case CKR_MECHANISM_INVALID:
113             return "CKR_MECHANISM_INVALID";
114         case CKR_MECHANISM_PARAM_INVALID:
115             return "CKR_MECHANISM_PARAM_INVALID";
116         case CKR_OBJECT_HANDLE_INVALID:
117             return "CKR_OBJECT_HANDLE_INVALID";
118         case CKR_OPERATION_ACTIVE:
119             return "CKR_OPERATION_ACTIVE";
120         case CKR_OPERATION_NOT_INITIALIZED:
121             return "CKR_OPERATION_NOT_INITIALIZED";
122         case CKR_PIN_INCORRECT:
123             return "CKR_PIN_INCORRECT";
124         case CKR_PIN_INVALID:
125             return "CKR_PIN_INVALID";
126         case CKR_PIN_LEN_RANGE:
127             return "CKR_PIN_LEN_RANGE";
128         case CKR_SESSION_CLOSED:
129             return "CKR_SESSION_CLOSED";
130         case CKR_SESSION_COUNT:
131             return "CKR_SESSION_COUNT";
132         case CKR_SESSION_HANDLE_INVALID:
133             return "CKR_SESSION_HANDLE_INVALID";
134         case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
135             return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
136         case CKR_SESSION_READ_ONLY:
137             return "CKR_SESSION_READ_ONLY";
138         case CKR_SESSION_EXISTS:
139             return "CKR_SESSION_EXISTS";
140         case CKR_SIGNATURE_INVALID:
141             return "CKR_SIGNATURE_INVALID";
142         case CKR_SIGNATURE_LEN_RANGE:
143             return "CKR_SIGNATURE_LEN_RANGE";
144         case CKR_TEMPLATE_INCOMPLETE:
145             return "CKR_TEMPLATE_INCOMPLETE";
146         case CKR_TEMPLATE_INCONSISTENT:
147             return "CKR_TEMPLATE_INCONSISTENT";
148         case CKR_TOKEN_NOT_PRESENT:
149             return "CKR_TOKEN_NOT_PRESENT";
150         case CKR_TOKEN_NOT_RECOGNIZED:
151             return "CKR_TOKEN_NOT_RECOGNIZED";
152         case CKR_TOKEN_WRITE_PROTECTED:
153             return "CKR_TOKEN_WRITE_PROTECTED";
154         case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
155             return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
156         case CKR_UNWRAPPING_KEY_SIZE_RANGE:
157             return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
158         case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
159             return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
160         case CKR_USER_ALREADY_LOGGED_IN:
161             return "CKR_USER_ALREADY_LOGGED_IN";
162         case CKR_USER_NOT_LOGGED_IN:
163             return "CKR_USER_NOT_LOGGED_IN";
164         case CKR_USER_PIN_NOT_INITIALIZED:
165             return "CKR_USER_PIN_NOT_INITIALIZED";
166         case CKR_USER_TYPE_INVALID:
167             return "CKR_USER_TYPE_INVALID";
168         case CKR_WRAPPED_KEY_INVALID:
169             return "CKR_WRAPPED_KEY_INVALID";
170         case CKR_WRAPPED_KEY_LEN_RANGE:
171             return "CKR_WRAPPED_KEY_LEN_RANGE";
172         case CKR_WRAPPING_KEY_HANDLE_INVALID:
173             return "CKR_WRAPPING_KEY_HANDLE_INVALID";
174         case CKR_WRAPPING_KEY_SIZE_RANGE:
175             return "CKR_WRAPPING_KEY_SIZE_RANGE";
176         case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
177             return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
178         case CKR_RANDOM_SEED_NOT_SUPPORTED:
179             return "CKR_RANDOM_SEED_NOT_SUPPORTED";
180         /*CKR_VENDOR_DEFINED is not a constant but a macro which expands in to an */
181         /*expression. Which we are not allowed to use in a switch.*/
182         /*case CKR_VENDOR_DEFINED:*/
183         case 0x80000000:
184             return "CKR_VENDOR_DEFINED";
185         case CKR_BUFFER_TOO_SMALL:
186             return "CKR_BUFFER_TOO_SMALL";
187         case CKR_SAVED_STATE_INVALID:
188             return "CKR_SAVED_STATE_INVALID";
189         case CKR_INFORMATION_SENSITIVE:
190             return "CKR_INFORMATION_SENSITIVE";
191         case CKR_STATE_UNSAVEABLE:
192             return "CKR_STATE_UNSAVEABLE";
193         case CKR_CRYPTOKI_NOT_INITIALIZED:
194             return "CKR_CRYPTOKI_NOT_INITIALIZED";
195         case CKR_CRYPTOKI_ALREADY_INITIALIZED:
196             return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
197         case CKR_MUTEX_BAD:
198             return "CKR_MUTEX_BAD";
199         case CKR_MUTEX_NOT_LOCKED:
200             return "CKR_MUTEX_NOT_LOCKED";
201         default:
202             return "Unknown error";
203         }
204 }
205 
206 void
hsm_ctx_set_error(hsm_ctx_t * ctx,int error,const char * action,const char * message,...)207 hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action,
208                  const char *message, ...)
209 {
210     va_list args;
211 
212     if (ctx && ctx->error == 0) {
213         ctx->error = error;
214         ctx->error_action = action;
215 
216         va_start(args, message);
217         vsnprintf(ctx->error_message, sizeof(ctx->error_message),
218             message, args);
219         va_end(args);
220     }
221 }
222 
223 /*! Check HSM Context for Error
224 
225 If the rv is not CKR_OK, and there is not previous error registered in
226 the context, to set the context error based on PKCS#11 return value.
227 
228 \param ctx      HSM context
229 \param rv       PKCS#11 return value
230 \param action   action for which the error occured
231 \param message  error message format string
232 \return         0 if rv == CKR_OK, otherwise 1
233 */
234 static int
hsm_pkcs11_check_error(hsm_ctx_t * ctx,CK_RV rv,const char * action)235 hsm_pkcs11_check_error(hsm_ctx_t *ctx, CK_RV rv, const char *action)
236 {
237     if (rv != CKR_OK) {
238         if (ctx && ctx->error == 0) {
239             ctx->error = (int) rv;
240             ctx->error_action = action;
241             strlcpy(ctx->error_message, ldns_pkcs11_rv_str(rv), sizeof(ctx->error_message));
242         }
243         return 1;
244     }
245     return 0;
246 }
247 
248 /*! Unload PKCS#11 provider */
249 static void
hsm_pkcs11_unload_functions(void * handle)250 hsm_pkcs11_unload_functions(void *handle)
251 {
252     if (handle) {
253 #if defined(HAVE_LOADLIBRARY)
254         /* no idea */
255 #elif defined(HAVE_DLOPEN)
256         (void) dlclose(handle);
257 #endif
258     }
259 }
260 
261 /*! Load PKCS#11 provider */
262 static CK_RV
hsm_pkcs11_load_functions(hsm_module_t * module)263 hsm_pkcs11_load_functions(hsm_module_t *module)
264 {
265     CK_C_GetFunctionList pGetFunctionList = NULL;
266 
267     if (module && module->path) {
268         /* library provided by application or user */
269 
270 #if defined(HAVE_LOADLIBRARY)
271         /* Load PKCS #11 library */
272         HINSTANCE hDLL = LoadLibrary(_T(module->path));
273 
274         if (hDLL == NULL) {
275             /* Failed to load the PKCS #11 library */
276             return CKR_FUNCTION_FAILED;
277         }
278 
279         /* Retrieve the entry point for C_GetFunctionList */
280         pGetFunctionList = (CK_C_GetFunctionList)
281             GetProcAddress(hDLL, _T("C_GetFunctionList"));
282 
283 #elif defined(HAVE_DLOPEN)
284         /* Load PKCS #11 library */
285         void* pDynLib = dlopen(module->path, RTLD_NOW | RTLD_LOCAL);
286 
287         if (pDynLib == NULL) {
288             /* Failed to load the PKCS #11 library */
289             return CKR_FUNCTION_FAILED;
290         }
291 
292         /* Retrieve the entry point for C_GetFunctionList */
293         pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList");
294         /* Store the handle so we can dlclose it later */
295         module->handle = pDynLib;
296 
297 #else
298         return CKR_FUNCTION_FAILED;
299 #endif
300     } else {
301         /* No library provided, use the statically compiled softHSM */
302 #ifdef HAVE_PKCS11_MODULE
303         return C_GetFunctionList(pkcs11_functions);
304 #else
305         return CKR_FUNCTION_FAILED;
306 #endif
307     }
308 
309     if (pGetFunctionList == NULL) {
310         /* Failed to load the PKCS #11 library */
311         return CKR_FUNCTION_FAILED;
312     }
313 
314     /* Retrieve the function list */
315     (pGetFunctionList)((CK_FUNCTION_LIST_PTR_PTR)(&module->sym));
316     return CKR_OK;
317 }
318 
319 static void
hsm_remove_leading_zeroes(CK_BYTE_PTR data,CK_ULONG * len)320 hsm_remove_leading_zeroes(CK_BYTE_PTR data, CK_ULONG *len)
321 {
322     CK_BYTE_PTR p = data;
323     CK_ULONG l;
324 
325     if (data == NULL || len == NULL) return;
326 
327     l = *len;
328 
329     while ((unsigned short int)(*p) == 0 && l > 1) {
330         p++;
331         l--;
332     }
333 
334     if (p != data) {
335         memmove(data, p, l);
336         *len = l;
337     }
338 }
339 
340 static int
hsm_pkcs11_check_token_name(hsm_ctx_t * ctx,CK_FUNCTION_LIST_PTR pkcs11_functions,CK_SLOT_ID slotId,const char * token_name)341 hsm_pkcs11_check_token_name(hsm_ctx_t *ctx,
342                             CK_FUNCTION_LIST_PTR pkcs11_functions,
343                             CK_SLOT_ID slotId,
344                             const char *token_name)
345 {
346     /* token label is always 32 bytes */
347     char token_name_bytes[HSM_TOKEN_LABEL_LENGTH];
348     int result = 0;
349     CK_RV rv;
350     CK_TOKEN_INFO token_info;
351 
352     rv = pkcs11_functions->C_GetTokenInfo(slotId, &token_info);
353     if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
354         return 0;
355     }
356 
357     memset(token_name_bytes, ' ', HSM_TOKEN_LABEL_LENGTH);
358     if (strlen(token_name) < HSM_TOKEN_LABEL_LENGTH) {
359         memcpy(token_name_bytes, token_name, strlen(token_name));
360     } else {
361         memcpy(token_name_bytes, token_name, HSM_TOKEN_LABEL_LENGTH);
362     }
363 
364     result = memcmp(token_info.label,
365                     token_name_bytes,
366                     HSM_TOKEN_LABEL_LENGTH) == 0;
367 
368     return result;
369 }
370 
371 hsm_repository_t *
hsm_repository_new(char * name,char * module,char * tokenlabel,char * pin,uint8_t use_pubkey,uint8_t allowextract,uint8_t require_backup)372 hsm_repository_new(char* name, char* module, char* tokenlabel, char* pin,
373     uint8_t use_pubkey, uint8_t allowextract, uint8_t require_backup)
374 {
375     hsm_repository_t* r;
376 
377     if (!name || !module || !tokenlabel) return NULL;
378 
379     r = malloc(sizeof(hsm_repository_t));
380     if (!r) return NULL;
381 
382     r->next = NULL;
383     r->pin = NULL;
384     r->name = strdup(name);
385     r->module = strdup(module);
386     r->tokenlabel = strdup(tokenlabel);
387     if (!r->name || !r->module || !r->tokenlabel) {
388         hsm_repository_free(r);
389         return NULL;
390     }
391     if (pin) {
392         r->pin = strdup(pin);
393         if (!r->pin) {
394             hsm_repository_free(r);
395             return NULL;
396         }
397     }
398     r->use_pubkey = use_pubkey;
399     r->allow_extract = allowextract;
400     r->require_backup = require_backup;
401     return r;
402 }
403 
404 void
hsm_repository_free(hsm_repository_t * r)405 hsm_repository_free(hsm_repository_t *r)
406 {
407     if (r) {
408         if (r->next) hsm_repository_free(r->next);
409         if (r->name) free(r->name);
410         if (r->module) free(r->module);
411         if (r->tokenlabel) free(r->tokenlabel);
412         if (r->pin) free(r->pin);
413     }
414     free(r);
415 }
416 
417 static int
hsm_get_slot_id(hsm_ctx_t * ctx,CK_FUNCTION_LIST_PTR pkcs11_functions,const char * token_name,CK_SLOT_ID * slotId)418 hsm_get_slot_id(hsm_ctx_t *ctx,
419                 CK_FUNCTION_LIST_PTR pkcs11_functions,
420                 const char *token_name, CK_SLOT_ID *slotId)
421 {
422     CK_RV rv;
423     CK_ULONG slotCount;
424     CK_SLOT_ID cur_slot;
425     CK_SLOT_ID *slotIds;
426     int found = 0;
427 
428     if (token_name == NULL || slotId == NULL) return HSM_ERROR;
429 
430     rv = pkcs11_functions->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
431     if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
432         return HSM_ERROR;
433     }
434 
435     if (slotCount < 1) {
436         hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
437                           "No slots found in HSM");
438         return HSM_ERROR;
439     } else if (slotCount > (SIZE_MAX / sizeof(CK_SLOT_ID))) {
440         hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
441                           "Too many slots found in HSM");
442         return HSM_ERROR;
443     }
444 
445     slotIds = malloc(sizeof(CK_SLOT_ID) * slotCount);
446     if(slotIds == NULL) {
447         hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
448                           "Could not allocate slot ID table");
449         return HSM_ERROR;
450     }
451 
452     rv = pkcs11_functions->C_GetSlotList(CK_TRUE, slotIds, &slotCount);
453     if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
454         return HSM_ERROR;
455     }
456 
457     for (cur_slot = 0; cur_slot < slotCount; cur_slot++) {
458         if (hsm_pkcs11_check_token_name(ctx,
459                                         pkcs11_functions,
460                                         slotIds[cur_slot],
461                                         token_name)) {
462             *slotId = slotIds[cur_slot];
463             found = 1;
464             break;
465         }
466     }
467     free(slotIds);
468     if (!found) {
469         hsm_ctx_set_error(ctx, -1, "hsm_get_slot_id()",
470             "could not find token with the name %s", token_name);
471         return HSM_ERROR;
472     }
473 
474     return HSM_OK;
475 }
476 
477 /* internal functions */
478 static hsm_module_t *
hsm_module_new(const char * repository,const char * token_label,const char * path,const hsm_config_t * config)479 hsm_module_new(const char *repository,
480                const char *token_label,
481                const char *path,
482                const hsm_config_t *config)
483 {
484     hsm_module_t *module;
485 
486     if (!repository || !path) return NULL;
487 
488 
489     module = malloc(sizeof(hsm_module_t));
490     if (!module) return NULL;
491 
492     if (config) {
493         module->config = malloc(sizeof(hsm_config_t));
494         if (!module->config) {
495             free(module);
496             return NULL;
497         }
498         memcpy(module->config, config, sizeof(hsm_config_t));
499     } else {
500         module->config = NULL;
501     }
502 
503     module->id = 0; /*TODO i think we can remove this*/
504     module->name = strdup(repository);
505     module->token_label = strdup(token_label);
506     module->path = strdup(path);
507     module->handle = NULL;
508     module->sym = NULL;
509 
510     return module;
511 }
512 
513 static void
hsm_module_free(hsm_module_t * module)514 hsm_module_free(hsm_module_t *module)
515 {
516     if (module) {
517         if (module->name) free(module->name);
518         if (module->token_label) free(module->token_label);
519         if (module->path) free(module->path);
520         if (module->config) free(module->config);
521 
522         free(module);
523     }
524 }
525 
526 static hsm_session_t *
hsm_session_new(hsm_module_t * module,CK_SESSION_HANDLE session_handle)527 hsm_session_new(hsm_module_t *module, CK_SESSION_HANDLE session_handle)
528 {
529     hsm_session_t *session;
530     session = malloc(sizeof(hsm_session_t));
531     session->module = module;
532     session->session = session_handle;
533     return session;
534 }
535 
536 static void
hsm_session_free(hsm_session_t * session)537 hsm_session_free(hsm_session_t *session) {
538     if (session) {
539         free(session);
540     }
541 }
542 
543 /*! Set default HSM configuration */
544 static void
hsm_config_default(hsm_config_t * config)545 hsm_config_default(hsm_config_t *config)
546 {
547     config->use_pubkey = 1;
548     config->allow_extract = 0;
549 }
550 
551 /* creates a session_t structure, and automatically adds and initializes
552  * a module_t struct for it
553  */
554 static int
hsm_session_init(hsm_ctx_t * ctx,hsm_session_t ** session,const char * repository,const char * token_label,const char * module_path,const char * pin,const hsm_config_t * config)555 hsm_session_init(hsm_ctx_t *ctx, hsm_session_t **session,
556                  const char *repository, const char *token_label,
557                  const char *module_path, const char *pin,
558                  const hsm_config_t *config)
559 {
560     CK_RV rv;
561     CK_RV rv_login;
562     hsm_module_t *module;
563     CK_SLOT_ID slot_id;
564     CK_SESSION_HANDLE session_handle;
565     int first = 1, result;
566 
567     CK_C_INITIALIZE_ARGS InitArgs = {NULL, NULL, NULL, NULL,
568                                      CKF_OS_LOCKING_OK, NULL };
569 
570     if (pin == NULL) return HSM_ERROR;
571 
572     module = hsm_module_new(repository, token_label, module_path, config);
573     if (!module) return HSM_ERROR;
574     rv = hsm_pkcs11_load_functions(module);
575     if (rv != CKR_OK) {
576         hsm_ctx_set_error(ctx, HSM_MODULE_NOT_FOUND,
577 	    "hsm_session_init()",
578 	    "PKCS#11 module load failed: %s", module_path);
579         hsm_module_free(module);
580         return HSM_MODULE_NOT_FOUND;
581     }
582     rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Initialize((CK_VOID_PTR) &InitArgs);
583     /* ALREADY_INITIALIZED is ok, apparently we are using a second
584      * device with the same library */
585     if (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
586         if (hsm_pkcs11_check_error(ctx, rv, "Initialization")) {
587             hsm_module_free(module);
588             return HSM_ERROR;
589         }
590     } else {
591         first = 0;
592     }
593     result = hsm_get_slot_id(ctx, module->sym, token_label, &slot_id);
594     if (result != HSM_OK) {
595         hsm_module_free(module);
596         return HSM_ERROR;
597     }
598     rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_OpenSession(slot_id,
599                                CKF_SERIAL_SESSION | CKF_RW_SESSION,
600                                NULL,
601                                NULL,
602                                &session_handle);
603     if (hsm_pkcs11_check_error(ctx, rv, "Open first session")) {
604         hsm_module_free(module);
605         return HSM_ERROR;
606     }
607     rv_login = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Login(session_handle,
608                                    CKU_USER,
609                                    (unsigned char *) pin,
610                                    strlen((char *)pin));
611 
612     if (rv_login == CKR_OK) {
613         *session = hsm_session_new(module, session_handle);
614         return HSM_OK;
615     } else {
616         /* uninitialize the session again */
617         if (session_handle) {
618             rv = ((CK_FUNCTION_LIST_PTR) module->sym)->
619                    C_CloseSession(session_handle);
620             if (hsm_pkcs11_check_error(ctx, rv,
621                 "finalize after failed login")) {
622                 hsm_module_free(module);
623                 return HSM_ERROR;
624             }
625         }
626         /* if this was not the first, don't close the library for
627          * the rest of us */
628         if (first) {
629             rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Finalize(NULL);
630             if (hsm_pkcs11_check_error(ctx, rv, "finalize after failed login")) {
631                 hsm_module_free(module);
632                 return HSM_ERROR;
633             }
634         }
635         hsm_module_free(module);
636         *session = NULL;
637         switch(rv_login) {
638         case CKR_PIN_INCORRECT:
639             hsm_ctx_set_error(ctx, HSM_PIN_INCORRECT,
640 	            "hsm_session_init()",
641 		    "Incorrect PIN for repository %s", repository);
642             return HSM_PIN_INCORRECT;
643         default:
644             return HSM_ERROR;
645         }
646     }
647 }
648 
649 /* open a second session from the given one */
650 static hsm_session_t *
hsm_session_clone(hsm_ctx_t * ctx,hsm_session_t * session)651 hsm_session_clone(hsm_ctx_t *ctx, hsm_session_t *session)
652 {
653     CK_RV rv;
654     CK_SLOT_ID slot_id;
655     CK_SESSION_HANDLE session_handle;
656     hsm_session_t *new_session;
657     int result;
658 
659     result = hsm_get_slot_id(ctx,
660                               session->module->sym,
661                               session->module->token_label,
662                               &slot_id);
663     if (result != HSM_OK) return NULL;
664     rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_OpenSession(slot_id,
665                                     CKF_SERIAL_SESSION | CKF_RW_SESSION,
666                                     NULL,
667                                     NULL,
668                                     &session_handle);
669 
670     if (hsm_pkcs11_check_error(ctx, rv, "Clone session")) {
671         return NULL;
672     }
673     new_session = hsm_session_new(session->module, session_handle);
674 
675     return new_session;
676 }
677 
678 static hsm_ctx_t *
hsm_ctx_new()679 hsm_ctx_new()
680 {
681     hsm_ctx_t *ctx;
682     ctx = malloc(sizeof(hsm_ctx_t));
683     if (ctx) {
684         memset(ctx->session, 0, sizeof(ctx->session));
685         ctx->session_count = 0;
686         ctx->error = 0;
687     }
688     return ctx;
689 }
690 
691 /* ctx_free frees the structure */
692 static void
hsm_ctx_free(hsm_ctx_t * ctx)693 hsm_ctx_free(hsm_ctx_t *ctx)
694 {
695     unsigned int i;
696 
697     if (ctx) {
698         for (i = 0; i < ctx->session_count; i++) {
699             hsm_session_free(ctx->session[i]);
700         }
701         free(ctx);
702     }
703 }
704 
705 /* close the session, and free the allocated data
706  *
707  * if unload is non-zero, C_Logout() is called,
708  * the dlopen()d module is closed and unloaded
709  * (only call this on the last session for each
710  * module, ie. the one in the global ctx)
711  */
712 static void
hsm_session_close(hsm_ctx_t * ctx,hsm_session_t * session,int unload)713 hsm_session_close(hsm_ctx_t *ctx, hsm_session_t *session, int unload)
714 {
715     /* If we loaded this library more than once, we may have
716      * already finalized it before, so we can safely ignore
717      * NOT_INITIALIZED */
718     CK_RV rv;
719     if (unload) {
720         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Logout(session->session);
721         if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
722             (void) hsm_pkcs11_check_error(ctx, rv, "Logout");
723         }
724     }
725     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session->session);
726     if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
727         (void) hsm_pkcs11_check_error(ctx, rv, "Close session");
728     }
729     if (unload) {
730         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Finalize(NULL);
731         if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
732             (void) hsm_pkcs11_check_error(ctx, rv, "Finalize");
733             hsm_pkcs11_unload_functions(session->module->handle);
734         }
735         hsm_module_free(session->module);
736         session->module = NULL;
737     }
738     hsm_session_free(session);
739 }
740 
741 /* ctx_close closes all session, and free
742  * the structures.
743  *
744  * if unload is non-zero, the associated dynamic libraries are unloaded
745  * (hence only use that on the last, global, ctx)
746  */
747 static void
hsm_ctx_close(hsm_ctx_t * ctx,int unload)748 hsm_ctx_close(hsm_ctx_t *ctx, int unload)
749 {
750     size_t i;
751 
752     if (!ctx) return;
753     for (i = 0; i < ctx->session_count; i++) {
754         hsm_session_close(ctx, ctx->session[i], unload);
755         ctx->session[i] = NULL;
756     }
757     hsm_ctx_free(ctx);
758 
759 }
760 
761 
762 /* adds a session to the context.
763  * returns  0 on success
764  *          1 if the maximum number of sessions (HSM_MAX_SESSIONS) was
765  *            reached
766  *          -1 if one of the arguments is NULL
767  */
768 static int
hsm_ctx_add_session(hsm_ctx_t * ctx,hsm_session_t * session)769 hsm_ctx_add_session(hsm_ctx_t *ctx, hsm_session_t *session)
770 {
771     if (!ctx || !session) return -1;
772     if (ctx->session_count >= HSM_MAX_SESSIONS) return 1;
773     ctx->session[ctx->session_count] = session;
774     ctx->session_count++;
775     return 0;
776 }
777 
778 static hsm_ctx_t *
hsm_ctx_clone(hsm_ctx_t * ctx)779 hsm_ctx_clone(hsm_ctx_t *ctx)
780 {
781     unsigned int i;
782     hsm_ctx_t *new_ctx;
783     hsm_session_t *new_session;
784 
785     new_ctx = NULL;
786     if (ctx) {
787         new_ctx = hsm_ctx_new();
788         for (i = 0; i < ctx->session_count; i++) {
789             new_session = hsm_session_clone(ctx, ctx->session[i]);
790             if (!new_session) {
791                 /* one of the sessions failed to clone. Clear the
792                  * new ctx and return NULL */
793                 hsm_ctx_close(new_ctx, 0);
794                 return NULL;
795             }
796             hsm_ctx_add_session(new_ctx, new_session);
797         }
798         new_ctx->keycache = ctx->keycache;
799         new_ctx->keycache_lock = ctx->keycache_lock;
800     }
801     return new_ctx;
802 }
803 
804 static libhsm_key_t *
libhsm_key_new()805 libhsm_key_new()
806 {
807     libhsm_key_t *key;
808     key = malloc(sizeof(libhsm_key_t));
809     key->modulename = NULL;
810     key->private_key = 0;
811     key->public_key = 0;
812     return key;
813 }
814 
815 /* find the session belonging to a key, by iterating over the modules
816  * in the context */
817 static hsm_session_t *
hsm_find_key_session(hsm_ctx_t * ctx,const libhsm_key_t * key)818 hsm_find_key_session(hsm_ctx_t *ctx, const libhsm_key_t *key)
819 {
820     unsigned int i;
821     if (!key || !key->modulename) return NULL;
822     for (i = 0; i < ctx->session_count; i++) {
823         if (ctx->session[i] && !strcmp(ctx->session[i]->module->name, key->modulename)) {
824             return ctx->session[i];
825         }
826     }
827     return NULL;
828 }
829 
830 /* Returns the key type (algorithm) of the given key */
831 static CK_KEY_TYPE
hsm_get_key_algorithm(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key)832 hsm_get_key_algorithm(hsm_ctx_t *ctx, const hsm_session_t *session,
833                       const libhsm_key_t *key)
834 {
835     CK_RV rv;
836     CK_KEY_TYPE key_type;
837 
838     CK_ATTRIBUTE template[] = {
839         {CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}
840     };
841 
842     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
843                                       session->session,
844                                       key->private_key,
845                                       template,
846                                       1);
847     if (hsm_pkcs11_check_error(ctx, rv,
848                                "Get attr value algorithm type")) {
849         /* this is actually not a good return value;
850          * CKK_RSA is also 0. But we can't return a negative
851          * value. Should we #define a specific 'key type' that
852          * indicates an error? (TODO) */
853         return 0;
854     }
855 
856     if ((CK_LONG)template[0].ulValueLen < 1) {
857         /* this is actually not a good return value;
858          * CKK_RSA is also 0. But we can't return a negative
859          * value. Should we #define a specific 'key type' that
860          * indicates an error? (TODO) */
861         return 0;
862     }
863 
864     return key_type;
865 }
866 
867 /* returns a CK_ULONG with the key size of the given RSA key. The
868  * key is not checked for type. For RSA, the number of bits in the
869  * modulus is the key size (CKA_MODULUS_BITS)
870  */
871 static CK_ULONG
hsm_get_key_size_rsa(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key)872 hsm_get_key_size_rsa(hsm_ctx_t *ctx, const hsm_session_t *session,
873                      const libhsm_key_t *key)
874 {
875     CK_RV rv;
876     CK_ULONG modulus_bits;
877 
878     /* Template for public keys */
879     CK_ATTRIBUTE template[] = {
880         {CKA_MODULUS_BITS, &modulus_bits, sizeof(CK_KEY_TYPE)}
881     };
882 
883     /* Template for private keys */
884     CK_BYTE_PTR modulus = NULL;
885     int mask;
886     CK_ATTRIBUTE template2[] = {
887         {CKA_MODULUS, NULL, 0}
888     };
889 
890     if (key->public_key) {
891         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
892                                           session->session,
893                                           key->public_key,
894                                           template,
895                                           1);
896         if (hsm_pkcs11_check_error(ctx, rv,
897                                    "Get attr value algorithm type")) {
898             return 0;
899         }
900 
901         if ((CK_ULONG)template[0].ulValueLen < 1) {
902             return 0;
903         }
904     } else {
905         // Get buffer size
906         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
907                                           session->session,
908                                           key->private_key,
909                                           template2,
910                                           1);
911         if (hsm_pkcs11_check_error(ctx, rv, "Could not get the size of the modulus of the private key")) {
912             return 0;
913         }
914 
915         // Allocate memory
916         modulus = (CK_BYTE_PTR)malloc(template2[0].ulValueLen);
917         template2[0].pValue = modulus;
918         if (modulus == NULL) {
919             hsm_ctx_set_error(ctx, -1, "hsm_get_key_size_rsa()",
920                 "Error allocating memory for modulus");
921             return 0;
922         }
923 
924         // Get attribute
925         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
926                                           session->session,
927                                           key->private_key,
928                                           template2,
929                                           1);
930         if (hsm_pkcs11_check_error(ctx, rv, "Could not get the modulus of the private key")) {
931             free(modulus);
932             return 0;
933         }
934 
935 	// Calculate size
936         modulus_bits = template2[0].ulValueLen * 8;
937         mask = 0x80;
938         for (int i = 0; modulus_bits && (modulus[i] & mask) == 0; modulus_bits--) {
939             mask >>= 1;
940             if (mask == 0) {
941                 i++;
942                 mask = 0x80;
943             }
944         }
945         free(modulus);
946     }
947 
948     return modulus_bits;
949 }
950 
951 /* returns a CK_ULONG with the key size of the given DSA key. The
952  * key is not checked for type. For DSA, the number of bits in the
953  * prime is the key size (CKA_PRIME)
954  */
955 static CK_ULONG
hsm_get_key_size_dsa(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key)956 hsm_get_key_size_dsa(hsm_ctx_t *ctx, const hsm_session_t *session,
957                      const libhsm_key_t *key)
958 {
959     CK_RV rv;
960 
961     /* Template */
962     CK_ATTRIBUTE template2[] = {
963         {CKA_PRIME, NULL, 0}
964     };
965 
966     // Get buffer size
967     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
968                                       session->session,
969                                       key->private_key,
970                                       template2,
971                                       1);
972     if (hsm_pkcs11_check_error(ctx, rv, "Could not get the size of the prime of the private key")) {
973         return 0;
974     }
975 
976     return template2[0].ulValueLen * 8;
977 }
978 
979 /* Returns the DER decoded value of Q for ECDSA key
980  * Byte string with uncompressed form of a curve point, "x | y"
981  */
982 static unsigned char *
hsm_get_key_ecdsa_value(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key,CK_ULONG * data_len)983 hsm_get_key_ecdsa_value(hsm_ctx_t *ctx, const hsm_session_t *session,
984                      const libhsm_key_t *key, CK_ULONG *data_len)
985 {
986     CK_RV rv;
987     CK_BYTE_PTR value = NULL;
988     CK_BYTE_PTR data = NULL;
989     CK_ULONG value_len = 0;
990     CK_ULONG header_len = 0;
991 
992     CK_ATTRIBUTE template[] = {
993         {CKA_EC_POINT, NULL, 0},
994     };
995 
996     if (!session || !session->module || !key || !data_len) {
997         return NULL;
998     }
999 
1000     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1001                                       session->session,
1002                                       key->public_key,
1003                                       template,
1004                                       1);
1005     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
1006         return NULL;
1007     }
1008     value_len = template[0].ulValueLen;
1009 
1010     value = template[0].pValue = malloc(value_len);
1011     if (!value) {
1012         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1013             "Error allocating memory for value");
1014         return NULL;
1015     }
1016     memset(value, 0, value_len);
1017 
1018     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1019                                       session->session,
1020                                       key->public_key,
1021                                       template,
1022                                       1);
1023     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
1024         free(value);
1025         return NULL;
1026     }
1027 
1028     if(value_len != template[0].ulValueLen) {
1029         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1030            "HSM returned two different length for a same CKA_EC_POINT. " \
1031             "Abnormal behaviour detected.");
1032         free(value);
1033         return NULL;
1034     }
1035 
1036     /* Check that we have the first two octets */
1037     if (value_len < 2) {
1038         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1039             "The DER value is too short");
1040         free(value);
1041         return NULL;
1042     }
1043 
1044     /* Check the identifier octet, PKCS#11 requires octet string */
1045     if (value[0] != 0x04) {
1046         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1047             "Invalid identifier octet in the DER value");
1048         free(value);
1049         return NULL;
1050     }
1051     header_len++;
1052 
1053     /* Check the length octets, but we do not validate the length */
1054     if (value[1] <= 0x7F) {
1055         header_len++;
1056     } else if (value[1] == 0x80) {
1057         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1058             "Indefinite length is not supported in DER values");
1059         free(value);
1060         return NULL;
1061     } else {
1062         header_len++;
1063         header_len += value[1] & 0x80;
1064     }
1065 
1066     /* Check that we have more data than the header */
1067     if (value_len - header_len < 2) {
1068         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1069             "The value is too short");
1070         free(value);
1071         return NULL;
1072     }
1073 
1074     /* Check that we have uncompressed data */
1075     /* TODO: Not supporting compressed data */
1076     if (value[header_len] != 0x04) {
1077         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1078             "The value is not uncompressed");
1079         free(value);
1080         return NULL;
1081     }
1082     header_len++;
1083 
1084     *data_len = value_len - header_len;
1085     data = malloc(*data_len);
1086     if (data == NULL) {
1087         hsm_ctx_set_error(ctx, -1, "hsm_get_key_ecdsa_value()",
1088             "Error allocating memory for data");
1089         free(value);
1090         return NULL;
1091     }
1092 
1093     memcpy(data, value + header_len, *data_len);
1094     free(value);
1095 
1096     return data;
1097 }
1098 
1099 /* returns a CK_ULONG with the key size of the given ECDSA key. The
1100  * key is not checked for type. For ECDSA, the number of bits in the
1101  * value X is the key size
1102  */
1103 static CK_ULONG
hsm_get_key_size_ecdsa(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key)1104 hsm_get_key_size_ecdsa(hsm_ctx_t *ctx, const hsm_session_t *session,
1105                      const libhsm_key_t *key)
1106 {
1107     CK_ULONG value_len;
1108     unsigned char* value = hsm_get_key_ecdsa_value(ctx, session, key, &value_len);
1109     CK_ULONG bits = 0;
1110 
1111     if (value == NULL) return 0;
1112 
1113     if( ((CK_ULONG) - 1) / (8/2) < value_len) {
1114 	    free(value);
1115 	    return 0;
1116     }
1117 
1118     /* value = x | y */
1119     bits = value_len * 8 / 2;
1120     free(value);
1121 
1122     return bits;
1123 }
1124 
1125 /* Returns the DER decoded value of the EDDSA public key
1126  * Byte string with b-bit public key in little endian order
1127  */
1128 static unsigned char *
hsm_get_key_eddsa_value(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key,CK_ULONG * data_len)1129 hsm_get_key_eddsa_value(hsm_ctx_t *ctx, const hsm_session_t *session,
1130                      const libhsm_key_t *key, CK_ULONG *data_len)
1131 {
1132     CK_RV rv;
1133     CK_BYTE_PTR value = NULL;
1134     CK_BYTE_PTR data = NULL;
1135     CK_ULONG value_len = 0;
1136     CK_ULONG header_len = 0;
1137 
1138     CK_ATTRIBUTE template[] = {
1139         {CKA_EC_POINT, NULL, 0},
1140     };
1141 
1142     if (!session || !session->module || !key || !data_len) {
1143         return NULL;
1144     }
1145 
1146     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1147                                       session->session,
1148                                       key->public_key,
1149                                       template,
1150                                       1);
1151     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
1152         return NULL;
1153     }
1154     value_len = template[0].ulValueLen;
1155 
1156     value = template[0].pValue = malloc(value_len);
1157     if (!value) {
1158         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1159             "Error allocating memory for value");
1160         return NULL;
1161     }
1162     memset(value, 0, value_len);
1163 
1164     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1165                                       session->session,
1166                                       key->public_key,
1167                                       template,
1168                                       1);
1169     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
1170         free(value);
1171         return NULL;
1172     }
1173 
1174     if(value_len != template[0].ulValueLen) {
1175         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1176            "HSM returned two different length for the same CKA_EC_POINT. " \
1177             "Abnormal behaviour detected.");
1178         free(value);
1179         return NULL;
1180     }
1181 
1182     /* Check that we have the first two octets */
1183     if (value_len < 2) {
1184         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1185             "The DER value is too short");
1186         free(value);
1187         return NULL;
1188     }
1189 
1190     /* Check the identifier octet, PKCS#11 requires octet string */
1191     if (value[0] != 0x04) {
1192         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1193             "Invalid identifier octet in the DER value");
1194         free(value);
1195         return NULL;
1196     }
1197     header_len++;
1198 
1199     /* Check the length octets, but we do not validate the length */
1200     if (value[1] <= 0x7F) {
1201         header_len++;
1202     } else if (value[1] == 0x80) {
1203         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1204             "Indefinite length is not supported in DER values");
1205         free(value);
1206         return NULL;
1207     } else {
1208         header_len++;
1209         header_len += value[1] & 0x80;
1210     }
1211 
1212     /* Check that we have more data than the header */
1213     if (value_len - header_len < 2) {
1214         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1215             "The value is too short");
1216         free(value);
1217         return NULL;
1218     }
1219 
1220     *data_len = value_len - header_len;
1221     data = malloc(*data_len);
1222     if (data == NULL) {
1223         hsm_ctx_set_error(ctx, -1, "hsm_get_key_eddsa_value()",
1224             "Error allocating memory for data");
1225         free(value);
1226         return NULL;
1227     }
1228 
1229     memcpy(data, value + header_len, *data_len);
1230     free(value);
1231 
1232     return data;
1233 }
1234 
1235 /* returns a CK_ULONG with the key size of the given EDDSA key. The
1236  * key is not checked for type. For EDDSA, the key size is the number
1237  * of bits in the curve not the size of the public key representation,
1238  * which is larger.
1239  */
1240 static CK_ULONG
hsm_get_key_size_eddsa(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key)1241 hsm_get_key_size_eddsa(hsm_ctx_t *ctx, const hsm_session_t *session,
1242                      const libhsm_key_t *key)
1243 {
1244     CK_ULONG value_len;
1245     unsigned char* value = hsm_get_key_eddsa_value(ctx, session, key, &value_len);
1246     CK_ULONG bits = 0;
1247 
1248     if (value == NULL) return 0;
1249 
1250     if( ((CK_ULONG) - 1) / 8 < value_len) {
1251         free(value);
1252         return 0;
1253     }
1254 
1255     bits = value_len * 8;
1256     free(value);
1257 
1258     switch (bits) {
1259         // ED25519 keys are 255 bits represented as 256 bits (RFC8080 section 3)
1260         case 256:
1261             bits = 255;
1262             break;
1263         // ED448 keys are 448 bits represented as 456 bits (RFC8080 section 3)
1264         case 456:
1265             bits = 448;
1266             break;
1267         default:
1268             bits = 0;
1269             break;
1270     }
1271 
1272     return bits;
1273 }
1274 
1275 /* Wrapper for specific key size functions */
1276 static CK_ULONG
hsm_get_key_size(hsm_ctx_t * ctx,const hsm_session_t * session,const libhsm_key_t * key,const unsigned long algorithm)1277 hsm_get_key_size(hsm_ctx_t *ctx, const hsm_session_t *session,
1278                  const libhsm_key_t *key, const unsigned long algorithm)
1279 {
1280     switch (algorithm) {
1281         case CKK_RSA:
1282             return hsm_get_key_size_rsa(ctx, session, key);
1283             break;
1284         case CKK_DSA:
1285             return hsm_get_key_size_dsa(ctx, session, key);
1286             break;
1287         case CKK_GOSTR3410:
1288             /* GOST public keys always have a size of 512 bits */
1289             return 512;
1290         case CKK_EC:
1291             return hsm_get_key_size_ecdsa(ctx, session, key);
1292         case CKK_EC_EDWARDS:
1293             return hsm_get_key_size_eddsa(ctx, session, key);
1294         default:
1295             return 0;
1296     }
1297 }
1298 
1299 static CK_OBJECT_HANDLE
hsm_find_object_handle_for_id(hsm_ctx_t * ctx,const hsm_session_t * session,CK_OBJECT_CLASS key_class,CK_BYTE * id,CK_ULONG id_len)1300 hsm_find_object_handle_for_id(hsm_ctx_t *ctx,
1301                               const hsm_session_t *session,
1302                               CK_OBJECT_CLASS key_class,
1303                               CK_BYTE *id,
1304                               CK_ULONG id_len)
1305 {
1306     CK_ULONG objectCount;
1307     CK_OBJECT_HANDLE object;
1308     CK_RV rv;
1309 
1310     CK_ATTRIBUTE template[] = {
1311         { CKA_CLASS, &key_class, sizeof(key_class) },
1312         { CKA_ID, id, id_len },
1313     };
1314 
1315     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
1316                                                  template, 2);
1317     if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
1318         return 0;
1319     }
1320 
1321     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
1322                                          &object,
1323                                          1,
1324                                          &objectCount);
1325     if (hsm_pkcs11_check_error(ctx, rv, "Find object")) {
1326         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
1327         hsm_pkcs11_check_error(ctx, rv, "Find objects cleanup");
1328         return 0;
1329     }
1330 
1331     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
1332     if (hsm_pkcs11_check_error(ctx, rv, "Find object final")) {
1333         return 0;
1334     }
1335 
1336     if (objectCount > 0) {
1337         return object;
1338     } else {
1339         return 0;
1340     }
1341 }
1342 
1343 /*
1344  * Parses the null-terminated string hex as hex values,
1345  * Returns allocated data that needs to be freed (or NULL on error)
1346  * len will contain the number of bytes allocated, or 0 on error
1347  */
1348 static unsigned char *
hsm_hex_parse(const char * hex,size_t * len)1349 hsm_hex_parse(const char *hex, size_t *len)
1350 {
1351     unsigned char *bytes;
1352     /* length of the hex input */
1353     size_t hex_len;
1354     size_t i;
1355 
1356     if (!len) return NULL;
1357     *len = 0;
1358 
1359     if (!hex) return NULL;
1360     hex_len = strlen(hex);
1361     if (hex_len % 2 != 0) {
1362         return NULL;
1363     }
1364 
1365     *len = hex_len / 2;
1366     bytes = malloc(*len);
1367     for (i = 0; i < *len; i++) {
1368         bytes[i] = ldns_hexdigit_to_int(hex[2*i]) * 16 +
1369                    ldns_hexdigit_to_int(hex[2*i+1]);
1370     }
1371     return bytes;
1372 }
1373 
1374 /* put a hexadecimal representation of the data from src into dst
1375  * len is the number of bytes to read from src
1376  * dst must have allocated enough space (len*2 + 1)
1377  */
1378 static void
hsm_hex_unparse(char * dst,const unsigned char * src,size_t len)1379 hsm_hex_unparse(char *dst, const unsigned char *src, size_t len)
1380 {
1381     size_t dst_len = len*2 + 1;
1382     size_t i;
1383 
1384     for (i = 0; i < len; i++) {
1385         snprintf(dst + (2*i), dst_len, "%02x", src[i]);
1386     }
1387     dst[len*2] = '\0';
1388 }
1389 
1390 /* returns an allocated byte array with the CKA_ID for the given object
1391  * len will contain the result size
1392  * returns NULL and size zero if not found in this session
1393  */
1394 static CK_BYTE *
hsm_get_id_for_object(hsm_ctx_t * ctx,const hsm_session_t * session,CK_OBJECT_HANDLE object,size_t * len)1395 hsm_get_id_for_object(hsm_ctx_t *ctx,
1396                       const hsm_session_t *session,
1397                       CK_OBJECT_HANDLE object,
1398                       size_t *len)
1399 {
1400     CK_RV rv;
1401     CK_BYTE *id = NULL;
1402 
1403     CK_ATTRIBUTE template[] = {
1404         {CKA_ID, id, 0}
1405     };
1406 
1407     /* find out the size of the id first */
1408     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1409                                       session->session,
1410                                       object,
1411                                       template,
1412                                       1);
1413     if (hsm_pkcs11_check_error(ctx, rv, "Get attr value")) {
1414         *len = 0;
1415         return NULL;
1416     }
1417 
1418     if ((CK_LONG)template[0].ulValueLen < 1) {
1419         /* No CKA_ID found, return NULL */
1420         *len = 0;
1421         return NULL;
1422     }
1423 
1424     template[0].pValue = malloc(template[0].ulValueLen);
1425     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1426                                       session->session,
1427                                       object,
1428                                       template,
1429                                       1);
1430     if (hsm_pkcs11_check_error(ctx, rv, "Get attr value 2")) {
1431         *len = 0;
1432         free(template[0].pValue);
1433         return NULL;
1434     }
1435 
1436     *len = template[0].ulValueLen;
1437     return template[0].pValue;
1438 }
1439 
1440 /* returns an libhsm_key_t object for the given *private key* object handle
1441  * the module, private key, and public key handle are set
1442  * The session needs to be free to perform a search for the public key
1443  */
1444 static libhsm_key_t *
libhsm_key_new_privkey_object_handle(hsm_ctx_t * ctx,const hsm_session_t * session,CK_OBJECT_HANDLE object)1445 libhsm_key_new_privkey_object_handle(hsm_ctx_t *ctx,
1446                                   const hsm_session_t *session,
1447                                   CK_OBJECT_HANDLE object)
1448 {
1449     libhsm_key_t *key;
1450     CK_BYTE *id;
1451     size_t len;
1452 
1453     id = hsm_get_id_for_object(ctx, session, object, &len);
1454 
1455     if (!id) return NULL;
1456 
1457     key = libhsm_key_new();
1458     key->modulename = strdup(session->module->name);
1459     key->private_key = object;
1460 
1461     key->public_key = hsm_find_object_handle_for_id(
1462                           ctx,
1463                           session,
1464                           CKO_PUBLIC_KEY,
1465                           id,
1466                           len);
1467 
1468     free(id);
1469     return key;
1470 }
1471 
1472 /* helper function to find both key counts or the keys themselves
1473  * if the argument store is 0, results are not returned; the
1474  * function will only set the count and return NULL
1475  * Otherwise, a newly allocated key array will be returned
1476  * (on error, the count will also be zero and NULL returned)
1477  */
1478 static libhsm_key_t **
hsm_list_keys_session_internal(hsm_ctx_t * ctx,const hsm_session_t * session,size_t * count,int store)1479 hsm_list_keys_session_internal(hsm_ctx_t *ctx,
1480                                const hsm_session_t *session,
1481                                size_t *count,
1482                                int store)
1483 {
1484     libhsm_key_t **keys = NULL;
1485     libhsm_key_t *key;
1486     CK_RV rv;
1487     CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
1488     CK_ATTRIBUTE template[] = {
1489         { CKA_CLASS, &key_class, sizeof(key_class) },
1490     };
1491     CK_ULONG total_count = 0;
1492     CK_ULONG objectCount = 1;
1493     /* find 100 keys at a time (and loop until there are none left) */
1494     CK_ULONG max_object_count = 100;
1495     CK_ULONG i, j;
1496     CK_OBJECT_HANDLE object[max_object_count];
1497     CK_OBJECT_HANDLE *key_handles = NULL, *new_key_handles = NULL;
1498 
1499 
1500     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
1501                                                  template, 1);
1502     if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
1503         goto err;
1504     }
1505 
1506     j = 0;
1507     while (objectCount > 0) {
1508         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
1509                                                  object,
1510                                                  max_object_count,
1511                                                  &objectCount);
1512         if (hsm_pkcs11_check_error(ctx, rv, "Find first object")) {
1513             rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
1514             hsm_pkcs11_check_error(ctx, rv, "Find objects cleanup");
1515             goto err;
1516         }
1517 
1518         total_count += objectCount;
1519         if (objectCount > 0 && store) {
1520             if (SIZE_MAX / sizeof(CK_OBJECT_HANDLE) < total_count) {
1521                 hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
1522                     "Too much object handle returned by HSM to allocate key_handles");
1523                 goto err;
1524             }
1525 
1526             new_key_handles = realloc(key_handles, total_count * sizeof(CK_OBJECT_HANDLE));
1527             if (new_key_handles != NULL) {
1528                 key_handles = new_key_handles;
1529             } else {
1530                 hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
1531                     "Error allocating memory for object handle (OOM)");
1532                 goto err;
1533             }
1534 
1535             for (i = 0; i < objectCount; i++) {
1536                 key_handles[j] = object[i];
1537                 j++;
1538             }
1539         }
1540     }
1541 
1542     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
1543     if (hsm_pkcs11_check_error(ctx, rv, "Find objects final")) {
1544         goto err;
1545     }
1546 
1547     if (store) {
1548         if(SIZE_MAX / sizeof(libhsm_key_t *) < total_count) {
1549                 hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
1550                     "Too much object handle returned by HSM to allocate keys");
1551                 goto err;
1552         }
1553 
1554         keys = malloc(total_count * sizeof(libhsm_key_t *));
1555         if(keys == NULL) {
1556                 hsm_ctx_set_error(ctx, -1, "hsm_list_keys_session_internal",
1557                     "Error allocating memory for keys table (OOM)");
1558                 goto err;
1559         }
1560 
1561         for (i = 0; i < total_count; i++) {
1562             key = libhsm_key_new_privkey_object_handle(ctx, session,
1563                                                     key_handles[i]);
1564             if(!key) {
1565 		    libhsm_key_list_free(keys, i);
1566 		    goto err;
1567 	    }
1568             keys[i] = key;
1569         }
1570     }
1571     free(key_handles);
1572 
1573     *count = total_count;
1574     return keys;
1575 
1576 err:
1577     free(key_handles);
1578     *count = 0;
1579     return NULL;
1580 }
1581 
1582 
1583 /* returns an array of all keys available to the given session
1584  *
1585  * \param session the session to find the keys in
1586  * \param count this value will contain the number of keys found
1587  *
1588  * \return the list of keys
1589  */
1590 static libhsm_key_t **
hsm_list_keys_session(hsm_ctx_t * ctx,const hsm_session_t * session,size_t * count)1591 hsm_list_keys_session(hsm_ctx_t *ctx, const hsm_session_t *session,
1592                       size_t *count)
1593 {
1594     return hsm_list_keys_session_internal(ctx, session, count, 1);
1595 }
1596 
1597 /* returns a newly allocated key structure containing the key data
1598  * for the given CKA_ID available in the session. Returns NULL if not
1599  * found
1600  */
1601 static libhsm_key_t *
hsm_find_key_by_id_session(hsm_ctx_t * ctx,const hsm_session_t * session,const unsigned char * id,size_t len)1602 hsm_find_key_by_id_session(hsm_ctx_t *ctx, const hsm_session_t *session,
1603                            const unsigned char *id, size_t len)
1604 {
1605     libhsm_key_t *key;
1606     CK_OBJECT_HANDLE private_key_handle;
1607 
1608     private_key_handle = hsm_find_object_handle_for_id(
1609                              ctx,
1610                              session,
1611                              CKO_PRIVATE_KEY,
1612                              (CK_BYTE *) id,
1613                              (CK_ULONG) len);
1614     if (private_key_handle != 0) {
1615         key = libhsm_key_new_privkey_object_handle(ctx, session,
1616                                                 private_key_handle);
1617         return key;
1618     } else {
1619         return NULL;
1620     }
1621 }
1622 
1623 /* Find a key pair by CKA_ID (as byte array)
1624 
1625 The returned key structure can be freed with free()
1626 
1627 \param context HSM context
1628 \param id CKA_ID of key to find (array of bytes)
1629 \param len number of bytes in the id
1630 \return key identifier or NULL if not found
1631 */
1632 static libhsm_key_t *
hsm_find_key_by_id_bin(hsm_ctx_t * ctx,const unsigned char * id,size_t len)1633 hsm_find_key_by_id_bin(hsm_ctx_t *ctx,
1634                        const unsigned char *id,
1635                        size_t len)
1636 {
1637     libhsm_key_t *key;
1638     unsigned int i;
1639 
1640     if (!id) return NULL;
1641 
1642     /* OPENDNSSEC-955: This procedure is mutexed to prevent a C_Login or
1643      * C_OpenSession happening at the same * time as looking up a key with
1644      * C_FindObject.  Some HSMs like SoftHSM in database backend mode don't
1645      * like this.
1646      */
1647     pthread_mutex_lock(&_hsm_ctx_mutex);
1648     for (i = 0; i < ctx->session_count; i++) {
1649         key = hsm_find_key_by_id_session(ctx, ctx->session[i], id, len);
1650         if (key) {
1651             pthread_mutex_unlock(&_hsm_ctx_mutex);
1652             return key;
1653         }
1654     }
1655     pthread_mutex_unlock(&_hsm_ctx_mutex);
1656     return NULL;
1657 }
1658 
1659 
1660 /**
1661  * returns the first session found if repository is null, otherwise
1662  * finds the session belonging to the repository with the given name
1663  * returns NULL if not found
1664  */
1665 static hsm_session_t *
hsm_find_repository_session(hsm_ctx_t * ctx,const char * repository)1666 hsm_find_repository_session(hsm_ctx_t *ctx, const char *repository)
1667 {
1668     unsigned int i;
1669     if (!repository) {
1670         for (i = 0; i < ctx->session_count; i++) {
1671             if (ctx->session[i]) {
1672                 return ctx->session[i];
1673             }
1674         }
1675     } else {
1676         for (i = 0; i < ctx->session_count; i++) {
1677             if (ctx->session[i] &&
1678                 strcmp(repository, ctx->session[i]->module->name) == 0)
1679             {
1680                 return ctx->session[i];
1681             }
1682         }
1683     }
1684 
1685     hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
1686                     "hsm_find_repository_session()",
1687                     "Can't find repository: %s", repository);
1688 
1689     return NULL;
1690 }
1691 
1692 static ldns_rdf *
hsm_get_key_rdata_rsa(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1693 hsm_get_key_rdata_rsa(hsm_ctx_t *ctx, hsm_session_t *session,
1694                   const libhsm_key_t *key)
1695 {
1696     CK_RV rv;
1697     CK_BYTE_PTR public_exponent = NULL;
1698     CK_ULONG public_exponent_len = 0;
1699     CK_BYTE_PTR modulus = NULL;
1700     CK_ULONG modulus_len = 0;
1701     unsigned long hKey = 0;
1702     unsigned char *data = NULL;
1703     size_t data_size = 0;
1704 
1705     CK_ATTRIBUTE template[] = {
1706         {CKA_PUBLIC_EXPONENT, NULL, 0},
1707         {CKA_MODULUS, NULL, 0},
1708     };
1709     ldns_rdf *rdf;
1710 
1711     if (!session || !session->module) {
1712         return NULL;
1713     }
1714 
1715     if (key->public_key) {
1716         hKey = key->public_key;
1717     } else {
1718         hKey = key->private_key;
1719     }
1720 
1721     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1722                                       session->session,
1723                                       hKey,
1724                                       template,
1725                                       2);
1726     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
1727         return NULL;
1728     }
1729     public_exponent_len = template[0].ulValueLen;
1730     modulus_len = template[1].ulValueLen;
1731 
1732     public_exponent = template[0].pValue = malloc(public_exponent_len);
1733     if (!public_exponent) {
1734         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
1735             "Error allocating memory for public exponent");
1736         return NULL;
1737     }
1738 
1739     modulus = template[1].pValue = malloc(modulus_len);
1740     if (!modulus) {
1741         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
1742             "Error allocating memory for modulus");
1743         free(public_exponent);
1744         return NULL;
1745     }
1746 
1747     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1748                                       session->session,
1749                                       hKey,
1750                                       template,
1751                                       2);
1752     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
1753         free(template[0].pValue);
1754         free(template[1].pValue);
1755         return NULL;
1756     }
1757 
1758     // Remove leading zeroes
1759     hsm_remove_leading_zeroes(public_exponent, &public_exponent_len);
1760     hsm_remove_leading_zeroes(modulus, &modulus_len);
1761 
1762     data_size = public_exponent_len + modulus_len + 1;
1763     if (public_exponent_len <= 255) {
1764         data = malloc(data_size);
1765         if (!data) {
1766             hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
1767                 "Error allocating memory for pub key rr data");
1768             free(public_exponent);
1769             free(modulus);
1770             return NULL;
1771         }
1772         data[0] = public_exponent_len;
1773         memcpy(&data[1], public_exponent, public_exponent_len);
1774         memcpy(&data[1 + public_exponent_len], modulus, modulus_len);
1775     } else if (public_exponent_len <= 65535) {
1776         data_size += 2;
1777         data = malloc(data_size);
1778         if (!data) {
1779             hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
1780                 "Error allocating memory for pub key rr data");
1781             free(public_exponent);
1782             free(modulus);
1783             return NULL;
1784         }
1785         data[0] = 0;
1786         ldns_write_uint16(&data[1], (uint16_t) public_exponent_len);
1787         memcpy(&data[3], public_exponent, public_exponent_len);
1788         memcpy(&data[3 + public_exponent_len], modulus, modulus_len);
1789     } else {
1790         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_rsa()",
1791             "Public exponent too big");
1792         free(public_exponent);
1793         free(modulus);
1794         return NULL;
1795     }
1796     rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, data_size, data);
1797     free(public_exponent);
1798     free(modulus);
1799 
1800     return rdf;
1801 }
1802 
1803 static ldns_rdf *
hsm_get_key_rdata_dsa(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1804 hsm_get_key_rdata_dsa(hsm_ctx_t *ctx, hsm_session_t *session,
1805                   const libhsm_key_t *key)
1806 {
1807     CK_RV rv;
1808     CK_BYTE_PTR prime = NULL;
1809     CK_ULONG prime_len = 0;
1810     CK_BYTE_PTR subprime = NULL;
1811     CK_ULONG subprime_len = 0;
1812     CK_BYTE_PTR base = NULL;
1813     CK_ULONG base_len = 0;
1814     CK_BYTE_PTR value = NULL;
1815     CK_ULONG value_len = 0;
1816     unsigned char *data = NULL;
1817     size_t data_size = 0;
1818 
1819     CK_ATTRIBUTE template[] = {
1820         {CKA_PRIME, NULL, 0},
1821         {CKA_SUBPRIME, NULL, 0},
1822         {CKA_BASE, NULL, 0},
1823         {CKA_VALUE, NULL, 0},
1824     };
1825     ldns_rdf *rdf;
1826 
1827     if (!session || !session->module) {
1828         return NULL;
1829     }
1830 
1831     /* DSA needs the public key compared with RSA */
1832     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1833                                       session->session,
1834                                       key->public_key,
1835                                       template,
1836                                       4);
1837     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
1838         return NULL;
1839     }
1840     prime_len = template[0].ulValueLen;
1841     subprime_len = template[1].ulValueLen;
1842     base_len = template[2].ulValueLen;
1843     value_len = template[3].ulValueLen;
1844 
1845     prime = template[0].pValue = malloc(prime_len);
1846     if (!prime) {
1847         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_dsa()",
1848             "Error allocating memory for prime");
1849         return NULL;
1850     }
1851 
1852     subprime = template[1].pValue = malloc(subprime_len);
1853     if (!subprime) {
1854         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_dsa()",
1855             "Error allocating memory for subprime");
1856         free(prime);
1857         return NULL;
1858     }
1859 
1860     base = template[2].pValue = malloc(base_len);
1861     if (!base) {
1862         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_dsa()",
1863             "Error allocating memory for base");
1864         free(prime);
1865         free(subprime);
1866         return NULL;
1867     }
1868 
1869     value = template[3].pValue = malloc(value_len);
1870     if (!value) {
1871         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_dsa()",
1872             "Error allocating memory for value");
1873         free(prime);
1874         free(subprime);
1875         free(base);
1876         return NULL;
1877     }
1878 
1879     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1880                                       session->session,
1881                                       key->public_key,
1882                                       template,
1883                                       4);
1884     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
1885         free(prime);
1886         free(subprime);
1887         free(base);
1888         free(value);
1889         return NULL;
1890     }
1891 
1892     data_size = prime_len + subprime_len + base_len + value_len + 1;
1893     data = malloc(data_size);
1894     if (!data) {
1895         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_dsa()",
1896             "Error allocating memory for pub key rr data");
1897         free(prime);
1898         free(subprime);
1899         free(base);
1900         free(value);
1901         return NULL;
1902     }
1903     data[0] = (prime_len - 64) / 8;
1904     memcpy(&data[1], subprime, subprime_len);
1905     memcpy(&data[1 + subprime_len], prime, prime_len);
1906     memcpy(&data[1 + subprime_len + prime_len], base, base_len);
1907     memcpy(&data[1 + subprime_len + prime_len + base_len], value, value_len);
1908 
1909     rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, data_size, data);
1910     free(prime);
1911     free(subprime);
1912     free(base);
1913     free(value);
1914 
1915     return rdf;
1916 }
1917 
1918 static ldns_rdf *
hsm_get_key_rdata_gost(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1919 hsm_get_key_rdata_gost(hsm_ctx_t *ctx, hsm_session_t *session,
1920                   const libhsm_key_t *key)
1921 {
1922     CK_RV rv;
1923     CK_BYTE_PTR value = NULL;
1924     CK_ULONG value_len = 0;
1925 
1926     CK_ATTRIBUTE template[] = {
1927         {CKA_VALUE, NULL, 0},
1928     };
1929     ldns_rdf *rdf;
1930 
1931     if (!session || !session->module) {
1932         return NULL;
1933     }
1934 
1935     /* GOST needs the public key compared with RSA */
1936     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1937                                       session->session,
1938                                       key->public_key,
1939                                       template,
1940                                       1);
1941     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
1942         return NULL;
1943     }
1944     value_len = template[0].ulValueLen;
1945 
1946     value = template[0].pValue = malloc(value_len);
1947     if (!value) {
1948         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata_gost()",
1949             "Error allocating memory for value");
1950         return NULL;
1951     }
1952 
1953     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
1954                                       session->session,
1955                                       key->public_key,
1956                                       template,
1957                                       1);
1958     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
1959         free(value);
1960         return NULL;
1961     }
1962 
1963     rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
1964     return rdf;
1965 }
1966 
1967 static ldns_rdf *
hsm_get_key_rdata_ecdsa(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1968 hsm_get_key_rdata_ecdsa(hsm_ctx_t *ctx, hsm_session_t *session,
1969                   const libhsm_key_t *key)
1970 {
1971     CK_ULONG value_len;
1972     unsigned char* value = hsm_get_key_ecdsa_value(ctx, session, key, &value_len);
1973 
1974     if (value == NULL) return NULL;
1975 
1976     ldns_rdf *rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
1977 
1978     return rdf;
1979 }
1980 
1981 static ldns_rdf *
hsm_get_key_rdata_eddsa(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1982 hsm_get_key_rdata_eddsa(hsm_ctx_t *ctx, hsm_session_t *session,
1983                   const libhsm_key_t *key)
1984 {
1985     CK_ULONG value_len;
1986     unsigned char* value = hsm_get_key_eddsa_value(ctx, session, key, &value_len);
1987 
1988     if (value == NULL) return NULL;
1989 
1990     ldns_rdf *rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, value_len, value);
1991 
1992     return rdf;
1993 }
1994 
1995 static ldns_rdf *
hsm_get_key_rdata(hsm_ctx_t * ctx,hsm_session_t * session,const libhsm_key_t * key)1996 hsm_get_key_rdata(hsm_ctx_t *ctx, hsm_session_t *session,
1997                   const libhsm_key_t *key)
1998 {
1999     switch (hsm_get_key_algorithm(ctx, session, key)) {
2000         case CKK_RSA:
2001             return hsm_get_key_rdata_rsa(ctx, session, key);
2002             break;
2003         case CKK_DSA:
2004             return hsm_get_key_rdata_dsa(ctx, session, key);
2005             break;
2006         case CKK_GOSTR3410:
2007             return hsm_get_key_rdata_gost(ctx, session, key);
2008             break;
2009         case CKK_EC:
2010             return hsm_get_key_rdata_ecdsa(ctx, session, key);
2011         case CKK_EC_EDWARDS:
2012             return hsm_get_key_rdata_eddsa(ctx, session, key);
2013         default:
2014             return 0;
2015     }
2016 }
2017 
2018 /* this function allocates memory for the mechanism ID and enough room
2019  * to leave the upcoming digest data. It fills in the mechanism id
2020  * use with care. The returned data must be free'd by the caller.
2021  * Only used by RSA PKCS. */
2022 static CK_BYTE *
hsm_create_prefix(CK_ULONG digest_len,ldns_algorithm algorithm,CK_ULONG * data_size)2023 hsm_create_prefix(CK_ULONG digest_len,
2024                   ldns_algorithm algorithm,
2025                   CK_ULONG *data_size)
2026 {
2027     CK_BYTE *data;
2028     const CK_BYTE RSA_MD5_ID[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };
2029     const CK_BYTE RSA_SHA1_ID[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 };
2030     const CK_BYTE RSA_SHA256_ID[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
2031     const CK_BYTE RSA_SHA512_ID[] = { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 };
2032 
2033     switch((ldns_signing_algorithm)algorithm) {
2034         case LDNS_SIGN_RSAMD5:
2035             *data_size = sizeof(RSA_MD5_ID) + digest_len;
2036             data = malloc(*data_size);
2037             memcpy(data, RSA_MD5_ID, sizeof(RSA_MD5_ID));
2038             break;
2039         case LDNS_SIGN_RSASHA1:
2040         case LDNS_SIGN_RSASHA1_NSEC3:
2041             *data_size = sizeof(RSA_SHA1_ID) + digest_len;
2042             data = malloc(*data_size);
2043             memcpy(data, RSA_SHA1_ID, sizeof(RSA_SHA1_ID));
2044             break;
2045 	case LDNS_SIGN_RSASHA256:
2046             *data_size = sizeof(RSA_SHA256_ID) + digest_len;
2047             data = malloc(*data_size);
2048             memcpy(data, RSA_SHA256_ID, sizeof(RSA_SHA256_ID));
2049             break;
2050 	case LDNS_SIGN_RSASHA512:
2051             *data_size = sizeof(RSA_SHA512_ID) + digest_len;
2052             data = malloc(*data_size);
2053             memcpy(data, RSA_SHA512_ID, sizeof(RSA_SHA512_ID));
2054             break;
2055         case LDNS_SIGN_DSA:
2056         case LDNS_SIGN_DSA_NSEC3:
2057         case LDNS_SIGN_ECC_GOST:
2058         case LDNS_SIGN_ECDSAP256SHA256:
2059         case LDNS_SIGN_ECDSAP384SHA384:
2060             *data_size = digest_len;
2061             data = malloc(*data_size);
2062             break;
2063         default:
2064             return NULL;
2065     }
2066     return data;
2067 }
2068 
2069 static CK_BYTE *
hsm_digest_through_hsm(hsm_ctx_t * ctx,hsm_session_t * session,CK_MECHANISM_TYPE mechanism_type,CK_ULONG digest_len,ldns_buffer * sign_buf)2070 hsm_digest_through_hsm(hsm_ctx_t *ctx,
2071                        hsm_session_t *session,
2072                        CK_MECHANISM_TYPE mechanism_type,
2073                        CK_ULONG digest_len,
2074                        ldns_buffer *sign_buf)
2075 {
2076     CK_MECHANISM digest_mechanism;
2077     CK_BYTE *digest;
2078     CK_RV rv;
2079 
2080     digest_mechanism.pParameter = NULL;
2081     digest_mechanism.ulParameterLen = 0;
2082     digest_mechanism.mechanism = mechanism_type;
2083     digest = malloc(digest_len);
2084     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DigestInit(session->session,
2085                                                  &digest_mechanism);
2086     if (hsm_pkcs11_check_error(ctx, rv, "HSM digest init")) {
2087         free(digest);
2088         return NULL;
2089     }
2090 
2091     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Digest(session->session,
2092                                         ldns_buffer_begin(sign_buf),
2093                                         ldns_buffer_position(sign_buf),
2094                                         digest,
2095                                         &digest_len);
2096     if (hsm_pkcs11_check_error(ctx, rv, "HSM digest")) {
2097         free(digest);
2098         return NULL;
2099     }
2100     return digest;
2101 }
2102 
2103 static ldns_rdf *
hsm_sign_buffer(hsm_ctx_t * ctx,ldns_buffer * sign_buf,const libhsm_key_t * key,ldns_algorithm algorithm)2104 hsm_sign_buffer(hsm_ctx_t *ctx,
2105                 ldns_buffer *sign_buf,
2106                 const libhsm_key_t *key,
2107                 ldns_algorithm algorithm)
2108 {
2109     CK_RV rv;
2110     CK_ULONG signatureLen = HSM_MAX_SIGNATURE_LENGTH;
2111     CK_BYTE signature[HSM_MAX_SIGNATURE_LENGTH];
2112     CK_MECHANISM sign_mechanism;
2113 
2114     int data_direct = 0; // don't pre-create digest, use data directly
2115 
2116     ldns_rdf *sig_rdf;
2117     CK_BYTE *digest = NULL;
2118     CK_ULONG digest_len = 0;
2119 
2120     CK_BYTE *data = NULL;
2121     CK_ULONG data_len = 0;
2122 
2123     hsm_session_t *session;
2124 
2125     session = hsm_find_key_session(ctx, key);
2126     if (!session) return NULL;
2127 
2128     /* some HSMs don't really handle CKM_SHA1_RSA_PKCS well, so
2129      * we'll do the hashing manually */
2130     /* When adding algorithms, remember there is another switch below */
2131     switch ((ldns_signing_algorithm)algorithm) {
2132         case LDNS_SIGN_RSAMD5:
2133             digest_len = 16;
2134             digest = hsm_digest_through_hsm(ctx, session,
2135                                             CKM_MD5, digest_len,
2136                                             sign_buf);
2137             break;
2138         case LDNS_SIGN_RSASHA1:
2139         case LDNS_SIGN_RSASHA1_NSEC3:
2140         case LDNS_SIGN_DSA:
2141         case LDNS_SIGN_DSA_NSEC3:
2142             digest_len = LDNS_SHA1_DIGEST_LENGTH;
2143             digest = malloc(digest_len);
2144             digest = ldns_sha1(ldns_buffer_begin(sign_buf),
2145                                ldns_buffer_position(sign_buf),
2146                                digest);
2147             break;
2148 
2149         case LDNS_SIGN_RSASHA256:
2150         case LDNS_SIGN_ECDSAP256SHA256:
2151             digest_len = LDNS_SHA256_DIGEST_LENGTH;
2152             digest = malloc(digest_len);
2153             digest = ldns_sha256(ldns_buffer_begin(sign_buf),
2154                                  ldns_buffer_position(sign_buf),
2155                                  digest);
2156             break;
2157         case LDNS_SIGN_ECDSAP384SHA384:
2158             digest_len = LDNS_SHA384_DIGEST_LENGTH;
2159             digest = malloc(digest_len);
2160             digest = ldns_sha384(ldns_buffer_begin(sign_buf),
2161                                  ldns_buffer_position(sign_buf),
2162                                  digest);
2163             break;
2164         case LDNS_SIGN_RSASHA512:
2165             digest_len = LDNS_SHA512_DIGEST_LENGTH;
2166             digest = malloc(digest_len);
2167             digest = ldns_sha512(ldns_buffer_begin(sign_buf),
2168                                  ldns_buffer_position(sign_buf),
2169                                  digest);
2170             break;
2171         case LDNS_SIGN_ECC_GOST:
2172             digest_len = 32;
2173             digest = hsm_digest_through_hsm(ctx, session,
2174                                             CKM_GOSTR3411, digest_len,
2175                                             sign_buf);
2176             break;
2177 #if (LDNS_REVISION >= ((1<<16)|(7<<8)|(0)))
2178         case LDNS_SIGN_ED25519:
2179             data_direct = 1;
2180             break;
2181         case LDNS_SIGN_ED448:
2182             data_direct = 1;
2183             break;
2184 #endif
2185         default:
2186             /* log error? or should we not even get here for
2187              * unsupported algorithms? */
2188             return NULL;
2189     }
2190 
2191     if (!data_direct && !digest) {
2192         return NULL;
2193     }
2194 
2195     if (data_direct) {
2196         data = ldns_buffer_begin(sign_buf);
2197         data_len = ldns_buffer_position(sign_buf);
2198     } else {
2199         /* CKM_RSA_PKCS does the padding, but cannot know the identifier
2200          * prefix, so we need to add that ourselves.
2201          * The other algorithms will just get the digest buffer returned. */
2202         data = hsm_create_prefix(digest_len, algorithm, &data_len);
2203         memcpy(data + data_len - digest_len, digest, digest_len);
2204     }
2205 
2206     sign_mechanism.pParameter = NULL;
2207     sign_mechanism.ulParameterLen = 0;
2208     switch((ldns_signing_algorithm)algorithm) {
2209         case LDNS_SIGN_RSAMD5:
2210         case LDNS_SIGN_RSASHA1:
2211         case LDNS_SIGN_RSASHA1_NSEC3:
2212         case LDNS_SIGN_RSASHA256:
2213         case LDNS_SIGN_RSASHA512:
2214             sign_mechanism.mechanism = CKM_RSA_PKCS;
2215             break;
2216         case LDNS_SIGN_DSA:
2217         case LDNS_SIGN_DSA_NSEC3:
2218             sign_mechanism.mechanism = CKM_DSA;
2219             break;
2220         case LDNS_SIGN_ECC_GOST:
2221             sign_mechanism.mechanism = CKM_GOSTR3410;
2222             break;
2223         case LDNS_SIGN_ECDSAP256SHA256:
2224         case LDNS_SIGN_ECDSAP384SHA384:
2225             sign_mechanism.mechanism = CKM_ECDSA;
2226             break;
2227 #if (LDNS_REVISION >= ((1<<16)|(7<<8)|(0)))
2228         case LDNS_SIGN_ED25519:
2229             sign_mechanism.mechanism = CKM_EDDSA;
2230             break;
2231         case LDNS_SIGN_ED448:
2232             sign_mechanism.mechanism = CKM_EDDSA;
2233             break;
2234 #endif
2235         default:
2236             /* log error? or should we not even get here for
2237              * unsupported algorithms? */
2238             free(data);
2239             free(digest);
2240             return NULL;
2241     }
2242 
2243     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_SignInit(
2244                                       session->session,
2245                                       &sign_mechanism,
2246                                       key->private_key);
2247     if (hsm_pkcs11_check_error(ctx, rv, "sign init")) {
2248         if (!data_direct) {
2249             free(data);
2250             free(digest);
2251         }
2252         return NULL;
2253     }
2254 
2255     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Sign(session->session, data, data_len,
2256                                       signature,
2257                                       &signatureLen);
2258     if (hsm_pkcs11_check_error(ctx, rv, "sign final")) {
2259         if (!data_direct) {
2260             free(data);
2261             free(digest);
2262         }
2263         return NULL;
2264     }
2265 
2266     sig_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
2267                                     signatureLen,
2268                                     signature);
2269 
2270     if (!data_direct) {
2271         free(data);
2272         free(digest);
2273     }
2274 
2275     return sig_rdf;
2276 
2277 }
2278 
2279 static int
hsm_dname_is_wildcard(const ldns_rdf * dname)2280 hsm_dname_is_wildcard(const ldns_rdf* dname)
2281 {
2282     return ( ldns_dname_label_count(dname) > 0 &&
2283              ldns_rdf_data(dname)[0] == 1 &&
2284              ldns_rdf_data(dname)[1] == '*');
2285 }
2286 
2287 static ldns_rr *
hsm_create_empty_rrsig(const ldns_rr_list * rrset,const hsm_sign_params_t * sign_params)2288 hsm_create_empty_rrsig(const ldns_rr_list *rrset,
2289                        const hsm_sign_params_t *sign_params)
2290 {
2291     ldns_rr *rrsig;
2292     uint32_t orig_ttl;
2293     uint32_t orig_class;
2294     time_t now;
2295     uint8_t label_count;
2296 
2297     label_count = ldns_dname_label_count(
2298                        ldns_rr_owner(ldns_rr_list_rr(rrset, 0)));
2299     /* RFC 4035 section 2.2: dnssec label length and wildcards */
2300     if (hsm_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0)))) {
2301         label_count--;
2302     }
2303 
2304     rrsig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
2305 
2306     /* set the type on the new signature */
2307     orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));
2308     orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
2309 
2310     ldns_rr_set_class(rrsig, orig_class);
2311     ldns_rr_set_ttl(rrsig, orig_ttl);
2312     ldns_rr_set_owner(rrsig,
2313               ldns_rdf_clone(
2314                    ldns_rr_owner(
2315                     ldns_rr_list_rr(rrset,
2316                             0))));
2317 
2318     /* fill in what we know of the signature */
2319 
2320     /* set the orig_ttl */
2321     (void)ldns_rr_rrsig_set_origttl(
2322            rrsig,
2323            ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
2324                      orig_ttl));
2325     /* the signers name */
2326     (void)ldns_rr_rrsig_set_signame(
2327                rrsig,
2328                ldns_rdf_clone(sign_params->owner));
2329     /* label count - get it from the first rr in the rr_list */
2330     (void)ldns_rr_rrsig_set_labels(
2331             rrsig,
2332             ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
2333                                  label_count));
2334     /* inception, expiration */
2335     now = time_now();
2336     if (sign_params->inception != 0) {
2337         (void)ldns_rr_rrsig_set_inception(
2338                 rrsig,
2339                 ldns_native2rdf_int32(
2340                     LDNS_RDF_TYPE_TIME,
2341                     sign_params->inception));
2342     } else {
2343         (void)ldns_rr_rrsig_set_inception(
2344                 rrsig,
2345                 ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
2346     }
2347     if (sign_params->expiration != 0) {
2348         (void)ldns_rr_rrsig_set_expiration(
2349                 rrsig,
2350                 ldns_native2rdf_int32(
2351                     LDNS_RDF_TYPE_TIME,
2352                     sign_params->expiration));
2353     } else {
2354         (void)ldns_rr_rrsig_set_expiration(
2355                  rrsig,
2356                 ldns_native2rdf_int32(
2357                     LDNS_RDF_TYPE_TIME,
2358                     now + LDNS_DEFAULT_EXP_TIME));
2359     }
2360 
2361     (void)ldns_rr_rrsig_set_keytag(
2362            rrsig,
2363            ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
2364                                  sign_params->keytag));
2365 
2366     (void)ldns_rr_rrsig_set_algorithm(
2367             rrsig,
2368             ldns_native2rdf_int8(
2369                 LDNS_RDF_TYPE_ALG,
2370                 sign_params->algorithm));
2371 
2372     (void)ldns_rr_rrsig_set_typecovered(
2373             rrsig,
2374             ldns_native2rdf_int16(
2375                 LDNS_RDF_TYPE_TYPE,
2376                 ldns_rr_get_type(ldns_rr_list_rr(rrset,
2377                                                  0))));
2378 
2379     return rrsig;
2380 }
2381 
2382 
2383 /*
2384  *  API functions
2385  */
2386 
2387 int
hsm_open2(hsm_repository_t * rlist,char * (pin_callback)(unsigned int,const char *,unsigned int))2388 hsm_open2(hsm_repository_t* rlist,
2389          char *(pin_callback)(unsigned int, const char *, unsigned int))
2390 {
2391     hsm_config_t module_config;
2392     hsm_repository_t* repo = NULL;
2393     char* module_pin = NULL;
2394     int result = HSM_OK;
2395     int tries;
2396     int repositories = 0;
2397 
2398     pthread_mutex_lock(&_hsm_ctx_mutex);
2399     /* create an internal context with an attached session for each
2400      * configured HSM. */
2401     if ((_hsm_ctx = hsm_ctx_new())) {
2402         keycache_create(_hsm_ctx);
2403     }
2404 
2405     repo = rlist;
2406     while (repo) {
2407         hsm_config_default(&module_config);
2408         module_config.use_pubkey = repo->use_pubkey;
2409         module_config.allow_extract = repo->allow_extract;
2410         if (repo->name && repo->module && repo->tokenlabel) {
2411             if (repo->pin) {
2412                 result = hsm_attach(repo->name, repo->tokenlabel,
2413                     repo->module, repo->pin, &module_config);
2414             } else {
2415                 if (pin_callback) {
2416                     result = HSM_PIN_INCORRECT;
2417                     tries = 0;
2418                     while (result == HSM_PIN_INCORRECT && tries < 3) {
2419                         module_pin = pin_callback(_hsm_ctx->session_count,
2420                             repo->name, tries?HSM_PIN_RETRY:HSM_PIN_FIRST);
2421                         if (module_pin == NULL) break;
2422                         result = hsm_attach(repo->name, repo->tokenlabel,
2423                             repo->module, module_pin, &module_config);
2424                         if (result == HSM_OK) {
2425                             pin_callback(_hsm_ctx->session_count - 1,
2426                                 repo->name, HSM_PIN_SAVE);
2427                         }
2428                         memset(module_pin, 0, strlen(module_pin));
2429                         tries++;
2430                     }
2431                 } else {
2432                     /* no pin, no callback */
2433                     hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_open2()",
2434                         "No pin or callback function");
2435                     result = HSM_ERROR;
2436                 }
2437             }
2438             if (result != HSM_OK) {
2439                 break;
2440             }
2441             repositories++;
2442         }
2443         repo = repo->next;
2444     }
2445     if (result == HSM_OK && repositories == 0) {
2446         hsm_ctx_set_error(_hsm_ctx, HSM_NO_REPOSITORIES, "hsm_open2()",
2447             "No repositories found");
2448         result = HSM_NO_REPOSITORIES;
2449     }
2450     pthread_mutex_unlock(&_hsm_ctx_mutex);
2451     return result;
2452 }
2453 
2454 void
hsm_close()2455 hsm_close()
2456 {
2457     pthread_mutex_lock(&_hsm_ctx_mutex);
2458     keycache_destroy(_hsm_ctx);
2459     hsm_ctx_close(_hsm_ctx, 1);
2460     _hsm_ctx = NULL;
2461     pthread_mutex_unlock(&_hsm_ctx_mutex);
2462 }
2463 
2464 hsm_ctx_t *
hsm_create_context()2465 hsm_create_context()
2466 {
2467     hsm_ctx_t* newctx;
2468     pthread_mutex_lock(&_hsm_ctx_mutex);
2469     newctx = hsm_ctx_clone(_hsm_ctx);
2470     pthread_mutex_unlock(&_hsm_ctx_mutex);
2471     return newctx;
2472 }
2473 
2474 int
hsm_check_context()2475 hsm_check_context()
2476 {
2477     unsigned int i;
2478     hsm_session_t *session;
2479     CK_SESSION_INFO info;
2480     CK_RV rv;
2481     CK_SESSION_HANDLE session_handle;
2482     hsm_ctx_t *ctx;
2483 
2484     pthread_mutex_lock(&_hsm_ctx_mutex);
2485     ctx = _hsm_ctx;
2486 
2487     for (i = 0; i < ctx->session_count; i++) {
2488         session = ctx->session[i];
2489         if (session == NULL) continue;
2490 
2491         /* Get session info */
2492         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetSessionInfo(
2493                                         session->session,
2494                                         &info);
2495         if (hsm_pkcs11_check_error(ctx, rv, "get session info")) {
2496             pthread_mutex_unlock(&_hsm_ctx_mutex);
2497             return HSM_ERROR;
2498         }
2499 
2500         /* Check session info */
2501         if (info.state != CKS_RW_USER_FUNCTIONS) {
2502             hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_check_context()",
2503                               "Session not logged in");
2504             pthread_mutex_unlock(&_hsm_ctx_mutex);
2505             return HSM_ERROR;
2506         }
2507 
2508         /* Try open and close a session with the token */
2509         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_OpenSession(info.slotID,
2510                                         CKF_SERIAL_SESSION | CKF_RW_SESSION,
2511                                         NULL,
2512                                         NULL,
2513                                         &session_handle);
2514         if (hsm_pkcs11_check_error(ctx, rv, "test open session")) {
2515             pthread_mutex_unlock(&_hsm_ctx_mutex);
2516             return HSM_ERROR;
2517         }
2518         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session_handle);
2519         if (hsm_pkcs11_check_error(ctx, rv, "test close session")) {
2520             pthread_mutex_unlock(&_hsm_ctx_mutex);
2521             return HSM_ERROR;
2522         }
2523     }
2524 
2525     pthread_mutex_unlock(&_hsm_ctx_mutex);
2526     return HSM_OK;
2527 }
2528 
2529 void
hsm_destroy_context(hsm_ctx_t * ctx)2530 hsm_destroy_context(hsm_ctx_t *ctx)
2531 {
2532     hsm_ctx_close(ctx, 0);
2533 }
2534 
2535 /**
2536  * Returns an allocated hsm_sign_params_t with some defaults
2537  */
2538 hsm_sign_params_t *
hsm_sign_params_new()2539 hsm_sign_params_new()
2540 {
2541     hsm_sign_params_t *params;
2542     params = malloc(sizeof(hsm_sign_params_t));
2543     if (!params) {
2544         return NULL;
2545     }
2546     params->algorithm = LDNS_RSASHA256;
2547     params->flags = LDNS_KEY_ZONE_KEY;
2548     params->inception = 0;
2549     params->expiration = 0;
2550     params->keytag = 0;
2551     params->owner = NULL;
2552     return params;
2553 }
2554 
2555 void
hsm_sign_params_free(hsm_sign_params_t * params)2556 hsm_sign_params_free(hsm_sign_params_t *params)
2557 {
2558     if (params) {
2559         if (params->owner) ldns_rdf_deep_free(params->owner);
2560         free(params);
2561     }
2562 }
2563 
2564 void
libhsm_key_free(libhsm_key_t * key)2565 libhsm_key_free(libhsm_key_t *key)
2566 {
2567     free(key->modulename);
2568     free(key);
2569 }
2570 
2571 libhsm_key_t **
hsm_list_keys(hsm_ctx_t * ctx,size_t * count)2572 hsm_list_keys(hsm_ctx_t *ctx, size_t *count)
2573 {
2574     libhsm_key_t **keys = NULL;
2575     size_t key_count = 0;
2576     size_t cur_key_count;
2577     libhsm_key_t **session_keys;
2578     unsigned int i, j;
2579 
2580     for (i = 0; i < ctx->session_count; i++) {
2581         session_keys = hsm_list_keys_session(ctx, ctx->session[i],
2582                                              &cur_key_count);
2583         keys = realloc(keys,
2584                        (key_count + cur_key_count) * sizeof(libhsm_key_t *));
2585         for (j = 0; j < cur_key_count; j++) {
2586             keys[key_count + j] = session_keys[j];
2587         }
2588         key_count += cur_key_count;
2589         free(session_keys);
2590     }
2591     if (count) {
2592         *count = key_count;
2593     }
2594     return keys;
2595 }
2596 
2597 libhsm_key_t **
hsm_list_keys_repository(hsm_ctx_t * ctx,size_t * count,const char * repository)2598 hsm_list_keys_repository(hsm_ctx_t *ctx,
2599                          size_t *count,
2600                          const char *repository)
2601 {
2602     hsm_session_t *session;
2603 
2604     if (!repository) return NULL;
2605 
2606     session = hsm_find_repository_session(ctx, repository);
2607     if (!session) {
2608         *count = 0;
2609         return NULL;
2610     }
2611     return hsm_list_keys_session(ctx, session, count);
2612 }
2613 
2614 libhsm_key_t *
hsm_find_key_by_id(hsm_ctx_t * ctx,const char * id)2615 hsm_find_key_by_id(hsm_ctx_t *ctx, const char *id)
2616 {
2617     unsigned char *id_bytes;
2618     size_t len;
2619     libhsm_key_t *key;
2620 
2621     id_bytes = hsm_hex_parse(id, &len);
2622 
2623     if (!id_bytes) return NULL;
2624 
2625     key = hsm_find_key_by_id_bin(ctx, id_bytes, len);
2626     free(id_bytes);
2627     return key;
2628 }
2629 
2630 static void
generate_unique_id(hsm_ctx_t * ctx,unsigned char * buf,size_t bufsize)2631 generate_unique_id(hsm_ctx_t *ctx, unsigned char *buf, size_t bufsize)
2632 {
2633     libhsm_key_t *key;
2634     /* check whether this key doesn't happen to exist already */
2635     hsm_random_buffer(ctx, buf, bufsize);
2636     while ((key = hsm_find_key_by_id_bin(ctx, buf, bufsize))) {
2637 	libhsm_key_free(key);
2638 	hsm_random_buffer(ctx, buf, bufsize);
2639     }
2640 
2641 }
2642 
2643 libhsm_key_t *
hsm_generate_rsa_key(hsm_ctx_t * ctx,const char * repository,unsigned long keysize)2644 hsm_generate_rsa_key(hsm_ctx_t *ctx,
2645                      const char *repository,
2646                      unsigned long keysize)
2647 {
2648     libhsm_key_t *new_key;
2649     hsm_session_t *session;
2650     /* ids we create are 16 bytes of data */
2651     unsigned char id[16];
2652     /* that's 33 bytes in string (16*2 + 1 for \0) */
2653     char id_str[33];
2654     CK_RV rv;
2655     CK_OBJECT_HANDLE publicKey, privateKey;
2656     CK_KEY_TYPE keyType = CKK_RSA;
2657     CK_MECHANISM mechanism = {
2658         CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
2659     };
2660     CK_BYTE publicExponent[] = { 1, 0, 1 };
2661     CK_BBOOL ctrue = CK_TRUE;
2662     CK_BBOOL cfalse = CK_FALSE;
2663     CK_BBOOL ctoken = CK_TRUE;
2664     CK_BBOOL cextractable = CK_FALSE;
2665 
2666     session = hsm_find_repository_session(ctx, repository);
2667     if (!session) return NULL;
2668     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
2669 
2670     generate_unique_id(ctx, id, 16);
2671 
2672     /* the CKA_LABEL will contain a hexadecimal string representation
2673      * of the id */
2674     hsm_hex_unparse(id_str, id, 16);
2675 
2676     if (! session->module->config->use_pubkey) {
2677         ctoken = CK_FALSE;
2678     }
2679 
2680     CK_ATTRIBUTE publicKeyTemplate[] = {
2681         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)   },
2682         { CKA_ID,                  id,       16               },
2683         { CKA_KEY_TYPE,            &keyType, sizeof(keyType)  },
2684         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)    },
2685         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)   },
2686         { CKA_WRAP,                &cfalse,  sizeof(cfalse)   },
2687         { CKA_TOKEN,               &ctoken,  sizeof(ctoken)   },
2688         { CKA_MODULUS_BITS,        &keysize, sizeof(keysize)  },
2689         { CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
2690     };
2691 
2692     CK_ATTRIBUTE privateKeyTemplate[] = {
2693         { CKA_LABEL,(CK_UTF8CHAR *) id_str, strlen (id_str) },
2694         { CKA_ID,          id,       16                     },
2695         { CKA_KEY_TYPE,    &keyType, sizeof(keyType) },
2696         { CKA_SIGN,        &ctrue,   sizeof (ctrue) },
2697         { CKA_DECRYPT,     &cfalse,  sizeof (cfalse) },
2698         { CKA_UNWRAP,      &cfalse,  sizeof (cfalse) },
2699         { CKA_SENSITIVE,   &ctrue,   sizeof (ctrue) },
2700         { CKA_TOKEN,       &ctrue,   sizeof (ctrue)  },
2701         { CKA_PRIVATE,     &ctrue,   sizeof (ctrue)  },
2702         { CKA_EXTRACTABLE, &cextractable,  sizeof (cextractable) }
2703     };
2704 
2705     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
2706                                                  &mechanism,
2707                                                  publicKeyTemplate, 9,
2708                                                  privateKeyTemplate, 10,
2709                                                  &publicKey,
2710                                                  &privateKey);
2711     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
2712         return NULL;
2713     }
2714 
2715     new_key = libhsm_key_new();
2716     new_key->modulename = strdup(session->module->name);
2717 
2718     if (session->module->config->use_pubkey) {
2719         new_key->public_key = publicKey;
2720     } else {
2721         /* Destroy the object directly in order to optimize storage in HSM */
2722         /* Ignore return value, it is just a session object and will be destroyed later */
2723         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session, publicKey);
2724         new_key->public_key = 0;
2725     }
2726 
2727     new_key->private_key = privateKey;
2728     return new_key;
2729 }
2730 
2731 libhsm_key_t *
hsm_generate_dsa_key(hsm_ctx_t * ctx,const char * repository,unsigned long keysize)2732 hsm_generate_dsa_key(hsm_ctx_t *ctx,
2733                      const char *repository,
2734                      unsigned long keysize)
2735 {
2736     CK_RV rv;
2737     libhsm_key_t *new_key;
2738     hsm_session_t *session;
2739     CK_OBJECT_HANDLE domainPar, publicKey, privateKey;
2740     CK_BBOOL ctrue = CK_TRUE;
2741     CK_BBOOL cfalse = CK_FALSE;
2742     CK_BBOOL cextractable = CK_FALSE;
2743 
2744     /* ids we create are 16 bytes of data */
2745     unsigned char id[16];
2746     /* that's 33 bytes in string (16*2 + 1 for \0) */
2747     char id_str[33];
2748 
2749     session = hsm_find_repository_session(ctx, repository);
2750     if (!session) return NULL;
2751     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
2752 
2753     generate_unique_id(ctx, id, 16);
2754 
2755     /* the CKA_LABEL will contain a hexadecimal string representation
2756      * of the id */
2757     hsm_hex_unparse(id_str, id, 16);
2758 
2759     CK_KEY_TYPE keyType = CKK_DSA;
2760     CK_MECHANISM mechanism1 = {
2761         CKM_DSA_PARAMETER_GEN, NULL_PTR, 0
2762     };
2763     CK_MECHANISM mechanism2 = {
2764         CKM_DSA_KEY_PAIR_GEN, NULL_PTR, 0
2765     };
2766 
2767     /* The maximum size for DSA in DNSSEC */
2768     CK_BYTE dsa_p[128];
2769     CK_BYTE dsa_q[20];
2770     CK_BYTE dsa_g[128];
2771 
2772     CK_ATTRIBUTE domainTemplate[] = {
2773         { CKA_PRIME_BITS,          &keysize, sizeof(keysize) }
2774     };
2775 
2776     CK_ATTRIBUTE publicKeyTemplate[] = {
2777         { CKA_PRIME,               dsa_p,    sizeof(dsa_p)   },
2778         { CKA_SUBPRIME,            dsa_q,    sizeof(dsa_q)   },
2779         { CKA_BASE,                dsa_g,    sizeof(dsa_g)   },
2780         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)  },
2781         { CKA_ID,                  id,       16              },
2782         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2783         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)   },
2784         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)  },
2785         { CKA_WRAP,                &cfalse,  sizeof(cfalse)  },
2786         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   }
2787     };
2788 
2789     CK_ATTRIBUTE privateKeyTemplate[] = {
2790         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen (id_str) },
2791         { CKA_ID,                  id,       16              },
2792         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2793         { CKA_SIGN,                &ctrue,   sizeof(ctrue)   },
2794         { CKA_DECRYPT,             &cfalse,  sizeof(cfalse)  },
2795         { CKA_UNWRAP,              &cfalse,  sizeof(cfalse)  },
2796         { CKA_SENSITIVE,           &ctrue,   sizeof(ctrue)   },
2797         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   },
2798         { CKA_PRIVATE,             &ctrue,   sizeof(ctrue)   },
2799         { CKA_EXTRACTABLE, &cextractable,  sizeof (cextractable) }
2800     };
2801 
2802     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
2803 
2804     /* Generate the domain parameters */
2805 
2806     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKey(session->session,
2807                                                  &mechanism1,
2808                                                  domainTemplate, 1,
2809                                                  &domainPar);
2810     if (hsm_pkcs11_check_error(ctx, rv, "generate domain parameters")) {
2811         return NULL;
2812     }
2813 
2814     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(session->session,
2815                                                  domainPar, publicKeyTemplate, 3);
2816     if (hsm_pkcs11_check_error(ctx, rv, "get domain parameters")) {
2817         return NULL;
2818     }
2819 
2820     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session, domainPar);
2821     if (hsm_pkcs11_check_error(ctx, rv, "destroy domain parameters")) {
2822         return NULL;
2823     }
2824 
2825     /* Generate key pair */
2826 
2827     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
2828                                                  &mechanism2,
2829                                                  publicKeyTemplate, 10,
2830                                                  privateKeyTemplate, 10,
2831                                                  &publicKey,
2832                                                  &privateKey);
2833     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
2834         return NULL;
2835     }
2836 
2837     new_key = libhsm_key_new();
2838     new_key->modulename = strdup(session->module->name);
2839     new_key->public_key = publicKey;
2840     new_key->private_key = privateKey;
2841 
2842     return new_key;
2843 }
2844 
2845 libhsm_key_t *
hsm_generate_gost_key(hsm_ctx_t * ctx,const char * repository)2846 hsm_generate_gost_key(hsm_ctx_t *ctx,
2847                      const char *repository)
2848 {
2849     CK_RV rv;
2850     libhsm_key_t *new_key;
2851     hsm_session_t *session;
2852     CK_OBJECT_HANDLE publicKey, privateKey;
2853     CK_BBOOL ctrue = CK_TRUE;
2854     CK_BBOOL cfalse = CK_FALSE;
2855     CK_BBOOL cextractable = CK_FALSE;
2856 
2857     /* ids we create are 16 bytes of data */
2858     unsigned char id[16];
2859     /* that's 33 bytes in string (16*2 + 1 for \0) */
2860     char id_str[33];
2861 
2862     session = hsm_find_repository_session(ctx, repository);
2863     if (!session) return NULL;
2864     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
2865 
2866     generate_unique_id(ctx, id, 16);
2867 
2868     /* the CKA_LABEL will contain a hexadecimal string representation
2869      * of the id */
2870     hsm_hex_unparse(id_str, id, 16);
2871 
2872     CK_KEY_TYPE keyType = CKK_GOSTR3410;
2873     CK_MECHANISM mechanism = {
2874         CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0
2875     };
2876 
2877     CK_BYTE oid1[] = { 0x06, 0x07, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };
2878     CK_BYTE oid2[] = { 0x06, 0x07, 0x2A, 0x85, 0x03, 0x02, 0x02, 0x1E, 0x01 };
2879 
2880     CK_ATTRIBUTE publicKeyTemplate[] = {
2881         { CKA_GOSTR3410PARAMS,     oid1,     sizeof(oid1)    },
2882         { CKA_GOSTR3411PARAMS,     oid2,     sizeof(oid2)    },
2883         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)  },
2884         { CKA_ID,                  id,       16              },
2885         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2886         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)   },
2887         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)  },
2888         { CKA_WRAP,                &cfalse,  sizeof(cfalse)  },
2889         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   }
2890     };
2891 
2892     CK_ATTRIBUTE privateKeyTemplate[] = {
2893         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen (id_str) },
2894         { CKA_ID,                  id,       16              },
2895         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2896         { CKA_SIGN,                &ctrue,   sizeof(ctrue)   },
2897         { CKA_DECRYPT,             &cfalse,  sizeof(cfalse)  },
2898         { CKA_UNWRAP,              &cfalse,  sizeof(cfalse)  },
2899         { CKA_SENSITIVE,           &ctrue,   sizeof(ctrue)   },
2900         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   },
2901         { CKA_PRIVATE,             &ctrue,   sizeof(ctrue)   },
2902         { CKA_EXTRACTABLE,         &cextractable,  sizeof (cextractable) }
2903     };
2904 
2905     /* Generate key pair */
2906 
2907     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
2908                                                  &mechanism,
2909                                                  publicKeyTemplate, 9,
2910                                                  privateKeyTemplate, 10,
2911                                                  &publicKey,
2912                                                  &privateKey);
2913     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
2914         return NULL;
2915     }
2916 
2917     new_key = libhsm_key_new();
2918     new_key->modulename = strdup(session->module->name);
2919     new_key->public_key = publicKey;
2920     new_key->private_key = privateKey;
2921 
2922     return new_key;
2923 }
2924 
2925 libhsm_key_t *
hsm_generate_ecdsa_key(hsm_ctx_t * ctx,const char * repository,const char * curve)2926 hsm_generate_ecdsa_key(hsm_ctx_t *ctx,
2927                        const char *repository,
2928                        const char *curve)
2929 {
2930     CK_RV rv;
2931     libhsm_key_t *new_key;
2932     hsm_session_t *session;
2933     CK_OBJECT_HANDLE publicKey, privateKey;
2934     CK_BBOOL ctrue = CK_TRUE;
2935     CK_BBOOL cfalse = CK_FALSE;
2936     CK_BBOOL cextractable = CK_FALSE;
2937 
2938     /* ids we create are 16 bytes of data */
2939     unsigned char id[16];
2940     /* that's 33 bytes in string (16*2 + 1 for \0) */
2941     char id_str[33];
2942 
2943     session = hsm_find_repository_session(ctx, repository);
2944     if (!session) return NULL;
2945     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
2946 
2947     generate_unique_id(ctx, id, 16);
2948 
2949     /* the CKA_LABEL will contain a hexadecimal string representation
2950      * of the id */
2951     hsm_hex_unparse(id_str, id, 16);
2952 
2953     CK_KEY_TYPE keyType = CKK_EC;
2954     CK_MECHANISM mechanism = {
2955         CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
2956     };
2957 
2958     CK_BYTE oidP256[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 };
2959     CK_BYTE oidP384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 };
2960 
2961     CK_ATTRIBUTE publicKeyTemplate[] = {
2962         { CKA_EC_PARAMS,           NULL,     0               },
2963         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)  },
2964         { CKA_ID,                  id,       16              },
2965         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2966         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)   },
2967         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)  },
2968         { CKA_WRAP,                &cfalse,  sizeof(cfalse)  },
2969         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   }
2970     };
2971 
2972     CK_ATTRIBUTE privateKeyTemplate[] = {
2973         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen (id_str) },
2974         { CKA_ID,                  id,       16              },
2975         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
2976         { CKA_SIGN,                &ctrue,   sizeof(ctrue)   },
2977         { CKA_DECRYPT,             &cfalse,  sizeof(cfalse)  },
2978         { CKA_UNWRAP,              &cfalse,  sizeof(cfalse)  },
2979         { CKA_SENSITIVE,           &ctrue,   sizeof(ctrue)   },
2980         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   },
2981         { CKA_PRIVATE,             &ctrue,   sizeof(ctrue)   },
2982         { CKA_EXTRACTABLE,         &cextractable,  sizeof (cextractable) }
2983     };
2984 
2985     /* Select the curve */
2986     if (strcmp(curve, "P-256") == 0)
2987     {
2988         publicKeyTemplate[0].pValue = oidP256;
2989         publicKeyTemplate[0].ulValueLen = sizeof(oidP256);
2990     }
2991     else if (strcmp(curve, "P-384") == 0)
2992     {
2993         publicKeyTemplate[0].pValue = oidP384;
2994         publicKeyTemplate[0].ulValueLen = sizeof(oidP384);
2995     }
2996     else
2997     {
2998         return NULL;
2999     }
3000 
3001     /* Generate key pair */
3002 
3003     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
3004                                                  &mechanism,
3005                                                  publicKeyTemplate, 8,
3006                                                  privateKeyTemplate, 10,
3007                                                  &publicKey,
3008                                                  &privateKey);
3009     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
3010         return NULL;
3011     }
3012 
3013     new_key = libhsm_key_new();
3014     new_key->modulename = strdup(session->module->name);
3015     new_key->public_key = publicKey;
3016     new_key->private_key = privateKey;
3017 
3018     return new_key;
3019 }
3020 
3021 libhsm_key_t *
hsm_generate_eddsa_key(hsm_ctx_t * ctx,const char * repository,const char * curve)3022 hsm_generate_eddsa_key(hsm_ctx_t *ctx,
3023                        const char *repository,
3024                        const char *curve)
3025 {
3026     CK_RV rv;
3027     libhsm_key_t *new_key;
3028     hsm_session_t *session;
3029     CK_OBJECT_HANDLE publicKey, privateKey;
3030     CK_BBOOL ctrue = CK_TRUE;
3031     CK_BBOOL cfalse = CK_FALSE;
3032     CK_BBOOL cextractable = CK_FALSE;
3033 
3034     /* ids we create are 16 bytes of data */
3035     unsigned char id[16];
3036     /* that's 33 bytes in string (16*2 + 1 for \0) */
3037     char id_str[33];
3038 
3039     session = hsm_find_repository_session(ctx, repository);
3040     if (!session) return NULL;
3041     cextractable = session->module->config->allow_extract ? CK_TRUE : CK_FALSE;
3042 
3043     generate_unique_id(ctx, id, 16);
3044 
3045     /* the CKA_LABEL will contain a hexadecimal string representation
3046      * of the id */
3047     hsm_hex_unparse(id_str, id, 16);
3048 
3049     CK_KEY_TYPE keyType = CKK_EC_EDWARDS;
3050     CK_MECHANISM mechanism = {
3051         CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL_PTR, 0
3052     };
3053 
3054     CK_BYTE oid25519[] = { 0x06, 0x03, 0x2B, 0x65, 0x70 };
3055     CK_BYTE oid448[] = { 0x06, 0x03, 0x2B, 0x65, 0x71 };
3056 
3057     CK_ATTRIBUTE publicKeyTemplate[] = {
3058         { CKA_EC_PARAMS,           NULL,     0               },
3059         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)  },
3060         { CKA_ID,                  id,       16              },
3061         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
3062         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)   },
3063         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)  },
3064         { CKA_WRAP,                &cfalse,  sizeof(cfalse)  },
3065         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   }
3066     };
3067 
3068     CK_ATTRIBUTE privateKeyTemplate[] = {
3069         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen (id_str) },
3070         { CKA_ID,                  id,       16              },
3071         { CKA_KEY_TYPE,            &keyType, sizeof(keyType) },
3072         { CKA_SIGN,                &ctrue,   sizeof(ctrue)   },
3073         { CKA_DECRYPT,             &cfalse,  sizeof(cfalse)  },
3074         { CKA_UNWRAP,              &cfalse,  sizeof(cfalse)  },
3075         { CKA_SENSITIVE,           &ctrue,   sizeof(ctrue)   },
3076         { CKA_TOKEN,               &ctrue,   sizeof(ctrue)   },
3077         { CKA_PRIVATE,             &ctrue,   sizeof(ctrue)   },
3078         { CKA_EXTRACTABLE,         &cextractable,  sizeof (cextractable) }
3079     };
3080 
3081     /* Select the curve */
3082     if (strcmp(curve, "edwards25519") == 0)
3083     {
3084         publicKeyTemplate[0].pValue = oid25519;
3085         publicKeyTemplate[0].ulValueLen = sizeof(oid25519);
3086     }
3087     else if (strcmp(curve, "edwards448") == 0)
3088     {
3089         publicKeyTemplate[0].pValue = oid448;
3090         publicKeyTemplate[0].ulValueLen = sizeof(oid448);
3091     }
3092     else
3093     {
3094         return NULL;
3095     }
3096 
3097     /* Generate key pair */
3098 
3099     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
3100                                                  &mechanism,
3101                                                  publicKeyTemplate, 8,
3102                                                  privateKeyTemplate, 10,
3103                                                  &publicKey,
3104                                                  &privateKey);
3105     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
3106         return NULL;
3107     }
3108 
3109     new_key = libhsm_key_new();
3110     new_key->modulename = strdup(session->module->name);
3111     new_key->public_key = publicKey;
3112     new_key->private_key = privateKey;
3113 
3114     return new_key;
3115 }
3116 
3117 int
hsm_remove_key(hsm_ctx_t * ctx,libhsm_key_t * key)3118 hsm_remove_key(hsm_ctx_t *ctx, libhsm_key_t *key)
3119 {
3120     CK_RV rv;
3121     hsm_session_t *session;
3122     if (!key) return -1;
3123 
3124     session = hsm_find_key_session(ctx, key);
3125     if (!session) return -2;
3126 
3127     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
3128                                                key->private_key);
3129     if (hsm_pkcs11_check_error(ctx, rv, "Destroy private key")) {
3130         return -3;
3131     }
3132     key->private_key = 0;
3133 
3134     if (key->public_key) {
3135         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
3136                                                    key->public_key);
3137         if (hsm_pkcs11_check_error(ctx, rv, "Destroy public key")) {
3138             return -4;
3139         }
3140     }
3141     key->public_key = 0;
3142 
3143     return 0;
3144 }
3145 
3146 void
libhsm_key_list_free(libhsm_key_t ** key_list,size_t count)3147 libhsm_key_list_free(libhsm_key_t **key_list, size_t count)
3148 {
3149     size_t i;
3150     for (i = 0; i < count; i++) {
3151         libhsm_key_free(key_list[i]);
3152     }
3153     free(key_list);
3154 }
3155 
3156 char *
hsm_get_key_id(hsm_ctx_t * ctx,const libhsm_key_t * key)3157 hsm_get_key_id(hsm_ctx_t *ctx, const libhsm_key_t *key)
3158 {
3159     unsigned char *id;
3160     char *id_str;
3161     size_t len;
3162     hsm_session_t *session;
3163 
3164     if (!key) return NULL;
3165 
3166     session = hsm_find_key_session(ctx, key);
3167     if (!session) return NULL;
3168 
3169     id = hsm_get_id_for_object(ctx, session, key->private_key, &len);
3170     if (!id) return NULL;
3171 
3172     /* this is plain binary data, we need to convert it to hex */
3173     id_str = malloc(len * 2 + 1);
3174     if (!id_str) {
3175         free(id);
3176         return NULL;
3177     }
3178 
3179     hsm_hex_unparse(id_str, id, len);
3180 
3181     free(id);
3182 
3183     return id_str;
3184 }
3185 
3186 libhsm_key_info_t *
hsm_get_key_info(hsm_ctx_t * ctx,const libhsm_key_t * key)3187 hsm_get_key_info(hsm_ctx_t *ctx,
3188                  const libhsm_key_t *key)
3189 {
3190     libhsm_key_info_t *key_info;
3191     hsm_session_t *session;
3192 
3193     session = hsm_find_key_session(ctx, key);
3194     if (!session) return NULL;
3195 
3196     key_info = malloc(sizeof(libhsm_key_info_t));
3197 
3198     key_info->id = hsm_get_key_id(ctx, key);
3199     if (key_info->id == NULL) {
3200         key_info->id = strdup("");
3201     }
3202 
3203     key_info->algorithm = (unsigned long) hsm_get_key_algorithm(ctx,
3204                                                                 session,
3205                                                                 key);
3206     key_info->keysize = (unsigned long) hsm_get_key_size(ctx,
3207                                                          session,
3208                                                          key,
3209                                                          key_info->algorithm);
3210 
3211     switch(key_info->algorithm) {
3212         case CKK_RSA:
3213             key_info->algorithm_name = strdup("RSA");
3214             break;
3215         case CKK_DSA:
3216             key_info->algorithm_name = strdup("DSA");
3217             break;
3218         case CKK_GOSTR3410:
3219             key_info->algorithm_name = strdup("GOST");
3220             break;
3221         case CKK_EC:
3222             key_info->algorithm_name = strdup("ECDSA");
3223             break;
3224         case CKK_EC_EDWARDS:
3225             key_info->algorithm_name = strdup("EDDSA");
3226             break;
3227         default:
3228             key_info->algorithm_name = malloc(HSM_MAX_ALGONAME);
3229             snprintf(key_info->algorithm_name, HSM_MAX_ALGONAME,
3230                 "%lu", key_info->algorithm);
3231             break;
3232     }
3233 
3234     return key_info;
3235 }
3236 
3237 void
libhsm_key_info_free(libhsm_key_info_t * key_info)3238 libhsm_key_info_free(libhsm_key_info_t *key_info)
3239 {
3240     if (key_info) {
3241         if (key_info->id) {
3242             free(key_info->id);
3243         }
3244         if (key_info->algorithm_name) {
3245             free(key_info->algorithm_name);
3246         }
3247         free(key_info);
3248     }
3249 }
3250 
3251 ldns_rr*
hsm_sign_rrset(hsm_ctx_t * ctx,const ldns_rr_list * rrset,const libhsm_key_t * key,const hsm_sign_params_t * sign_params)3252 hsm_sign_rrset(hsm_ctx_t *ctx,
3253                const ldns_rr_list* rrset,
3254                const libhsm_key_t *key,
3255                const hsm_sign_params_t *sign_params)
3256 {
3257     ldns_rr *signature;
3258     ldns_buffer *sign_buf;
3259     ldns_rdf *b64_rdf;
3260     size_t i;
3261 
3262     if (!key) return NULL;
3263     if (!sign_params) return NULL;
3264 
3265     signature = hsm_create_empty_rrsig((ldns_rr_list *)rrset,
3266                                        sign_params);
3267 
3268     /* right now, we have: a key, a semi-sig and an rrset. For
3269      * which we can create the sig and base64 encode that and
3270      * add that to the signature */
3271     sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
3272 
3273     if (ldns_rrsig2buffer_wire(sign_buf, signature)
3274         != LDNS_STATUS_OK) {
3275         ldns_buffer_free(sign_buf);
3276         /* ERROR */
3277         ldns_rr_free(signature);
3278         return NULL;
3279     }
3280 
3281     /* make it canonical */
3282     for(i = 0; i < ldns_rr_list_rr_count(rrset); i++) {
3283         ldns_rr2canonical(ldns_rr_list_rr(rrset, i));
3284     }
3285 
3286     /* add the rrset in sign_buf */
3287     if (ldns_rr_list2buffer_wire(sign_buf, rrset)
3288         != LDNS_STATUS_OK) {
3289         ldns_buffer_free(sign_buf);
3290         ldns_rr_free(signature);
3291         return NULL;
3292     }
3293 
3294     b64_rdf = hsm_sign_buffer(ctx, sign_buf, key, sign_params->algorithm);
3295 
3296     ldns_buffer_free(sign_buf);
3297     if (!b64_rdf) {
3298         /* signing went wrong */
3299         ldns_rr_free(signature);
3300         return NULL;
3301     }
3302 
3303     ldns_rr_rrsig_set_sig(signature, b64_rdf);
3304 
3305     return signature;
3306 }
3307 
3308 int
hsm_keytag(const char * loc,int alg,int sep,uint16_t * keytag)3309 hsm_keytag(const char* loc, int alg, int sep, uint16_t* keytag)
3310 {
3311 	uint16_t tag;
3312 	hsm_ctx_t *hsm_ctx;
3313 	hsm_sign_params_t *sign_params;
3314 	libhsm_key_t *hsmkey;
3315 	ldns_rr *dnskey_rr;
3316 
3317 	if (!loc) {
3318 		return 1;
3319 	}
3320 
3321 	if (!(hsm_ctx = hsm_create_context())) {
3322 		return 1;
3323 	}
3324 	if (!(sign_params = hsm_sign_params_new())) {
3325 		hsm_destroy_context(hsm_ctx);
3326 		return 1;
3327 	}
3328 
3329 	/* The owner name is not relevant for the keytag calculation.
3330 	 * However, a ldns_rdf_clone down the path will trip over it. */
3331 	sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "dummy");
3332 	sign_params->algorithm = (ldns_algorithm) alg;
3333 	sign_params->flags = LDNS_KEY_ZONE_KEY;
3334 	if (sep)
3335 		sign_params->flags |= LDNS_KEY_SEP_KEY;
3336 
3337 	hsmkey = hsm_find_key_by_id(hsm_ctx, loc);
3338 	if (!hsmkey) {
3339 		hsm_sign_params_free(sign_params);
3340 		hsm_destroy_context(hsm_ctx);
3341 		return 1;
3342 	}
3343 
3344 	dnskey_rr = hsm_get_dnskey(hsm_ctx, hsmkey, sign_params);
3345 	if (!dnskey_rr) {
3346 		libhsm_key_free(hsmkey);
3347 		hsm_sign_params_free(sign_params);
3348 		hsm_destroy_context(hsm_ctx);
3349 		return 1;
3350 	}
3351 
3352 	tag = ldns_calc_keytag(dnskey_rr);
3353 
3354 	ldns_rr_free(dnskey_rr);
3355 	libhsm_key_free(hsmkey);
3356 	hsm_sign_params_free(sign_params);
3357 	hsm_destroy_context(hsm_ctx);
3358 
3359 	if (keytag)
3360             *keytag = tag;
3361 	return 0;
3362 }
3363 
3364 ldns_rr *
hsm_get_dnskey(hsm_ctx_t * ctx,const libhsm_key_t * key,const hsm_sign_params_t * sign_params)3365 hsm_get_dnskey(hsm_ctx_t *ctx,
3366                const libhsm_key_t *key,
3367                const hsm_sign_params_t *sign_params)
3368 {
3369     /* CK_RV rv; */
3370     ldns_rr *dnskey;
3371     hsm_session_t *session;
3372     ldns_rdf *rdata;
3373 
3374     if (!key) {
3375         hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL key");
3376         return NULL;
3377     }
3378     if (!sign_params) {
3379         hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL sign_params");
3380         return NULL;
3381     }
3382     session = hsm_find_key_session(ctx, key);
3383     if (!session) return NULL;
3384 
3385     dnskey = ldns_rr_new();
3386     ldns_rr_set_type(dnskey, LDNS_RR_TYPE_DNSKEY);
3387 
3388     ldns_rr_set_owner(dnskey, ldns_rdf_clone(sign_params->owner));
3389 
3390     ldns_rr_push_rdf(dnskey,
3391             ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
3392                 sign_params->flags));
3393     ldns_rr_push_rdf(dnskey,
3394                      ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
3395                                           LDNS_DNSSEC_KEYPROTO));
3396     ldns_rr_push_rdf(dnskey,
3397                      ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG,
3398                                           sign_params->algorithm));
3399 
3400     rdata = hsm_get_key_rdata(ctx, session, key);
3401     if (rdata == NULL) {
3402         ldns_rr_free(dnskey);
3403         return NULL;
3404     }
3405     ldns_rr_push_rdf(dnskey, rdata);
3406 
3407     return dnskey;
3408 }
3409 
3410 int
hsm_random_buffer(hsm_ctx_t * ctx,unsigned char * buffer,unsigned long length)3411 hsm_random_buffer(hsm_ctx_t *ctx,
3412                   unsigned char *buffer,
3413                   unsigned long length)
3414 {
3415     CK_RV rv;
3416     unsigned int i;
3417     hsm_session_t *session;
3418     if (!buffer) return -1;
3419 
3420     /* just try every attached token. If one errors (be it NO_RNG, or
3421      * any other error, simply try the next */
3422     for (i = 0; i < ctx->session_count; i++) {
3423         session = ctx->session[i];
3424         if (session) {
3425             rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateRandom(
3426                                          session->session,
3427                                          buffer,
3428                                          length);
3429             if (rv == CKR_OK) {
3430                 return 0;
3431             }
3432         }
3433     }
3434     return 1;
3435 }
3436 
3437 uint32_t
hsm_random32(hsm_ctx_t * ctx)3438 hsm_random32(hsm_ctx_t *ctx)
3439 {
3440     uint32_t rnd;
3441     int result;
3442     unsigned char rnd_buf[4];
3443     result = hsm_random_buffer(ctx, rnd_buf, 4);
3444     if (result == 0) {
3445         memcpy(&rnd, rnd_buf, 4);
3446         return rnd;
3447     } else {
3448         return 0;
3449     }
3450 }
3451 
3452 uint64_t
hsm_random64(hsm_ctx_t * ctx)3453 hsm_random64(hsm_ctx_t *ctx)
3454 {
3455     uint64_t rnd;
3456     int result;
3457     unsigned char rnd_buf[8];
3458     result = hsm_random_buffer(ctx, rnd_buf, 8);
3459     if (result == 0) {
3460         memcpy(&rnd, rnd_buf, 8);
3461         return rnd;
3462     } else {
3463         return 0;
3464     }
3465 }
3466 
3467 
3468 /*
3469  * Additional functions
3470  */
3471 
hsm_attach(const char * repository,const char * token_label,const char * path,const char * pin,const hsm_config_t * config)3472 int hsm_attach(const char *repository,
3473                const char *token_label,
3474                const char *path,
3475                const char *pin,
3476                const hsm_config_t *config)
3477 {
3478     hsm_session_t *session;
3479     int result;
3480 
3481     result = hsm_session_init(_hsm_ctx,
3482                               &session,
3483                               repository,
3484                               token_label,
3485                               path,
3486                               pin,
3487                               config);
3488     if (result == HSM_OK) {
3489         result = hsm_ctx_add_session(_hsm_ctx, session);
3490     }
3491     return result;
3492 }
3493 
3494 int
hsm_token_attached(hsm_ctx_t * ctx,const char * repository)3495 hsm_token_attached(hsm_ctx_t *ctx, const char *repository)
3496 {
3497     unsigned int i;
3498     for (i = 0; i < ctx->session_count; i++) {
3499         if (ctx->session[i] &&
3500             strcmp(ctx->session[i]->module->name, repository) == 0) {
3501                 return 1;
3502         }
3503     }
3504 
3505     hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
3506                     "hsm_token_attached()",
3507                     "Can't find repository: %s", repository);
3508     return 0;
3509 }
3510 
3511 char *
hsm_get_error(hsm_ctx_t * gctx)3512 hsm_get_error(hsm_ctx_t *gctx)
3513 {
3514     hsm_ctx_t *ctx;
3515 
3516     char *message;
3517 
3518     if (!gctx) {
3519         ctx = _hsm_ctx;
3520     } else {
3521         ctx = gctx;
3522     }
3523 
3524     if (ctx->error) {
3525         ctx->error = 0;
3526         message = malloc(HSM_ERROR_MSGSIZE);
3527 
3528         if (message == NULL) {
3529             return strdup("libhsm memory allocation failed");
3530         }
3531 
3532         snprintf(message, HSM_ERROR_MSGSIZE,
3533             "%s: %s",
3534             ctx->error_action ? ctx->error_action : "unknown()",
3535             ctx->error_message[0] ? ctx->error_message : "unknown error");
3536         return message;
3537     };
3538 
3539     return NULL;
3540 }
3541 
3542 void
hsm_print_session(hsm_session_t * session)3543 hsm_print_session(hsm_session_t *session)
3544 {
3545     printf("\t\tmodule at %p (sym %p)\n", (void *) session->module, (void *) session->module->sym);
3546     printf("\t\tmodule path: %s\n", session->module->path);
3547     printf("\t\trepository name: %s\n", session->module->name);
3548     printf("\t\ttoken label: %s\n", session->module->token_label);
3549     printf("\t\tsess handle: %u\n", (unsigned int) session->session);
3550 }
3551 
3552 void
hsm_print_ctx(hsm_ctx_t * ctx)3553 hsm_print_ctx(hsm_ctx_t *ctx) {
3554     unsigned int i;
3555     printf("CTX Sessions: %lu\n",
3556            (long unsigned int) ctx->session_count);
3557     for (i = 0; i < ctx->session_count; i++) {
3558         printf("\tSession at %p\n", (void *) ctx->session[i]);
3559         hsm_print_session(ctx->session[i]);
3560     }
3561 }
3562 
3563 void
hsm_print_key(hsm_ctx_t * ctx,libhsm_key_t * key)3564 hsm_print_key(hsm_ctx_t *ctx, libhsm_key_t *key) {
3565     libhsm_key_info_t *key_info;
3566     if (key) {
3567         key_info = hsm_get_key_info(ctx, key);
3568         if (key_info) {
3569             printf("key:\n");
3570             printf("\tprivkey handle: %u\n", (unsigned int) key->private_key);
3571             if (key->public_key) {
3572                 printf("\tpubkey handle: %u\n", (unsigned int) key->public_key);
3573             } else {
3574                 printf("\tpubkey handle: %s\n", "NULL");
3575             }
3576             printf("\trepository: %s\n", key->modulename);
3577             printf("\talgorithm: %s\n", key_info->algorithm_name);
3578             printf("\tsize: %lu\n", key_info->keysize);
3579             printf("\tid: %s\n", key_info->id);
3580             libhsm_key_info_free(key_info);
3581         } else {
3582             printf("key: hsm_get_key_info() returned NULL\n");
3583         }
3584     } else {
3585         printf("key: <void>\n");
3586     }
3587 }
3588 
3589 void
hsm_print_error(hsm_ctx_t * gctx)3590 hsm_print_error(hsm_ctx_t *gctx)
3591 {
3592     char *message;
3593 
3594     message = hsm_get_error(gctx);
3595 
3596     if (message) {
3597         fprintf(stderr, "%s\n", message);
3598         free(message);
3599     } else {
3600         fprintf(stderr, "Unknown error\n");
3601     }
3602 }
3603 
3604 void
hsm_print_tokeninfo(hsm_ctx_t * ctx)3605 hsm_print_tokeninfo(hsm_ctx_t *ctx)
3606 {
3607     CK_RV rv;
3608     CK_SLOT_ID slot_id;
3609     CK_TOKEN_INFO token_info;
3610     unsigned int i;
3611     hsm_session_t *session;
3612     int result;
3613 
3614     for (i = 0; i < ctx->session_count; i++) {
3615         session = ctx->session[i];
3616 
3617         result = hsm_get_slot_id(ctx,
3618                                   session->module->sym,
3619                                   session->module->token_label,
3620                                   &slot_id);
3621         if (result != HSM_OK) return;
3622 
3623         rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_GetTokenInfo(slot_id, &token_info);
3624         if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
3625             return;
3626         }
3627 
3628         printf("Repository: %s\n",session->module->name);
3629 
3630         printf("\tModule:        %s\n", session->module->path);
3631         printf("\tSlot:          %lu\n", slot_id);
3632         printf("\tToken Label:   %.*s\n",
3633             (int) sizeof(token_info.label), token_info.label);
3634         printf("\tManufacturer:  %.*s\n",
3635             (int) sizeof(token_info.manufacturerID), token_info.manufacturerID);
3636         printf("\tModel:         %.*s\n",
3637             (int) sizeof(token_info.model), token_info.model);
3638         printf("\tSerial:        %.*s\n",
3639             (int) sizeof(token_info.serialNumber), token_info.serialNumber);
3640 
3641         if (i + 1 != ctx->session_count)
3642             printf("\n");
3643     }
3644 }
3645 
3646 static int
keycache_cmpfunc(const void * a,const void * b)3647 keycache_cmpfunc(const void* a, const void* b)
3648 {
3649     const char* x = (const char*)a;
3650     const char* y = (const char*)b;
3651     return strcmp(x, y);
3652 }
3653 
3654 static void
keycache_delfunc(ldns_rbnode_t * node,void * cargo)3655 keycache_delfunc(ldns_rbnode_t* node, void* cargo)
3656 {
3657     (void)cargo;
3658     free((void*)node->key);
3659     free(((libhsm_key_t*)node->data)->modulename);
3660     free((void*)node->data);
3661     free((void*)node);
3662 }
3663 
3664 void
keycache_create(hsm_ctx_t * ctx)3665 keycache_create(hsm_ctx_t* ctx)
3666 {
3667     ctx->keycache = ldns_rbtree_create(keycache_cmpfunc);
3668     _hsm_ctx->keycache_lock = malloc(sizeof (pthread_mutex_t));
3669     pthread_mutex_init(_hsm_ctx->keycache_lock, NULL);
3670 }
3671 
3672 void
keycache_destroy(hsm_ctx_t * ctx)3673 keycache_destroy(hsm_ctx_t* ctx)
3674 {
3675     ldns_traverse_postorder(ctx->keycache, keycache_delfunc, NULL);
3676     ldns_rbtree_free(ctx->keycache);
3677     pthread_mutex_destroy(ctx->keycache_lock);
3678     free(ctx->keycache_lock);
3679     ctx->keycache_lock = NULL;
3680 }
3681 
3682 const libhsm_key_t*
keycache_lookup(hsm_ctx_t * ctx,const char * locator)3683 keycache_lookup(hsm_ctx_t* ctx, const char* locator)
3684 {
3685     ldns_rbnode_t* node;
3686 
3687     pthread_mutex_lock(ctx->keycache_lock);
3688         node = ldns_rbtree_search(ctx->keycache, locator);
3689     pthread_mutex_unlock(ctx->keycache_lock);
3690     if (node == LDNS_RBTREE_NULL || node == NULL) {
3691         libhsm_key_t* key;
3692         if ((key = hsm_find_key_by_id(ctx, locator)) == NULL) {
3693             node = NULL;
3694         } else {
3695             node = malloc(sizeof(ldns_rbnode_t));
3696             node->key = strdup(locator);
3697             node->data = key;
3698             pthread_mutex_lock(ctx->keycache_lock);
3699                 node = ldns_rbtree_insert(ctx->keycache, node);
3700             pthread_mutex_unlock(ctx->keycache_lock);
3701         }
3702     }
3703 
3704     if (node == LDNS_RBTREE_NULL || node == NULL)
3705         return NULL;
3706     else
3707         return node->data;
3708 }
3709