diff options
Diffstat (limited to 'SoftHSMv2/src/bin/util')
-rw-r--r-- | SoftHSMv2/src/bin/util/Makefile.am | 40 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp | 704 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util-botan.h | 142 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp | 790 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util-ossl.h | 142 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util.1 | 259 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util.cpp | 1318 | ||||
-rw-r--r-- | SoftHSMv2/src/bin/util/softhsm2-util.h | 77 |
8 files changed, 3472 insertions, 0 deletions
diff --git a/SoftHSMv2/src/bin/util/Makefile.am b/SoftHSMv2/src/bin/util/Makefile.am new file mode 100644 index 0000000..a552e14 --- /dev/null +++ b/SoftHSMv2/src/bin/util/Makefile.am @@ -0,0 +1,40 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/../common \ + -I$(srcdir)/../../lib/ \ + -I$(srcdir)/../../lib/common \ + -I$(srcdir)/../../lib/crypto \ + -I$(srcdir)/../../lib/data_mgr \ + -I$(srcdir)/../../lib/object_store \ + -I$(srcdir)/../../lib/pkcs11 \ + @CRYPTO_INCLUDES@ \ + @SQLITE3_INCLUDES@ + +dist_man_MANS = softhsm2-util.1 + +bin_PROGRAMS = softhsm2-util + +AUTOMAKE_OPTIONS = subdir-objects + +softhsm2_util_SOURCES = softhsm2-util.cpp \ + ../common/findslot.cpp \ + ../common/getpw.cpp \ + ../common/library.cpp + +softhsm2_util_LDADD = @CRYPTO_LIBS@ \ + @SQLITE3_LIBS@ \ + ../../lib/libsofthsm_convarch.la + +# Compile with support of OpenSSL +if WITH_OPENSSL +softhsm2_util_SOURCES += softhsm2-util-ossl.cpp \ + ../../lib/crypto/OSSLComp.cpp +endif + +# Compile with support of Botan +if WITH_BOTAN +softhsm2_util_SOURCES += softhsm2-util-botan.cpp +endif + +EXTRA_DIST = $(srcdir)/*.h \ + $(srcdir)/*.cpp diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp new file mode 100644 index 0000000..cecc0ce --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-botan.cpp @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-botan.cpp + + Code specific for Botan + *****************************************************************************/ + +#include <config.h> +#define UTIL_BOTAN +#include "softhsm2-util.h" +#include "softhsm2-util-botan.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <botan/init.h> +#include <botan/auto_rng.h> +#include <botan/pkcs8.h> +#include <botan/bigint.h> +#include <botan/version.h> +#include <botan/der_enc.h> + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) +#include <botan/libstate.h> +bool wasInitialized = false; +#endif + +// Init Botan +void crypto_init() +{ +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + // The PKCS#11 library might be using Botan + // Check if it has already initialized Botan + if (Botan::Global_State_Management::global_state_exists()) + { + wasInitialized = true; + } + + if (!wasInitialized) + { + Botan::LibraryInitializer::initialize("thread_safe=true"); + } +#else + Botan::LibraryInitializer::initialize("thread_safe=true"); +#endif +} + +// Final Botan +void crypto_final() +{ +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14) + if (!wasInitialized) + { + Botan::LibraryInitializer::deinitialize(); + } +#else + Botan::LibraryInitializer::deinitialize(); +#endif +} + +// Import a aes secret key from given path +int crypto_import_aes_key +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* label, + char* objID, + size_t objIDLen +) +{ + const size_t cMaxAesKeySize = 1024 + 1; // including null-character + char aesKeyValue[cMaxAesKeySize]; + FILE* fp = fopen(filePath, "rb"); + if (fp == NULL) + { + fprintf(stderr, "ERROR: Could not open the secret key file.\n"); + return 1; + } + if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL) + { + fprintf(stderr, "ERROR: Could not read the secret key file.\n"); + fclose(fp); + return 1; + } + fclose(fp); + + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_AES; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, &aesKeyValue, strlen(aesKeyValue) } + }; + + CK_OBJECT_HANDLE hKey; + CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the secret key in the token. " + "Maybe the algorithm is not supported.\n"); + return 1; + } + + return 0; +} + +// Import a key pair from given path +int crypto_import_key_pair +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* filePIN, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey +) +{ + Botan::Private_Key* pkey = crypto_read_file(filePath, filePIN); + if (pkey == NULL) + { + return 1; + } + + Botan::RSA_PrivateKey* rsa = NULL; + Botan::DSA_PrivateKey* dsa = NULL; +#ifdef WITH_ECC + Botan::ECDSA_PrivateKey* ecdsa = NULL; +#endif + + if (pkey->algo_name().compare("RSA") == 0) + { + rsa = dynamic_cast<Botan::RSA_PrivateKey*>(pkey); + } + else if (pkey->algo_name().compare("DSA") == 0) + { + dsa = dynamic_cast<Botan::DSA_PrivateKey*>(pkey); + } +#ifdef WITH_ECC + else if (pkey->algo_name().compare("ECDSA") == 0) + { + ecdsa = dynamic_cast<Botan::ECDSA_PrivateKey*>(pkey); + } +#endif + else + { + fprintf(stderr, "ERROR: %s is not a supported algorithm.\n", + pkey->algo_name().c_str()); + delete pkey; + return 1; + } + + int result = 0; + + if (rsa) + { + result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa); + } + else if (dsa) + { + result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa); + } +#ifdef WITH_ECC + else if (ecdsa) + { + result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa); + } +#endif + else + { + fprintf(stderr, "ERROR: Could not get the key material.\n"); + result = 1; + } + + delete pkey; + return result; +} + +// Read the key from file +Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN) +{ + if (filePath == NULL) + { + return NULL; + } + + Botan::AutoSeeded_RNG* rng = new Botan::AutoSeeded_RNG(); + Botan::Private_Key* pkey = NULL; + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + if (filePIN == NULL) + { + pkey = Botan::PKCS8::load_key(std::string(filePath), *rng); + } + else + { + pkey = Botan::PKCS8::load_key(std::string(filePath), *rng, std::string(filePIN)); + } +#else + if (filePIN == NULL) + { + pkey = Botan::PKCS8::load_key(filePath, *rng); + } + else + { + pkey = Botan::PKCS8::load_key(filePath, *rng, filePIN); + } +#endif + } + catch (std::exception& e) + { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "ERROR: Perhaps wrong path to file, wrong file format, " + "or wrong PIN to file (--file-pin <PIN>).\n"); + delete rng; + return NULL; + } + delete rng; + + return pkey; +} + +// Save the key data in PKCS#11 +int crypto_save_rsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::RSA_PrivateKey* rsa +) +{ + rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa); + if (!keyMat) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN }, + { CKA_PRIVATE_EXPONENT, keyMat->bigD, keyMat->sizeD }, + { CKA_PRIME_1, keyMat->bigP, keyMat->sizeP }, + { CKA_PRIME_2, keyMat->bigQ, keyMat->sizeQ }, + { CKA_EXPONENT_1, keyMat->bigDMP1, keyMat->sizeDMP1 }, + { CKA_EXPONENT_2, keyMat->bigDMQ1, keyMat->sizeDMQ1 }, + { CKA_COEFFICIENT, keyMat->bigIQMP, keyMat->sizeIQMP } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_rsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_rsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa) +{ + if (rsa == NULL) + { + return NULL; + } + + rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + keyMat->sizeE = rsa->get_e().bytes(); + keyMat->sizeN = rsa->get_n().bytes(); + keyMat->sizeD = rsa->get_d().bytes(); + keyMat->sizeP = rsa->get_p().bytes(); + keyMat->sizeQ = rsa->get_q().bytes(); + keyMat->sizeDMP1 = rsa->get_d1().bytes(); + keyMat->sizeDMQ1 = rsa->get_d2().bytes(); + keyMat->sizeIQMP = rsa->get_c().bytes(); + + keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE); + keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1); + keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1); + keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP); + + if + ( + !keyMat->bigE || + !keyMat->bigN || + !keyMat->bigD || + !keyMat->bigP || + !keyMat->bigQ || + !keyMat->bigDMP1 || + !keyMat->bigDMQ1 || + !keyMat->bigIQMP + ) + { + crypto_free_rsa(keyMat); + return NULL; + } + + rsa->get_e().binary_encode((Botan::byte*)keyMat->bigE); + rsa->get_n().binary_encode((Botan::byte*)keyMat->bigN); + rsa->get_d().binary_encode((Botan::byte*)keyMat->bigD); + rsa->get_p().binary_encode((Botan::byte*)keyMat->bigP); + rsa->get_q().binary_encode((Botan::byte*)keyMat->bigQ); + rsa->get_d1().binary_encode((Botan::byte*)keyMat->bigDMP1); + rsa->get_d2().binary_encode((Botan::byte*)keyMat->bigDMQ1); + rsa->get_c().binary_encode((Botan::byte*)keyMat->bigIQMP); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_rsa(rsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigE) free(keyMat->bigE); + if (keyMat->bigN) free(keyMat->bigN); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigDMP1) free(keyMat->bigDMP1); + if (keyMat->bigDMQ1) free(keyMat->bigDMQ1); + if (keyMat->bigIQMP) free(keyMat->bigIQMP); + free(keyMat); +} + +// Save the key data in PKCS#11 +int crypto_save_dsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::DSA_PrivateKey* dsa +) +{ + dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigY, keyMat->sizeY } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigX, keyMat->sizeX } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_dsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2); + crypto_free_dsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa) +{ + if (dsa == NULL) + { + return NULL; + } + + dsa_key_material_t *keyMat = (dsa_key_material_t *)malloc(sizeof(dsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + keyMat->sizeP = dsa->group_p().bytes(); + keyMat->sizeQ = dsa->group_q().bytes(); + keyMat->sizeG = dsa->group_g().bytes(); + keyMat->sizeX = dsa->get_x().bytes(); + keyMat->sizeY = dsa->get_y().bytes(); + + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG); + keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX); + keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY); + + if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY) + { + crypto_free_dsa(keyMat); + return NULL; + } + + dsa->group_p().binary_encode((Botan::byte*)keyMat->bigP); + dsa->group_q().binary_encode((Botan::byte*)keyMat->bigQ); + dsa->group_g().binary_encode((Botan::byte*)keyMat->bigG); + dsa->get_x().binary_encode((Botan::byte*)keyMat->bigX); + dsa->get_y().binary_encode((Botan::byte*)keyMat->bigY); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_dsa(dsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigG) free(keyMat->bigG); + if (keyMat->bigX) free(keyMat->bigX); + if (keyMat->bigY) free(keyMat->bigY); + free(keyMat); +} + +#ifdef WITH_ECC +// Save the key data in PKCS#11 +int crypto_save_ecdsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + Botan::ECDSA_PrivateKey* ecdsa +) +{ + ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_ECDSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_EC_POINT, keyMat->derQ, keyMat->sizeQ } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_VALUE, keyMat->bigD, keyMat->sizeD } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_ecdsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_ecdsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the Botan key to binary +ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa) +{ + if (ecdsa == NULL) + { + return NULL; + } + + ecdsa_key_material_t *keyMat = (ecdsa_key_material_t *)malloc(sizeof(ecdsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + std::vector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + Botan::secure_vector<Botan::byte> derPoint; +#else + Botan::SecureVector<Botan::byte> derEC = ecdsa->domain().DER_encode(Botan::EC_DOMPAR_ENC_OID); + Botan::SecureVector<Botan::byte> derPoint; +#endif + + try + { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) + Botan::secure_vector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(), + Botan::PointGFp::UNCOMPRESSED); +#else + Botan::SecureVector<Botan::byte> repr = Botan::EC2OSP(ecdsa->public_point(), + Botan::PointGFp::UNCOMPRESSED); +#endif + + derPoint = Botan::DER_Encoder() + .encode(repr, Botan::OCTET_STRING) + .get_contents(); + } + catch (...) + { + return NULL; + } + + keyMat->sizeParams = derEC.size(); + keyMat->sizeD = ecdsa->private_value().bytes(); + keyMat->sizeQ = derPoint.size(); + + keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + + if (!keyMat->derParams || !keyMat->bigD || !keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + memcpy(keyMat->derParams, &derEC[0], derEC.size()); + ecdsa->private_value().binary_encode((Botan::byte*)keyMat->bigD); + memcpy(keyMat->derQ, &derPoint[0], derPoint.size()); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->derParams) free(keyMat->derParams); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->derQ) free(keyMat->derQ); + free(keyMat); +} +#endif diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-botan.h b/SoftHSMv2/src/bin/util/softhsm2-util-botan.h new file mode 100644 index 0000000..8cd4a5e --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-botan.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-botan.h + + Header file for Botan implemented + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_BOTAN_H + +#include <botan/rsa.h> +#include <botan/dsa.h> +#ifdef WITH_ECC +#include <botan/ecdsa.h> +#endif + +typedef struct rsa_key_material_t { + CK_ULONG sizeE; + CK_ULONG sizeN; + CK_ULONG sizeD; + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeDMP1; + CK_ULONG sizeDMQ1; + CK_ULONG sizeIQMP; + CK_VOID_PTR bigE; + CK_VOID_PTR bigN; + CK_VOID_PTR bigD; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigDMP1; + CK_VOID_PTR bigDMQ1; + CK_VOID_PTR bigIQMP; + rsa_key_material_t() { + sizeE = 0; + sizeN = 0; + sizeD = 0; + sizeP = 0; + sizeQ = 0; + sizeDMP1 = 0; + sizeDMQ1 = 0; + sizeIQMP = 0; + bigE = NULL_PTR; + bigN = NULL_PTR; + bigD = NULL_PTR; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigDMP1 = NULL_PTR; + bigDMQ1 = NULL_PTR; + bigIQMP = NULL_PTR; + } +} rsa_key_material_t; + +typedef struct dsa_key_material_t { + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeG; + CK_ULONG sizeX; + CK_ULONG sizeY; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigG; + CK_VOID_PTR bigX; + CK_VOID_PTR bigY; + dsa_key_material_t() { + sizeP = 0; + sizeQ = 0; + sizeG = 0; + sizeX = 0; + sizeY = 0; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigG = NULL_PTR; + bigX = NULL_PTR; + bigY = NULL_PTR; + } +} dsa_key_material_t; + +#ifdef WITH_ECC +typedef struct ecdsa_key_material_t { + CK_ULONG sizeParams; + CK_ULONG sizeD; + CK_ULONG sizeQ; + CK_VOID_PTR derParams; + CK_VOID_PTR bigD; + CK_VOID_PTR derQ; + ecdsa_key_material_t() { + sizeParams = 0; + sizeD = 0; + sizeQ = 0; + derParams = NULL_PTR; + bigD = NULL_PTR; + derQ = NULL_PTR; + } +} ecdsa_key_material_t; +#endif + +Botan::Private_Key* crypto_read_file(char* filePath, char* filePIN); + +// RSA +int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::RSA_PrivateKey* rsa); +rsa_key_material_t* crypto_malloc_rsa(Botan::RSA_PrivateKey* rsa); +void crypto_free_rsa(rsa_key_material_t* keyMat); + +// DSA +int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::DSA_PrivateKey* dsa); +dsa_key_material_t* crypto_malloc_dsa(Botan::DSA_PrivateKey* dsa); +void crypto_free_dsa(dsa_key_material_t* keyMat); + +// ECDSA +#ifdef WITH_ECC +int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, Botan::ECDSA_PrivateKey* ecdsa); +ecdsa_key_material_t* crypto_malloc_ecdsa(Botan::ECDSA_PrivateKey* ecdsa); +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat); +#endif + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp new file mode 100644 index 0000000..fedfd28 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-ossl.cpp + + Code specific for OpenSSL + *****************************************************************************/ + +#include <config.h> +#define UTIL_OSSL +#include "softhsm2-util.h" +#include "softhsm2-util-ossl.h" +#include "OSSLComp.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iostream> +#include <fstream> + +#include <openssl/pem.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pkcs12.h> + +// Init OpenSSL +void crypto_init() +{ + // We do not need to do this one + // OpenSSL_add_all_algorithms(); +#ifdef WITH_FIPS + // The PKCS#11 library might be using a FIPS capable OpenSSL + if (FIPS_mode()) + return; + if (!FIPS_mode_set(1)) + { + fprintf(stderr, "ERROR: can't enter into FIPS mode.\n"); + exit(0); + } +#endif +} + +// Final OpenSSL +void crypto_final() +{ + // EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); +} + +int crypto_import_aes_key +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* label, + char* objID, + size_t objIDLen +) +{ + const size_t cMaxAesKeySize = 1024 + 1; // including null-character + char aesKeyValue[cMaxAesKeySize]; + FILE* fp = fopen(filePath, "rb"); + if (fp == NULL) + { + fprintf(stderr, "ERROR: Could not open the secret key file.\n"); + return 1; + } + if (fgets(aesKeyValue, cMaxAesKeySize, fp) == NULL) + { + fprintf(stderr, "ERROR: Could not read the secret key file.\n"); + fclose(fp); + return 1; + } + fclose(fp); + + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_AES; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, &aesKeyValue, strlen(aesKeyValue) } + }; + + CK_OBJECT_HANDLE hKey; + CK_RV rv = p11->C_CreateObject(hSession, keyTemplate, 9, &hKey); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the secret key in the token. " + "Maybe the algorithm is not supported.\n"); + return 1; + } + + return 0; +} + +// Import a key pair from given path +int crypto_import_key_pair +( + CK_SESSION_HANDLE hSession, + char* filePath, + char* filePIN, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey +) +{ + EVP_PKEY* pkey = crypto_read_file(filePath, filePIN); + if (pkey == NULL) + { + return 1; + } + + RSA* rsa = NULL; + DSA* dsa = NULL; +#ifdef WITH_ECC + EC_KEY* ecdsa = NULL; +#endif + + switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) + { + case EVP_PKEY_RSA: + rsa = EVP_PKEY_get1_RSA(pkey); + break; + case EVP_PKEY_DSA: + dsa = EVP_PKEY_get1_DSA(pkey); + break; +#ifdef WITH_ECC + case EVP_PKEY_EC: + ecdsa = EVP_PKEY_get1_EC_KEY(pkey); + break; +#endif + default: + fprintf(stderr, "ERROR: Cannot handle this algorithm.\n"); + EVP_PKEY_free(pkey); + return 1; + break; + } + EVP_PKEY_free(pkey); + + int result = 0; + + if (rsa) + { + result = crypto_save_rsa(hSession, label, objID, objIDLen, noPublicKey, rsa); + RSA_free(rsa); + } + else if (dsa) + { + result = crypto_save_dsa(hSession, label, objID, objIDLen, noPublicKey, dsa); + DSA_free(dsa); + } +#ifdef WITH_ECC + else if (ecdsa) + { + result = crypto_save_ecdsa(hSession, label, objID, objIDLen, noPublicKey, ecdsa); + EC_KEY_free(ecdsa); + } +#endif + else + { + fprintf(stderr, "ERROR: Could not get the key material.\n"); + result = 1; + } + + return result; +} + +// Read the key from file +EVP_PKEY* crypto_read_file(char* filePath, char* filePIN) +{ + BIO* in = NULL; + PKCS8_PRIV_KEY_INFO* p8inf = NULL; + EVP_PKEY* pkey = NULL; + X509_SIG* p8 = NULL; + + if (!(in = BIO_new_file(filePath, "rb"))) + { + fprintf(stderr, "ERROR: Could open the PKCS#8 file: %s\n", filePath); + return NULL; + } + + // The PKCS#8 file is encrypted + if (filePIN) + { + p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); + BIO_free(in); + + if (!p8) + { + fprintf(stderr, "ERROR: Could not read the PKCS#8 file. " + "Maybe the file is not encrypted.\n"); + return NULL; + } + + p8inf = PKCS8_decrypt(p8, filePIN, strlen(filePIN)); + X509_SIG_free(p8); + + if (!p8inf) + { + fprintf(stderr, "ERROR: Could not decrypt the PKCS#8 file. " + "Maybe wrong PIN to file (--file-pin <PIN>)\n"); + return NULL; + } + } + else + { + p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); + BIO_free(in); + + if (!p8inf) + { + fprintf(stderr, "ERROR: Could not read the PKCS#8 file. " + "Maybe it is encypted (--file-pin <PIN>)\n"); + return NULL; + } + } + + // Convert the PKCS#8 to OpenSSL + pkey = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if (!pkey) + { + fprintf(stderr, "ERROR: Could not convert the key.\n"); + return NULL; + } + + return pkey; +} + +// Save the key data in PKCS#11 +int crypto_save_rsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + RSA* rsa +) +{ + rsa_key_material_t* keyMat = crypto_malloc_rsa(rsa); + if (!keyMat) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PUBLIC_EXPONENT, keyMat->bigE, keyMat->sizeE }, + { CKA_MODULUS, keyMat->bigN, keyMat->sizeN }, + { CKA_PRIVATE_EXPONENT, keyMat->bigD, keyMat->sizeD }, + { CKA_PRIME_1, keyMat->bigP, keyMat->sizeP }, + { CKA_PRIME_2, keyMat->bigQ, keyMat->sizeQ }, + { CKA_EXPONENT_1, keyMat->bigDMP1, keyMat->sizeDMP1 }, + { CKA_EXPONENT_2, keyMat->bigDMQ1, keyMat->sizeDMQ1 }, + { CKA_COEFFICIENT, keyMat->bigIQMP, keyMat->sizeIQMP } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 19, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_rsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_rsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +rsa_key_material_t* crypto_malloc_rsa(RSA* rsa) +{ + if (rsa == NULL) + { + return NULL; + } + + rsa_key_material_t* keyMat = (rsa_key_material_t*)malloc(sizeof(rsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM* bn_e = NULL; + const BIGNUM* bn_n = NULL; + const BIGNUM* bn_d = NULL; + const BIGNUM* bn_p = NULL; + const BIGNUM* bn_q = NULL; + const BIGNUM* bn_dmp1 = NULL; + const BIGNUM* bn_dmq1 = NULL; + const BIGNUM* bn_iqmp = NULL; + RSA_get0_factors(rsa, &bn_p, &bn_q); + RSA_get0_crt_params(rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp); + RSA_get0_key(rsa, &bn_n, &bn_e, &bn_d); + + keyMat->sizeE = BN_num_bytes(bn_e); + keyMat->sizeN = BN_num_bytes(bn_n); + keyMat->sizeD = BN_num_bytes(bn_d); + keyMat->sizeP = BN_num_bytes(bn_p); + keyMat->sizeQ = BN_num_bytes(bn_q); + keyMat->sizeDMP1 = BN_num_bytes(bn_dmp1); + keyMat->sizeDMQ1 = BN_num_bytes(bn_dmq1); + keyMat->sizeIQMP = BN_num_bytes(bn_iqmp); + + keyMat->bigE = (CK_VOID_PTR)malloc(keyMat->sizeE); + keyMat->bigN = (CK_VOID_PTR)malloc(keyMat->sizeN); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigDMP1 = (CK_VOID_PTR)malloc(keyMat->sizeDMP1); + keyMat->bigDMQ1 = (CK_VOID_PTR)malloc(keyMat->sizeDMQ1); + keyMat->bigIQMP = (CK_VOID_PTR)malloc(keyMat->sizeIQMP); + + if + ( + !keyMat->bigE || + !keyMat->bigN || + !keyMat->bigD || + !keyMat->bigP || + !keyMat->bigQ || + !keyMat->bigDMP1 || + !keyMat->bigDMQ1 || + !keyMat->bigIQMP + ) + { + crypto_free_rsa(keyMat); + return NULL; + } + + BN_bn2bin(bn_e, (unsigned char*)keyMat->bigE); + BN_bn2bin(bn_n, (unsigned char*)keyMat->bigN); + BN_bn2bin(bn_d, (unsigned char*)keyMat->bigD); + BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP); + BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ); + BN_bn2bin(bn_dmp1, (unsigned char*)keyMat->bigDMP1); + BN_bn2bin(bn_dmq1, (unsigned char*)keyMat->bigDMQ1); + BN_bn2bin(bn_iqmp, (unsigned char*)keyMat->bigIQMP); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_rsa(rsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigE) free(keyMat->bigE); + if (keyMat->bigN) free(keyMat->bigN); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigDMP1) free(keyMat->bigDMP1); + if (keyMat->bigDMQ1) free(keyMat->bigDMQ1); + if (keyMat->bigIQMP) free(keyMat->bigIQMP); + free(keyMat); +} + +// Save the key data in PKCS#11 +int crypto_save_dsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + DSA* dsa +) +{ + dsa_key_material_t* keyMat = crypto_malloc_dsa(dsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigY, keyMat->sizeY } + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, keyMat->bigP, keyMat->sizeP }, + { CKA_SUBPRIME, keyMat->bigQ, keyMat->sizeQ }, + { CKA_BASE, keyMat->bigG, keyMat->sizeG }, + { CKA_VALUE, keyMat->bigX, keyMat->sizeX } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 15, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_dsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 12, &hKey2); + crypto_free_dsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +dsa_key_material_t* crypto_malloc_dsa(DSA* dsa) +{ + if (dsa == NULL) + { + return NULL; + } + + dsa_key_material_t* keyMat = (dsa_key_material_t*)malloc(sizeof(dsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM* bn_p = NULL; + const BIGNUM* bn_q = NULL; + const BIGNUM* bn_g = NULL; + const BIGNUM* bn_priv_key = NULL; + const BIGNUM* bn_pub_key = NULL; + DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); + DSA_get0_key(dsa, &bn_pub_key, &bn_priv_key); + + keyMat->sizeP = BN_num_bytes(bn_p); + keyMat->sizeQ = BN_num_bytes(bn_q); + keyMat->sizeG = BN_num_bytes(bn_g); + keyMat->sizeX = BN_num_bytes(bn_priv_key); + keyMat->sizeY = BN_num_bytes(bn_pub_key); + + keyMat->bigP = (CK_VOID_PTR)malloc(keyMat->sizeP); + keyMat->bigQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + keyMat->bigG = (CK_VOID_PTR)malloc(keyMat->sizeG); + keyMat->bigX = (CK_VOID_PTR)malloc(keyMat->sizeX); + keyMat->bigY = (CK_VOID_PTR)malloc(keyMat->sizeY); + + if (!keyMat->bigP || !keyMat->bigQ || !keyMat->bigG || !keyMat->bigX || !keyMat->bigY) + { + crypto_free_dsa(keyMat); + return NULL; + } + + BN_bn2bin(bn_p, (unsigned char*)keyMat->bigP); + BN_bn2bin(bn_q, (unsigned char*)keyMat->bigQ); + BN_bn2bin(bn_g, (unsigned char*)keyMat->bigG); + BN_bn2bin(bn_priv_key, (unsigned char*)keyMat->bigX); + BN_bn2bin(bn_pub_key, (unsigned char*)keyMat->bigY); + + return keyMat; +} + +// Free the memory of the key +void crypto_free_dsa(dsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->bigP) free(keyMat->bigP); + if (keyMat->bigQ) free(keyMat->bigQ); + if (keyMat->bigG) free(keyMat->bigG); + if (keyMat->bigX) free(keyMat->bigX); + if (keyMat->bigY) free(keyMat->bigY); + free(keyMat); +} + +#ifdef WITH_ECC + +// Save the key data in PKCS#11 +int crypto_save_ecdsa +( + CK_SESSION_HANDLE hSession, + char* label, + char* objID, + size_t objIDLen, + int noPublicKey, + EC_KEY* ecdsa +) +{ + ecdsa_key_material_t* keyMat = crypto_malloc_ecdsa(ecdsa); + if (keyMat == NULL) + { + fprintf(stderr, "ERROR: Could not convert the key material to binary information.\n"); + return 1; + } + + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY, privClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_EC; + CK_BBOOL ckTrue = CK_TRUE, ckFalse = CK_FALSE, ckToken = CK_TRUE; + if (noPublicKey) + { + ckToken = CK_FALSE; + } + CK_ATTRIBUTE pubTemplate[] = { + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_TOKEN, &ckToken, sizeof(ckToken) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_WRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_EC_POINT, keyMat->derQ, keyMat->sizeQ }, + }; + CK_ATTRIBUTE privTemplate[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_LABEL, label, strlen(label) }, + { CKA_ID, objID, objIDLen }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckFalse, sizeof(ckFalse) }, + { CKA_UNWRAP, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, keyMat->derParams, keyMat->sizeParams }, + { CKA_VALUE, keyMat->bigD, keyMat->sizeD } + }; + + CK_OBJECT_HANDLE hKey1, hKey2; + CK_RV rv = p11->C_CreateObject(hSession, privTemplate, 13, &hKey1); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not save the private key in the token. " + "Maybe the algorithm is not supported.\n"); + crypto_free_ecdsa(keyMat); + return 1; + } + + rv = p11->C_CreateObject(hSession, pubTemplate, 10, &hKey2); + crypto_free_ecdsa(keyMat); + + if (rv != CKR_OK) + { + p11->C_DestroyObject(hSession, hKey1); + fprintf(stderr, "ERROR: Could not save the public key in the token.\n"); + return 1; + } + + printf("The key pair has been imported.\n"); + + return 0; +} + +// Convert the OpenSSL key to binary +ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ec_key) +{ + int result; + + if (ec_key == NULL) + { + return NULL; + } + + ecdsa_key_material_t* keyMat = (ecdsa_key_material_t*)malloc(sizeof(ecdsa_key_material_t)); + if (keyMat == NULL) + { + return NULL; + } + + const BIGNUM *d = EC_KEY_get0_private_key(ec_key); + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + const EC_POINT *point = EC_KEY_get0_public_key(ec_key); + + keyMat->sizeParams = i2d_ECPKParameters(group, NULL); + keyMat->sizeD = BN_num_bytes(d); + + keyMat->derParams = (CK_VOID_PTR)malloc(keyMat->sizeParams); + keyMat->bigD = (CK_VOID_PTR)malloc(keyMat->sizeD); + keyMat->derQ = NULL; + + if (!keyMat->derParams || !keyMat->bigD) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + /* + * i2d functions increment the pointer, so we have to use a + * sacrificial pointer + */ + unsigned char *derParams = (unsigned char*) keyMat->derParams; + result = i2d_ECPKParameters(group, &derParams); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + BN_bn2bin(d, (unsigned char*)keyMat->bigD); + + size_t point_length = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + NULL, + 0, + NULL); + + // Definite, short + if (point_length <= 0x7f) + { + keyMat->sizeQ = 2 + point_length; + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + if (!keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + unsigned char *derQ = (unsigned char *)keyMat->derQ; + derQ[0] = V_ASN1_OCTET_STRING; + derQ[1] = point_length & 0x7f; + result = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + &derQ[2], + point_length, + NULL); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + } + // Definite, long + else + { + // Count significate bytes + size_t bytes = sizeof(size_t); + for(; bytes > 0; bytes--) + { + size_t value = point_length >> ((bytes - 1) * 8); + if (value & 0xFF) break; + } + + keyMat->sizeQ = 2 + bytes + point_length; + keyMat->derQ = (CK_VOID_PTR)malloc(keyMat->sizeQ); + if (!keyMat->derQ) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + + unsigned char *derQ = (unsigned char *)keyMat->derQ; + derQ[0] = V_ASN1_OCTET_STRING; + derQ[1] = 0x80 | bytes; + + size_t len = point_length; + for (size_t i = 1; i <= bytes; i++) + { + derQ[2+bytes-i] = (unsigned char) (len & 0xFF); + len >>= 8; + } + + result = EC_POINT_point2oct(group, + point, + POINT_CONVERSION_UNCOMPRESSED, + &derQ[2+bytes], + point_length, + NULL); + if (result == 0) + { + crypto_free_ecdsa(keyMat); + return NULL; + } + } + + return keyMat; +} + +// Free the memory of the key +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat) +{ + if (keyMat == NULL) return; + if (keyMat->derParams) free(keyMat->derParams); + if (keyMat->bigD) free(keyMat->bigD); + if (keyMat->derQ) free(keyMat->derQ); + free(keyMat); +} + +#endif diff --git a/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h new file mode 100644 index 0000000..7a2a31a --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util-ossl.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util-ossl.h + + Header file for OpenSSL implemented + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H + +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#ifdef WITH_ECC +#include <openssl/ec.h> +#endif + +typedef struct rsa_key_material_t { + CK_ULONG sizeE; + CK_ULONG sizeN; + CK_ULONG sizeD; + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeDMP1; + CK_ULONG sizeDMQ1; + CK_ULONG sizeIQMP; + CK_VOID_PTR bigE; + CK_VOID_PTR bigN; + CK_VOID_PTR bigD; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigDMP1; + CK_VOID_PTR bigDMQ1; + CK_VOID_PTR bigIQMP; + rsa_key_material_t() { + sizeE = 0; + sizeN = 0; + sizeD = 0; + sizeP = 0; + sizeQ = 0; + sizeDMP1 = 0; + sizeDMQ1 = 0; + sizeIQMP = 0; + bigE = NULL_PTR; + bigN = NULL_PTR; + bigD = NULL_PTR; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigDMP1 = NULL_PTR; + bigDMQ1 = NULL_PTR; + bigIQMP = NULL_PTR; + } +} rsa_key_material_t; + +typedef struct dsa_key_material_t { + CK_ULONG sizeP; + CK_ULONG sizeQ; + CK_ULONG sizeG; + CK_ULONG sizeX; + CK_ULONG sizeY; + CK_VOID_PTR bigP; + CK_VOID_PTR bigQ; + CK_VOID_PTR bigG; + CK_VOID_PTR bigX; + CK_VOID_PTR bigY; + dsa_key_material_t() { + sizeP = 0; + sizeQ = 0; + sizeG = 0; + sizeX = 0; + sizeY = 0; + bigP = NULL_PTR; + bigQ = NULL_PTR; + bigG = NULL_PTR; + bigX = NULL_PTR; + bigY = NULL_PTR; + } +} dsa_key_material_t; + +#ifdef WITH_ECC +typedef struct ecdsa_key_material_t { + CK_ULONG sizeParams; + CK_ULONG sizeD; + CK_ULONG sizeQ; + CK_VOID_PTR derParams; + CK_VOID_PTR bigD; + CK_VOID_PTR derQ; + ecdsa_key_material_t() { + sizeParams = 0; + sizeD = 0; + sizeQ = 0; + derParams = NULL_PTR; + bigD = NULL_PTR; + derQ = NULL_PTR; + } +} ecdsa_key_material_t; +#endif + +EVP_PKEY* crypto_read_file(char* filePath, char* filePIN); + +// RSA +int crypto_save_rsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, RSA* rsa); +rsa_key_material_t* crypto_malloc_rsa(RSA* rsa); +void crypto_free_rsa(rsa_key_material_t* keyMat); + +// DSA +int crypto_save_dsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, DSA* dsa); +dsa_key_material_t* crypto_malloc_dsa(DSA* dsa); +void crypto_free_dsa(dsa_key_material_t* keyMat); + +#ifdef WITH_ECC +// ECDSA +int crypto_save_ecdsa(CK_SESSION_HANDLE hSession, char* label, char* objID, size_t objIDLen, int noPublicKey, EC_KEY* ecdsa); +ecdsa_key_material_t* crypto_malloc_ecdsa(EC_KEY* ecdsa); +void crypto_free_ecdsa(ecdsa_key_material_t* keyMat); +#endif + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_OSSL_H diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.1 b/SoftHSMv2/src/bin/util/softhsm2-util.1 new file mode 100644 index 0000000..1998226 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.1 @@ -0,0 +1,259 @@ +.TH SOFTHSM2-UTIL 1 "22 September 2017" "SoftHSM" +.SH NAME +softhsm2-util \- support tool for libsofthsm2 +.SH SYNOPSIS +.B softhsm2-util \-\-show-slots +.PP +.B softhsm2-util \-\-init-token +.B \-\-free +.B \-\-label +.I text +\\ +.ti +0.7i +.RB [ \-\-so-pin +.I PIN +.B \-\-pin +.IR PIN ] +.PP +.B softhsm2-util \-\-import +.I path +.RB [ \-\-file-pin +.IR PIN ] +.B \-\-token +.I label +\\ +.ti +0.7i +.RB [ \-\-pin +.I PIN +.B \-\-no\-public\-key] +.B \-\-label +.I text +.B \-\-id +.I hex +.PP +.B softhsm2-util \-\-import +.I path +.B \-\-aes +.B \-\-token +.I label +\\ +.ti +0.7i +.RB [ \-\-pin +.I PIN] +.B \-\-label +.I text +.B \-\-id +.I hex +.PP +.B softhsm2-util \-\-delete\-token +.B \-\-token +.I text +.SH DESCRIPTION +.B softhsm2-util +is a support tool mainly for libsofthsm2. It can also +be used with other PKCS#11 libraries by using the option +.B \-\-module +.PP +Read the sections below to get more information on +the libsofthsm2 and PKCS#11. +Most applications assumes that the token they want +to use is already initialized. +It is then up to the user +to initialize the PKCS#11 token. +This is done by using the PKCS#11 interface, +but instead of writing your own +tool you can use the +.B softhsm2-util +tool. +.PP +Keys are usually created directly in the token, +but the user may want to use an existing key pair. +Keys can be imported to a token by using the PKCS#11 interface, +but this tool can also be used if the +user has the key pair in a PKCS#8 file. +If you need to convert keys from +BIND .private-key format over to PKCS#8, +one can +use +.BR softhsm2-keyconv . +.LP +The libary +.BR libsofthsm2 , +known as SoftHSM, provides cryptographic functionality +by using the PKCS#11 API. +It was developed as a part of the OpenDNSSEC project, +thus designed to meet the requirements +of OpenDNSSEC, +but can also work together with other +software that want to use the functionality +of the PKCS#11 API. +.PP +SoftHSM is a software implementation of a generic cryptographic device with a PKCS#11 interface. +These devices are often called tokens. +Read in the manual softhsm2.conf(5) on how to create these +tokens and how they are added to a slot in SoftHSM. +.LP +The +.B PKCS#11 +API +can be used to handle and store cryptographic keys. +This interface +specifies how to communicate with cryptographic devices such as HSMs +(Hardware Security Modules) and smart cards. +The purpose of these devices +is, among others, +to generate cryptographic keys and sign information without +revealing private-key material to the outside world. +They are often designed +to perform well on these specific tasks +compared to ordinary processes in a normal computer. +.LP +.SH ACTIONS +.TP +.B \-\-delete\-token +Delete the token at a given slot. +Use with +.BR \-\-token +or +.BR \-\-serial . +Any content in token will be erased. +.TP +.B \-\-help\fR, \fB\-h\fR +Show the help information. +.TP +.B \-\-import \fIpath\fR +Import a key pair from the given +.IR path . +The file must be in PKCS#8-format. +.br +Use with +.BR \-\-slot +or +.BR \-\-token +or +.BR \-\-serial , +.BR \-\-file-pin , +.BR \-\-pin , +.BR \-\-no\-public\-key , +.BR \-\-label , +and +.BR \-\-id . +.br +Can also be used with +.BR \-\-aes +to use file as is and import it as AES. +.TP +.B \-\-init-token +Initialize the token at a given slot, token label or token serial. +If the token is already initialized then this command +will reinitialize it, thus erasing all the objects in the token. +The matching Security Officer (SO) PIN must also +be provided when doing reinitialization. +Initialized tokens will be reassigned to another slot (based on +the token serial number). +.br +Use with +.BR \-\-slot +or +.BR \-\-token +or +.BR \-\-serial +or +.BR \-\-free , +.BR \-\-label , +.BR \-\-so-pin , +and +.BR \-\-pin . +.LP +.TP +.B \-\-show-slots +Display all the available slots and their current status. +.TP +.B \-\-version\fR, \fB\-v\fR +Show the version info. +.SH OPTIONS +.TP +.B \-\-aes +Used to tell import to use file as is and import it as AES. +.TP +.B \-\-file-pin \fIPIN\fR +The +.I PIN +will be used to decrypt the PKCS#8 file. +If not given then the PKCS#8 file is assumed to be unencrypted. +.TP +.B \-\-force +Use this option to override the warnings and force the given action. +.TP +.B \-\-free +Use the first free/uninitialized token. +.TP +.B \-\-id \fIhex\fR +Choose an ID of the key pair. +The ID is in hexadecimal with a variable length. +Use with +.B \-\-force +when importing a key pair if the ID already exists. +.TP +.B \-\-label \fItext\fR +Defines the +.I label +of the object or the token that will be set. +.TP +.B \-\-module \fIpath\fR +Use another PKCS#11 library than SoftHSM. +.TP +.B \-\-no\-public\-key +Do not import the public key. +.TP +.B \-\-pin \fIPIN\fR +The +.I PIN +for the normal user. +.TP +.B \-\-serial \fInumber\fR +Will use the token with a matching serial number. +.TP +.B \-\-slot \fInumber\fR +The slot where the token is located. +.TP +.B \-\-so-pin \fIPIN\fR +The +.I PIN +for the Security Officer (SO). +.TP +.B \-\-token \fIlabel\fR +Will use the token with a matching token label. +.SH EXAMPLES +.LP +The token can be initialized using this command: +.LP +.RS +.nf +softhsm2-util \-\-init-token \-\-slot 1 \-\-label "mytoken" +.fi +.RE +.LP +A key pair can be imported using the softhsm tool where you specify the path +to the key file, slot number, label and ID of the new objects, and the +user PIN. +The file must be in PKCS#8 format. +.LP +.RS +.nf +softhsm2-util \-\-import key1.pem \-\-token "mytoken" \-\-label "My key" \\ +.ti +0.7i +\-\-id A1B2 \-\-pin 123456 +.fi +(Add, \-\-file-pin +.IR PIN , +if the key file is encrypted.) +.RE +.LP +.SH AUTHORS +Written by Rickard Bellgrim, Francis Dupont, René Post, and Roland van Rijswijk. +.LP +.SH "SEE ALSO" +.IR softhsm2-keyconv (1), +.IR softhsm2-migrate (1), +.IR softhsm2.conf (5) diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.cpp b/SoftHSMv2/src/bin/util/softhsm2-util.cpp new file mode 100644 index 0000000..465df4a --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.cpp @@ -0,0 +1,1318 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util.cpp + + This program can be used for interacting with HSMs using PKCS#11. + The default library is the libsofthsm2.so + *****************************************************************************/ + +#include <config.h> +#include "softhsm2-util.h" +#include "findslot.h" +#include "getpw.h" +#include "library.h" +#include "log.h" +#include "Configuration.h" +#include "SimpleConfigLoader.h" +#include "Directory.h" +#include "MutexFactory.h" +#include "ObjectStoreToken.h" +#include "OSPathSep.h" + +#if defined(WITH_OPENSSL) +#include "OSSLCryptoFactory.h" +#else +#include "BotanCryptoFactory.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#ifndef _WIN32 +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#else +#include <direct.h> +#include <io.h> +#endif +#include <iostream> +#include <fstream> + +// Initialise the one-and-only instance + +#ifdef HAVE_CXX11 + +std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr); +std::unique_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr<MutexFactory> MutexFactory::instance(NULL); +std::auto_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(NULL); +#endif + +#endif + +// Display the usage +void usage() +{ + printf("Support tool for PKCS#11\n"); + printf("Usage: softhsm2-util [ACTION] [OPTIONS]\n"); + printf("Action:\n"); + printf(" --delete-token Delete the token at a given slot.\n"); + printf(" Use with --token or --serial.\n"); + printf(" WARNING: Any content in token will be erased.\n"); + printf(" -h Shows this help screen.\n"); + printf(" --help Shows this help screen.\n"); + printf(" --import <path> Import a key pair from the given path.\n"); + printf(" The file must be in PKCS#8-format.\n"); + printf(" Use with --slot or --token or --serial, --file-pin,\n"); + printf(" --label, --id, --no-public-key, and --pin.\n"); + printf(" --init-token Initialize the token at a given slot.\n"); + printf(" Use with --slot or --token or --serial or --free,\n"); + printf(" --label, --so-pin, and --pin.\n"); + printf(" WARNING: Any content in token will be erased.\n"); + printf(" --show-slots Display all the available slots.\n"); + printf(" -v Show version info.\n"); + printf(" --version Show version info.\n"); + printf("Options:\n"); + printf(" --aes Used to tell import to use file as is and import it as AES.\n"); + printf(" --file-pin <PIN> Supply a PIN if the file is encrypted.\n"); + printf(" --force Used to override a warning.\n"); + printf(" --free Use the first free/uninitialized token.\n"); + printf(" --id <hex> Defines the ID of the object. Hexadecimal characters.\n"); + printf(" Use with --force if multiple key pairs may share\n"); + printf(" the same ID.\n"); + printf(" --label <text> Defines the label of the object or the token.\n"); + printf(" --module <path> Use another PKCS#11 library than SoftHSM.\n"); + printf(" --no-public-key Do not import the public key.\n"); + printf(" --pin <PIN> The PIN for the normal user.\n"); + printf(" --serial <number> Will use the token with a matching serial number.\n"); + printf(" --slot <number> The slot where the token is located.\n"); + printf(" --so-pin <PIN> The PIN for the Security Officer (SO).\n"); + printf(" --token <label> Will use the token with a matching token label.\n"); +} + +// Enumeration of the long options +enum { + OPT_DELETE_TOKEN = 0x100, + OPT_FILE_PIN, + OPT_FORCE, + OPT_FREE, + OPT_HELP, + OPT_ID, + OPT_IMPORT, + OPT_INIT_TOKEN, + OPT_LABEL, + OPT_MODULE, + OPT_NO_PUBLIC_KEY, + OPT_PIN, + OPT_SERIAL, + OPT_SHOW_SLOTS, + OPT_SLOT, + OPT_SO_PIN, + OPT_TOKEN, + OPT_VERSION, + OPT_AES +}; + +// Text representation of the long options +static const struct option long_options[] = { + { "delete-token", 0, NULL, OPT_DELETE_TOKEN }, + { "file-pin", 1, NULL, OPT_FILE_PIN }, + { "force", 0, NULL, OPT_FORCE }, + { "free", 0, NULL, OPT_FREE }, + { "help", 0, NULL, OPT_HELP }, + { "id", 1, NULL, OPT_ID }, + { "import", 1, NULL, OPT_IMPORT }, + { "init-token", 0, NULL, OPT_INIT_TOKEN }, + { "label", 1, NULL, OPT_LABEL }, + { "module", 1, NULL, OPT_MODULE }, + { "no-public-key", 0, NULL, OPT_NO_PUBLIC_KEY }, + { "pin", 1, NULL, OPT_PIN }, + { "serial", 1, NULL, OPT_SERIAL }, + { "show-slots", 0, NULL, OPT_SHOW_SLOTS }, + { "slot", 1, NULL, OPT_SLOT }, + { "so-pin", 1, NULL, OPT_SO_PIN }, + { "token", 1, NULL, OPT_TOKEN }, + { "version", 0, NULL, OPT_VERSION }, + { "aes", 0, NULL, OPT_AES }, + { NULL, 0, NULL, 0 } +}; + +CK_FUNCTION_LIST_PTR p11; + +// The main function +int main(int argc, char* argv[]) +{ + int option_index = 0; + int opt; + + char* inPath = NULL; + char* soPIN = NULL; + char* userPIN = NULL; + char* filePIN = NULL; + char* label = NULL; + char* module = NULL; + char* objectID = NULL; + char* slot = NULL; + char* serial = NULL; + char* token = NULL; + char* errMsg = NULL; + int forceExec = 0; + bool freeToken = false; + int noPublicKey = 0; + bool importAES = false; + + int doInitToken = 0; + int doShowSlots = 0; + int doImport = 0; + int doDeleteToken = 0; + int action = 0; + bool needP11 = false; + int rv = 0; + CK_SLOT_ID slotID = 0; + + moduleHandle = NULL; + p11 = NULL; + + while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1) + { + switch (opt) + { + case OPT_SHOW_SLOTS: + doShowSlots = 1; + action++; + needP11 = true; + break; + case OPT_INIT_TOKEN: + doInitToken = 1; + action++; + needP11 = true; + break; + case OPT_IMPORT: + doImport = 1; + action++; + inPath = optarg; + needP11 = true; + break; + case OPT_AES: + importAES = true; + break; + case OPT_DELETE_TOKEN: + doDeleteToken = 1; + action++; + break; + case OPT_SLOT: + slot = optarg; + break; + case OPT_LABEL: + label = optarg; + break; + case OPT_SERIAL: + serial = optarg; + break; + case OPT_TOKEN: + token = optarg; + break; + case OPT_MODULE: + module = optarg; + break; + case OPT_NO_PUBLIC_KEY: + noPublicKey = 1; + break; + case OPT_ID: + objectID = optarg; + break; + case OPT_SO_PIN: + soPIN = optarg; + break; + case OPT_PIN: + userPIN = optarg; + break; + case OPT_FILE_PIN: + filePIN = optarg; + break; + case OPT_FORCE: + forceExec = 1; + break; + case OPT_FREE: + freeToken = true; + break; + case OPT_VERSION: + case 'v': + printf("%s\n", PACKAGE_VERSION); + exit(0); + break; + case OPT_HELP: + case 'h': + default: + usage(); + exit(0); + break; + } + } + + // No action given, display the usage. + if (action != 1) + { + usage(); + exit(1); + } + + if (needP11) + { + // Check the basic setup of SoftHSM + if (!checkSetup()) + { + fprintf(stderr, "ERROR: Please verify that the SoftHSM configuration is correct.\n"); + exit(1); + } + + // Get a pointer to the function list for PKCS#11 library + CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg); + if (!pGetFunctionList) + { + fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + + // Load the function list + (*pGetFunctionList)(&p11); + + // Initialize the library + CK_RV p11rv = p11->C_Initialize(NULL_PTR); + if (p11rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB); + fprintf(stderr, "ERROR: Please check log files for additional information.\n"); + exit(1); + } + } + + // We should create the token. + if (doInitToken) + { + // Get the slotID + rv = findSlot(slot, serial, token, freeToken, slotID); + if (!rv) + { + rv = initToken(slotID, label, soPIN, userPIN); + } + } + + // Show all available slots + if (!rv && doShowSlots) + { + rv = showSlots(); + } + + // Import a key pair from the given path + if (!rv && doImport) + { + // Get the slotID + rv = findSlot(slot, serial, token, slotID); + if (!rv) + { + rv = importAES ? importSecretKey(inPath, slotID, userPIN, label, objectID) + : importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey); + } + } + + // We should delete the token. + if (!rv && doDeleteToken) + { + if (deleteToken(serial, token)) + { + rv = 0; + } + else + { + rv = 1; + } + } + + // Finalize the library + if (needP11) + { + p11->C_Finalize(NULL_PTR); + unloadLibrary(moduleHandle); + } + + return rv; +} + +// Check the basic setup of SoftHSM +bool checkSetup() +{ + // Initialize the SoftHSM internal functions + if (!initSoftHSM()) + { + finalizeSoftHSM(); + return false; + } + + std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR); + + // Try open the token directory + Directory storeDir(basedir); + if (!storeDir.isValid()) + { + fprintf(stderr, "ERROR: Failed to enumerate object store in %s\n", basedir.c_str()); + finalizeSoftHSM(); + return false; + } + + finalizeSoftHSM(); + return true; +} + +// Initialize the token +int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN) +{ + char so_pin_copy[MAX_PIN_LEN+1]; + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the token must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (strlen(label) > 32) + { + fprintf(stderr, "ERROR: The token label must not have a length " + "greater than 32 chars.\n"); + return 1; + } + + // Get the passwords + if (getPW(soPIN, so_pin_copy, CKU_SO) != 0) + { + fprintf(stderr, "ERROR: Could not get SO PIN\n"); + return 1; + } + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + return 1; + } + + // Load the variables + CK_UTF8CHAR paddedLabel[32]; + memset(paddedLabel, ' ', sizeof(paddedLabel)); + memcpy(paddedLabel, label, strlen(label)); + + CK_RV rv = p11->C_InitToken(slotID, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy), paddedLabel); + + switch (rv) + { + case CKR_OK: + break; + case CKR_SLOT_ID_INVALID: + fprintf(stderr, "CKR_SLOT_ID_INVALID: Slot %lu does not exist.\n", slotID); + return 1; + break; + case CKR_PIN_INCORRECT: + fprintf(stderr, "CKR_PIN_INCORRECT: The given SO PIN does not match the " + "one in the token. Needed when reinitializing the token.\n"); + return 1; + break; + case CKR_TOKEN_NOT_PRESENT: + fprintf(stderr, "CKR_TOKEN_NOT_PRESENT: The token is not present. " + "Please read the HSM manual for further assistance.\n"); + return 1; + break; + default: + fprintf(stderr, "ERROR rv=0x%08X: Could not initialize the token.\n", (unsigned int)rv); + fprintf(stderr, "Please check log files for additional information.\n"); + return 1; + break; + } + + CK_SESSION_HANDLE hSession; + rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not open a session with the library.\n"); + return 1; + } + + rv = p11->C_Login(hSession, CKU_SO, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy)); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + return 1; + } + + rv = p11->C_InitPIN(hSession, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the user PIN.\n"); + return 1; + } + + // Get the token info + CK_TOKEN_INFO tokenInfo; + rv = p11->C_GetTokenInfo(slotID, &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the initialized token in slot %lu.\n", slotID); + return 1; + } + + // Reload the library + p11->C_Finalize(NULL_PTR); + rv = p11->C_Initialize(NULL_PTR); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not initialize the library.\n"); + return 1; + } + + // Get the slotID + CK_SLOT_ID newSlotID; + if (findSlot(tokenInfo, newSlotID)) + { + return 1; + } + + if (slotID == newSlotID) + { + printf("The token has been initialized on slot %lu\n", newSlotID); + } + else + { + printf("The token has been initialized and is reassigned to slot %lu\n", newSlotID); + } + + return 0; +} + +// Delete the token +bool deleteToken(char* serial, char* token) +{ + if (serial == NULL && token == NULL) + { + fprintf(stderr, "ERROR: A token must be supplied. " + "Use --serial <serial> or --token <label>\n"); + return false; + } + + // Initialize the SoftHSM internal functions + if (!initSoftHSM()) + { + finalizeSoftHSM(); + return false; + } + + bool rv = true; + std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR); + std::string tokendir; + + rv = findTokenDirectory(basedir, tokendir, serial, token); + + if (rv) + { + std::string fulldir = basedir; + if (fulldir.find_last_of(OS_PATHSEP) != (fulldir.size()-1)) + { + fulldir += OS_PATHSEP + tokendir; + } + else + { + fulldir += tokendir; + } + + rv = rmdir(fulldir); + if (rv) + { + printf("The token (%s) has been deleted.\n", fulldir.c_str()); + } + } + + finalizeSoftHSM(); + + return rv; +} + +bool initSoftHSM() +{ + // Not using threading + MutexFactory::i()->disable(); + + // Initiate SecureMemoryRegistry + if (SecureMemoryRegistry::i() == NULL) + { + fprintf(stderr, "ERROR: Could not initiate SecureMemoryRegistry.\n"); + return false; + } + + // Build the CryptoFactory + if (CryptoFactory::i() == NULL) + { + fprintf(stderr, "ERROR: Could not initiate CryptoFactory.\n"); + return false; + } + +#ifdef WITH_FIPS + // Check the FIPS status + if (!CryptoFactory::i()->getFipsSelfTestStatus()) + { + fprintf(stderr, "ERROR: FIPS self test failed.\n"); + return false; + } +#endif + + // Load the configuration + if (!Configuration::i()->reload(SimpleConfigLoader::i())) + { + fprintf(stderr, "ERROR: Could not load the SoftHSM configuration.\n"); + return false; + } + + // Configure the log level + if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL))) + { + fprintf(stderr, "ERROR: Could not configure the log level.\n"); + return false; + } + + // Configure object store storage backend used by all tokens. + if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND))) + { + fprintf(stderr, "ERROR: Could not select token backend.\n"); + return false; + } + + return true; +} + +void finalizeSoftHSM() +{ + CryptoFactory::reset(); + SecureMemoryRegistry::reset(); +} + +// Find the token directory +bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label) +{ + if (serial == NULL && label == NULL) + { + return false; + } + + // Load the variables + CK_UTF8CHAR paddedSerial[16]; + CK_UTF8CHAR paddedLabel[32]; + if (serial != NULL) + { + size_t inSize = strlen(serial); + size_t outSize = sizeof(paddedSerial); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --serial is too long.\n"); + return false; + } + memset(paddedSerial, ' ', outSize); + memcpy(paddedSerial, serial, inSize); + } + if (label != NULL) + { + size_t inSize = strlen(label); + size_t outSize = sizeof(paddedLabel); + if (inSize > outSize) + { + fprintf(stderr, "ERROR: --token is too long.\n"); + return false; + } + memset(paddedLabel, ' ', outSize); + memcpy(paddedLabel, label, inSize); + } + + // Find all tokens in the specified path + Directory storeDir(basedir); + + if (!storeDir.isValid()) + { + fprintf(stderr, "Failed to enumerate object store in %s\n", basedir.c_str()); + + return false; + } + + // Assume that all subdirectories are tokens + std::vector<std::string> dirs = storeDir.getSubDirs(); + + ByteString tokenLabel; + ByteString tokenSerial; + CK_UTF8CHAR paddedTokenSerial[16]; + CK_UTF8CHAR paddedTokenLabel[32]; + size_t counter = 0; + for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); i++) + { + memset(paddedTokenSerial, ' ', sizeof(paddedTokenSerial)); + memset(paddedTokenLabel, ' ', sizeof(paddedTokenLabel)); + + // Create a token instance + ObjectStoreToken* token = ObjectStoreToken::accessToken(basedir, *i); + + if (!token->isValid()) + { + delete token; + continue; + } + + if (token->getTokenLabel(tokenLabel) && tokenLabel.size() <= sizeof(paddedTokenLabel)) + { + strncpy((char*) paddedTokenLabel, (char*) tokenLabel.byte_str(), tokenLabel.size()); + } + if (token->getTokenSerial(tokenSerial) && tokenSerial.size() <= sizeof(paddedTokenSerial)) + { + strncpy((char*) paddedTokenSerial, (char*) tokenSerial.byte_str(), tokenSerial.size()); + } + + if (serial != NULL && label == NULL && + memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0) + { + printf("Found token (%s) with matching serial.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + if (serial == NULL && label != NULL && + memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0) + { + printf("Found token (%s) with matching token label.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + if (serial != NULL && label != NULL && + memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0 && + memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0) + { + printf("Found token (%s) with matching serial and token label.\n", i->c_str()); + tokendir = i->c_str(); + counter++; + } + + delete token; + } + + if (counter == 1) return true; + if (counter > 1) + { + fprintf(stderr, "ERROR: Found multiple matching tokens.\n"); + return false; + } + + fprintf(stderr, "ERROR: Could not find a token using --serial or --token.\n"); + return false; +} + + +// Delete a directory +bool rmdir(std::string path) +{ + bool rv = true; + +#ifndef _WIN32 + // Enumerate the directory + DIR* dir = opendir(path.c_str()); + + if (dir == NULL) + { + fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str()); + return false; + } + + // Enumerate the directory + struct dirent* entry = NULL; + + while ((entry = readdir(dir)) != NULL) + { + bool handled = false; + + // Check if this is the . or .. entry + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + { + continue; + } + + // Convert the name of the entry to a C++ string + std::string name(entry->d_name); + std::string fullPath = path + OS_PATHSEP + name; + +#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE) + // Determine the type of the entry + switch(entry->d_type) + { + case DT_DIR: + // This is a directory + rv = rmdir(fullPath); + handled = true; + break; + case DT_REG: + // This is a regular file + rv = rm(fullPath); + handled = true; + break; + default: + break; + } +#endif + + if (rv == false) + break; + + if (!handled) + { + // The entry type has to be determined using lstat + struct stat entryStatus; + + if (!lstat(fullPath.c_str(), &entryStatus)) + { + if (S_ISDIR(entryStatus.st_mode)) + { + // This is a directory + rv = rmdir(fullPath); + } + else if (S_ISREG(entryStatus.st_mode)) + { + // This is a regular file + rv = rm(fullPath); + } + } + + if (rv == false) + break; + } + } + + // Close the directory + closedir(dir); +#else + // Enumerate the directory + std::string pattern; + intptr_t h; + struct _finddata_t fi; + + if ((path.back() == '/') || (path.back() == '\\')) + pattern = path + "*"; + else + pattern = path + "/*"; + memset(&fi, 0, sizeof(fi)); + h = _findfirst(pattern.c_str(), &fi); + if (h == -1) + { + // empty directory + if (errno == ENOENT) + goto finished; + + fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str()); + + return false; + } + + // scan files & subdirs + do + { + // Check if this is the . or .. entry + if (!strcmp(fi.name, ".") || !strcmp(fi.name, "..")) + continue; + + std::string fullPath = path + OS_PATHSEP + fi.name; + if ((fi.attrib & _A_SUBDIR) == 0) + { + // This is a regular file + rv = rm(fullPath); + } + else + { + // This is a directory + rv = rmdir(fullPath); + } + + memset(&fi, 0, sizeof(fi)); + + if (rv == false) + break; + } while (_findnext(h, &fi) == 0); + + (void) _findclose(h); + + finished: +#endif + + if (rv == false) + return false; + + int result; +#ifndef _WIN32 + result = ::rmdir(path.c_str()); +#else + result = _rmdir(path.c_str()); +#endif + + if (result != 0) + { + fprintf(stderr, "ERROR: Could not delete the directory: %s\n", path.c_str()); + return false; + } + + return true; +} + +// Delete a file +bool rm(std::string path) +{ + int result; + +#ifndef _WIN32 + result = ::remove(path.c_str()); +#else + result = _unlink(path.c_str()); +#endif + + if (result != 0) + { + fprintf(stderr, "ERROR: Could not delete the file: %s\n", path.c_str()); + return false; + } + + return true; +} + +// Show what slots are available +int showSlots() +{ + CK_ULONG ulSlotCount; + CK_RV rv = p11->C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the number of slots.\n"); + return 1; + } + + CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); + if (!pSlotList) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return 1; + } + + rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the slot list.\n"); + free(pSlotList); + return 1; + } + + printf("Available slots:\n"); + + for (CK_ULONG i = 0; i < ulSlotCount; i++) + { + CK_SLOT_INFO slotInfo; + CK_TOKEN_INFO tokenInfo; + + rv = p11->C_GetSlotInfo(pSlotList[i], &slotInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about slot %lu.\n", pSlotList[i]); + continue; + } + + printf("Slot %lu\n", pSlotList[i]); + printf(" Slot info:\n"); + printf(" Description: %.*s\n", 64, slotInfo.slotDescription); + printf(" Manufacturer ID: %.*s\n", 32, slotInfo.manufacturerID); + printf(" Hardware version: %i.%i\n", slotInfo.hardwareVersion.major, + slotInfo.hardwareVersion.minor); + printf(" Firmware version: %i.%i\n", slotInfo.firmwareVersion.major, + slotInfo.firmwareVersion.minor); + printf(" Token present: "); + if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) + { + printf("no\n"); + continue; + } + + printf("yes\n"); + printf(" Token info:\n"); + + rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n", + pSlotList[i]); + continue; + } + + printf(" Manufacturer ID: %.*s\n", 32, tokenInfo.manufacturerID); + printf(" Model: %.*s\n", 16, tokenInfo.model); + printf(" Hardware version: %i.%i\n", tokenInfo.hardwareVersion.major, + tokenInfo.hardwareVersion.minor); + printf(" Firmware version: %i.%i\n", tokenInfo.firmwareVersion.major, + tokenInfo.firmwareVersion.minor); + printf(" Serial number: %.*s\n", 16, tokenInfo.serialNumber); + printf(" Initialized: "); + if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0) + { + printf("no\n"); + } + else + { + printf("yes\n"); + } + + printf(" User PIN init.: "); + if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == 0) + { + printf("no\n"); + } + else + { + printf("yes\n"); + } + + printf(" Label: %.*s\n", 32, tokenInfo.label); + + } + + free(pSlotList); + + return 0; +} + +// Import a key pair from given path +int importKeyPair +( + char* filePath, + char* filePIN, + CK_SLOT_ID slotID, + char* userPIN, + char* label, + char* objectID, + int forceExec, + int noPublicKey +) +{ + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the object must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (objectID == NULL) + { + fprintf(stderr, "ERROR: An ID for the object must be supplied. " + "Use --id <hex>\n"); + return 1; + } + + size_t objIDLen = 0; + char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen); + if (objID == NULL) + { + fprintf(stderr, "Please edit --id <hex> to correct error.\n"); + return 1; + } + + CK_SESSION_HANDLE hSession; + CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + if (rv == CKR_SLOT_ID_INVALID) + { + fprintf(stderr, "ERROR: The given slot does not exist.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not open a session on the given slot.\n"); + } + free(objID); + return 1; + } + + // Get the password + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + free(objID); + return 1; + } + + rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + if (rv == CKR_PIN_INCORRECT) { + fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + } + free(objID); + return 1; + } + + CK_OBJECT_HANDLE oHandle = searchObject(hSession, objID, objIDLen); + if (oHandle != CK_INVALID_HANDLE && forceExec == 0) + { + free(objID); + fprintf(stderr, "ERROR: The ID is already assigned to another object. " + "Use --force to override this message.\n"); + return 1; + } + + crypto_init(); + int result = crypto_import_key_pair(hSession, filePath, filePIN, label, objID, objIDLen, noPublicKey); + crypto_final(); + + free(objID); + + return result; +} + +// Import a secret key from given path +int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID) +{ + char user_pin_copy[MAX_PIN_LEN+1]; + + if (label == NULL) + { + fprintf(stderr, "ERROR: A label for the object must be supplied. " + "Use --label <text>\n"); + return 1; + } + + if (objectID == NULL) + { + fprintf(stderr, "ERROR: An ID for the object must be supplied. " + "Use --id <hex>\n"); + return 1; + } + + size_t objIDLen = 0; + char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen); + if (objID == NULL) + { + fprintf(stderr, "Please edit --id <hex> to correct error.\n"); + return 1; + } + + // Get the password + if (getPW(userPIN, user_pin_copy, CKU_USER) != 0) + { + fprintf(stderr, "ERROR: Could not get user PIN\n"); + return 1; + } + + CK_SESSION_HANDLE hSession; + CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL_PTR, NULL_PTR, &hSession); + if (rv != CKR_OK) + { + if (rv == CKR_SLOT_ID_INVALID) + { + fprintf(stderr, "ERROR: The given slot does not exist.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not open a session on the given slot.\n"); + } + return 1; + } + + rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy)); + if (rv != CKR_OK) + { + if (rv == CKR_PIN_INCORRECT) { + fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n"); + } + else + { + fprintf(stderr, "ERROR: Could not log in on the token.\n"); + } + return 1; + } + + crypto_init(); + int result = crypto_import_aes_key(hSession, filePath, label, objID, objIDLen); + crypto_final(); + + return result; +} + +// Convert a char array of hexadecimal characters into a binary representation +char* hexStrToBin(char* objectID, int idLength, size_t* newLen) +{ + char* bytes = NULL; + + if (idLength < 2 || idLength % 2 != 0) + { + fprintf(stderr, "ERROR: Invalid length on hex string.\n"); + return NULL; + } + + for (int i = 0; i < idLength; i++) + { + if (hexdigit_to_int(objectID[i]) == -1) + { + fprintf(stderr, "ERROR: Invalid character in hex string.\n"); + return NULL; + } + } + + *newLen = idLength / 2; + bytes = (char*) malloc(*newLen); + if (bytes == NULL) + { + fprintf(stderr, "ERROR: Could not allocate memory.\n"); + return NULL; + } + + for (size_t i = 0; i < *newLen; i++) + { + bytes[i] = hexdigit_to_int(objectID[2*i]) * 16 + + hexdigit_to_int(objectID[2*i+1]); + } + + return bytes; +} + +// Return the integer value of a hexadecimal character +int hexdigit_to_int(char ch) +{ + switch (ch) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'a': + case 'A': + return 10; + case 'b': + case 'B': + return 11; + case 'c': + case 'C': + return 12; + case 'd': + case 'D': + return 13; + case 'e': + case 'E': + return 14; + case 'f': + case 'F': + return 15; + default: + return -1; + } +} + +// Search for an object +CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen) +{ + if (objID == NULL) + { + return CK_INVALID_HANDLE; + } + + CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY; + CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE; + CK_ULONG objectCount = 0; + + CK_ATTRIBUTE objTemplate[] = { + { CKA_CLASS, &oClass, sizeof(oClass) }, + { CKA_ID, objID, objIDLen } + }; + + CK_RV rv = p11->C_FindObjectsInit(hSession, objTemplate, 2); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not prepare the object search.\n"); + return CK_INVALID_HANDLE; + } + + rv = p11->C_FindObjects(hSession, &hObject, 1, &objectCount); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not get the search results.\n"); + return CK_INVALID_HANDLE; + } + + rv = p11->C_FindObjectsFinal(hSession); + if (rv != CKR_OK) + { + fprintf(stderr, "ERROR: Could not finalize the search.\n"); + return CK_INVALID_HANDLE; + } + + if (objectCount == 0) + { + return CK_INVALID_HANDLE; + } + + return hObject; +} diff --git a/SoftHSMv2/src/bin/util/softhsm2-util.h b/SoftHSMv2/src/bin/util/softhsm2-util.h new file mode 100644 index 0000000..3c49314 --- /dev/null +++ b/SoftHSMv2/src/bin/util/softhsm2-util.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + softhsm2-util.h + + This program can be used for interacting with HSMs using PKCS#11. + The default library is the libsofthsm2.so + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SOFTHSM2_UTIL_H +#define _SOFTHSM_V2_SOFTHSM2_UTIL_H + +#include "cryptoki.h" +#include <string> + +// Main functions + +void usage(); +bool checkSetup(); +int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN); +bool deleteToken(char* serial, char* token); +bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label); +bool rmdir(std::string path); +bool rm(std::string path); +int showSlots(); +int importKeyPair(char* filePath, char* filePIN, CK_SLOT_ID slotID, char* userPIN, char* objectLabel, char* objectID, int forceExec, int noPublicKey); +int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID); +int crypto_import_key_pair(CK_SESSION_HANDLE hSession, char* filePath, char* filePIN, char* label, char* objID, size_t objIDLen, int noPublicKey); +int crypto_import_aes_key(CK_SESSION_HANDLE hSession, char* filePath, char* label, char* objID, size_t objIDLen); + +// Support functions + +void crypto_init(); +void crypto_final(); + +/// SoftHSM internal funtions +bool initSoftHSM(); +void finalizeSoftHSM(); + +/// Hex +char* hexStrToBin(char* objectID, int idLength, size_t* newLen); +int hexdigit_to_int(char ch); + +/// Library +#if !defined(UTIL_BOTAN) && !defined(UTIL_OSSL) +static void* moduleHandle; +#endif +extern CK_FUNCTION_LIST_PTR p11; + +/// PKCS#11 support +CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen); + +#endif // !_SOFTHSM_V2_SOFTHSM2_UTIL_H |