aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp')
-rw-r--r--SoftHSMv2/src/bin/util/softhsm2-util-ossl.cpp790
1 files changed, 790 insertions, 0 deletions
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