aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp')
-rw-r--r--SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp798
1 files changed, 798 insertions, 0 deletions
diff --git a/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp
new file mode 100644
index 0000000..0e6dc90
--- /dev/null
+++ b/SoftHSMv2/src/bin/migrate/softhsm2-migrate.cpp
@@ -0,0 +1,798 @@
+/*
+ * 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-migrate.cpp
+
+ This program can be used for migrating SoftHSM v1 databases to any
+ PKCS#11 library. The default library is the libsofthsm2.so
+ *****************************************************************************/
+
+#include <config.h>
+#include "softhsm2-migrate.h"
+#include "findslot.h"
+#include "getpw.h"
+#include "library.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <iostream>
+#include <fstream>
+#include <sched.h>
+
+#ifdef _WIN32
+#define sched_yield() SleepEx(0, 0)
+#endif
+
+// Display the usage
+void usage()
+{
+ printf("SoftHSM migration tool. From SoftHSM v1 database to PKCS#11.\n");
+ printf("Usage: softhsm2-migrate [OPTIONS]\n");
+ printf("Options:\n");
+ printf(" -h Shows this help screen.\n");
+ printf(" --help Shows this help screen.\n");
+ printf(" --db <path> The SoftHSM v1 database that is going to be migrated.\n");
+ printf(" --module <path> Use another PKCS#11 library than SoftHSM.\n");
+ printf(" --no-public-key Do not migrate 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(" --token <label> Will use the token with a matching token label.\n");
+ printf(" -v Show version info.\n");
+ printf(" --version Show version info.\n");
+}
+
+// Enumeration of the long options
+enum {
+ OPT_HELP = 0x100,
+ OPT_DB,
+ OPT_MODULE,
+ OPT_NO_PUBLIC_KEY,
+ OPT_PIN,
+ OPT_SERIAL,
+ OPT_SLOT,
+ OPT_TOKEN,
+ OPT_VERSION
+};
+
+// Text representation of the long options
+static const struct option long_options[] = {
+ { "help", 0, NULL, OPT_HELP },
+ { "db", 1, NULL, OPT_DB },
+ { "module", 1, NULL, OPT_MODULE },
+ { "no-public-key", 0, NULL, OPT_NO_PUBLIC_KEY },
+ { "pin", 1, NULL, OPT_PIN },
+ { "serial", 1, NULL, OPT_SERIAL },
+ { "slot", 1, NULL, OPT_SLOT },
+ { "token" , 1, NULL, OPT_TOKEN },
+ { "version", 0, NULL, OPT_VERSION },
+ { NULL, 0, NULL, 0 }
+};
+
+CK_FUNCTION_LIST_PTR p11;
+
+// Prepared statements
+sqlite3_stmt* select_an_attribute_sql = NULL;
+sqlite3_stmt* select_object_ids_sql = NULL;
+sqlite3_stmt* count_object_id_sql = NULL;
+
+
+// The main function
+int main(int argc, char* argv[])
+{
+ int option_index = 0;
+ int opt;
+
+ char* dbPath = NULL;
+ char* userPIN = NULL;
+ char* module = NULL;
+ char* slot = NULL;
+ char* serial = NULL;
+ char* token = NULL;
+ char *errMsg = NULL;
+ int noPublicKey = 0;
+
+ int result = 0;
+ CK_RV rv;
+
+ moduleHandle = NULL;
+ p11 = NULL;
+ CK_SLOT_ID slotID = 0;
+
+ if (argc == 1)
+ {
+ usage();
+ exit(0);
+ }
+
+ while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
+ {
+ switch (opt)
+ {
+ case OPT_DB:
+ dbPath = optarg;
+ break;
+ case OPT_SLOT:
+ slot = 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_PIN:
+ userPIN = optarg;
+ break;
+ case OPT_VERSION:
+ case 'v':
+ printf("%s\n", PACKAGE_VERSION);
+ exit(0);
+ break;
+ case OPT_HELP:
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ break;
+ }
+ }
+
+ // Get a pointer to the function list for PKCS#11 library
+ CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg);
+ if (pGetFunctionList == NULL)
+ {
+ 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
+ rv = p11->C_Initialize(NULL_PTR);
+ if (rv != 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);
+ }
+
+ // Get the slotID
+ result = findSlot(slot, serial, token, slotID);
+
+ if (!result)
+ {
+ // Migrate the database
+ result = migrate(dbPath, slotID, userPIN, noPublicKey);
+ }
+
+ // Finalize the library
+ p11->C_Finalize(NULL_PTR);
+ unloadLibrary(moduleHandle);
+
+ return result;
+}
+
+// Migrate the database
+int migrate(char* dbPath, CK_SLOT_ID slotID, char* userPIN, int noPublicKey)
+{
+ CK_SESSION_HANDLE hSession;
+ sqlite3* db = NULL;
+ int result;
+
+ if (dbPath == NULL)
+ {
+ fprintf(stderr, "ERROR: A path to the database must be supplied. "
+ "Use --db <path>\n");
+ return 1;
+ }
+
+ // Open the database
+ db = openDB(dbPath);
+ if (db == NULL)
+ {
+ return 1;
+ }
+
+ // Connect to the PKCS#11 library
+ result = openP11(slotID, userPIN, &hSession);
+ if (result)
+ {
+ sqlite3_close(db);
+ return result;
+ }
+
+ // Prepare the statements
+ if (prepStatements(db))
+ {
+ fprintf(stderr, "ERROR: Could not prepare the statements\n");
+ finalStatements();
+ sqlite3_close(db);
+ return 1;
+ }
+
+ // Start the migration
+ result = db2session(db, hSession, noPublicKey);
+
+ // Finalize the statements
+ finalStatements();
+
+ sqlite3_close(db);
+
+ if (result)
+ {
+ fprintf(stderr, "ERROR: Unable to migrate all of the objects.\n");
+ }
+ else
+ {
+ printf("The database has been migrated to the new HSM\n");
+ }
+
+ return result;
+}
+
+// Prepare the statements
+int prepStatements(sqlite3* db)
+{
+ select_an_attribute_sql = NULL;
+ select_object_ids_sql = NULL;
+ count_object_id_sql = NULL;
+
+ const char select_an_attribute_str[] = "SELECT value,length FROM Attributes WHERE objectID = ? AND type = ?;";
+ const char select_object_ids_str[] = "SELECT objectID FROM Objects;";
+ const char count_object_id_str[] = "SELECT COUNT(objectID) FROM Objects;";
+
+ if
+ (
+ sqlite3_prepare_v2(db, select_an_attribute_str, -1, &select_an_attribute_sql, NULL) ||
+ sqlite3_prepare_v2(db, select_object_ids_str, -1, &select_object_ids_sql, NULL) ||
+ sqlite3_prepare_v2(db, count_object_id_str, -1, &count_object_id_sql, NULL)
+ )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+// Finalize the statements
+void finalStatements()
+{
+ if (select_an_attribute_sql) sqlite3_finalize(select_an_attribute_sql);
+ if (select_object_ids_sql) sqlite3_finalize(select_object_ids_sql);
+ if (count_object_id_sql) sqlite3_finalize(count_object_id_sql);
+}
+
+// Open a connection to a valid SoftHSM v1 database
+sqlite3* openDB(char* dbPath)
+{
+ int result;
+ sqlite3* db = NULL;
+ sqlite3_stmt* pragStatem = NULL;
+ int dbVersion;
+
+ // Open the database
+ result = sqlite3_open(dbPath, &db);
+ if (result)
+ {
+ fprintf(stderr, "ERROR: Could not open token database. "
+ "Probably wrong path or privileges: %s\n", dbPath);
+ return NULL;
+ }
+
+ // Check the schema version
+ if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &pragStatem, NULL))
+ {
+ fprintf(stderr, "ERROR: Could not prepare a SQL statement\n");
+ sqlite3_close(db);
+ return NULL;
+ }
+ if (sqlite3_step(pragStatem) == SQLITE_ROW)
+ {
+ dbVersion = sqlite3_column_int(pragStatem, 0);
+ sqlite3_finalize(pragStatem);
+
+ if (dbVersion != 100)
+ {
+ fprintf(stderr, "ERROR: Wrong database schema version: %s\n", dbPath);
+ sqlite3_close(db);
+ return NULL;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: The token database has not been initialized by SoftHSM\n");
+ sqlite3_finalize(pragStatem);
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ // Check that the Token table exist
+ result = sqlite3_exec(db, "SELECT COUNT(variableID) FROM Token;", NULL, NULL, NULL);
+ if (result)
+ {
+ fprintf(stderr, "ERROR: The Token table is missing the in database\n");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ // Check that the Objects table exist
+ result = sqlite3_exec(db, "SELECT COUNT(objectID) FROM Objects;", NULL, NULL, NULL);
+ if (result)
+ {
+ fprintf(stderr, "ERROR: The Objects table is missing the in database\n");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ // Check that the Attributes table exist
+ result = sqlite3_exec(db, "SELECT COUNT(attributeID) FROM Attributes;", NULL, NULL, NULL);
+ if (result)
+ {
+ fprintf(stderr, "ERROR: The Attributes table is missing in the database\n");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+// Connect and login to the token
+int openP11(CK_SLOT_ID slotID, char* userPIN, CK_SESSION_HANDLE* hSession)
+{
+ char user_pin_copy[MAX_PIN_LEN+1];
+ CK_RV 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;
+ }
+
+ // Get the password
+ if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
+ {
+ fprintf(stderr, "ERROR: Could not get user PIN\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;
+ }
+
+ return 0;
+}
+
+// Migrate the database to the session
+int db2session(sqlite3* db, CK_SESSION_HANDLE hSession, int noPublicKey)
+{
+ CK_ULONG objectCount;
+ int result = 0, rv;
+ CK_OBJECT_HANDLE* objects = NULL;
+ CK_OBJECT_CLASS ckClass;
+
+ // Get all objects
+ objects = getObjects(db, &objectCount);
+ if (objects == NULL)
+ {
+ fprintf(stderr, "ERROR: Could not find any objects in the database.\n");
+ return 1;
+ }
+
+ // Loop over all objects
+ for (unsigned i = 0; i < objectCount; i++)
+ {
+ ckClass = getObjectClass(objects[i]);
+
+ switch (ckClass)
+ {
+ case CKO_PUBLIC_KEY:
+ if (noPublicKey) continue;
+ if (getKeyType(objects[i]) != CKK_RSA)
+ {
+ fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. "
+ "Continuing.\n", objects[i]);
+ result = 1;
+ break;
+ }
+ rv = dbRSAPub2session(db, objects[i], hSession);
+ if (rv) result = 1;
+ break;
+ case CKO_PRIVATE_KEY:
+ if (getKeyType(objects[i]) != CKK_RSA)
+ {
+ fprintf(stderr, "ERROR: Cannot export object %lu. Only supporting RSA keys. "
+ "Continuing.\n", objects[i]);
+ result = 1;
+ break;
+ }
+ rv = dbRSAPriv2session(db, objects[i], hSession);
+ if (rv) result = 1;
+ break;
+ case CKO_VENDOR_DEFINED:
+ fprintf(stderr, "ERROR: Could not get the class of object %lu. "
+ "Continuing.\n", objects[i]);
+ result = 1;
+ break;
+ default:
+ fprintf(stderr, "ERROR: Not supporting class %lu in object %lu. "
+ "Continuing.\n", ckClass, objects[i]);
+ result = 1;
+ break;
+ }
+ }
+
+ free(objects);
+
+ return result;
+}
+
+// Get the key type from key objects
+CK_KEY_TYPE getKeyType(CK_OBJECT_HANDLE objectRef)
+{
+ int retSQL = 0;
+ CK_KEY_TYPE retVal = CKK_VENDOR_DEFINED;
+
+ sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+ sqlite3_bind_int(select_an_attribute_sql, 2, CKA_KEY_TYPE);
+
+ // Get result
+ while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+ {
+ sched_yield();
+ }
+
+ // Get attribute
+ if (retSQL == SQLITE_ROW)
+ {
+ CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+ CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+ if (pValue != NULL_PTR && length == sizeof(CK_KEY_TYPE))
+ {
+ retVal = *(CK_KEY_TYPE*)pValue;
+ }
+ }
+
+ sqlite3_reset(select_an_attribute_sql);
+
+ return retVal;
+}
+
+// Get the class of the object
+CK_OBJECT_CLASS getObjectClass(CK_OBJECT_HANDLE objectRef)
+{
+ int retSQL = 0;
+ CK_OBJECT_CLASS retVal = CKO_VENDOR_DEFINED;
+
+ sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+ sqlite3_bind_int(select_an_attribute_sql, 2, CKA_CLASS);
+
+ // Get the result
+ while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+ {
+ sched_yield();
+ }
+
+ // Get attribute
+ if (retSQL == SQLITE_ROW)
+ {
+ CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+ CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+ if (pValue != NULL_PTR && length == sizeof(CK_OBJECT_CLASS))
+ {
+ retVal = *(CK_OBJECT_CLASS*)pValue;
+ }
+ }
+
+ sqlite3_reset(select_an_attribute_sql);
+
+ return retVal;
+}
+
+// Get all object IDs
+CK_OBJECT_HANDLE* getObjects(sqlite3* /*db*/, CK_ULONG* objectCount)
+{
+ CK_ULONG objectsInDB;
+ CK_ULONG counter = 0;
+ CK_OBJECT_HANDLE* objectRefs = NULL;
+ int retSQL = 0;
+
+ *objectCount = 0;
+
+ // Find out how many objects we have.
+ while ((retSQL = sqlite3_step(count_object_id_sql)) == SQLITE_BUSY)
+ {
+ sched_yield();
+ }
+
+ if (retSQL != SQLITE_ROW)
+ {
+ fprintf(stderr, "ERROR: Could not count the number of objects in the database\n");
+ sqlite3_reset(count_object_id_sql);
+ return NULL;
+ }
+
+ // Get the number of objects
+ objectsInDB = sqlite3_column_int(count_object_id_sql, 0);
+ sqlite3_reset(count_object_id_sql);
+
+ if (!objectsInDB)
+ {
+ fprintf(stderr, "ERROR: There are not objects in the database\n");
+ return NULL;
+ }
+
+ // Create the object-reference buffer
+ objectRefs = (CK_OBJECT_HANDLE*)malloc(objectsInDB * sizeof(CK_OBJECT_HANDLE));
+ if (objectRefs == NULL)
+ {
+ fprintf(stderr, "ERROR: Could not allocate memory\n");
+ return NULL;
+ }
+
+ // Get all the object ids
+ while
+ (
+ ((retSQL = sqlite3_step(select_object_ids_sql)) == SQLITE_BUSY || retSQL == SQLITE_ROW) &&
+ counter < objectsInDB
+ )
+ {
+ if(retSQL == SQLITE_BUSY)
+ {
+ sched_yield();
+ continue;
+ }
+
+ objectRefs[counter++] = sqlite3_column_int(select_object_ids_sql, 0);
+ }
+
+ *objectCount = counter;
+
+ sqlite3_reset(select_object_ids_sql);
+
+ return objectRefs;
+}
+
+// Extract the information about the public RSA key and save it in the token
+int dbRSAPub2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession)
+{
+ int result = 0;
+ int i;
+ CK_OBJECT_HANDLE hKey;
+ CK_RV rv;
+
+ CK_ATTRIBUTE pubTemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_KEY_TYPE, NULL, 0 },
+ { CKA_TOKEN, NULL, 0 },
+ { CKA_PRIVATE, NULL, 0 },
+ { CKA_MODIFIABLE, NULL, 0 },
+ { CKA_LABEL, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_START_DATE, NULL, 0 },
+ { CKA_END_DATE, NULL, 0 },
+ { CKA_DERIVE, NULL, 0 },
+ { CKA_SUBJECT, NULL, 0 },
+ { CKA_ENCRYPT, NULL, 0 },
+ { CKA_VERIFY, NULL, 0 },
+ { CKA_VERIFY_RECOVER, NULL, 0 },
+ { CKA_WRAP, NULL, 0 },
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 }
+ };
+
+ for (i = 0; i < 17; i++)
+ {
+ result = getAttribute(objectID, &pubTemplate[i]);
+ if (result)
+ {
+ freeTemplate(pubTemplate, 17);
+ return 1;
+ }
+ }
+
+ rv = p11->C_CreateObject(hSession, pubTemplate, 17, &hKey);
+ if (rv != CKR_OK)
+ {
+ fprintf(stderr, "ERROR %X: Could not save the public key in the token. "
+ "Skipping object %lu\n", (unsigned int)rv, objectID);
+ result = 1;
+ }
+ else
+ {
+ printf("Object %lu has been migrated\n", objectID);
+ }
+
+ freeTemplate(pubTemplate, 17);
+
+ return result;
+}
+
+// Extract the information about the private RSA key and save it in the token
+int dbRSAPriv2session(sqlite3* /*db*/, CK_OBJECT_HANDLE objectID, CK_SESSION_HANDLE hSession)
+{
+ int result = 0;
+ int i;
+ CK_OBJECT_HANDLE hKey;
+ CK_RV rv;
+
+ CK_ATTRIBUTE privTemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_TOKEN, NULL, 0 },
+ { CKA_PRIVATE, NULL, 0 },
+ { CKA_MODIFIABLE, NULL, 0 },
+ { CKA_LABEL, NULL, 0 },
+ { CKA_KEY_TYPE, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_START_DATE, NULL, 0 },
+ { CKA_END_DATE, NULL, 0 },
+ { CKA_DERIVE, NULL, 0 },
+ { CKA_SUBJECT, NULL, 0 },
+ { CKA_SENSITIVE, NULL, 0 },
+ { CKA_DECRYPT, NULL, 0 },
+ { CKA_SIGN, NULL, 0 },
+ { CKA_SIGN_RECOVER, NULL, 0 },
+ { CKA_UNWRAP, NULL, 0 },
+ { CKA_EXTRACTABLE, NULL, 0 },
+ { CKA_WRAP_WITH_TRUSTED, NULL, 0 },
+ { CKA_MODULUS, NULL, 0 },
+ { CKA_PUBLIC_EXPONENT, NULL, 0 },
+ { CKA_PRIVATE_EXPONENT, NULL, 0 },
+ { CKA_PRIME_1, NULL, 0 },
+ { CKA_PRIME_2, NULL, 0 }
+// SoftHSM v1 did not store these values
+// { CKA_EXPONENT_1, NULL, 0 },
+// { CKA_EXPONENT_2, NULL, 0 },
+// { CKA_COEFFICIENT, NULL, 0 }
+ };
+
+ for (i = 0; i < 23; i++)
+ {
+ result = getAttribute(objectID, &privTemplate[i]);
+ if (result)
+ {
+ freeTemplate(privTemplate, 23);
+ return 1;
+ }
+ }
+
+ rv = p11->C_CreateObject(hSession, privTemplate, 23, &hKey);
+ if (rv != CKR_OK)
+ {
+ fprintf(stderr, "ERROR %X: Could not save the private key in the token. "
+ "Skipping object %lu\n", (unsigned int)rv, objectID);
+ result = 1;
+ }
+ else
+ {
+ printf("Object %lu has been migrated\n", objectID);
+ }
+
+ freeTemplate(privTemplate, 23);
+
+ return result;
+}
+
+// Get the value of the given attribute
+int getAttribute(CK_OBJECT_HANDLE objectRef, CK_ATTRIBUTE* attTemplate)
+{
+ int retSQL = 0;
+ int retVal = 0;
+
+ sqlite3_bind_int(select_an_attribute_sql, 1, objectRef);
+ sqlite3_bind_int(select_an_attribute_sql, 2, attTemplate->type);
+
+ // Get result
+ while ((retSQL = sqlite3_step(select_an_attribute_sql)) == SQLITE_BUSY)
+ {
+ sched_yield();
+ }
+
+ // Get the attribute
+ if (retSQL == SQLITE_ROW)
+ {
+ CK_VOID_PTR pValue = (CK_VOID_PTR)sqlite3_column_blob(select_an_attribute_sql, 0);
+ CK_ULONG length = sqlite3_column_int(select_an_attribute_sql, 1);
+
+ if (length)
+ {
+ attTemplate->pValue = malloc(length);
+ if (!attTemplate->pValue)
+ {
+ fprintf(stderr, "ERROR: Could not allocate memory. "
+ "Skipping object %lu\n", objectRef);
+ retVal = 1;
+ }
+ else
+ {
+ // Copy data
+ memcpy(attTemplate->pValue, pValue, length);
+ }
+ }
+
+ attTemplate->ulValueLen = length;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Do not have attribute %lu. "
+ "Skipping object %lu\n", attTemplate->type, objectRef);
+ retVal = 1;
+ }
+
+ sqlite3_reset(select_an_attribute_sql);
+
+ return retVal;
+}
+
+// Free allocated memory in the template
+void freeTemplate(CK_ATTRIBUTE* attTemplate, int size)
+{
+ int i;
+
+ if (!attTemplate) return;
+
+ for (i = 0; i < size; i++)
+ {
+ if(attTemplate[i].pValue)
+ {
+ free(attTemplate[i].pValue);
+ }
+ }
+}