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