OpenDNSSEC-libhsm  1.3.8
/build/buildd/opendnssec-1.3.8/libhsm/src/libhsm.c
Go to the documentation of this file.
00001 /* $Id: libhsm.c 6191 2012-02-28 16:36:01Z rb $ */
00002 
00003 /*
00004  * Copyright (c) 2009 .SE (The Internet Infrastructure Foundation).
00005  * Copyright (c) 2009 NLNet Labs.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00021  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00023  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00025  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00026  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00027  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include "config.h"
00031 
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <strings.h>
00035 #include <stdlib.h>
00036 #include <unistd.h>
00037 #include <dlfcn.h>
00038 
00039 #include <libxml/tree.h>
00040 #include <libxml/parser.h>
00041 #include <libxml/xpath.h>
00042 #include <libxml/xpathInternals.h>
00043 #include <libxml/relaxng.h>
00044 
00045 #include "libhsm.h"
00046 #include "libhsmdns.h"
00047 #include "compat.h"
00048 
00049 #include <pkcs11.h>
00050 
00052 #define HSM_TOKEN_LABEL_LENGTH 32
00053 
00055 static hsm_ctx_t *_hsm_ctx;
00056 
00058 static char *
00059 ldns_pkcs11_rv_str(CK_RV rv)
00060 {
00061     switch (rv)
00062         {
00063         case CKR_OK:
00064             return "CKR_OK";
00065         case CKR_CANCEL:
00066             return "CKR_CANCEL";
00067         case CKR_HOST_MEMORY:
00068             return "CKR_HOST_MEMORY";
00069         case CKR_GENERAL_ERROR:
00070             return "CKR_GENERAL_ERROR";
00071         case CKR_FUNCTION_FAILED:
00072             return "CKR_FUNCTION_FAILED";
00073         case CKR_SLOT_ID_INVALID:
00074             return "CKR_SLOT_ID_INVALID";
00075         case CKR_ATTRIBUTE_READ_ONLY:
00076             return "CKR_ATTRIBUTE_READ_ONLY";
00077         case CKR_ATTRIBUTE_SENSITIVE:
00078             return "CKR_ATTRIBUTE_SENSITIVE";
00079         case CKR_ATTRIBUTE_TYPE_INVALID:
00080             return "CKR_ATTRIBUTE_TYPE_INVALID";
00081         case CKR_ATTRIBUTE_VALUE_INVALID:
00082             return "CKR_ATTRIBUTE_VALUE_INVALID";
00083         case CKR_DATA_INVALID:
00084             return "CKR_DATA_INVALID";
00085         case CKR_DATA_LEN_RANGE:
00086             return "CKR_DATA_LEN_RANGE";
00087         case CKR_DEVICE_ERROR:
00088             return "CKR_DEVICE_ERROR";
00089         case CKR_DEVICE_MEMORY:
00090             return "CKR_DEVICE_MEMORY";
00091         case CKR_DEVICE_REMOVED:
00092             return "CKR_DEVICE_REMOVED";
00093         case CKR_ENCRYPTED_DATA_INVALID:
00094             return "CKR_ENCRYPTED_DATA_INVALID";
00095         case CKR_ENCRYPTED_DATA_LEN_RANGE:
00096             return "CKR_ENCRYPTED_DATA_LEN_RANGE";
00097         case CKR_FUNCTION_CANCELED:
00098             return "CKR_FUNCTION_CANCELED";
00099         case CKR_FUNCTION_NOT_PARALLEL:
00100             return "CKR_FUNCTION_NOT_PARALLEL";
00101         case CKR_KEY_HANDLE_INVALID:
00102             return "CKR_KEY_HANDLE_INVALID";
00103         case CKR_KEY_SIZE_RANGE:
00104             return "CKR_KEY_SIZE_RANGE";
00105         case CKR_KEY_TYPE_INCONSISTENT:
00106             return "CKR_KEY_TYPE_INCONSISTENT";
00107         case CKR_MECHANISM_INVALID:
00108             return "CKR_MECHANISM_INVALID";
00109         case CKR_MECHANISM_PARAM_INVALID:
00110             return "CKR_MECHANISM_PARAM_INVALID";
00111         case CKR_OBJECT_HANDLE_INVALID:
00112             return "CKR_OBJECT_HANDLE_INVALID";
00113         case CKR_OPERATION_ACTIVE:
00114             return "CKR_OPERATION_ACTIVE";
00115         case CKR_OPERATION_NOT_INITIALIZED:
00116             return "CKR_OPERATION_NOT_INITIALIZED";
00117         case CKR_PIN_INCORRECT:
00118             return "CKR_PIN_INCORRECT";
00119         case CKR_PIN_INVALID:
00120             return "CKR_PIN_INVALID";
00121         case CKR_PIN_LEN_RANGE:
00122             return "CKR_PIN_LEN_RANGE";
00123         case CKR_SESSION_CLOSED:
00124             return "CKR_SESSION_CLOSED";
00125         case CKR_SESSION_COUNT:
00126             return "CKR_SESSION_COUNT";
00127         case CKR_SESSION_HANDLE_INVALID:
00128             return "CKR_SESSION_HANDLE_INVALID";
00129         case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
00130             return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
00131         case CKR_SESSION_READ_ONLY:
00132             return "CKR_SESSION_READ_ONLY";
00133         case CKR_SESSION_EXISTS:
00134             return "CKR_SESSION_EXISTS";
00135         case CKR_SIGNATURE_INVALID:
00136             return "CKR_SIGNATURE_INVALID";
00137         case CKR_SIGNATURE_LEN_RANGE:
00138             return "CKR_SIGNATURE_LEN_RANGE";
00139         case CKR_TEMPLATE_INCOMPLETE:
00140             return "CKR_TEMPLATE_INCOMPLETE";
00141         case CKR_TEMPLATE_INCONSISTENT:
00142             return "CKR_TEMPLATE_INCONSISTENT";
00143         case CKR_TOKEN_NOT_PRESENT:
00144             return "CKR_TOKEN_NOT_PRESENT";
00145         case CKR_TOKEN_NOT_RECOGNIZED:
00146             return "CKR_TOKEN_NOT_RECOGNIZED";
00147         case CKR_TOKEN_WRITE_PROTECTED:
00148             return "CKR_TOKEN_WRITE_PROTECTED";
00149         case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
00150             return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
00151         case CKR_UNWRAPPING_KEY_SIZE_RANGE:
00152             return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
00153         case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
00154             return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
00155         case CKR_USER_ALREADY_LOGGED_IN:
00156             return "CKR_USER_ALREADY_LOGGED_IN";
00157         case CKR_USER_NOT_LOGGED_IN:
00158             return "CKR_USER_NOT_LOGGED_IN";
00159         case CKR_USER_PIN_NOT_INITIALIZED:
00160             return "CKR_USER_PIN_NOT_INITIALIZED";
00161         case CKR_USER_TYPE_INVALID:
00162             return "CKR_USER_TYPE_INVALID";
00163         case CKR_WRAPPED_KEY_INVALID:
00164             return "CKR_WRAPPED_KEY_INVALID";
00165         case CKR_WRAPPED_KEY_LEN_RANGE:
00166             return "CKR_WRAPPED_KEY_LEN_RANGE";
00167         case CKR_WRAPPING_KEY_HANDLE_INVALID:
00168             return "CKR_WRAPPING_KEY_HANDLE_INVALID";
00169         case CKR_WRAPPING_KEY_SIZE_RANGE:
00170             return "CKR_WRAPPING_KEY_SIZE_RANGE";
00171         case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
00172             return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
00173         case CKR_RANDOM_SEED_NOT_SUPPORTED:
00174             return "CKR_RANDOM_SEED_NOT_SUPPORTED";
00175         case CKR_VENDOR_DEFINED:
00176             return "CKR_VENDOR_DEFINED";
00177         case CKR_BUFFER_TOO_SMALL:
00178             return "CKR_BUFFER_TOO_SMALL";
00179         case CKR_SAVED_STATE_INVALID:
00180             return "CKR_SAVED_STATE_INVALID";
00181         case CKR_INFORMATION_SENSITIVE:
00182             return "CKR_INFORMATION_SENSITIVE";
00183         case CKR_STATE_UNSAVEABLE:
00184             return "CKR_STATE_UNSAVEABLE";
00185         case CKR_CRYPTOKI_NOT_INITIALIZED:
00186             return "CKR_CRYPTOKI_NOT_INITIALIZED";
00187         case CKR_CRYPTOKI_ALREADY_INITIALIZED:
00188             return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
00189         case CKR_MUTEX_BAD:
00190             return "CKR_MUTEX_BAD";
00191         case CKR_MUTEX_NOT_LOCKED:
00192             return "CKR_MUTEX_NOT_LOCKED";
00193         default:
00194             return "Unknown error";
00195         }
00196 }
00197 
00209 static void
00210 hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action,
00211                  const char *message, ...)
00212 {
00213     va_list args;
00214 
00215     if (ctx && ctx->error == 0) {
00216         ctx->error = error;
00217         ctx->error_action = action;
00218 
00219         va_start(args, message);
00220         vsnprintf(ctx->error_message, sizeof(ctx->error_message),
00221             message, args);
00222         va_end(args);
00223     }
00224 }
00225 
00237 static int
00238 hsm_pkcs11_check_error(hsm_ctx_t *ctx, CK_RV rv, const char *action)
00239 {
00240     if (rv != CKR_OK) {
00241         if (ctx && ctx->error == 0) {
00242             ctx->error = (int) rv;
00243             ctx->error_action = action;
00244             strlcpy(ctx->error_message, ldns_pkcs11_rv_str(rv), sizeof(ctx->error_message));
00245         }
00246         return 1;
00247     }
00248     return 0;
00249 }
00250 
00252 static void
00253 hsm_pkcs11_unload_functions(void *handle)
00254 {
00255     int result;
00256     if (handle) {
00257 #if defined(HAVE_LOADLIBRARY)
00258         /* no idea */
00259 #elif defined(HAVE_DLOPEN)
00260         result = dlclose(handle);
00261 #endif
00262     }
00263 }
00264 
00266 static CK_RV
00267 hsm_pkcs11_load_functions(hsm_module_t *module)
00268 {
00269     CK_C_GetFunctionList pGetFunctionList = NULL;
00270 
00271     if (module && module->path) {
00272         /* library provided by application or user */
00273 
00274 #if defined(HAVE_LOADLIBRARY)
00275         /* Load PKCS #11 library */
00276         HINSTANCE hDLL = LoadLibrary(_T(module->path));
00277 
00278         if (hDLL == NULL) {
00279             /* Failed to load the PKCS #11 library */
00280             return CKR_FUNCTION_FAILED;
00281         }
00282 
00283         /* Retrieve the entry point for C_GetFunctionList */
00284         pGetFunctionList = (CK_C_GetFunctionList)
00285             GetProcAddress(hDLL, _T("C_GetFunctionList"));
00286 
00287 #elif defined(HAVE_DLOPEN)
00288         /* Load PKCS #11 library */
00289         void* pDynLib = dlopen(module->path, RTLD_NOW | RTLD_LOCAL);
00290 
00291         if (pDynLib == NULL) {
00292             /* Failed to load the PKCS #11 library */
00293             return CKR_FUNCTION_FAILED;
00294         }
00295 
00296         /* Retrieve the entry point for C_GetFunctionList */
00297         pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList");
00298         /* Store the handle so we can dlclose it later */
00299         module->handle = pDynLib;
00300 
00301 #else
00302         return CKR_FUNCTION_FAILED;
00303 #endif
00304     } else {
00305         /* No library provided, use the statically compiled softHSM */
00306 #ifdef HAVE_PKCS11_MODULE
00307         return C_GetFunctionList(pkcs11_functions);
00308 #else
00309         return CKR_FUNCTION_FAILED;
00310 #endif
00311     }
00312 
00313     if (pGetFunctionList == NULL) {
00314         /* Failed to load the PKCS #11 library */
00315         return CKR_FUNCTION_FAILED;
00316     }
00317 
00318     /* Retrieve the function list */
00319     (pGetFunctionList)((CK_FUNCTION_LIST_PTR)(&module->sym));
00320     return CKR_OK;
00321 }
00322 
00323 static void
00324 hsm_remove_leading_zeroes(CK_BYTE_PTR data, CK_ULONG *len)
00325 {
00326     CK_BYTE_PTR p = data;
00327     CK_ULONG l;
00328 
00329     if (data == NULL || len == NULL) return;
00330 
00331     l = *len;
00332 
00333     while ((unsigned short int)(*p) == 0 && l > 1) {
00334         p++;
00335         l--;
00336     }
00337 
00338     if (p != data) {
00339         memmove(data, p, l);
00340         *len = l;
00341     }
00342 }
00343 
00344 static int
00345 hsm_pkcs11_check_token_name(hsm_ctx_t *ctx,
00346                             CK_FUNCTION_LIST_PTR pkcs11_functions,
00347                             CK_SLOT_ID slotId,
00348                             const char *token_name)
00349 {
00350     /* token label is always 32 bytes */
00351     char token_name_bytes[HSM_TOKEN_LABEL_LENGTH];
00352     int result = 0;
00353     CK_RV rv;
00354     CK_TOKEN_INFO token_info;
00355 
00356     rv = pkcs11_functions->C_GetTokenInfo(slotId, &token_info);
00357     if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
00358         return 0;
00359     }
00360 
00361     memset(token_name_bytes, ' ', HSM_TOKEN_LABEL_LENGTH);
00362     if (strlen(token_name) < HSM_TOKEN_LABEL_LENGTH) {
00363         memcpy(token_name_bytes, token_name, strlen(token_name));
00364     } else {
00365         memcpy(token_name_bytes, token_name, HSM_TOKEN_LABEL_LENGTH);
00366     }
00367 
00368     result = memcmp(token_info.label,
00369                     token_name_bytes,
00370                     HSM_TOKEN_LABEL_LENGTH) == 0;
00371 
00372     return result;
00373 }
00374 
00375 
00376 int
00377 hsm_get_slot_id(hsm_ctx_t *ctx,
00378                 CK_FUNCTION_LIST_PTR pkcs11_functions,
00379                 const char *token_name, CK_SLOT_ID *slotId)
00380 {
00381     CK_RV rv;
00382     CK_ULONG slotCount;
00383     CK_SLOT_ID cur_slot;
00384     CK_SLOT_ID *slotIds;
00385     int found = 0;
00386 
00387     if (token_name == NULL || slotId == NULL) return HSM_ERROR;
00388 
00389     rv = pkcs11_functions->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
00390     if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
00391         return HSM_ERROR;
00392     }
00393 
00394     if (slotCount < 1) {
00395         hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_get_slot_id()",
00396                           "No slots found in HSM");
00397         return HSM_ERROR;
00398     }
00399 
00400     slotIds = malloc(sizeof(CK_SLOT_ID) * slotCount);
00401     rv = pkcs11_functions->C_GetSlotList(CK_TRUE, slotIds, &slotCount);
00402     if (hsm_pkcs11_check_error(ctx, rv, "get slot list")) {
00403         return HSM_ERROR;
00404     }
00405 
00406     for (cur_slot = 0; cur_slot < slotCount; cur_slot++) {
00407         if (hsm_pkcs11_check_token_name(ctx,
00408                                         pkcs11_functions,
00409                                         slotIds[cur_slot],
00410                                         token_name)) {
00411             *slotId = slotIds[cur_slot];
00412             found = 1;
00413             break;
00414         }
00415     }
00416     free(slotIds);
00417     if (!found) {
00418         hsm_ctx_set_error(ctx, -1, "hsm_get_slot_id()",
00419             "could not find token with the name %s", token_name);
00420         return HSM_ERROR;
00421     }
00422 
00423     return HSM_OK;
00424 }
00425 
00426 /* internal functions */
00427 static hsm_module_t *
00428 hsm_module_new(const char *repository,
00429                const char *token_label,
00430                const char *path,
00431                const hsm_config_t *config)
00432 {
00433     hsm_module_t *module;
00434 
00435     if (!repository || !path) return NULL;
00436 
00437     
00438     module = malloc(sizeof(hsm_module_t));
00439     if (!module) return NULL;
00440 
00441     if (config) {
00442         module->config = malloc(sizeof(hsm_config_t));
00443         if (!module->config) {
00444             free(module);
00445             return NULL;
00446         }
00447         memcpy(module->config, config, sizeof(hsm_config_t));
00448     } else {
00449         module->config = NULL;
00450     }
00451 
00452     module->id = 0; /*TODO i think we can remove this*/
00453     module->name = strdup(repository);
00454     module->token_label = strdup(token_label);
00455     module->path = strdup(path);
00456     module->handle = NULL;
00457     module->sym = NULL;
00458     
00459     return module;
00460 }
00461 
00462 static void
00463 hsm_module_free(hsm_module_t *module)
00464 {
00465     if (module) {
00466         if (module->name) free(module->name);
00467         if (module->token_label) free(module->token_label);
00468         if (module->path) free(module->path);
00469         if (module->config) free(module->config);
00470 
00471         free(module);
00472     }
00473 }
00474 
00475 static hsm_session_t *
00476 hsm_session_new(hsm_module_t *module, CK_SESSION_HANDLE session_handle)
00477 {
00478     hsm_session_t *session;
00479     session = malloc(sizeof(hsm_session_t));
00480     session->module = module;
00481     session->session = session_handle;
00482     return session;
00483 }
00484 
00485 static void
00486 hsm_session_free(hsm_session_t *session) {
00487     if (session) {
00488         free(session);
00489     }
00490 }
00491 
00493 static void
00494 hsm_config_default(hsm_config_t *config)
00495 {
00496     config->use_pubkey = 1;
00497 }
00498 
00499 /* creates a session_t structure, and automatically adds and initializes
00500  * a module_t struct for it
00501  */
00502 static int
00503 hsm_session_init(hsm_ctx_t *ctx, hsm_session_t **session,
00504                  const char *repository, const char *token_label,
00505                  const char *module_path, const char *pin,
00506                  const hsm_config_t *config)
00507 {
00508     CK_RV rv;
00509     CK_RV rv_login;
00510     hsm_module_t *module;
00511     CK_SLOT_ID slot_id;
00512     CK_SESSION_HANDLE session_handle;
00513     int first = 1, result;
00514 
00515     CK_C_INITIALIZE_ARGS InitArgs = {NULL, NULL, NULL, NULL,
00516                                      CKF_OS_LOCKING_OK, NULL };
00517 
00518     module = hsm_module_new(repository, token_label, module_path, config);
00519     if (!module) return HSM_ERROR;
00520     rv = hsm_pkcs11_load_functions(module);
00521     if (rv != CKR_OK) {
00522         hsm_ctx_set_error(ctx, HSM_MODULE_NOT_FOUND,
00523             "hsm_session_init()",
00524             "PKCS#11 module load failed: %s", module_path);
00525         hsm_module_free(module);
00526         return HSM_MODULE_NOT_FOUND;
00527     }
00528     rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Initialize((CK_VOID_PTR) &InitArgs);
00529     /* ALREADY_INITIALIZED is ok, apparently we are using a second
00530      * device with the same library */
00531     if (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
00532         if (hsm_pkcs11_check_error(ctx, rv, "Initialization")) {
00533             hsm_module_free(module);
00534             return HSM_ERROR;
00535         }
00536     } else {
00537         first = 0;
00538     }
00539     result = hsm_get_slot_id(ctx, module->sym, token_label, &slot_id);
00540     if (result != HSM_OK) {
00541         hsm_module_free(module);
00542         return HSM_ERROR;
00543     }
00544     rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_OpenSession(slot_id,
00545                                CKF_SERIAL_SESSION | CKF_RW_SESSION,
00546                                NULL,
00547                                NULL,
00548                                &session_handle);
00549     if (hsm_pkcs11_check_error(ctx, rv, "Open first session")) {
00550         hsm_module_free(module);
00551         return HSM_ERROR;
00552     }
00553     rv_login = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Login(session_handle,
00554                                    CKU_USER,
00555                                    (unsigned char *) pin,
00556                                    strlen((char *)pin));
00557 
00558     if (rv_login == CKR_OK) {
00559         *session = hsm_session_new(module, session_handle);
00560         return HSM_OK;
00561     } else {
00562         /* uninitialize the session again */
00563         if (session_handle) {
00564             rv = ((CK_FUNCTION_LIST_PTR) module->sym)->
00565                    C_CloseSession(session_handle);
00566             if (hsm_pkcs11_check_error(ctx, rv,
00567                 "finalize after failed login")) {
00568                 hsm_module_free(module);
00569                 return HSM_ERROR;
00570             }
00571         }
00572         /* if this was not the first, don't close the library for
00573          * the rest of us */
00574         if (first) {
00575             rv = ((CK_FUNCTION_LIST_PTR) module->sym)->C_Finalize(NULL);
00576             if (hsm_pkcs11_check_error(ctx, rv, "finalize after failed login")) {
00577                 hsm_module_free(module);
00578                 return HSM_ERROR;
00579             }
00580         }
00581         hsm_module_free(module);
00582         *session = NULL;
00583         switch(rv_login) {
00584         case CKR_PIN_INCORRECT:
00585             hsm_ctx_set_error(ctx, HSM_PIN_INCORRECT,
00586                     "hsm_session_init()",
00587                     "Incorrect PIN for repository %s", repository);
00588             return HSM_PIN_INCORRECT;
00589         default:
00590             return HSM_ERROR;
00591         }
00592     }
00593 }
00594 
00595 /* open a second session from the given one */
00596 static hsm_session_t *
00597 hsm_session_clone(hsm_ctx_t *ctx, hsm_session_t *session)
00598 {
00599     CK_RV rv;
00600     CK_SLOT_ID slot_id;
00601     CK_SESSION_HANDLE session_handle;
00602     hsm_session_t *new_session;
00603     int result;
00604 
00605     result = hsm_get_slot_id(ctx,
00606                               session->module->sym,
00607                               session->module->token_label,
00608                               &slot_id);
00609     if (result != HSM_OK) return NULL;
00610     rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_OpenSession(slot_id,
00611                                     CKF_SERIAL_SESSION | CKF_RW_SESSION,
00612                                     NULL,
00613                                     NULL,
00614                                     &session_handle);
00615 
00616     if (hsm_pkcs11_check_error(ctx, rv, "Clone session")) {
00617         return NULL;
00618     }
00619     new_session = hsm_session_new(session->module, session_handle);
00620 
00621     return new_session;
00622 }
00623 
00624 static hsm_ctx_t *
00625 hsm_ctx_new()
00626 {
00627     hsm_ctx_t *ctx;
00628     ctx = malloc(sizeof(hsm_ctx_t));
00629     memset(ctx->session, 0, HSM_MAX_SESSIONS);
00630     ctx->session_count = 0;
00631     ctx->error = 0;
00632     return ctx;
00633 }
00634 
00635 /* ctx_free frees the structure */
00636 static void
00637 hsm_ctx_free(hsm_ctx_t *ctx)
00638 {
00639     unsigned int i;
00640     if (ctx) {
00641         for (i = 0; i < ctx->session_count; i++) {
00642             hsm_session_free(ctx->session[i]);
00643         }
00644         free(ctx);
00645     }
00646 }
00647 
00648 /* close the session, and free the allocated data
00649  *
00650  * if unload is non-zero, C_Logout() is called,
00651  * the dlopen()d module is closed and unloaded
00652  * (only call this on the last session for each
00653  * module, ie. the one in the global ctx)
00654  */
00655 static void
00656 hsm_session_close(hsm_ctx_t *ctx, hsm_session_t *session, int unload)
00657 {
00658     /* If we loaded this library more than once, we may have
00659      * already finalized it before, so we can safely ignore
00660      * NOT_INITIALIZED */
00661     CK_RV rv;
00662     if (unload) {
00663         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Logout(session->session);
00664         if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
00665             (void) hsm_pkcs11_check_error(ctx, rv, "Logout");
00666         }
00667     }
00668     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session->session);
00669     if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
00670         (void) hsm_pkcs11_check_error(ctx, rv, "Close session");
00671     }
00672     if (unload) {
00673         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Finalize(NULL);
00674         if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) {
00675             (void) hsm_pkcs11_check_error(ctx, rv, "Finalize");
00676             hsm_pkcs11_unload_functions(session->module->handle);
00677         }
00678         hsm_module_free(session->module);
00679         session->module = NULL;
00680     }
00681     hsm_session_free(session);
00682 }
00683 
00684 /* ctx_close closes all session, and free
00685  * the structures.
00686  *
00687  * if unload is non-zero, the associated dynamic libraries are unloaded
00688  * (hence only use that on the last, global, ctx)
00689  */
00690 static void
00691 hsm_ctx_close(hsm_ctx_t *ctx, int unload)
00692 {
00693     unsigned int i;
00694 
00695     if (ctx) {
00696         for (i = 0; i < ctx->session_count; i++) {
00697             /* todo syslog? */
00698             /*printf("close session %u (unload: %d)\n", i, unload);*/
00699             /*hsm_print_ctx(ctx);*/
00700             hsm_session_close(ctx, ctx->session[i], unload);
00701             ctx->session[i] = NULL;
00702             /* if this was the last session in the array, decrease
00703              * the session counter of the context */
00704             if (i == _hsm_ctx->session_count) {
00705                 while(ctx->session_count > 0 && !ctx->session[i]) {
00706                     ctx->session_count--;
00707                 }
00708             }
00709         }
00710         free(ctx);
00711     }
00712 }
00713 
00714 
00715 /* adds a session to the context.
00716  * returns  0 on success
00717  *          1 if the maximum number of sessions (HSM_MAX_SESSIONS) was
00718  *            reached
00719  *          -1 if one of the arguments is NULL
00720  */
00721 static int
00722 hsm_ctx_add_session(hsm_ctx_t *ctx, hsm_session_t *session)
00723 {
00724     if (!ctx || !session) return -1;
00725     if (ctx->session_count >= HSM_MAX_SESSIONS) return 1;
00726     ctx->session[ctx->session_count] = session;
00727     ctx->session_count++;
00728     return 0;
00729 }
00730 
00731 static hsm_ctx_t *
00732 hsm_ctx_clone(hsm_ctx_t *ctx)
00733 {
00734     unsigned int i;
00735     hsm_ctx_t *new_ctx;
00736     hsm_session_t *new_session;
00737 
00738     new_ctx = NULL;
00739     if (ctx) {
00740         new_ctx = hsm_ctx_new();
00741         for (i = 0; i < ctx->session_count; i++) {
00742             new_session = hsm_session_clone(ctx, ctx->session[i]);
00743             if (!new_session) {
00744                 /* one of the sessions failed to clone. Clear the
00745                  * new ctx and return NULL */
00746                 hsm_ctx_close(new_ctx, 0);
00747                 return NULL;
00748             }
00749             hsm_ctx_add_session(new_ctx, new_session);
00750         }
00751     }
00752     return new_ctx;
00753 }
00754 
00755 static hsm_key_t *
00756 hsm_key_new()
00757 {
00758     hsm_key_t *key;
00759     key = malloc(sizeof(hsm_key_t));
00760     key->module = NULL;
00761     key->private_key = 0;
00762     key->public_key = 0;
00763     return key;
00764 }
00765 
00766 /* find the session belonging to a key, by iterating over the modules
00767  * in the context */
00768 static hsm_session_t *
00769 hsm_find_key_session(hsm_ctx_t *ctx, const hsm_key_t *key)
00770 {
00771     unsigned int i;
00772     if (!key || !key->module) return NULL;
00773     if (!ctx) ctx = _hsm_ctx;
00774     for (i = 0; i < ctx->session_count; i++) {
00775         if (ctx->session[i] && ctx->session[i]->module == key->module) {
00776             return ctx->session[i];
00777         }
00778     }
00779     return NULL;
00780 }
00781 
00782 /* Returns the key type (algorithm) of the given key */
00783 static CK_KEY_TYPE
00784 hsm_get_key_algorithm(hsm_ctx_t *ctx, const hsm_session_t *session,
00785                       const hsm_key_t *key)
00786 {
00787     CK_RV rv;
00788     CK_KEY_TYPE key_type;
00789 
00790     CK_ATTRIBUTE template[] = {
00791         {CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}
00792     };
00793 
00794     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
00795                                       session->session,
00796                                       key->private_key,
00797                                       template,
00798                                       1);
00799     if (hsm_pkcs11_check_error(ctx, rv,
00800                                "Get attr value algorithm type")) {
00801         /* this is actually not a good return value;
00802          * CKK_RSA is also 0. But we can't return a negative
00803          * value. Should we #define a specific 'key type' that
00804          * indicates an error? (TODO) */
00805         return 0;
00806     }
00807 
00808     if ((CK_LONG)template[0].ulValueLen < 1) {
00809         /* this is actually not a good return value;
00810          * CKK_RSA is also 0. But we can't return a negative
00811          * value. Should we #define a specific 'key type' that
00812          * indicates an error? (TODO) */
00813         return 0;
00814     }
00815 
00816     return key_type;
00817 }
00818 
00819 /* returns a CK_ULONG with the key size of the given RSA key. The
00820  * key is not checked for type. For RSA, the number of bits in the
00821  * modulus is the key size (CKA_MODULUS_BITS)
00822  */
00823 static CK_ULONG
00824 hsm_get_key_size_rsa(hsm_ctx_t *ctx, const hsm_session_t *session,
00825                      const hsm_key_t *key)
00826 {
00827     CK_RV rv;
00828     CK_ULONG modulus_bits;
00829 
00830     /* Template for public keys */
00831     CK_ATTRIBUTE template[] = {
00832         {CKA_MODULUS_BITS, &modulus_bits, sizeof(CK_KEY_TYPE)}
00833     };
00834 
00835     /* Template for private keys */
00836     CK_BYTE_PTR modulus = NULL;
00837     int mask;
00838     CK_ATTRIBUTE template2[] = {
00839         {CKA_MODULUS, NULL, 0}
00840     };
00841 
00842     if (session->module->config->use_pubkey) {
00843         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
00844                                           session->session,
00845                                           key->public_key,
00846                                           template,
00847                                           1);
00848         if (hsm_pkcs11_check_error(ctx, rv,
00849                                    "Get attr value algorithm type")) {
00850             return 0;
00851         }
00852     
00853         if ((CK_ULONG)template[0].ulValueLen < 1) {
00854             return 0;
00855         }
00856     } else {
00857         // Get buffer size
00858         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
00859                                           session->session,
00860                                           key->private_key,
00861                                           template2,
00862                                           1);
00863         if (hsm_pkcs11_check_error(ctx, rv, "Could not get the size of the modulus of the private key")) {
00864             return 0;
00865         }
00866 
00867         // Allocate memory
00868         modulus = (CK_BYTE_PTR)malloc(template2[0].ulValueLen);
00869         template2[0].pValue = modulus;
00870         if (modulus == NULL) {
00871             hsm_ctx_set_error(ctx, -1, "hsm_get_key_size_rsa()",
00872                 "Error allocating memory for modulus");
00873             return 0;
00874         }
00875 
00876         // Get attribute
00877         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
00878                                           session->session,
00879                                           key->private_key,
00880                                           template2,
00881                                           1);
00882         if (hsm_pkcs11_check_error(ctx, rv, "Could not get the modulus of the private key")) {
00883             free(modulus);
00884             return 0;
00885         }
00886 
00887         // Calculate size
00888         modulus_bits = template2[0].ulValueLen * 8;
00889         mask = 0x80;
00890         for (int i = 0; modulus_bits && (modulus[i] & mask) == 0; modulus_bits--) {
00891             mask >>= 1;
00892             if (mask == 0) {
00893                 i++;
00894                 mask = 0x80;
00895             }
00896         }
00897         free(modulus);
00898     }
00899 
00900     return modulus_bits;
00901 }
00902 
00903 /* Wrapper for specific key size functions, currently only supports
00904  * CKK_RSA (the value 0) as algorithm identifier */
00905 static CK_ULONG
00906 hsm_get_key_size(hsm_ctx_t *ctx, const hsm_session_t *session,
00907                  const hsm_key_t *key, const unsigned long algorithm)
00908 {
00909     switch (algorithm) {
00910         case CKK_RSA:
00911             return hsm_get_key_size_rsa(ctx, session, key);
00912             break;
00913         default:
00914             return 0;
00915     }
00916 }
00917 
00918 static CK_OBJECT_HANDLE
00919 hsm_find_object_handle_for_id(hsm_ctx_t *ctx,
00920                               const hsm_session_t *session,
00921                               CK_OBJECT_CLASS key_class,
00922                               CK_BYTE *id,
00923                               CK_ULONG id_len)
00924 {
00925     CK_ULONG objectCount;
00926     CK_OBJECT_HANDLE object;
00927     CK_RV rv;
00928 
00929     CK_ATTRIBUTE template[] = {
00930         { CKA_CLASS, &key_class, sizeof(key_class) },
00931         { CKA_ID, id, id_len },
00932     };
00933 
00934     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
00935                                                  template, 2);
00936     if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
00937         return 0;
00938     }
00939 
00940     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
00941                                          &object,
00942                                          1,
00943                                          &objectCount);
00944     if (hsm_pkcs11_check_error(ctx, rv, "Find object")) {
00945         return 0;
00946     }
00947 
00948     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
00949     if (hsm_pkcs11_check_error(ctx, rv, "Find object final")) {
00950         return 0;
00951     }
00952 
00953     if (objectCount > 0) {
00954         return object;
00955     } else {
00956         return 0;
00957     }
00958 }
00959 
00960 /*
00961  * Parses the null-terminated string hex as hex values,
00962  * Returns allocated data that needs to be freed (or NULL on error)
00963  * len will contain the number of bytes allocated, or 0 on error
00964  */
00965 static unsigned char *
00966 hsm_hex_parse(const char *hex, size_t *len)
00967 {
00968     unsigned char *bytes;
00969     /* length of the hex input */
00970     size_t hex_len;
00971     size_t i;
00972 
00973     if (!len) return NULL;
00974     *len = 0;
00975 
00976     if (!hex) return NULL;
00977     hex_len = strlen(hex);
00978     if (hex_len % 2 != 0) {
00979         return NULL;
00980     }
00981 
00982     *len = hex_len / 2;
00983     bytes = malloc(*len);
00984     for (i = 0; i < *len; i++) {
00985         bytes[i] = ldns_hexdigit_to_int(hex[2*i]) * 16 +
00986                    ldns_hexdigit_to_int(hex[2*i+1]);
00987     }
00988     return bytes;
00989 }
00990 
00991 /* put a hexadecimal representation of the data from src into dst
00992  * len is the number of bytes to read from src
00993  * dst must have allocated enough space (len*2 + 1)
00994  */
00995 static void
00996 hsm_hex_unparse(char *dst, const unsigned char *src, size_t len)
00997 {
00998     size_t dst_len = len*2 + 1;
00999     size_t i;
01000 
01001     for (i = 0; i < len; i++) {
01002         snprintf(dst + (2*i), dst_len, "%02x", src[i]);
01003     }
01004     dst[len*2] = '\0';
01005 }
01006 
01007 /* returns an allocated byte array with the CKA_ID for the given object
01008  * len will contain the result size
01009  * returns NULL and size zero if not found in this session
01010  */
01011 static CK_BYTE *
01012 hsm_get_id_for_object(hsm_ctx_t *ctx,
01013                       const hsm_session_t *session,
01014                       CK_OBJECT_HANDLE object,
01015                       size_t *len)
01016 {
01017     CK_RV rv;
01018     CK_BYTE *id = NULL;
01019 
01020     CK_ATTRIBUTE template[] = {
01021         {CKA_ID, id, 0}
01022     };
01023 
01024     /* find out the size of the id first */
01025     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
01026                                       session->session,
01027                                       object,
01028                                       template,
01029                                       1);
01030     if (hsm_pkcs11_check_error(ctx, rv, "Get attr value")) {
01031         *len = 0;
01032         return NULL;
01033     }
01034 
01035     if ((CK_LONG)template[0].ulValueLen < 1) {
01036         /* No CKA_ID found, return NULL */
01037         *len = 0;
01038         return NULL;
01039     }
01040 
01041     template[0].pValue = malloc(template[0].ulValueLen);
01042     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
01043                                       session->session,
01044                                       object,
01045                                       template,
01046                                       1);
01047     if (hsm_pkcs11_check_error(ctx, rv, "Get attr value 2")) {
01048         *len = 0;
01049         free(template[0].pValue);
01050         return NULL;
01051     }
01052 
01053     *len = template[0].ulValueLen;
01054     return template[0].pValue;
01055 }
01056 
01057 /* returns an hsm_key_t object for the given *private key* object handle
01058  * the module, private key, and public key handle are set
01059  * The session needs to be free to perform a search for the public key
01060  */
01061 static hsm_key_t *
01062 hsm_key_new_privkey_object_handle(hsm_ctx_t *ctx,
01063                                   const hsm_session_t *session,
01064                                   CK_OBJECT_HANDLE object)
01065 {
01066     hsm_key_t *key;
01067     CK_BYTE *id;
01068     size_t len;
01069 
01070     id = hsm_get_id_for_object(ctx, session, object, &len);
01071 
01072     if (!id) return NULL;
01073 
01074     key = hsm_key_new();
01075     key->module = session->module;
01076     key->private_key = object;
01077     
01078     if (session->module->config->use_pubkey) {
01079         key->public_key = hsm_find_object_handle_for_id(
01080                               ctx,
01081                               session,
01082                               CKO_PUBLIC_KEY,
01083                               id,
01084                               len);
01085     } else {
01086         key->public_key = 0;
01087     }
01088 
01089     free(id);
01090     return key;
01091 }
01092 
01093 /* helper function to find both key counts or the keys themselves
01094  * if the argument store is 0, results are not returned; the
01095  * function will only set the count and return NULL
01096  * Otherwise, a newly allocated key array will be returned
01097  * (on error, the count will also be zero and NULL returned)
01098  */
01099 static hsm_key_t **
01100 hsm_list_keys_session_internal(hsm_ctx_t *ctx,
01101                                const hsm_session_t *session,
01102                                size_t *count,
01103                                int store)
01104 {
01105     hsm_key_t **keys = NULL;
01106     hsm_key_t *key;
01107     CK_RV rv;
01108     CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
01109     CK_ATTRIBUTE template[] = {
01110         { CKA_CLASS, &key_class, sizeof(key_class) },
01111     };
01112     CK_ULONG total_count = 0;
01113     CK_ULONG objectCount = 1;
01114     /* find 100 keys at a time (and loop until there are none left) */
01115     CK_ULONG max_object_count = 100;
01116     CK_ULONG i, j;
01117     CK_OBJECT_HANDLE object[max_object_count];
01118     CK_OBJECT_HANDLE *key_handles = NULL;
01119 
01120     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsInit(session->session,
01121                                                  template, 1);
01122     if (hsm_pkcs11_check_error(ctx, rv, "Find objects init")) {
01123         *count = 0;
01124         return NULL;
01125     }
01126     j = 0;
01127     while (objectCount > 0) {
01128         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjects(session->session,
01129                                                  object,
01130                                                  max_object_count,
01131                                                  &objectCount);
01132         if (hsm_pkcs11_check_error(ctx, rv, "Find first object")) {
01133             free(key_handles);
01134             *count = 0;
01135             return NULL;
01136         }
01137 
01138         total_count += objectCount;
01139         if (objectCount > 0 && store) {
01140             key_handles = realloc(key_handles, total_count * sizeof(CK_OBJECT_HANDLE));
01141             for (i = 0; i < objectCount; i++) {
01142                 key_handles[j] = object[i];
01143                 j++;
01144             }
01145         }
01146     }
01147 
01148     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_FindObjectsFinal(session->session);
01149     if (hsm_pkcs11_check_error(ctx, rv, "Find objects final")) {
01150         free(key_handles);
01151         *count = 0;
01152         return NULL;
01153     }
01154 
01155     if (store) {
01156         keys = realloc(keys, total_count * sizeof(hsm_key_t *));
01157         for (i = 0; i < total_count; i++) {
01158             key = hsm_key_new_privkey_object_handle(ctx, session,
01159                                                     key_handles[i]);
01160             /* todo, if we get NULL, free all and return error? */
01161             keys[i] = key;
01162         }
01163     }
01164     free(key_handles);
01165 
01166     *count = total_count;
01167     return keys;
01168 }
01169 
01170 
01171 /* returns an array of all keys available to the given session
01172  *
01173  * \param session the session to find the keys in
01174  * \param count this value will contain the number of keys found
01175  *
01176  * \return the list of keys
01177  */
01178 hsm_key_t **
01179 hsm_list_keys_session(hsm_ctx_t *ctx, const hsm_session_t *session,
01180                       size_t *count)
01181 {
01182     return hsm_list_keys_session_internal(ctx, session, count, 1);
01183 }
01184 
01185 /* returns a count all keys available to the given session
01186  *
01187  * \param session the session to find the keys in
01188  *
01189  * \return the number of keys
01190  */
01191 size_t
01192 hsm_count_keys_session(hsm_ctx_t *ctx, const hsm_session_t *session)
01193 {
01194     size_t count = 0;
01195     (void) hsm_list_keys_session_internal(ctx, session, &count, 0);
01196     return count;
01197 }
01198 
01199 /* returns a newly allocated key structure containing the key data
01200  * for the given CKA_ID available in the session. Returns NULL if not
01201  * found
01202  */
01203 static hsm_key_t *
01204 hsm_find_key_by_id_session(hsm_ctx_t *ctx, const hsm_session_t *session,
01205                            const unsigned char *id, size_t len)
01206 {
01207     hsm_key_t *key;
01208     CK_OBJECT_HANDLE private_key_handle;
01209 
01210     private_key_handle = hsm_find_object_handle_for_id(
01211                              ctx,
01212                              session,
01213                              CKO_PRIVATE_KEY,
01214                              (CK_BYTE *) id,
01215                              (CK_ULONG) len);
01216     if (private_key_handle != 0) {
01217         key = hsm_key_new_privkey_object_handle(ctx, session,
01218                                                 private_key_handle);
01219         return key;
01220     } else {
01221         return NULL;
01222     }
01223 }
01224 
01225 /* Find a key pair by CKA_ID (as byte array)
01226 
01227 The returned key structure can be freed with hsm_key_free()
01228 
01229 \param context HSM context
01230 \param id CKA_ID of key to find (array of bytes)
01231 \param len number of bytes in the id
01232 \return key identifier or NULL if not found
01233 */
01234 static hsm_key_t *
01235 hsm_find_key_by_id_bin(hsm_ctx_t *ctx,
01236                        const unsigned char *id,
01237                        size_t len)
01238 {
01239     hsm_key_t *key;
01240     unsigned int i;
01241 
01242     if (!ctx) ctx = _hsm_ctx;
01243     if (!id) return NULL;
01244 
01245     for (i = 0; i < ctx->session_count; i++) {
01246         key = hsm_find_key_by_id_session(ctx, ctx->session[i], id, len);
01247         if (key) return key;
01248     }
01249     return NULL;
01250 }
01251 
01252 
01258 static hsm_session_t *
01259 hsm_find_repository_session(hsm_ctx_t *ctx, const char *repository)
01260 {
01261     unsigned int i;
01262     if (!repository) {
01263         for (i = 0; i < ctx->session_count; i++) {
01264             if (ctx->session[i]) {
01265                 return ctx->session[i];
01266             }
01267         }
01268     } else {
01269         for (i = 0; i < ctx->session_count; i++) {
01270             if (ctx->session[i] &&
01271                 strcmp(repository, ctx->session[i]->module->name) == 0)
01272             {
01273                 return ctx->session[i];
01274             }
01275         }
01276     }
01277 
01278     hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
01279                     "hsm_find_repository_session()",
01280                     "Can't find repository: %s", repository);
01281 
01282     return NULL;
01283 }
01284 
01285 static ldns_rdf *
01286 hsm_get_key_rdata(hsm_ctx_t *ctx, hsm_session_t *session,
01287                   const hsm_key_t *key)
01288 {
01289     CK_RV rv;
01290     CK_BYTE_PTR public_exponent = NULL;
01291     CK_ULONG public_exponent_len = 0;
01292     CK_BYTE_PTR modulus = NULL;
01293     CK_ULONG modulus_len = 0;
01294     unsigned long hKey = 0;
01295     unsigned char *data = NULL;
01296     size_t data_size = 0;
01297 
01298     CK_ATTRIBUTE template[] = {
01299         {CKA_PUBLIC_EXPONENT, NULL, 0},
01300         {CKA_MODULUS, NULL, 0},
01301     };
01302     ldns_rdf *rdf;
01303 
01304     if (!session || !session->module) {
01305         return NULL;
01306     }
01307 
01308     if (session->module->config->use_pubkey) {
01309         hKey = key->public_key;
01310     } else {
01311         hKey = key->private_key;
01312     }
01313 
01314     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
01315                                       session->session,
01316                                       hKey,
01317                                       template,
01318                                       2);
01319     if (hsm_pkcs11_check_error(ctx, rv, "C_GetAttributeValue")) {
01320         return NULL;
01321     }
01322     public_exponent_len = template[0].ulValueLen;
01323     modulus_len = template[1].ulValueLen;
01324 
01325     public_exponent = template[0].pValue = malloc(public_exponent_len);
01326     if (!public_exponent) {
01327         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata()",
01328             "Error allocating memory for public exponent");
01329         return NULL;
01330     }
01331 
01332     modulus = template[1].pValue = malloc(modulus_len);
01333     if (!modulus) {
01334         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata()",
01335             "Error allocating memory for modulus");
01336         free(public_exponent);
01337         return NULL;
01338     }
01339 
01340     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetAttributeValue(
01341                                       session->session,
01342                                       hKey,
01343                                       template,
01344                                       2);
01345     if (hsm_pkcs11_check_error(ctx, rv, "get attribute value")) {
01346         free(template[0].pValue);
01347         free(template[1].pValue);
01348         return NULL;
01349     }
01350 
01351     // Remove leading zeroes
01352     hsm_remove_leading_zeroes(public_exponent, &public_exponent_len);
01353     hsm_remove_leading_zeroes(modulus, &modulus_len);
01354 
01355     data_size = public_exponent_len + modulus_len + 1;
01356     if (public_exponent_len <= 256) {
01357         data = malloc(data_size);
01358         if (!data) {
01359             hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata()",
01360                 "Error allocating memory for pub key rr data");
01361             free(public_exponent);
01362             free(modulus);
01363             return NULL;
01364         }
01365         data[0] = public_exponent_len;
01366         memcpy(&data[1], public_exponent, public_exponent_len);
01367         memcpy(&data[1 + public_exponent_len], modulus, modulus_len);
01368     } else if (public_exponent_len <= 65535) {
01369         data_size += 2;
01370         data = malloc(data_size);
01371         if (!data) {
01372             hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata()",
01373                 "Error allocating memory for pub key rr data");
01374             free(public_exponent);
01375             free(modulus);
01376             return NULL;
01377         }
01378         data[0] = 0;
01379         ldns_write_uint16(&data[1], (uint16_t) public_exponent_len);
01380         memcpy(&data[3], public_exponent, public_exponent_len);
01381         memcpy(&data[3 + public_exponent_len], modulus, modulus_len);
01382     } else {
01383         hsm_ctx_set_error(ctx, -1, "hsm_get_key_rdata()",
01384             "Public exponent too big");
01385         free(public_exponent);
01386         free(modulus);
01387         return NULL;
01388     }
01389     rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, data_size, data);
01390     free(public_exponent);
01391     free(modulus);
01392 
01393     return rdf;
01394 }
01395 
01396 /* this function allocates memory for the mechanism ID and enough room
01397  * to leave the upcoming digest data. It fills in the mechanism id
01398  * use with care. The returned data must be free'd by the caller */
01399 static CK_BYTE *
01400 hsm_create_prefix(CK_ULONG digest_len,
01401                   ldns_algorithm algorithm,
01402                   CK_ULONG *data_size)
01403 {
01404     CK_BYTE *data;
01405     const CK_BYTE RSA_MD5_ID[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };
01406     const CK_BYTE RSA_SHA1_ID[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 };
01407     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 };
01408     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 };
01409 
01410     switch(algorithm) {
01411         case LDNS_SIGN_RSAMD5:
01412             *data_size = sizeof(RSA_MD5_ID) + digest_len;
01413             data = malloc(*data_size);
01414             memcpy(data, RSA_MD5_ID, sizeof(RSA_MD5_ID));
01415             break;
01416         case LDNS_SIGN_RSASHA1:
01417         case LDNS_SIGN_RSASHA1_NSEC3:
01418             *data_size = sizeof(RSA_SHA1_ID) + digest_len;
01419             data = malloc(*data_size);
01420             memcpy(data, RSA_SHA1_ID, sizeof(RSA_SHA1_ID));
01421             break;
01422         case LDNS_SIGN_RSASHA256:
01423             *data_size = sizeof(RSA_SHA256_ID) + digest_len;
01424             data = malloc(*data_size);
01425             memcpy(data, RSA_SHA256_ID, sizeof(RSA_SHA256_ID));
01426             break;
01427         case LDNS_SIGN_RSASHA512:
01428             *data_size = sizeof(RSA_SHA512_ID) + digest_len;
01429             data = malloc(*data_size);
01430             memcpy(data, RSA_SHA512_ID, sizeof(RSA_SHA512_ID));
01431             break;
01432         default:
01433             return NULL;
01434     }
01435     return data;
01436 }
01437 
01438 static CK_BYTE *
01439 hsm_digest_through_hsm(hsm_ctx_t *ctx,
01440                        hsm_session_t *session,
01441                        CK_MECHANISM_TYPE mechanism_type,
01442                        CK_ULONG digest_len,
01443                        ldns_buffer *sign_buf)
01444 {
01445     CK_MECHANISM digest_mechanism;
01446     CK_BYTE *digest;
01447     CK_RV rv;
01448 
01449     digest_mechanism.pParameter = NULL;
01450     digest_mechanism.ulParameterLen = 0;
01451     digest_mechanism.mechanism = mechanism_type;
01452     digest = malloc(digest_len);
01453     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DigestInit(session->session,
01454                                                  &digest_mechanism);
01455     if (hsm_pkcs11_check_error(ctx, rv, "HSM digest init")) {
01456         free(digest);
01457         return NULL;
01458     }
01459 
01460     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Digest(session->session,
01461                                         ldns_buffer_begin(sign_buf),
01462                                         ldns_buffer_position(sign_buf),
01463                                         digest,
01464                                         &digest_len);
01465     if (hsm_pkcs11_check_error(ctx, rv, "HSM digest")) {
01466         free(digest);
01467         return NULL;
01468     }
01469     return digest;
01470 }
01471 
01472 static ldns_rdf *
01473 hsm_sign_buffer(hsm_ctx_t *ctx,
01474                 ldns_buffer *sign_buf,
01475                 const hsm_key_t *key,
01476                 ldns_algorithm algorithm)
01477 {
01478     CK_RV rv;
01479     /* TODO: depends on type and key, or just leave it at current
01480      * maximum? */
01481     CK_ULONG signatureLen = 512;
01482     CK_BYTE *signature = NULL;
01483     CK_MECHANISM sign_mechanism;
01484 
01485     ldns_rdf *sig_rdf;
01486     CK_BYTE *digest = NULL;
01487     CK_ULONG digest_len;
01488 
01489     CK_BYTE *data = NULL;
01490     CK_ULONG data_len = 0;
01491 
01492     hsm_session_t *session;
01493 
01494     session = hsm_find_key_session(ctx, key);
01495     if (!session) return NULL;
01496 
01497     signature = malloc(signatureLen);
01498     if (signature == NULL) {
01499         return NULL;
01500     }
01501 
01502     /* some HSMs don't really handle CKM_SHA1_RSA_PKCS well, so
01503      * we'll do the hashing manually */
01504     /* When adding algorithms, remember there is another switch below */
01505     switch (algorithm) {
01506         case LDNS_SIGN_RSAMD5:
01507             digest_len = 16;
01508             digest = hsm_digest_through_hsm(ctx, session,
01509                                             CKM_MD5, digest_len,
01510                                             sign_buf);
01511             break;
01512 
01513         case LDNS_SIGN_RSASHA1:
01514         case LDNS_SIGN_RSASHA1_NSEC3:
01515             digest_len = LDNS_SHA1_DIGEST_LENGTH;
01516             digest = malloc(digest_len);
01517             digest = ldns_sha1(ldns_buffer_begin(sign_buf),
01518                                ldns_buffer_position(sign_buf),
01519                                digest);
01520             break;
01521 
01522         case LDNS_SIGN_RSASHA256:
01523             digest_len = LDNS_SHA256_DIGEST_LENGTH;
01524             digest = malloc(digest_len);
01525             digest = ldns_sha256(ldns_buffer_begin(sign_buf),
01526                                  ldns_buffer_position(sign_buf),
01527                                  digest);
01528             break;
01529 
01530         case LDNS_SIGN_RSASHA512:
01531             digest_len = LDNS_SHA512_DIGEST_LENGTH;
01532             digest = malloc(digest_len);
01533             digest = ldns_sha512(ldns_buffer_begin(sign_buf),
01534                                  ldns_buffer_position(sign_buf),
01535                                  digest);
01536             break;
01537 
01538         default:
01539             /* log error? or should we not even get here for
01540              * unsupported algorithms? */
01541             free(signature);
01542             return NULL;
01543     }
01544 
01545     if (!digest) {
01546         free(signature);
01547         return NULL;
01548     }
01549 
01550     /* CKM_RSA_PKCS does the padding, but cannot know the identifier
01551      * prefix, so we need to add that ourselves */
01552     data = hsm_create_prefix(digest_len, algorithm, &data_len);
01553     memcpy(data + data_len - digest_len, digest, digest_len);
01554 
01555     sign_mechanism.pParameter = NULL;
01556     sign_mechanism.ulParameterLen = 0;
01557     switch(algorithm) {
01558         case LDNS_SIGN_RSAMD5:
01559         case LDNS_SIGN_RSASHA1:
01560         case LDNS_SIGN_RSASHA1_NSEC3:
01561         case LDNS_SIGN_RSASHA256:
01562         case LDNS_SIGN_RSASHA512:
01563             sign_mechanism.mechanism = CKM_RSA_PKCS;
01564             break;
01565         default:
01566             /* log error? or should we not even get here for
01567              * unsupported algorithms? */
01568             free(data);
01569             free(digest);
01570             free(signature);
01571             return NULL;
01572     }
01573 
01574     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_SignInit(
01575                                       session->session,
01576                                       &sign_mechanism,
01577                                       key->private_key);
01578     if (hsm_pkcs11_check_error(ctx, rv, "sign init")) {
01579         free(data);
01580         free(digest);
01581         free(signature);
01582         return NULL;
01583     }
01584 
01585     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Sign(session->session, data, data_len,
01586                                       signature,
01587                                       &signatureLen);
01588     if (hsm_pkcs11_check_error(ctx, rv, "sign final")) {
01589         free(data);
01590         free(digest);
01591         free(signature);
01592         return NULL;
01593     }
01594 
01595     sig_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
01596                                     signatureLen,
01597                                     signature);
01598 
01599     free(data);
01600     free(digest);
01601     free(signature);
01602 
01603     return sig_rdf;
01604 
01605 }
01606 
01607 static int
01608 hsm_dname_is_wildcard(const ldns_rdf* dname)
01609 {
01610     return ( ldns_dname_label_count(dname) > 0 &&
01611              ldns_rdf_data(dname)[0] == 1 &&
01612              ldns_rdf_data(dname)[1] == '*');
01613 }
01614 
01615 static ldns_rr *
01616 hsm_create_empty_rrsig(const ldns_rr_list *rrset,
01617                        const hsm_sign_params_t *sign_params)
01618 {
01619     ldns_rr *rrsig;
01620     uint32_t orig_ttl;
01621     uint32_t orig_class;
01622     time_t now;
01623     uint8_t label_count;
01624 
01625     label_count = ldns_dname_label_count(
01626                        ldns_rr_owner(ldns_rr_list_rr(rrset, 0)));
01627     /* RFC 4035 section 2.2: dnssec label length and wildcards */
01628     if (hsm_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0)))) {
01629         label_count--;
01630     }
01631 
01632     rrsig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
01633 
01634     /* set the type on the new signature */
01635     orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));
01636     orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
01637 
01638     ldns_rr_set_class(rrsig, orig_class);
01639     ldns_rr_set_ttl(rrsig, orig_ttl);
01640     ldns_rr_set_owner(rrsig,
01641               ldns_rdf_clone(
01642                    ldns_rr_owner(
01643                     ldns_rr_list_rr(rrset,
01644                             0))));
01645 
01646     /* fill in what we know of the signature */
01647 
01648     /* set the orig_ttl */
01649     (void)ldns_rr_rrsig_set_origttl(
01650            rrsig,
01651            ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
01652                      orig_ttl));
01653     /* the signers name */
01654     (void)ldns_rr_rrsig_set_signame(
01655                rrsig,
01656                ldns_rdf_clone(sign_params->owner));
01657     /* label count - get it from the first rr in the rr_list */
01658     (void)ldns_rr_rrsig_set_labels(
01659             rrsig,
01660             ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
01661                                  label_count));
01662     /* inception, expiration */
01663     now = time(NULL);
01664     if (sign_params->inception != 0) {
01665         (void)ldns_rr_rrsig_set_inception(
01666                 rrsig,
01667                 ldns_native2rdf_int32(
01668                     LDNS_RDF_TYPE_TIME,
01669                     sign_params->inception));
01670     } else {
01671         (void)ldns_rr_rrsig_set_inception(
01672                 rrsig,
01673                 ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
01674     }
01675     if (sign_params->expiration != 0) {
01676         (void)ldns_rr_rrsig_set_expiration(
01677                 rrsig,
01678                 ldns_native2rdf_int32(
01679                     LDNS_RDF_TYPE_TIME,
01680                     sign_params->expiration));
01681     } else {
01682         (void)ldns_rr_rrsig_set_expiration(
01683                  rrsig,
01684                 ldns_native2rdf_int32(
01685                     LDNS_RDF_TYPE_TIME,
01686                     now + LDNS_DEFAULT_EXP_TIME));
01687     }
01688 
01689     (void)ldns_rr_rrsig_set_keytag(
01690            rrsig,
01691            ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
01692                                  sign_params->keytag));
01693 
01694     (void)ldns_rr_rrsig_set_algorithm(
01695             rrsig,
01696             ldns_native2rdf_int8(
01697                 LDNS_RDF_TYPE_ALG,
01698                 sign_params->algorithm));
01699 
01700     (void)ldns_rr_rrsig_set_typecovered(
01701             rrsig,
01702             ldns_native2rdf_int16(
01703                 LDNS_RDF_TYPE_TYPE,
01704                 ldns_rr_get_type(ldns_rr_list_rr(rrset,
01705                                                  0))));
01706 
01707     return rrsig;
01708 }
01709 
01710 
01711 /*
01712  *  API functions
01713  */
01714 
01715 int
01716 hsm_open(const char *config,
01717          char *(pin_callback)(const char *repository, void *),
01718          void *data)
01719 {
01720     xmlDocPtr doc;
01721     xmlXPathContextPtr xpath_ctx;
01722     xmlXPathObjectPtr xpath_obj;
01723     xmlNode *curNode;
01724     xmlChar *xexpr;
01725 
01726     int i;
01727     char *config_file;
01728     char *repository;
01729     char *token_label;
01730     char *module_path;
01731     char *module_pin;
01732     hsm_config_t module_config;
01733     int result = HSM_OK;
01734     int tries;
01735     int repositories = 0;
01736 
01737     /* create an internal context with an attached session for each
01738      * configured HSM. */
01739     _hsm_ctx = hsm_ctx_new();
01740 
01741     if (config) {
01742         config_file = strdup(config);
01743     } else{
01744         config_file = strdup(HSM_DEFAULT_CONFIG);
01745     }
01746 
01747     /* Load XML document */
01748     doc = xmlParseFile(config_file);
01749     free(config_file);
01750     if (doc == NULL) {
01751         return HSM_CONFIG_FILE_ERROR;
01752     }
01753 
01754     /* Create xpath evaluation context */
01755     xpath_ctx = xmlXPathNewContext(doc);
01756     if(xpath_ctx == NULL) {
01757         xmlFreeDoc(doc);
01758         hsm_ctx_free(_hsm_ctx);
01759         _hsm_ctx = NULL;
01760         return -1;
01761     }
01762 
01763     /* Evaluate xpath expression */
01764     xexpr = (xmlChar *)"//Configuration/RepositoryList/Repository";
01765     xpath_obj = xmlXPathEvalExpression(xexpr, xpath_ctx);
01766     if(xpath_obj == NULL) {
01767         xmlXPathFreeContext(xpath_ctx);
01768         xmlFreeDoc(doc);
01769         hsm_ctx_free(_hsm_ctx);
01770         _hsm_ctx = NULL;
01771         return -1;
01772     }
01773 
01774     if (xpath_obj->nodesetval) {
01775         for (i = 0; i < xpath_obj->nodesetval->nodeNr; i++) {
01776             /*module = hsm_module_new();*/
01777             token_label = NULL;
01778             module_path = NULL;
01779             module_pin = NULL;
01780             hsm_config_default(&module_config);
01781                  
01782             curNode = xpath_obj->nodesetval->nodeTab[i]->xmlChildrenNode;
01783             repository = (char *) xmlGetProp(xpath_obj->nodesetval->nodeTab[i],
01784                                              (const xmlChar *)"name");
01785 
01786             while (curNode) {
01787                 if (xmlStrEqual(curNode->name, (const xmlChar *)"TokenLabel"))
01788                     token_label = (char *) xmlNodeGetContent(curNode);
01789                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Module"))
01790                     module_path = (char *) xmlNodeGetContent(curNode);
01791                 if (xmlStrEqual(curNode->name, (const xmlChar *)"PIN"))
01792                     module_pin = (char *) xmlNodeGetContent(curNode);
01793                 if (xmlStrEqual(curNode->name, (const xmlChar *)"SkipPublicKey"))
01794                     module_config.use_pubkey = 0;                
01795                 curNode = curNode->next;
01796             }
01797 
01798             if (repository && token_label && module_path) {
01799                 if (module_pin) {
01800                     result = hsm_attach(repository,
01801                                         token_label,
01802                                         module_path,
01803                                         module_pin,
01804                                         &module_config);
01805                     free(module_pin);
01806                 } else {
01807                     if (pin_callback) {
01808                         result = HSM_PIN_INCORRECT;
01809                         tries = 0;
01810                         while (result == HSM_PIN_INCORRECT &&
01811                                tries < 3) {
01812                             module_pin = pin_callback(repository,
01813                                                       data);
01814                             result = hsm_attach(repository,
01815                                                 token_label,
01816                                                 module_path,
01817                                                 module_pin,
01818                                                 &module_config);
01819                             memset(module_pin, 0, strlen(module_pin));
01820                             tries++;
01821                         }
01822                     } else {
01823                         /* no pin, no callback, ignore
01824                          * module and token */
01825                         result = HSM_OK;
01826                     }
01827                 }
01828                 free(repository);
01829                 free(token_label);
01830                 free(module_path);
01831 
01832                 if (result != HSM_OK) {
01833                                         break;
01834                                 }
01835 
01836                 repositories++;
01837             }
01838         }
01839     }
01840 
01841     xmlXPathFreeObject(xpath_obj);
01842     xmlXPathFreeContext(xpath_ctx);
01843     xmlFreeDoc(doc);
01844 
01845     if (result == HSM_OK && repositories == 0) {
01846         hsm_ctx_set_error(_hsm_ctx, HSM_NO_REPOSITORIES, "hsm_open()",
01847             "No repositories found");
01848         return HSM_NO_REPOSITORIES;
01849     }
01850 
01851     return result;
01852 }
01853 
01854 char *
01855 hsm_prompt_pin(const char *repository, void *data)
01856 {
01857     char *prompt;
01858     char *r;
01859     (void) data;
01860     prompt = malloc(64);
01861     snprintf(prompt, 64, "Enter PIN for token %s:", repository);
01862 #ifdef HAVE_GETPASSPHRASE
01863     r = getpassphrase("Enter PIN:");
01864 #else
01865     r = getpass("Enter PIN:");
01866 #endif
01867     free(prompt);
01868     return r;
01869 }
01870 
01871 int
01872 hsm_close()
01873 {
01874     hsm_ctx_close(_hsm_ctx, 1);
01875     return 0;
01876 }
01877 
01878 hsm_ctx_t *
01879 hsm_create_context()
01880 {
01881     return hsm_ctx_clone(_hsm_ctx);
01882 }
01883 
01884 int
01885 hsm_check_context(hsm_ctx_t *ctx)
01886 {
01887     unsigned int i;
01888     hsm_session_t *session;
01889     CK_SESSION_INFO info;
01890     CK_RV rv;
01891     CK_SESSION_HANDLE session_handle;
01892 
01893     if (ctx == NULL) {
01894         ctx = _hsm_ctx;
01895     }
01896 
01897     for (i = 0; i < ctx->session_count; i++) {
01898         session = ctx->session[i];
01899         if (session == NULL) continue;
01900 
01901         /* Get session info */
01902         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GetSessionInfo(
01903                                         session->session,
01904                                         &info);
01905         if (hsm_pkcs11_check_error(ctx, rv, "get session info")) {
01906             return HSM_ERROR;
01907         }
01908 
01909         /* Check session info */
01910         if (info.state != CKS_RW_USER_FUNCTIONS) {
01911             hsm_ctx_set_error(ctx, HSM_ERROR, "hsm_check_context()",
01912                               "Session not logged in");
01913             return HSM_ERROR;
01914         }
01915 
01916         /* Try open and close a session with the token */
01917         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_OpenSession(info.slotID,
01918                                         CKF_SERIAL_SESSION | CKF_RW_SESSION,
01919                                         NULL,
01920                                         NULL,
01921                                         &session_handle);
01922         if (hsm_pkcs11_check_error(ctx, rv, "test open session")) {
01923             return HSM_ERROR;
01924         }
01925         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_CloseSession(session_handle);
01926         if (hsm_pkcs11_check_error(ctx, rv, "test close session")) {
01927             return HSM_ERROR;
01928         }
01929     }
01930 
01931     return HSM_OK;
01932 }
01933 
01934 void
01935 hsm_destroy_context(hsm_ctx_t *ctx)
01936 {
01937     hsm_ctx_close(ctx, 0);
01938 }
01939 
01943 hsm_sign_params_t *
01944 hsm_sign_params_new()
01945 {
01946     hsm_sign_params_t *params;
01947     params = malloc(sizeof(hsm_sign_params_t));
01948     params->algorithm = LDNS_SIGN_RSASHA1;
01949     params->flags = LDNS_KEY_ZONE_KEY;
01950     params->inception = 0;
01951     params->expiration = 0;
01952     params->keytag = 0;
01953     params->owner = NULL;
01954     return params;
01955 }
01956 
01957 void
01958 hsm_sign_params_free(hsm_sign_params_t *params)
01959 {
01960     if (params) {
01961         if (params->owner) ldns_rdf_deep_free(params->owner);
01962         free(params);
01963     }
01964 }
01965 
01966 hsm_key_t **
01967 hsm_list_keys(hsm_ctx_t *ctx, size_t *count)
01968 {
01969     hsm_key_t **keys = NULL;
01970     size_t key_count = 0;
01971     size_t cur_key_count;
01972     hsm_key_t **session_keys;
01973     unsigned int i, j;
01974 
01975     if (!ctx) {
01976         ctx = _hsm_ctx;
01977     }
01978 
01979     for (i = 0; i < ctx->session_count; i++) {
01980         session_keys = hsm_list_keys_session(ctx, ctx->session[i],
01981                                              &cur_key_count);
01982         keys = realloc(keys,
01983                        (key_count + cur_key_count) * sizeof(hsm_key_t *));
01984         for (j = 0; j < cur_key_count; j++) {
01985             keys[key_count + j] = session_keys[j];
01986         }
01987         key_count += cur_key_count;
01988         free(session_keys);
01989     }
01990     if (count) {
01991         *count = key_count;
01992     }
01993     return keys;
01994 }
01995 
01996 hsm_key_t **
01997 hsm_list_keys_repository(hsm_ctx_t *ctx,
01998                          size_t *count,
01999                          const char *repository)
02000 {
02001     hsm_session_t *session;
02002 
02003     if (!repository) return NULL;
02004     if (!ctx) ctx = _hsm_ctx;
02005 
02006     session = hsm_find_repository_session(ctx, repository);
02007     if (!session) {
02008         *count = 0;
02009         return NULL;
02010     }
02011     return hsm_list_keys_session(ctx, session, count);
02012 }
02013 
02014 size_t
02015 hsm_count_keys(hsm_ctx_t *ctx)
02016 {
02017     size_t count = 0;
02018     unsigned int i;
02019 
02020     if (!ctx) ctx = _hsm_ctx;
02021     for (i = 0; i < ctx->session_count; i++) {
02022         count += hsm_count_keys_session(ctx, ctx->session[i]);
02023     }
02024     return count;
02025 }
02026 
02027 size_t
02028 hsm_count_keys_repository(hsm_ctx_t *ctx,
02029                           const char *repository)
02030 {
02031     hsm_session_t *session;
02032 
02033     if (!repository) return 0;
02034     if (!ctx) ctx = _hsm_ctx;
02035 
02036     session = hsm_find_repository_session(ctx, repository);
02037     if (!session) {
02038         return 0;
02039     }
02040     return hsm_count_keys_session(ctx, session);
02041 }
02042 
02043 hsm_key_t *
02044 hsm_find_key_by_id(hsm_ctx_t *ctx, const char *id)
02045 {
02046     unsigned char *id_bytes;
02047     size_t len;
02048     hsm_key_t *key;
02049 
02050     id_bytes = hsm_hex_parse(id, &len);
02051 
02052     if (!id_bytes) return NULL;
02053 
02054     key = hsm_find_key_by_id_bin(ctx, id_bytes, len);
02055     free(id_bytes);
02056     return key;
02057 }
02058 
02059 hsm_key_t *
02060 hsm_generate_rsa_key(hsm_ctx_t *ctx,
02061                      const char *repository,
02062                      unsigned long keysize)
02063 {
02064     hsm_key_t *new_key;
02065     hsm_session_t *session;
02066     /* ids we create are 16 bytes of data */
02067     unsigned char id[16];
02068     /* that's 33 bytes in string (16*2 + 1 for \0) */
02069     char id_str[33];
02070     CK_RV rv;
02071     CK_OBJECT_HANDLE publicKey, privateKey;
02072     CK_KEY_TYPE keyType = CKK_RSA;
02073     CK_MECHANISM mechanism = {
02074         CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
02075     };
02076     CK_BYTE publicExponent[] = { 1, 0, 1 };
02077     CK_BBOOL ctrue = CK_TRUE;
02078     CK_BBOOL cfalse = CK_FALSE;
02079     CK_BBOOL ctoken = CK_TRUE;
02080 
02081     if (!ctx) ctx = _hsm_ctx;
02082     session = hsm_find_repository_session(ctx, repository);
02083     if (!session) return NULL;
02084 
02085     /* check whether this key doesn't happen to exist already */
02086     do {
02087         hsm_random_buffer(ctx, id, 16);
02088     } while (hsm_find_key_by_id_bin(ctx, id, 16));
02089     /* the CKA_LABEL will contain a hexadecimal string representation
02090      * of the id */
02091     hsm_hex_unparse(id_str, id, 16);
02092 
02093     if (! session->module->config->use_pubkey) {
02094         ctoken = CK_FALSE;
02095     }
02096 
02097     CK_ATTRIBUTE publicKeyTemplate[] = {
02098         { CKA_LABEL,(CK_UTF8CHAR*) id_str,   strlen(id_str)   },
02099         { CKA_ID,                  id,       16               },
02100         { CKA_KEY_TYPE,            &keyType, sizeof(keyType)  },
02101         { CKA_VERIFY,              &ctrue,   sizeof(ctrue)    },
02102         { CKA_ENCRYPT,             &cfalse,  sizeof(cfalse)   },
02103         { CKA_WRAP,                &cfalse,  sizeof(cfalse)   },
02104         { CKA_TOKEN,               &ctoken,  sizeof(ctoken)   },
02105         { CKA_MODULUS_BITS,        &keysize, sizeof(keysize)  },
02106         { CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
02107     };
02108 
02109     CK_ATTRIBUTE privateKeyTemplate[] = {
02110         { CKA_LABEL,(CK_UTF8CHAR *) id_str, strlen (id_str) },
02111         { CKA_ID,          id,       16                     },
02112         { CKA_KEY_TYPE,    &keyType, sizeof(keyType) },
02113         { CKA_SIGN,        &ctrue,   sizeof (ctrue) },
02114         { CKA_DECRYPT,     &cfalse,  sizeof (cfalse) },
02115         { CKA_UNWRAP,      &cfalse,  sizeof (cfalse) },
02116         { CKA_SENSITIVE,   &ctrue,   sizeof (ctrue) },
02117         { CKA_TOKEN,       &ctrue,   sizeof (ctrue)  },
02118         { CKA_PRIVATE,     &ctrue,   sizeof (ctrue)  },
02119         { CKA_EXTRACTABLE, &cfalse,  sizeof (cfalse) }
02120     };
02121 
02122     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateKeyPair(session->session,
02123                                                  &mechanism,
02124                                                  publicKeyTemplate, 9,
02125                                                  privateKeyTemplate, 10,
02126                                                  &publicKey,
02127                                                  &privateKey);
02128     if (hsm_pkcs11_check_error(ctx, rv, "generate key pair")) {
02129         return NULL;
02130     }
02131 
02132     new_key = hsm_key_new();
02133     new_key->module = session->module;
02134 
02135     if (session->module->config->use_pubkey) {
02136         new_key->public_key = publicKey;        
02137     } else {
02138         new_key->public_key = 0;        
02139     }
02140 
02141     new_key->private_key = privateKey;
02142     return new_key;
02143 }
02144 
02145 int
02146 hsm_remove_key(hsm_ctx_t *ctx, hsm_key_t *key)
02147 {
02148     CK_RV rv;
02149     hsm_session_t *session;
02150     if (!ctx) ctx = _hsm_ctx;
02151     if (!key) return -1;
02152 
02153     session = hsm_find_key_session(ctx, key);
02154     if (!session) return -2;
02155 
02156     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
02157                                                key->private_key);
02158     if (hsm_pkcs11_check_error(ctx, rv, "Destroy private key")) {
02159         return -3;
02160     }
02161     key->private_key = 0;
02162 
02163     if (session->module->config->use_pubkey) {
02164         rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DestroyObject(session->session,
02165                                                    key->public_key);
02166         if (hsm_pkcs11_check_error(ctx, rv, "Destroy public key")) {
02167             return -4;
02168         }
02169     }
02170     key->public_key = 0;
02171 
02172     return 0;
02173 }
02174 
02175 void
02176 hsm_key_free(hsm_key_t *key)
02177 {
02178     if (key) {
02179         free(key);
02180     }
02181 }
02182 
02183 void
02184 hsm_key_list_free(hsm_key_t **key_list, size_t count)
02185 {
02186     size_t i;
02187     for (i = 0; i < count; i++) {
02188         hsm_key_free(key_list[i]);
02189     }
02190     free(key_list);
02191 }
02192 
02193 char *
02194 hsm_get_key_id(hsm_ctx_t *ctx, const hsm_key_t *key)
02195 {
02196     unsigned char *id;
02197     char *id_str;
02198     size_t len;
02199     hsm_session_t *session;
02200 
02201     if (!ctx) ctx = _hsm_ctx;
02202     if (!key) return NULL;
02203 
02204     session = hsm_find_key_session(ctx, key);
02205     if (!session) return NULL;
02206 
02207     id = hsm_get_id_for_object(ctx, session, key->private_key, &len);
02208     if (!id) return NULL;
02209 
02210     /* this is plain binary data, we need to convert it to hex */
02211     id_str = malloc(len * 2 + 1);
02212     if (!id_str) return NULL;
02213 
02214     hsm_hex_unparse(id_str, id, len);
02215 
02216     free(id);
02217 
02218     return id_str;
02219 }
02220 
02221 hsm_key_info_t *
02222 hsm_get_key_info(hsm_ctx_t *ctx,
02223                  const hsm_key_t *key)
02224 {
02225     hsm_key_info_t *key_info;
02226     hsm_session_t *session;
02227 
02228     if (!ctx) ctx = _hsm_ctx;
02229     session = hsm_find_key_session(ctx, key);
02230     if (!session) return NULL;
02231 
02232     key_info = malloc(sizeof(hsm_key_info_t));
02233 
02234     key_info->id = hsm_get_key_id(ctx, key);
02235     if (key_info->id == NULL) {
02236         key_info->id = strdup("");
02237     }
02238 
02239     key_info->algorithm = (unsigned long) hsm_get_key_algorithm(ctx,
02240                                                                 session,
02241                                                                 key);
02242     key_info->keysize = (unsigned long) hsm_get_key_size(ctx,
02243                                                          session,
02244                                                          key,
02245                                                          key_info->algorithm);
02246 
02247     switch(key_info->algorithm) {
02248         case CKK_RSA:
02249             key_info->algorithm_name = strdup("RSA");
02250             break;
02251          default:
02252             key_info->algorithm_name = malloc(HSM_MAX_ALGONAME);
02253             snprintf(key_info->algorithm_name, HSM_MAX_ALGONAME,
02254                 "%lu", key_info->algorithm);
02255             break;
02256     }
02257 
02258     return key_info;
02259 }
02260 
02261 void
02262 hsm_key_info_free(hsm_key_info_t *key_info)
02263 {
02264     if (key_info) {
02265         if (key_info->id) {
02266             free(key_info->id);
02267         }
02268         if (key_info->algorithm_name) {
02269             free(key_info->algorithm_name);
02270         }
02271         free(key_info);
02272     }
02273 }
02274 
02275 ldns_rr*
02276 hsm_sign_rrset(hsm_ctx_t *ctx,
02277                const ldns_rr_list* rrset,
02278                const hsm_key_t *key,
02279                const hsm_sign_params_t *sign_params)
02280 {
02281     ldns_rr *signature;
02282     ldns_buffer *sign_buf;
02283     ldns_rdf *b64_rdf;
02284     size_t i;
02285     (void) ctx;
02286 
02287     if (!key) return NULL;
02288     if (!sign_params) return NULL;
02289 
02290     signature = hsm_create_empty_rrsig((ldns_rr_list *)rrset,
02291                                        sign_params);
02292 
02293     /* right now, we have: a key, a semi-sig and an rrset. For
02294      * which we can create the sig and base64 encode that and
02295      * add that to the signature */
02296     sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
02297 
02298     if (ldns_rrsig2buffer_wire(sign_buf, signature)
02299         != LDNS_STATUS_OK) {
02300         ldns_buffer_free(sign_buf);
02301         /* ERROR */
02302         return NULL;
02303     }
02304 
02305     /* make it canonical */
02306     for(i = 0; i < ldns_rr_list_rr_count(rrset); i++) {
02307         ldns_rr2canonical(ldns_rr_list_rr(rrset, i));
02308     }
02309 
02310     /* add the rrset in sign_buf */
02311     if (ldns_rr_list2buffer_wire(sign_buf, rrset)
02312         != LDNS_STATUS_OK) {
02313         ldns_buffer_free(sign_buf);
02314         return NULL;
02315     }
02316 
02317     b64_rdf = hsm_sign_buffer(ctx, sign_buf, key, sign_params->algorithm);
02318 
02319     ldns_buffer_free(sign_buf);
02320     if (!b64_rdf) {
02321         /* signing went wrong */
02322         return NULL;
02323     }
02324 
02325     ldns_rr_rrsig_set_sig(signature, b64_rdf);
02326 
02327     return signature;
02328 }
02329 
02330 /* returns a newly allocated (not null-terminated!) string containing
02331  * the message digest of the given source string
02332  * digest length contains the length of the result
02333  * caller must free returned data with free()
02334  * returns NULL (and zero digest length) on error
02335  */
02336 static CK_BYTE *
02337 hsm_digest(hsm_ctx_t *ctx,
02338            hsm_session_t *session,
02339            CK_MECHANISM digest_mechanism,
02340            char *source,
02341            size_t length,
02342            size_t *digest_length)
02343 {
02344     CK_RV rv;
02345     CK_BYTE *digest;
02346     CK_ULONG d = 0;
02347 
02348     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_DigestInit(session->session,
02349                                                  &digest_mechanism);
02350     if (hsm_pkcs11_check_error(ctx, rv, "digest init")) {
02351         *digest_length = 0;
02352         return NULL;
02353     }
02354 
02355     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Digest(session->session,
02356                                         (CK_BYTE *)source,
02357                                         length,
02358                                         NULL,
02359                                         &d);
02360 
02361     if (hsm_pkcs11_check_error(ctx, rv, "digest to determine result size")) {
02362         *digest_length = 0;
02363         return NULL;
02364     }
02365     digest = malloc(d);
02366     rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_Digest(session->session,
02367                                         (CK_BYTE *)source,
02368                                         length,
02369                                         digest,
02370                                         &d);
02371     if (hsm_pkcs11_check_error(ctx, rv, "digest")) {
02372         *digest_length = 0;
02373         free(digest);
02374         return NULL;
02375     }
02376 
02377     *digest_length = d;
02378     return digest;
02379 }
02380 
02381 ldns_rdf *
02382 hsm_nsec3_hash_name(hsm_ctx_t *ctx,
02383                     ldns_rdf *name,
02384                     uint8_t algorithm,
02385                     uint16_t iterations,
02386                     uint8_t salt_length,
02387                     uint8_t *salt)
02388 {
02389     char *orig_owner_str;
02390     size_t hashed_owner_str_len;
02391     ldns_rdf *hashed_owner;
02392     char *hashed_owner_str;
02393     char *hashed_owner_b32;
02394     int hashed_owner_b32_len;
02395     uint32_t cur_it;
02396     char *hash = NULL;
02397     size_t hash_length = 0;
02398     ldns_status status;
02399     CK_MECHANISM mechanism;
02400     unsigned int i;
02401     hsm_session_t *session = NULL;
02402     char *error_name;
02403 
02404     switch(algorithm) {
02405     case 1:
02406         mechanism.mechanism = CKM_SHA_1;
02407         mechanism.pParameter = NULL;
02408         mechanism.ulParameterLen = 0;
02409         break;
02410     default:
02411         printf("unknown algo: %u\n", (unsigned int)algorithm);
02412         return NULL;
02413         break;
02414     }
02415 
02416     /* just use the first available session */
02417     if (!ctx) ctx = _hsm_ctx;
02418     for (i = 0; i < ctx->session_count; i++) {
02419         if (ctx->session[i]) session = ctx->session[i];
02420     }
02421     if (!session) {
02422         return NULL;
02423     }
02424 
02425     /* prepare the owner name according to the draft section bla */
02426     orig_owner_str = ldns_rdf2str(name);
02427 
02428     hashed_owner_str_len = salt_length + ldns_rdf_size(name);
02429     hashed_owner_str = LDNS_XMALLOC(char, hashed_owner_str_len);
02430     memcpy(hashed_owner_str, ldns_rdf_data(name), ldns_rdf_size(name));
02431     memcpy(hashed_owner_str + ldns_rdf_size(name), salt, salt_length);
02432 
02433     for (cur_it = iterations + 1; cur_it > 0; cur_it--) {
02434         if (hash != NULL) free(hash);
02435         hash = (char *) hsm_digest(ctx,
02436                                    session,
02437                                    mechanism,
02438                                    hashed_owner_str,
02439                                    hashed_owner_str_len,
02440                                    &hash_length);
02441 
02442         LDNS_FREE(hashed_owner_str);
02443         hashed_owner_str_len = salt_length + hash_length;
02444         hashed_owner_str = LDNS_XMALLOC(char, hashed_owner_str_len);
02445         if (!hashed_owner_str) {
02446             hsm_ctx_set_error(ctx, -1, "hsm_nsec3_hash_name()",
02447                 "Memory error");
02448             return NULL;
02449         }
02450         memcpy(hashed_owner_str, hash, hash_length);
02451         memcpy(hashed_owner_str + hash_length, salt, salt_length);
02452     }
02453 
02454     LDNS_FREE(hashed_owner_str);
02455     hashed_owner_str = hash;
02456     hashed_owner_str_len = hash_length;
02457     hashed_owner_b32 = LDNS_XMALLOC(char,
02458                               ldns_b32_ntop_calculate_size(
02459                                    hashed_owner_str_len) + 1);
02460     LDNS_FREE(orig_owner_str);
02461     hashed_owner_b32_len =
02462         (size_t) ldns_b32_ntop_extended_hex((uint8_t *) hashed_owner_str,
02463                                      hashed_owner_str_len,
02464                                      hashed_owner_b32,
02465                                      ldns_b32_ntop_calculate_size(
02466                                          hashed_owner_str_len));
02467     if (hashed_owner_b32_len < 1) {
02468         error_name = ldns_rdf2str(name);
02469         hsm_ctx_set_error(ctx, -1, "hsm_nsec3_hash_name()",
02470              "Error in base32 extended hex encoding "
02471              "of hashed owner name (name: %s, return code: %d)",
02472              error_name, hashed_owner_b32_len);
02473         LDNS_FREE(error_name);
02474         LDNS_FREE(hashed_owner_b32);
02475         return NULL;
02476     }
02477     hashed_owner_str_len = hashed_owner_b32_len;
02478     hashed_owner_b32[hashed_owner_b32_len] = '\0';
02479 
02480     status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32);
02481     if (status != LDNS_STATUS_OK) {
02482         hsm_ctx_set_error(ctx, -1, "hsm_nsec3_hash_name()",
02483             "Error creating rdf from %s", hashed_owner_b32);
02484         LDNS_FREE(hashed_owner_b32);
02485         return NULL;
02486     }
02487 
02488     free(hash);
02489     LDNS_FREE(hashed_owner_b32);
02490     return hashed_owner;
02491 }
02492 
02493 ldns_rr *
02494 hsm_get_dnskey(hsm_ctx_t *ctx,
02495                const hsm_key_t *key,
02496                const hsm_sign_params_t *sign_params)
02497 {
02498     /* CK_RV rv; */
02499     ldns_rr *dnskey;
02500     hsm_session_t *session;
02501     ldns_rdf *rdata;
02502 
02503     if (!ctx) ctx = _hsm_ctx;
02504     if (!key) {
02505         hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL key");
02506         return NULL;
02507     }
02508     if (!sign_params) {
02509         hsm_ctx_set_error(ctx, -1, "hsm_get_dnskey()", "Got NULL sign_params");
02510         return NULL;
02511     }
02512     session = hsm_find_key_session(ctx, key);
02513     if (!session) return NULL;
02514 
02515     dnskey = ldns_rr_new();
02516     ldns_rr_set_type(dnskey, LDNS_RR_TYPE_DNSKEY);
02517 
02518     ldns_rr_set_owner(dnskey, ldns_rdf_clone(sign_params->owner));
02519 
02520     ldns_rr_push_rdf(dnskey,
02521             ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
02522                 sign_params->flags));
02523     ldns_rr_push_rdf(dnskey,
02524                      ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
02525                                           LDNS_DNSSEC_KEYPROTO));
02526     ldns_rr_push_rdf(dnskey,
02527                      ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG,
02528                                           sign_params->algorithm));
02529 
02530     rdata = hsm_get_key_rdata(ctx, session, key);
02531     if (rdata == NULL) {
02532         return NULL;
02533     }
02534     ldns_rr_push_rdf(dnskey, rdata);
02535 
02536     return dnskey;
02537 }
02538 
02539 int
02540 hsm_random_buffer(hsm_ctx_t *ctx,
02541                   unsigned char *buffer,
02542                   unsigned long length)
02543 {
02544     CK_RV rv;
02545     unsigned int i;
02546     hsm_session_t *session;
02547     if (!buffer) return -1;
02548     if (!ctx) ctx = _hsm_ctx;
02549 
02550     /* just try every attached token. If one errors (be it NO_RNG, or
02551      * any other error, simply try the next */
02552     for (i = 0; i < ctx->session_count; i++) {
02553         session = ctx->session[i];
02554         if (session) {
02555             rv = ((CK_FUNCTION_LIST_PTR)session->module->sym)->C_GenerateRandom(
02556                                          session->session,
02557                                          buffer,
02558                                          length);
02559             if (rv == CKR_OK) {
02560                 return 0;
02561             }
02562         }
02563     }
02564     return 1;
02565 }
02566 
02567 uint32_t
02568 hsm_random32(hsm_ctx_t *ctx)
02569 {
02570     uint32_t rnd;
02571     int result;
02572     unsigned char rnd_buf[4];
02573     result = hsm_random_buffer(ctx, rnd_buf, 4);
02574     if (result == 0) {
02575         memcpy(&rnd, rnd_buf, 4);
02576         return rnd;
02577     } else {
02578         return 0;
02579     }
02580 }
02581 
02582 uint64_t
02583 hsm_random64(hsm_ctx_t *ctx)
02584 {
02585     uint64_t rnd;
02586     int result;
02587     unsigned char rnd_buf[8];
02588     result = hsm_random_buffer(ctx, rnd_buf, 8);
02589     if (result == 0) {
02590         memcpy(&rnd, rnd_buf, 8);
02591         return rnd;
02592     } else {
02593         return 0;
02594     }
02595 }
02596 
02597 
02598 /*
02599  * Additional functions
02600  */
02601 
02602 int hsm_attach(const char *repository,
02603                const char *token_label,
02604                const char *path,
02605                const char *pin,
02606                const hsm_config_t *config)
02607 {
02608     hsm_session_t *session;
02609     int result;
02610 
02611     result = hsm_session_init(_hsm_ctx,
02612                               &session,
02613                               repository,
02614                               token_label,
02615                               path,
02616                               pin,
02617                               config);
02618     if (result == HSM_OK) {
02619         return hsm_ctx_add_session(_hsm_ctx, session);
02620     } else {
02621         return result;
02622     }
02623 }
02624 
02626 int hsm_detach(const char *repository)
02627 {
02628     unsigned int i;
02629     for (i = 0; i < _hsm_ctx->session_count; i++) {
02630         if (_hsm_ctx->session[i] &&
02631             strcmp(_hsm_ctx->session[i]->module->name,
02632                    repository) == 0) {
02633             hsm_session_close(_hsm_ctx, _hsm_ctx->session[i], 1);
02634             _hsm_ctx->session[i] = NULL;
02635             /* if this was the last session in the list, decrease the
02636              * session count */
02637             if (i == _hsm_ctx->session_count) {
02638                 while(_hsm_ctx->session_count > 0 &&
02639                       !_hsm_ctx->session[i]) {
02640                     _hsm_ctx->session_count--;
02641                 }
02642             }
02643             return 0;
02644         }
02645     }
02646     return -1;
02647 }
02648 
02649 int
02650 hsm_token_attached(hsm_ctx_t *ctx, const char *repository)
02651 {
02652     unsigned int i;
02653     if (!ctx) ctx = _hsm_ctx;
02654     for (i = 0; i < ctx->session_count; i++) {
02655         if (ctx->session[i] &&
02656             strcmp(ctx->session[i]->module->name, repository) == 0) {
02657                 return 1;
02658         }
02659     }
02660 
02661     hsm_ctx_set_error(ctx, HSM_REPOSITORY_NOT_FOUND,
02662                     "hsm_token_attached()",
02663                     "Can't find repository: %s", repository);
02664     return 0;
02665 }
02666 
02667 int
02668 hsm_supported_algorithm(ldns_algorithm algorithm)
02669 {
02670     switch(algorithm) {
02671         case LDNS_SIGN_RSAMD5:
02672         case LDNS_SIGN_RSASHA1:
02673         case LDNS_SIGN_RSASHA1_NSEC3:
02674         case LDNS_SIGN_RSASHA256:
02675         case LDNS_SIGN_RSASHA512:
02676             return 0;
02677             break;
02678         default:
02679             return -1;
02680     }
02681 }
02682 
02683 char *
02684 hsm_get_error(hsm_ctx_t *gctx)
02685 {
02686     hsm_ctx_t *ctx;
02687 
02688     char *message;
02689 
02690     if (!gctx) {
02691         ctx = _hsm_ctx;
02692     } else {
02693         ctx = gctx;
02694     }
02695 
02696     if (ctx->error) {
02697         ctx->error = 0;
02698         message = malloc(HSM_ERROR_MSGSIZE);
02699 
02700         if (message == NULL) {
02701             return strdup("libhsm memory allocation failed");
02702         }
02703 
02704         snprintf(message, HSM_ERROR_MSGSIZE,
02705             "%s: %s",
02706             ctx->error_action ? ctx->error_action : "unknown()",
02707             ctx->error_message ? ctx->error_message : "unknown error");
02708         return message;
02709     };
02710 
02711     return NULL;
02712 }
02713 
02714 void
02715 hsm_print_session(hsm_session_t *session)
02716 {
02717     printf("\t\tmodule at %p (sym %p)\n", (void *) session->module, (void *) session->module->sym);
02718     printf("\t\tmodule path: %s\n", session->module->path);
02719     printf("\t\trepository name: %s\n", session->module->name);
02720     printf("\t\ttoken label: %s\n", session->module->token_label);
02721     printf("\t\tsess handle: %u\n", (unsigned int) session->session);
02722 }
02723 
02724 void
02725 hsm_print_ctx(hsm_ctx_t *gctx) {
02726     hsm_ctx_t *ctx;
02727     unsigned int i;
02728     if (!gctx) {
02729         ctx = _hsm_ctx;
02730     } else {
02731         ctx = gctx;
02732     }
02733     printf("CTX Sessions: %lu\n",
02734            (long unsigned int) ctx->session_count);
02735     for (i = 0; i < ctx->session_count; i++) {
02736         printf("\tSession at %p\n", (void *) ctx->session[i]);
02737         hsm_print_session(ctx->session[i]);
02738     }
02739 }
02740 
02741 void
02742 hsm_print_key(hsm_key_t *key) {
02743     hsm_key_info_t *key_info;
02744     if (key) {
02745         key_info = hsm_get_key_info(NULL, key);
02746         if (key_info) {
02747             printf("key:\n");
02748             printf("\tmodule: %p\n", (void *) key->module);
02749             printf("\tprivkey handle: %u\n", (unsigned int) key->private_key);
02750             if (key->module->config->use_pubkey) {
02751                 printf("\tpubkey handle: %u\n", (unsigned int) key->public_key);
02752             } else {
02753                 printf("\tpubkey handle: %s\n", "NULL");
02754             }
02755             printf("\trepository: %s\n", key->module->name);
02756             printf("\talgorithm: %s\n", key_info->algorithm_name);
02757             printf("\tsize: %lu\n", key_info->keysize);
02758             printf("\tid: %s\n", key_info->id);
02759             hsm_key_info_free(key_info);
02760         } else {
02761             printf("key: hsm_get_key_info() returned NULL\n");
02762         }
02763     } else {
02764         printf("key: <void>\n");
02765     }
02766 }
02767 
02768 void
02769 hsm_print_error(hsm_ctx_t *gctx)
02770 {
02771     char *message;
02772 
02773     message = hsm_get_error(gctx);
02774 
02775     if (message) {
02776         fprintf(stderr, "%s\n", message);
02777         free(message);
02778     } else {
02779         fprintf(stderr, "Unknown error\n");
02780     }
02781 }
02782 
02783 void
02784 hsm_print_tokeninfo(hsm_ctx_t *gctx)
02785 {
02786     CK_RV rv;
02787     CK_SLOT_ID slot_id;
02788     CK_TOKEN_INFO token_info;
02789     hsm_ctx_t *ctx;
02790     unsigned int i;
02791     hsm_session_t *session;
02792     int result;
02793 
02794     if (!gctx) {
02795         ctx = _hsm_ctx;
02796     } else {
02797         ctx = gctx;
02798     }
02799 
02800     for (i = 0; i < ctx->session_count; i++) {
02801         session = ctx->session[i];
02802 
02803         result = hsm_get_slot_id(ctx,
02804                                   session->module->sym,
02805                                   session->module->token_label,
02806                                   &slot_id);
02807         if (result != HSM_OK) return;
02808 
02809         rv = ((CK_FUNCTION_LIST_PTR) session->module->sym)->C_GetTokenInfo(slot_id, &token_info);
02810         if (hsm_pkcs11_check_error(ctx, rv, "C_GetTokenInfo")) {
02811             return;
02812         }
02813 
02814         printf("Repository: %s\n",session->module->name);
02815 
02816         printf("\tModule:        %s\n", session->module->path);
02817         printf("\tSlot:          %lu\n", slot_id);
02818         printf("\tToken Label:   %.*s\n",
02819             (int) sizeof(token_info.label), token_info.label);
02820         printf("\tManufacturer:  %.*s\n",
02821             (int) sizeof(token_info.manufacturerID), token_info.manufacturerID);
02822         printf("\tModel:         %.*s\n",
02823             (int) sizeof(token_info.model), token_info.model);
02824         printf("\tSerial:        %.*s\n",
02825             (int) sizeof(token_info.serialNumber), token_info.serialNumber);
02826 
02827         if (i + 1 != ctx->session_count)
02828             printf("\n");
02829     }
02830 }