From 1d47492875c09a8744cf8655d25ad43b72348410 Mon Sep 17 00:00:00 2001 From: DistroBaker Date: Tue, 27 Oct 2020 21:40:26 +0100 Subject: [PATCH] Merged update from upstream sources This is an automated DistroBaker update from upstream sources. If you do not know what this is about or would like to opt out, contact the OSCI team. Source: https://src.fedoraproject.org/rpms/opencryptoki.git#7efcdd3173d12f91795271ae5ed07047e6ae7e4d --- .gitignore | 1 + ...Fix-NVTOK.DAT-conversion-on-little-e.patch | 134 - ...Fix-private-token-object-conversion-.patch | 40 - ...Fix-public-token-object-conversion-o.patch | 34 - ...Remove-the-token-s-shared-memory-seg.patch | 93 - ...ublic-token-objects-in-new-data-form.patch | 107 - ...b307d934285709a9-PIN-conversion-tool.patch | 3575 ----------------- opencryptoki-3.14.0-crash-in-c_setpin.patch | 63 - ...i-3.14.0-early-error-in-c-initialize.patch | 85 - ...36937b6364c53219fb3c7922439f403e8d5e.patch | 22 - opencryptoki-3.15.0-timeb.patch | 183 + opencryptoki.spec | 25 +- sources | 2 +- 13 files changed, 192 insertions(+), 4172 deletions(-) delete mode 100644 0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch delete mode 100644 0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch delete mode 100644 0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch delete mode 100644 0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch delete mode 100644 0005-Fix-storing-of-public-token-objects-in-new-data-form.patch delete mode 100644 opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch delete mode 100644 opencryptoki-3.14.0-crash-in-c_setpin.patch delete mode 100644 opencryptoki-3.14.0-early-error-in-c-initialize.patch delete mode 100644 opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch create mode 100644 opencryptoki-3.15.0-timeb.patch diff --git a/.gitignore b/.gitignore index 7437f41..6402428 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ opencryptoki-2.3.1.tar.gz /opencryptoki-3.12.1.tar.gz /opencryptoki-3.13.0.tar.gz /opencryptoki-3.14.0.tar.gz +/opencryptoki-3.15.0.tar.gz diff --git a/0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch b/0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch deleted file mode 100644 index e51b2ea..0000000 --- a/0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 583f0210bb8f371c2071966f27b83c95230d50cc Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Thu, 2 Jul 2020 14:09:18 +0200 -Subject: [PATCH 1/2] pkcstok_migrate: Fix NVTOK.DAT conversion on little - endian platforms - -The new format stores all numeric fields in big endian, while the old -format uses the platform endianness. So convert the fields to big endian -during conversion. - -Signed-off-by: Ingo Franzki ---- - usr/sbin/pkcstok_migrate/pkcstok_migrate.c | 84 ++++++++++++++++++++++++++---- - 1 file changed, 74 insertions(+), 10 deletions(-) - -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -index e90a5c91..e0c19125 100644 ---- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -@@ -1077,6 +1077,42 @@ static CK_RV load_NVTOK_DAT(const char *data_store, const char *nvtok_name, - goto done; - } - -+ if (stbuf.st_size == sizeof(TOKEN_DATA)) { -+ /* The 312 version always uses big endian */ -+ td->token_info.flags = be32toh(td->token_info.flags); -+ td->token_info.ulMaxSessionCount -+ = be32toh(td->token_info.ulMaxSessionCount); -+ td->token_info.ulSessionCount -+ = be32toh(td->token_info.ulSessionCount); -+ td->token_info.ulMaxRwSessionCount -+ = be32toh(td->token_info.ulMaxRwSessionCount); -+ td->token_info.ulRwSessionCount -+ = be32toh(td->token_info.ulRwSessionCount); -+ td->token_info.ulMaxPinLen = be32toh(td->token_info.ulMaxPinLen); -+ td->token_info.ulMinPinLen = be32toh(td->token_info.ulMinPinLen); -+ td->token_info.ulTotalPublicMemory -+ = be32toh(td->token_info.ulTotalPublicMemory); -+ td->token_info.ulFreePublicMemory -+ = be32toh(td->token_info.ulFreePublicMemory); -+ td->token_info.ulTotalPrivateMemory -+ = be32toh(td->token_info.ulTotalPrivateMemory); -+ td->token_info.ulFreePrivateMemory -+ = be32toh(td->token_info.ulFreePrivateMemory); -+ td->tweak_vector.allow_weak_des -+ = be32toh(td->tweak_vector.allow_weak_des); -+ td->tweak_vector.check_des_parity -+ = be32toh(td->tweak_vector.check_des_parity); -+ td->tweak_vector.allow_key_mods -+ = be32toh(td->tweak_vector.allow_key_mods); -+ td->tweak_vector.netscape_mods -+ = be32toh(td->tweak_vector.netscape_mods); -+ td->dat.version = be32toh(td->dat.version); -+ td->dat.so_login_it = be64toh(td->dat.so_login_it); -+ td->dat.user_login_it = be64toh(td->dat.user_login_it); -+ td->dat.so_wrap_it = be64toh(td->dat.so_wrap_it); -+ td->dat.user_wrap_it = be64toh(td->dat.user_wrap_it); -+ } -+ - ret = CKR_OK; - - done: -@@ -1628,6 +1664,7 @@ static CK_RV create_NVTOK_DAT_312(const char *data_store, const char *sopin, - { - const char *nvtok = "NVTOK.DAT_312"; - char fname[PATH_MAX + 1 + strlen(nvtok) + 1]; -+ TOKEN_DATA be_tokdata; - FILE *fp = NULL; - CK_RV ret; - size_t rc; -@@ -1656,14 +1693,6 @@ static CK_RV create_NVTOK_DAT_312(const char *data_store, const char *sopin, - goto done; - } - -- /* Write old part into NVTOK.DAT_312 */ -- rc = fwrite(tokdata, sizeof(TOKEN_DATA_OLD), 1, fp); -- if (rc != 1) { -- TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); -- ret = CKR_FUNCTION_FAILED; -- goto done; -- } -- - /* Create additions for new format */ - ret = create_TOKEN_DATA_VERSION(sopin, userpin, tokdata); - if (ret != CKR_OK) { -@@ -1671,8 +1700,43 @@ static CK_RV create_NVTOK_DAT_312(const char *data_store, const char *sopin, - goto done; - } - -- /* Append TOKEN_DATA_VERSION to NVTOK.DAT_312 */ -- rc = fwrite(&(tokdata->dat), sizeof(TOKEN_DATA_VERSION), 1, fp); -+ /* The 312 version always uses big endian */ -+ memcpy(&be_tokdata, tokdata, sizeof(TOKEN_DATA)); -+ be_tokdata.token_info.flags = htobe32(tokdata->token_info.flags); -+ be_tokdata.token_info.ulMaxSessionCount -+ = htobe32(tokdata->token_info.ulMaxSessionCount); -+ be_tokdata.token_info.ulSessionCount -+ = htobe32(tokdata->token_info.ulSessionCount); -+ be_tokdata.token_info.ulMaxRwSessionCount -+ = htobe32(tokdata->token_info.ulMaxRwSessionCount); -+ be_tokdata.token_info.ulRwSessionCount -+ = htobe32(tokdata->token_info.ulRwSessionCount); -+ be_tokdata.token_info.ulMaxPinLen = htobe32(tokdata->token_info.ulMaxPinLen); -+ be_tokdata.token_info.ulMinPinLen = htobe32(tokdata->token_info.ulMinPinLen); -+ be_tokdata.token_info.ulTotalPublicMemory -+ = htobe32(tokdata->token_info.ulTotalPublicMemory); -+ be_tokdata.token_info.ulFreePublicMemory -+ = htobe32(tokdata->token_info.ulFreePublicMemory); -+ be_tokdata.token_info.ulTotalPrivateMemory -+ = htobe32(tokdata->token_info.ulTotalPrivateMemory); -+ be_tokdata.token_info.ulFreePrivateMemory -+ = htobe32(tokdata->token_info.ulFreePrivateMemory); -+ be_tokdata.tweak_vector.allow_weak_des -+ = htobe32(tokdata->tweak_vector.allow_weak_des); -+ be_tokdata.tweak_vector.check_des_parity -+ = htobe32(tokdata->tweak_vector.check_des_parity); -+ be_tokdata.tweak_vector.allow_key_mods -+ = htobe32(tokdata->tweak_vector.allow_key_mods); -+ be_tokdata.tweak_vector.netscape_mods -+ = htobe32(tokdata->tweak_vector.netscape_mods); -+ be_tokdata.dat.version = htobe32(tokdata->dat.version); -+ be_tokdata.dat.so_login_it = htobe64(tokdata->dat.so_login_it); -+ be_tokdata.dat.user_login_it = htobe64(tokdata->dat.user_login_it); -+ be_tokdata.dat.so_wrap_it = htobe64(tokdata->dat.so_wrap_it); -+ be_tokdata.dat.user_wrap_it = htobe64(tokdata->dat.user_wrap_it); -+ -+ /* Write converted token data into NVTOK.DAT_312 */ -+ rc = fwrite(&be_tokdata, sizeof(TOKEN_DATA), 1, fp); - if (rc != 1) { - TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); - ret = CKR_FUNCTION_FAILED; --- -2.16.2.windows.1 - diff --git a/0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch b/0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch deleted file mode 100644 index 6954bf2..0000000 --- a/0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 6faa13d83e5166e4bbe97d85935aca779fde9089 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Thu, 2 Jul 2020 14:46:29 +0200 -Subject: [PATCH 2/2] pkcstok_migrate: Fix private token object conversion on - little endian platforms - -The new format stores numeric fields in the object header in big endian, while -the old format uses the platform endianness. So convert the fields to big endian -during conversion. - -Signed-off-by: Ingo Franzki ---- - usr/sbin/pkcstok_migrate/pkcstok_migrate.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -index e0c19125..0148102c 100644 ---- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -@@ -239,7 +239,7 @@ static CK_RV make_OBJECT_PRIV_312(unsigned char **obj_new, unsigned int *obj_new - - /* Setup header */ - memset(&header, 0, sizeof(header)); -- header.tokversion = 0x0003000C; -+ header.tokversion = htobe32(0x0003000C); - header.private_flag = 0x01; - ret = aes_256_wrap(header.key_wrapped, obj_key, masterkey); - if (ret != CKR_OK) { -@@ -252,7 +252,7 @@ static CK_RV make_OBJECT_PRIV_312(unsigned char **obj_new, unsigned int *obj_new - header.iv[9] = 0; - header.iv[10] = 0; - header.iv[11] = 1; -- header.object_len = clear_len; -+ header.object_len = htobe32(clear_len); - memcpy(object, &header, HEADER_LEN); - - /* Encrypt body */ --- -2.16.2.windows.1 - diff --git a/0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch b/0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch deleted file mode 100644 index 331d09b..0000000 --- a/0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch +++ /dev/null @@ -1,34 +0,0 @@ -From c090136338b585370df6a8e29518f9e55d388fe5 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 6 Jul 2020 13:16:34 +0200 -Subject: [PATCH 3/5] pkcstok_migrate: Fix public token object conversion on - little endian platforms - -The new format stores numeric fields in the object header in big endian, while -the old format uses the platform endianness. So convert the fields to big endian -during conversion. - -Signed-off-by: Ingo Franzki ---- - usr/sbin/pkcstok_migrate/pkcstok_migrate.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -index 0148102c..136c010c 100644 ---- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -@@ -103,9 +103,9 @@ static CK_RV make_OBJECT_PUB_312(char **obj_new, unsigned int *obj_new_len, - - /* Setup object */ - memset(&header, 0, sizeof(header)); -- header.tokversion = 0x0003000C; -+ header.tokversion = htobe32(0x0003000C); - header.private_flag = 0x00; -- header.object_len = clear_len; -+ header.object_len = htobe32(clear_len); - memcpy(object, &header, sizeof(header)); - memcpy(object + sizeof(header), clear, clear_len); - --- -2.16.2.windows.1 - diff --git a/0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch b/0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch deleted file mode 100644 index 4520992..0000000 --- a/0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch +++ /dev/null @@ -1,93 +0,0 @@ -From d1dbc25c6f424a12860295008991cd1392c888a8 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 6 Jul 2020 09:56:31 +0200 -Subject: [PATCH 4/5] pkcstok_migrate: Remove the token's shared memory segment - -After successfully migration, remove the tokens shared memory segment. -This will be re-created on the first use of the token. - -Signed-off-by: Ingo Franzki ---- - usr/sbin/pkcstok_migrate/pkcstok_migrate.c | 38 +++++++++++++++++++++++++++++ - usr/sbin/pkcstok_migrate/pkcstok_migrate.mk | 2 +- - 2 files changed, 39 insertions(+), 1 deletion(-) - -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -index 136c010c..46e5e57f 100644 ---- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - #include - - #include "sw_crypt.h" -@@ -2108,6 +2109,36 @@ done: - - } - -+/** -+ * Removes the token_s shared memory from /dev/shm -+ */ -+static CK_RV remove_shared_memory(char *location) -+{ -+ char shm_name[PATH_MAX]; -+ int i, k, rc; -+ -+ i = k = 0; -+ shm_name[k++] = '/'; -+ if (location[i] == '/') -+ i++; -+ -+ for (; location[i]; i++, k++) { -+ if (location[i] == '/') -+ shm_name[k] = '.'; -+ else -+ shm_name[k] = location[i]; -+ } -+ shm_name[k] = '\0'; -+ -+ rc = shm_unlink(shm_name); -+ if (rc != 0) { -+ warnx("shm_unlink(%s) failed, errno=%s", shm_name, strerror(errno)); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ return CKR_OK; -+} -+ - /** - * Copy a file given by name from a src folder to a dst folder. - */ -@@ -2718,6 +2749,13 @@ int main(int argc, char **argv) - goto done; - } - -+ /* Remove the token's shared memory */ -+ ret = remove_shared_memory(data_store); -+ if (ret != CKR_OK) { -+ warnx("Failed to remove token's shared memory."); -+ goto done; -+ } -+ - /* Now insert new 'tokversion=3.12' parm in opencryptoki.conf */ - ret = update_opencryptoki_conf(slot_id, conf_dir); - if (ret != CKR_OK) { -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk b/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -index dc4582e5..028a383e 100644 ---- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -@@ -6,7 +6,7 @@ noinst_HEADERS += usr/include/local_types.h - noinst_HEADERS += usr/lib/common/h_extern.h - noinst_HEADERS += usr/lib/common/pkcs_utils.h - --usr_sbin_pkcstok_migrate_pkcstok_migrate_LDFLAGS = -lcrypto -ldl -+usr_sbin_pkcstok_migrate_pkcstok_migrate_LDFLAGS = -lcrypto -ldl -lrt - - usr_sbin_pkcstok_migrate_pkcstok_migrate_CFLAGS = \ - -DSTDLL_NAME=\"pkcstok_migrate\" \ --- -2.16.2.windows.1 - diff --git a/0005-Fix-storing-of-public-token-objects-in-new-data-form.patch b/0005-Fix-storing-of-public-token-objects-in-new-data-form.patch deleted file mode 100644 index a014b41..0000000 --- a/0005-Fix-storing-of-public-token-objects-in-new-data-form.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 6850ae623f9d36b70f1d2919c8390a4b14d393a1 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 6 Jul 2020 13:16:01 +0200 -Subject: [PATCH 5/5] Fix storing of public token objects in new data format - -The tokversion and object length field are supposed to be stored -in big endian (BE) on all platforms. This was not the case for public -token objects. - -Fix this by always storing it in BE, and add logic to the read routines -to automatically detect if the fields are in the expected byte order, -or not, and handle them accordingly. - -Signed-off-by: Ingo Franzki ---- - usr/lib/common/loadsave.c | 32 +++++++++++++++++++++++++++----- - 1 file changed, 27 insertions(+), 5 deletions(-) - -diff --git a/usr/lib/common/loadsave.c b/usr/lib/common/loadsave.c -index 068fdf36..b76dea9f 100644 ---- a/usr/lib/common/loadsave.c -+++ b/usr/lib/common/loadsave.c -@@ -2557,6 +2557,7 @@ CK_RV reload_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) - CK_ULONG size_64; - CK_RV rc; - uint32_t len; -+ uint32_t ver; - - if (tokdata->version < TOK_NEW_DATA_STORE) - return reload_token_object_old(tokdata, obj); -@@ -2580,9 +2581,18 @@ CK_RV reload_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) - goto done; - } - -+ memcpy(&ver, header, 4); - memcpy(&priv, header + 4, 1); - memcpy(&len, header + 60, 4); -- size = be32toh(len); -+ -+ /* -+ * In OCK 3.12 - 3.14 the version and size was not stored in BE. So if -+ * version field is in platform endianness, keep size as is also. -+ */ -+ if (ver == TOK_NEW_DATA_STORE) -+ size = len; -+ else -+ size = be32toh(len); - - buf = (CK_BYTE *) malloc(size); - if (buf == NULL) { -@@ -2647,8 +2657,9 @@ CK_RV save_public_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) - CK_ULONG clear_len; - CK_BBOOL flag = FALSE; - CK_RV rc; -- CK_ULONG_32 len; -+ CK_ULONG_32 len, be_len; - unsigned char reserved[7] = {0}; -+ uint32_t tmp; - - if (tokdata->version < TOK_NEW_DATA_STORE) - return save_public_token_object_old(tokdata, obj); -@@ -2669,11 +2680,14 @@ CK_RV save_public_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) - goto done; - } - -+ tmp = htobe32(tokdata->version); -+ be_len = htobe32(len); -+ - set_perm(fileno(fp)); -- if (fwrite(&tokdata->version, 4, 1, fp) != 1 -+ if (fwrite(&tmp, 4, 1, fp) != 1 - || fwrite(&flag, 1, 1, fp) != 1 - || fwrite(reserved, 7, 1, fp) != 1 -- || fwrite(&len, 4, 1, fp) != 1 -+ || fwrite(&be_len, 4, 1, fp) != 1 - || fwrite(clear, len, 1, fp) != 1) { - rc = CKR_FUNCTION_FAILED; - goto done; -@@ -2704,6 +2718,7 @@ CK_RV load_public_token_objects(STDLL_TokData_t *tokdata) - CK_BBOOL priv; - CK_ULONG_32 size; - unsigned char header[PUB_HEADER_LEN]; -+ uint32_t ver; - - if (tokdata->version < TOK_NEW_DATA_STORE) - return load_public_token_objects_old(tokdata); -@@ -2731,9 +2746,16 @@ CK_RV load_public_token_objects(STDLL_TokData_t *tokdata) - continue; - } - -+ memcpy(&ver, header, 4); - memcpy(&priv, header + 4, 1); - memcpy(&size, header + 12, 4); -- size = be32toh(size); -+ -+ /* -+ * In OCK 3.12 - 3.14 the version and size was not stored in BE. So if -+ * version field is in platform endianness, keep size as is also -+ */ -+ if (ver != TOK_NEW_DATA_STORE) -+ size = be32toh(size); - - if (priv == TRUE) { - fclose(fp2); --- -2.16.2.windows.1 - diff --git a/opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch b/opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch deleted file mode 100644 index ef02e85..0000000 --- a/opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch +++ /dev/null @@ -1,3575 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 289c5052..c1f24eb9 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -189,6 +189,12 @@ AC_ARG_ENABLE([p11sak], - [], - [enable_p11sak=yes]) - -+dnl --- pkcstok_migrate -+AC_ARG_ENABLE([pkcstok_migrate], -+ AS_HELP_STRING([--enable-pkcstok_migrate],[build pkcstok_migrate tool @<:@default=enabled@:>@]), -+ [], -+ [enable_pkcstok_migrate=yes]) -+ - dnl --- - dnl --- Check for external software - dnl --- Define what to check based on enabled features -@@ -592,6 +598,9 @@ AM_CONDITIONAL([ENABLE_PKCSEP11_SESSION], [test "x$enable_pkcsep11_session" = "x - dnl --- enable_p11sak - AM_CONDITIONAL([ENABLE_P11SAK], [test "x$enable_p11sak" = "xyes"]) - -+dnl --- enable_pkcstok_migrate -+AM_CONDITIONAL([ENABLE_PKCSTOK_MIGRATE], [test "x$enable_pkcstok_migrate" = "xyes"]) -+ - dnl --- enable_locks - if test "x$enable_locks" != "xno"; then - enable_locks=yes -@@ -625,6 +634,7 @@ AC_CONFIG_FILES([Makefile \ - man/man1/p11sak.1 \ - man/man1/pkcsep11_migrate.1 \ - man/man1/pkcsep11_session.1 \ -+ man/man1/pkcstok_migrate.1 \ - man/man5/opencryptoki.conf.5 \ - man/man7/opencryptoki.7 \ - man/man8/pkcsslotd.8]) -@@ -639,6 +649,7 @@ echo " Library build: $enable_library" - echo " Systemd service: $enable_systemd" - echo " Build with locks: $enable_locks" - echo " Build p11sak tool: $enable_p11sak" -+echo " token migrate tool: $enable_pkcstok_migrate" - echo - echo "Enabled token types:" - echo " ICA token: $enable_icatok" -diff --git a/man/man1/man1.mk b/man/man1/man1.mk -index 51d23d39..6102340f 100644 ---- a/man/man1/man1.mk -+++ b/man/man1/man1.mk -@@ -1,5 +1,9 @@ - man1_MANS += man/man1/pkcsconf.1 man/man1/pkcsicsf.1 - -+if ENABLE_PKCSTOK_MIGRATE -+man1_MANS += man/man1/pkcstok_migrate.1 -+endif -+ - if ENABLE_PKCSEP11_MIGRATE - man1_MANS += man/man1/pkcsep11_migrate.1 - endif -diff --git a/man/man1/pkcstok_migrate.1.in b/man/man1/pkcstok_migrate.1.in -new file mode 100644 -index 00000000..b17d10b8 ---- /dev/null -+++ b/man/man1/pkcstok_migrate.1.in -@@ -0,0 +1,69 @@ -+.\" pkcstok_migrate.1 -+.\" -+.\" Copyright IBM Corp. 2020 -+.\" See LICENSE for details. -+.\" -+.TH PKCSTOK_MIGRATE 1 "June 2020" "@PACKAGE_VERSION@" "openCryptoki" -+.SH NAME -+pkcstok_migrate \- utility to migrate an ICA, CCA, Soft, or EP11 token repository -+to the FIPS compliant format introduced with openCryptoki 3.12. -+ -+.SH SYNOPSIS -+\fBpkcstok_migrate\fP [\fB-h\fP] -+.br -+\fBpkcstok_migrate\fP \fB--slotid\fP \fIslot-number\fP \fB--datastore\fP \fIdatastore\fP -+\fB--confdir\fP \fIconfdir\fP [\fB--sopin\fP \fIsopin\fP] [\fB--userpin\fP -+\fIuserpin\fP] [\fB--verbose\fP \fIlevel\fP] -+ -+.SH DESCRIPTION -+Convert all objects inside a token repository to the new format introduced with -+version 3.12. All encrypted data inside the new format is stored using FIPS -+compliant methods. The new format affects the token's master key files (MK_SO -+and MK_USER), the NVTOK.DAT, and the token object files in the TOK_OBJ folder. -+ -+While using this tool no process using the token to be migrated must be running. -+Especially the pkcsslotd must be stopped before running this tool. -+ -+The tool creates a backup of the token repository to be migrated, and performs -+all migration actions on this backup, leaving the original repository folder -+completely untouched. The backup folder is located in the same directory as the -+original repository and is suffixed with _PKCSTOK_MIGRATE_TMP. -+ -+After a successful migration, the original repository is renamed with a suffix -+of _BAK and the backup folder is renamed to the original repository name, so -+that the migrated repository can immediately be used. The old folder may be -+deleted by the user manually later. -+ -+After a successful migration, the tool adds parameter 'tokversion = 3.12' to the -+token's slot configuration in the opencryptoki.conf file. The original config -+file is still available as opencryptoki.conf_BAK and may be removed by the user -+manually. -+ -+After an unsuccessful migration, the original repository is still available -+unchanged. -+ -+.SH "OPTIONS SUMMARY" -+.IP "\fB--slotid -s\fP \fISLOT-NUMBER\fP" 10 -+specifies the token slot number of the token repository to be migrated -+.IP "\fB--datastore -d\fP \fIDATASTORE\fP" 10 -+specifies the directory of the token repository to be migrated. -+.IP "\fB--confdir -c\fP \fICONFDIR\fP" 10 -+specifies the directory where the opencryptoki.conf file is located. -+.IP "\fB--sopin -p\fP \fISOPIN\fP" 10 -+specifies the SO pin. If not specified, the SO pin is prompted. -+.IP "\fB--userpin -u\fP \fIUSERPIN\fP" 10 -+specifies the user pin. If not specified, the user pin is prompted. -+.IP "\fB--verbose -v\fP \fILEVEL\fP" 10 -+specifies the verbose level: \fInone\fP, error, warn, info, devel, debug -+.IP "\fB--help -h\fP" 10 -+show usage information -+ -+.SH SEE ALSO -+.PD 0 -+.TP -+\fBpkcsconf\fP(1), -+.TP -+\fBopencryptoki\fP(7), -+.TP -+\fBpkcsslotd\fP(8). -+.PD -diff --git a/rpm/opencryptoki.spec b/rpm/opencryptoki.spec -index ae563406..64142e23 100644 ---- a/rpm/opencryptoki.spec -+++ b/rpm/opencryptoki.spec -@@ -239,8 +239,10 @@ exit 0 - %{_sbindir}/pkcsconf - %{_sbindir}/pkcsslotd - %{_sbindir}/p11sak -+%{_sbindir}/pkcstok_migrate - %{_mandir}/man1/pkcsconf.1* - %{_mandir}/man1/p11sak.1* -+%{_mandir}/man1/pkcstok_migrate.1* - %{_mandir}/man5/%{name}.conf.5* - %{_mandir}/man7/%{name}.7* - %{_mandir}/man8/pkcsslotd.8* -diff --git a/usr/lib/common/loadsave.c b/usr/lib/common/loadsave.c -index c30dd1ab..068fdf36 100644 ---- a/usr/lib/common/loadsave.c -+++ b/usr/lib/common/loadsave.c -@@ -1701,7 +1701,7 @@ static CK_RV aes_256_gcm_seal(unsigned char *out, - || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) != 1 - || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 - || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 -- || EVP_CipherFinal_ex(ctx, out, &outlen) != 1 -+ || EVP_CipherFinal_ex(ctx, out + outlen, &outlen) != 1 - || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) { - TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); - rc = ERR_GENERAL_ERROR; -@@ -1741,7 +1741,7 @@ static CK_RV aes_256_gcm_unseal(unsigned char *out, - || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 0) != 1 - || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 - || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 -- || EVP_CipherFinal_ex(ctx, out, &outlen) != 1) { -+ || EVP_CipherFinal_ex(ctx, out + outlen, &outlen) != 1) { - TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); - rc = ERR_GENERAL_ERROR; - goto done; -@@ -1759,6 +1759,7 @@ static CK_RV aes_256_wrap(unsigned char out[40], - { - CK_RV rc; - int outlen; -+ unsigned char buffer[40 + EVP_MAX_BLOCK_LENGTH]; - - EVP_CIPHER_CTX *ctx = NULL; - -@@ -1772,13 +1773,14 @@ static CK_RV aes_256_wrap(unsigned char out[40], - EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - - if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 1) != 1 -- || EVP_CipherUpdate(ctx, out, &outlen, in, 32) != 1 -- || EVP_CipherFinal_ex(ctx, out, &outlen) != 1) { -+ || EVP_CipherUpdate(ctx, buffer, &outlen, in, 32) != 1 -+ || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { - TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); - rc = ERR_GENERAL_ERROR; - goto done; - } - -+ memcpy(out, buffer, 40); - rc = CKR_OK; - done: - EVP_CIPHER_CTX_free(ctx); -@@ -1791,6 +1793,7 @@ static CK_RV aes_256_unwrap(unsigned char key[32], - { - CK_RV rc; - int outlen; -+ unsigned char buffer[32 + EVP_MAX_BLOCK_LENGTH]; - - EVP_CIPHER_CTX *ctx = NULL; - -@@ -1804,13 +1807,14 @@ static CK_RV aes_256_unwrap(unsigned char key[32], - EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - - if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 0) != 1 -- || EVP_CipherUpdate(ctx, key, &outlen, in, 40) != 1 -- || EVP_CipherFinal_ex(ctx, key, &outlen) != 1) { -+ || EVP_CipherUpdate(ctx, buffer, &outlen, in, 40) != 1 -+ || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { - TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); - rc = ERR_GENERAL_ERROR; - goto done; - } - -+ memcpy(key, buffer, 32); - rc = CKR_OK; - done: - EVP_CIPHER_CTX_free(ctx); -diff --git a/usr/lib/common/obj_mgr.c b/usr/lib/common/obj_mgr.c -index 3e4ba3b6..1bdbe64c 100644 ---- a/usr/lib/common/obj_mgr.c -+++ b/usr/lib/common/obj_mgr.c -@@ -1751,6 +1751,12 @@ CK_RV object_mgr_set_attribute_values(STDLL_TokData_t *tokdata, - save_token_object(tokdata, obj); - - if (priv_obj) { -+ if (tokdata->global_shm->num_priv_tok_obj == 0) { -+ TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); -+ rc = CKR_OBJECT_HANDLE_INVALID; -+ XProcUnLock(tokdata); -+ goto done; -+ } - rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> - priv_tok_objs, 0, - tokdata->global_shm-> -@@ -1765,6 +1771,12 @@ CK_RV object_mgr_set_attribute_values(STDLL_TokData_t *tokdata, - - entry = &tokdata->global_shm->priv_tok_objs[index]; - } else { -+ if (tokdata->global_shm->num_publ_tok_obj == 0) { -+ TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); -+ rc = CKR_OBJECT_HANDLE_INVALID; -+ XProcUnLock(tokdata); -+ goto done; -+ } - rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> - publ_tok_objs, 0, - tokdata->global_shm-> -@@ -1846,6 +1858,10 @@ CK_RV object_mgr_del_from_shm(OBJECT *obj, LW_SHM_TYPE *global_shm) - priv = object_is_private(obj); - - if (priv) { -+ if (global_shm->num_priv_tok_obj == 0) { -+ TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); -+ return CKR_OBJECT_HANDLE_INVALID; -+ } - rc = object_mgr_search_shm_for_obj(global_shm->priv_tok_objs, - 0, global_shm->num_priv_tok_obj - 1, - obj, &index); -@@ -1886,6 +1902,10 @@ CK_RV object_mgr_del_from_shm(OBJECT *obj, LW_SHM_TYPE *global_shm) - sizeof(TOK_OBJ_ENTRY)); - } - } else { -+ if (global_shm->num_publ_tok_obj == 0) { -+ TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); -+ return CKR_OBJECT_HANDLE_INVALID; -+ } - rc = object_mgr_search_shm_for_obj(global_shm->publ_tok_objs, - 0, global_shm->num_publ_tok_obj - 1, - obj, &index); -diff --git a/usr/lib/common/pkcs_utils.c b/usr/lib/common/pkcs_utils.c -new file mode 100644 -index 00000000..d3074d5c ---- /dev/null -+++ b/usr/lib/common/pkcs_utils.c -@@ -0,0 +1,477 @@ -+/* -+ * COPYRIGHT (c) International Business Machines Corp. 2020 -+ * -+ * This program is provided under the terms of the Common Public License, -+ * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this -+ * software constitutes recipient's acceptance of CPL-1.0 terms which can be -+ * found in the file LICENSE file or at -+ * https://opensource.org/licenses/cpl1.0.php -+ */ -+ -+/* -+ * Some routines that are shared between the pkcs utilities in usr/sbin. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "defs.h" -+#include "host_defs.h" -+ -+#define OCK_TOOL -+#include "pkcs_utils.h" -+ -+extern pkcs_trace_level_t trace_level; -+ -+void pkcs_trace(pkcs_trace_level_t level, const char *file, int line, -+ const char *fmt, ...) -+{ -+ va_list ap; -+ const char *fmt_pre; -+ char buf[1024]; -+ char *pbuf; -+ int buflen, len; -+ -+ if (level > trace_level) -+ return; -+ -+ pbuf = buf; -+ buflen = sizeof(buf); -+ -+ /* add file line */ -+ switch (level) { -+ case TRACE_LEVEL_NONE: -+ fmt_pre = ""; -+ break; -+ case TRACE_LEVEL_ERROR: -+ fmt_pre = "[%s:%d] ERROR: "; -+ break; -+ case TRACE_LEVEL_WARNING: -+ fmt_pre = "[%s:%d] WARN: "; -+ break; -+ case TRACE_LEVEL_INFO: -+ fmt_pre = "[%s:%d] INFO: "; -+ break; -+ case TRACE_LEVEL_DEVEL: -+ fmt_pre = "[%s:%d] DEVEL: "; -+ break; -+ case TRACE_LEVEL_DEBUG: -+ fmt_pre = "[%s:%d] DEBUG: "; -+ break; -+ default: -+ return; -+ } -+ snprintf(pbuf, buflen, fmt_pre, file, line); -+ -+ len = strlen(buf); -+ pbuf = buf + len; -+ buflen = sizeof(buf) - len; -+ -+ va_start(ap, fmt); -+ vsnprintf(pbuf, buflen, fmt, ap); -+ va_end(ap); -+ -+ printf("%s", buf); -+} -+ -+int compute_hash(int hash_type, int buf_size, char *buf, char *digest) -+{ -+ EVP_MD_CTX *md_ctx = NULL; -+ unsigned int result_size; -+ int rc; -+ -+ md_ctx = EVP_MD_CTX_create(); -+ -+ switch (hash_type) { -+ case HASH_SHA1: -+ rc = EVP_DigestInit(md_ctx, EVP_sha1()); -+ break; -+ case HASH_MD5: -+ rc = EVP_DigestInit(md_ctx, EVP_md5()); -+ break; -+ default: -+ rc = -1; -+ goto done; -+ } -+ -+ if (rc != 1) { -+ TRACE_ERROR("EVP_DigestInit() failed: rc = %d\n", rc); -+ rc = -1; -+ goto done; -+ } -+ -+ rc = EVP_DigestUpdate(md_ctx, buf, buf_size); -+ if (rc != 1) { -+ TRACE_ERROR("EVP_DigestUpdate() failed: rc = %d\n", rc); -+ rc = -1; -+ goto done; -+ } -+ -+ result_size = EVP_MD_CTX_size(md_ctx); -+ rc = EVP_DigestFinal(md_ctx, (unsigned char *) digest, &result_size); -+ if (rc != 1) { -+ TRACE_ERROR("EVP_DigestFinal() failed: rc = %d\n", rc); -+ rc = -1; -+ goto done; -+ } -+ -+ rc = 0; -+ -+done: -+ -+ EVP_MD_CTX_destroy(md_ctx); -+ -+ return rc; -+} -+ -+CK_RV local_rng(CK_BYTE *output, CK_ULONG bytes) -+{ -+ int ranfd; -+ int rlen; -+ unsigned int totallen = 0; -+ -+ ranfd = open("/dev/prandom", 0); -+ if (ranfd < 0) -+ ranfd = open("/dev/urandom", 0); -+ if (ranfd >= 0) { -+ do { -+ rlen = read(ranfd, output + totallen, bytes - totallen); -+ totallen += rlen; -+ } while (totallen < bytes); -+ close(ranfd); -+ return CKR_OK; -+ } -+ -+ return CKR_FUNCTION_FAILED; -+} -+ -+CK_RV aes_256_wrap(unsigned char out[40], const unsigned char in[32], -+ const unsigned char kek[32]) -+{ -+ CK_RV rc; -+ int outlen; -+ unsigned char buffer[40 + EVP_MAX_BLOCK_LENGTH]; -+ -+ EVP_CIPHER_CTX *ctx = NULL; -+ -+ ctx = EVP_CIPHER_CTX_new(); -+ if (ctx == NULL) { -+ TRACE_ERROR("EVP_CIPHER_CTX_new failed.\n"); -+ rc = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); -+ -+ if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 1) != 1 -+ || EVP_CipherUpdate(ctx, buffer, &outlen, in, 32) != 1 -+ || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { -+ TRACE_ERROR("EVP_Cipher funcs failed\n"); -+ rc = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ memcpy(out, buffer, 40); -+ rc = CKR_OK; -+done: -+ EVP_CIPHER_CTX_free(ctx); -+ return rc; -+} -+ -+CK_RV aes_256_unwrap(unsigned char key[32], const unsigned char in[40], -+ const unsigned char kek[32]) -+{ -+ CK_RV rc; -+ int outlen; -+ unsigned char buffer[32 + EVP_MAX_BLOCK_LENGTH]; -+ -+ EVP_CIPHER_CTX *ctx = NULL; -+ -+ ctx = EVP_CIPHER_CTX_new(); -+ if (ctx == NULL) { -+ TRACE_ERROR("EVP_CIPHER_CTX_new failed\n"); -+ rc = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); -+ -+ if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 0) != 1 -+ || EVP_CipherUpdate(ctx, buffer, &outlen, in, 40) != 1 -+ || EVP_CipherFinal_ex(ctx, buffer + outlen, &outlen) != 1) { -+ rc = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ memcpy(key, buffer, 32); -+ rc = CKR_OK; -+done: -+ EVP_CIPHER_CTX_free(ctx); -+ return rc; -+} -+ -+CK_RV aes_256_gcm_seal(unsigned char *out, unsigned char tag[16], -+ const unsigned char *aad, size_t aadlen, -+ const unsigned char *in, size_t inlen, -+ const unsigned char key[32], -+ const unsigned char iv[12]) -+{ -+ CK_RV rc; -+ int outlen; -+ -+ EVP_CIPHER_CTX *ctx = NULL; -+ -+ ctx = EVP_CIPHER_CTX_new(); -+ if (ctx == NULL) { -+ TRACE_ERROR("EVP_CIPHER_CTX_new failed\n"); -+ rc = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 -+ || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 -+ || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) != 1 -+ || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 -+ || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 -+ || EVP_CipherFinal_ex(ctx, out + outlen, &outlen) != 1 -+ || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) { -+ TRACE_ERROR("EVP_Cipher funcs failed\n"); -+ rc = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ rc = CKR_OK; -+done: -+ EVP_CIPHER_CTX_free(ctx); -+ return rc; -+} -+ -+int get_pin(char **pin, size_t *pinlen) -+{ -+ struct termios old, new; -+ int nread; -+ char *buff = NULL; -+ size_t buflen; -+ int rc = 0; -+ -+ /* turn echoing off */ -+ if (tcgetattr(fileno(stdin), &old) != 0) -+ return -1; -+ -+ new = old; -+ new.c_lflag &= ~ECHO; -+ if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) -+ return -1; -+ -+ /* read the pin -+ * Note: getline will allocate memory for buff. free it when done. -+ */ -+ nread = getline(&buff, &buflen, stdin); -+ if (nread == -1) { -+ rc = -1; -+ goto done; -+ } -+ -+ /* Restore terminal */ -+ (void) tcsetattr(fileno(stdin), TCSAFLUSH, &old); -+ -+ /* start a newline */ -+ printf("\n"); -+ fflush(stdout); -+ -+ /* Allocate PIN. -+ * Note: nread includes carriage return. -+ * Replace with terminating NULL. -+ */ -+ *pin = (char *) malloc(nread); -+ if (*pin == NULL) { -+ rc = -ENOMEM; -+ goto done; -+ } -+ -+ /* strip the carriage return since not part of pin. */ -+ buff[nread - 1] = '\0'; -+ memcpy(*pin, buff, nread); -+ /* don't include the terminating null in the pinlen */ -+ *pinlen = nread - 1; -+ -+done: -+ if (buff) -+ free(buff); -+ -+ return rc; -+} -+ -+/** -+ * Verify that SO PIN and user PIN are correct by comparing their SHA-1 -+ * values with the stored hashes in NVTOK.DAT. -+ */ -+int verify_pins(char *data_store, char *sopin, unsigned long sopinlen, -+ char *userpin, unsigned long userpinlen) -+{ -+ TOKEN_DATA td; -+ char fname[PATH_MAX]; -+ char pin_sha[SHA1_HASH_SIZE]; -+ FILE *fp = NULL; -+ int ret; -+ int tdnew; -+ struct stat stbuf; -+ size_t tdlen; -+ int fd; -+ -+ /* read the NVTOK.DAT */ -+ snprintf(fname, PATH_MAX, "%s/NVTOK.DAT", data_store); -+ fp = fopen((char *) fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("Cannot not open %s: %s\n", fname, strerror(errno)); -+ return -1; -+ } -+ -+ fd = fileno(fp); -+ if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { -+ ret = -1; -+ goto done; -+ } -+ -+ if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { -+ /* old data store/pin format */ -+ tdnew = 0; -+ tdlen = sizeof(TOKEN_DATA_OLD); -+ } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { -+ /* new data store/pin format */ -+ tdnew = 1; -+ tdlen = sizeof(TOKEN_DATA); -+ } else { -+ TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", -+ fname, stbuf.st_size); -+ ret = -1; -+ goto done; -+ } -+ -+ ret = fread(&td, tdlen, 1, fp); -+ if (ret != 1) { -+ TRACE_ERROR("Could not read %s: %s\n", fname, strerror(errno)); -+ ret = -1; -+ goto done; -+ } -+ -+ if (tdnew == 0) { -+ /* Now compute the SHAs for the SO and USER pins entered. -+ * Compare with the SHAs for SO and USER PINs saved in -+ * NVTOK.DAT to verify. -+ */ -+ -+ if (sopin != NULL) { -+ ret = compute_sha1(sopin, sopinlen, pin_sha); -+ if (ret) { -+ TRACE_ERROR("Failed to compute sha for SO.\n"); -+ goto done; -+ } -+ -+ if (memcmp(td.so_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { -+ TRACE_ERROR("SO PIN is incorrect.\n"); -+ ret = -1; -+ goto done; -+ } -+ } -+ -+ if (userpin != NULL) { -+ ret = compute_sha1(userpin, userpinlen, pin_sha); -+ if (ret) { -+ TRACE_ERROR("Failed to compute sha for USER.\n"); -+ goto done; -+ } -+ -+ if (memcmp(td.user_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { -+ TRACE_ERROR("USER PIN is incorrect.\n"); -+ ret = -1; -+ goto done; -+ } -+ } -+ } else if (tdnew == 1) { -+ if (sopin != NULL) { -+ unsigned char so_login_key[32]; -+ -+ ret = PKCS5_PBKDF2_HMAC(sopin, sopinlen, -+ td.dat.so_login_salt, 64, -+ td.dat.so_login_it, EVP_sha512(), -+ 256 / 8, so_login_key); -+ if (ret != 1) { -+ TRACE_ERROR("PBKDF2 failed.\n"); -+ goto done; -+ } -+ -+ if (CRYPTO_memcmp(td.dat.so_login_key, so_login_key, 32) != 0) { -+ TRACE_ERROR("USER PIN is incorrect.\n"); -+ ret = -1; -+ goto done; -+ } -+ } -+ if (userpin != NULL) { -+ unsigned char user_login_key[32]; -+ -+ ret = PKCS5_PBKDF2_HMAC(userpin, userpinlen, -+ td.dat.user_login_salt, 64, -+ td.dat.user_login_it, EVP_sha512(), -+ 256 / 8, user_login_key); -+ if (ret != 1) { -+ TRACE_ERROR("PBKDF2 failed.\n"); -+ goto done; -+ } -+ -+ if (CRYPTO_memcmp(td.dat.user_login_key, user_login_key, 32) != 0) { -+ TRACE_ERROR("USER PIN is incorrect.\n"); -+ ret = -1; -+ goto done; -+ } -+ } -+ } else { -+ TRACE_ERROR("Unknown token format.\n"); -+ ret = -1; -+ goto done; -+ } -+ ret = 0; -+ -+done: -+ /* clear out the hash */ -+ memset(pin_sha, 0, SHA1_HASH_SIZE); -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+void set_perm(int file) -+{ -+ struct group *grp; -+ -+ // Set absolute permissions or rw-rw---- -+ fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); -+ -+ grp = getgrnam("pkcs11"); // Obtain the group id -+ if (grp) { -+ // set ownership to root, and pkcs11 group -+ if (fchown(file, getuid(), grp->gr_gid) != 0) { -+ goto error; -+ } -+ } else { -+ goto error; -+ } -+ -+ return; -+ -+error: -+ TRACE_DEVEL("Unable to set permissions on file.\n"); -+} -diff --git a/usr/lib/common/pkcs_utils.h b/usr/lib/common/pkcs_utils.h -new file mode 100644 -index 00000000..248559cc ---- /dev/null -+++ b/usr/lib/common/pkcs_utils.h -@@ -0,0 +1,81 @@ -+/* -+ * COPYRIGHT (c) International Business Machines Corp. 2020 -+ * -+ * This program is provided under the terms of the Common Public License, -+ * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this -+ * software constitutes recipient's acceptance of CPL-1.0 terms which can be -+ * found in the file LICENSE file or at -+ * https://opensource.org/licenses/cpl1.0.php -+ */ -+ -+#ifndef PKCS_UTILS_H -+#define PKCS_UTILS_H -+ -+#include "pkcs11types.h" -+ -+#define MASTER_KEY_SIZE 24 -+#define MASTER_KEY_SIZE_CCA 64 -+#define MAX_MASTER_KEY_SIZE MASTER_KEY_SIZE_CCA -+ -+#define MK_FILE_SIZE_00 48 -+#define MK_FILE_SIZE_00_CCA 88 -+ -+#define HASH_SHA1 1 -+#define HASH_MD5 2 -+ -+#define compute_sha1(a,b,c) compute_hash((HASH_SHA1),(b),(a),(c)) -+#define compute_md5(a,b,c) compute_hash(HASH_MD5,(b),(a),(c)) -+ -+int compute_hash(int hash_type, int buf_size, char *buf, char *digest); -+ -+CK_RV local_rng(CK_BYTE *output, CK_ULONG bytes); -+ -+CK_RV aes_256_wrap(unsigned char out[40], const unsigned char in[32], -+ const unsigned char kek[32]); -+ -+CK_RV aes_256_unwrap(unsigned char key[32], const unsigned char in[40], -+ const unsigned char kek[32]); -+ -+CK_RV aes_256_gcm_seal(unsigned char *out, unsigned char tag[16], -+ const unsigned char *aad, size_t aadlen, -+ const unsigned char *in, size_t inlen, -+ const unsigned char key[32], -+ const unsigned char iv[12]); -+ -+int get_pin(char **pin, size_t *pinlen); -+ -+int verify_pins(char *data_store, char *sopin, unsigned long sopinlen, -+ char *userpin, unsigned long userpinlen); -+ -+void set_perm(int file); -+ -+#ifdef OCK_TOOL -+/* Log levels */ -+typedef enum { -+ TRACE_LEVEL_NONE = 0, -+ TRACE_LEVEL_ERROR, -+ TRACE_LEVEL_WARNING, -+ TRACE_LEVEL_INFO, -+ TRACE_LEVEL_DEVEL, -+ TRACE_LEVEL_DEBUG -+} pkcs_trace_level_t; -+ -+void pkcs_trace(pkcs_trace_level_t level, const char * file, int line, -+ const char *fmt, ...) -+ __attribute__ ((format(printf, 4, 5))); -+ -+#define TRACE_NONE(...) \ -+ pkcs_trace(TRACE_LEVEL_NONE, __FILE__, __LINE__, __VA_ARGS__) -+#define TRACE_ERROR(...) \ -+ pkcs_trace(TRACE_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__) -+#define TRACE_WARN(...) \ -+ pkcs_trace(TRACE_LEVEL_WARNING, __FILE__, __LINE__, __VA_ARGS__) -+#define TRACE_INFO(...) \ -+ pkcs_trace(TRACE_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__) -+#define TRACE_DEVEL(...) \ -+ pkcs_trace(TRACE_LEVEL_DEVEL, __FILE__, __LINE__, __VA_ARGS__) -+#define TRACE_DEBUG(...) \ -+ pkcs_trace(TRACE_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -+#endif /* OCK_TOOL */ -+ -+#endif -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -new file mode 100644 -index 00000000..e90a5c91 ---- /dev/null -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c -@@ -0,0 +1,2686 @@ -+/* -+ * COPYRIGHT (c) International Business Machines Corp. 2020 -+ * -+ * This program is provided under the terms of the Common Public License, -+ * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this -+ * software constitutes recipient's acceptance of CPL-1.0 terms which can be -+ * found in the file LICENSE file or at -+ * https://opensource.org/licenses/cpl1.0.php -+ */ -+ -+/* -+ * pkcstok_migrate - A tool for migrating ICA, CCA, Soft, and EP11 token -+ * repositories to 3.12 format. -+ * -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sw_crypt.h" -+#include "defs.h" -+#include "host_defs.h" -+#include "local_types.h" -+#include "h_extern.h" -+ -+#define OCK_TOOL -+#include "pkcs_utils.h" -+ -+ -+#define TOKVERSION_00 0x00000000 -+#define TOKVERSION_312 0x0003000C -+ -+#define INVALID_TOKEN "unknown/unsupported" -+ -+#define HEADER_LEN 64 -+#define FOOTER_LEN 16 -+ -+#define PKCSTOK_MIGRATE_MAX_PATH_LEN (PATH_MAX - 200) -+ -+pkcs_trace_level_t trace_level = TRACE_LEVEL_NONE; -+ -+/** -+ * Make a 3.12 format OBJECT_PUB: -+ * -+ * struct OBJECT_PUB { -+ * //-------------- <--+ -+ * u32 tokversion; | 16-byte header -+ * u8 private_flag; | -+ * u8 reserved[7]; | -+ * u32 object_len; | -+ * //-------------- <--+ -+ * u8 object[object_len]; | body -+ * //-------------- <--+ -+ * }; -+ */ -+static CK_RV make_OBJECT_PUB_312(char **obj_new, unsigned int *obj_new_len, -+ unsigned char *clear, unsigned int clear_len) -+{ -+ struct { -+ uint32_t tokversion; -+ uint8_t private_flag; -+ uint8_t reserved[7]; -+ uint32_t object_len; -+ } header; -+ uint32_t total_len; -+ char *object; -+ CK_RV ret; -+ -+ *obj_new = NULL; -+ *obj_new_len = 0; -+ -+ /* Check parms */ -+ if (!clear || clear_len == 0) { -+ TRACE_ERROR("Error in parms.\n"); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Allocate memory for new OBJECT_PUB */ -+ total_len = sizeof(header) + clear_len; -+ object = malloc(total_len); -+ if (object == NULL) { -+ TRACE_ERROR("cannot malloc %d bytes.\n", total_len); -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ /* Setup object */ -+ memset(&header, 0, sizeof(header)); -+ header.tokversion = 0x0003000C; -+ header.private_flag = 0x00; -+ header.object_len = clear_len; -+ memcpy(object, &header, sizeof(header)); -+ memcpy(object + sizeof(header), clear, clear_len); -+ -+ *obj_new = object; -+ *obj_new_len = total_len; -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * This function migrates the public obj to the current format. -+ */ -+static CK_RV migrate_public_token_object(const char *data_store, const char *name, -+ unsigned char *data, unsigned long len) -+{ -+ const char *tokobj = "TOK_OBJ"; -+ char fname[PATH_MAX + 1 + strlen(tokobj) + 1 + strlen(name) + 1]; -+ char *obj_new = NULL; -+ unsigned int obj_new_len; -+ FILE *fp = NULL; -+ CK_RV ret = 0; -+ -+ /* Create new public object */ -+ ret = make_OBJECT_PUB_312(&obj_new, &obj_new_len, data, len); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create an OBJECT_PUB_312, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Setup file name for new object */ -+ sprintf(fname, "%s/%s/%s", data_store, tokobj, name); -+ fp = fopen((char *) fname, "w"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp)); -+ -+ /* Save new object */ -+ if (fwrite(obj_new, obj_new_len, 1, fp) != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ free(obj_new); -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * Make a 3.12 format OBJECT_PRIV: -+ * -+ * struct OBJECT_PRIV { -+ * u32 total_len; -+ * --- auth ------- <--+ -+ * u32 tokversion | 64-byte header -+ * u8 private_flag | -+ * u8 reserved[3] | -+ * u8 key_wrapped[40] | -+ * u8 iv[12] | -+ * u32 object_len | -+ * --- auth+enc --- <--+ -+ * u8 object[object_len] | body -+ * ---------------- <--+ -+ * u8 tag[16] | 16-byte footer -+ * ---------------- <--+ -+ * } -+ */ -+static CK_RV make_OBJECT_PRIV_312(unsigned char **obj_new, unsigned int *obj_new_len, -+ const char *name, unsigned char *clear, -+ unsigned int clear_len, const CK_BYTE *masterkey) -+{ -+ struct { -+ uint32_t tokversion; -+ uint8_t private_flag; -+ uint8_t reserved[3]; -+ uint8_t key_wrapped[40]; -+ uint8_t iv[12]; -+ uint32_t object_len; -+ } header; -+ unsigned char *object; -+ CK_BYTE obj_key[32]; -+ uint32_t total_len; -+ CK_RV ret; -+ -+ *obj_new = NULL; -+ *obj_new_len = 0; -+ -+ /* Check parms */ -+ if (!name || !clear || clear_len == 0 || !masterkey) { -+ TRACE_ERROR("Error in parms.\n"); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* An obj name has by definition 8 chars */ -+ if (strlen(name) != 8) { -+ TRACE_ERROR("obj name %s does not have 8 chars, OBJ.IDX probably corrupted.\n", -+ name); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Allocate memory for new OBJECT_PRIV */ -+ total_len = sizeof(header) + clear_len + FOOTER_LEN; -+ object = malloc(total_len); -+ if (object == NULL) { -+ TRACE_ERROR("cannot malloc %d bytes.\n", total_len); -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ /* Create new object key */ -+ ret = local_rng(obj_key, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("local_rng failed with ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Setup header */ -+ memset(&header, 0, sizeof(header)); -+ header.tokversion = 0x0003000C; -+ header.private_flag = 0x01; -+ ret = aes_256_wrap(header.key_wrapped, obj_key, masterkey); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("aes_256_wrap failed with ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ memcpy(header.iv, name, 8); -+ header.iv[8] = 0; -+ header.iv[9] = 0; -+ header.iv[10] = 0; -+ header.iv[11] = 1; -+ header.object_len = clear_len; -+ memcpy(object, &header, HEADER_LEN); -+ -+ /* Encrypt body */ -+ ret = aes_256_gcm_seal(object + HEADER_LEN, /* ciphertext */ -+ object + HEADER_LEN + clear_len, /* tag */ -+ object, HEADER_LEN, /* aad */ -+ clear, clear_len, /* plaintext */ -+ obj_key, /* key */ -+ header.iv /* iv */); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("aes_256_gcm_seal failed with rc=%08lX.\n", ret); -+ goto done; -+ } -+ -+ *obj_new = object; -+ *obj_new_len = total_len; -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Decrypts the given version 0.0 private object with given old masterkey. -+ * -+ * struct OBJECT_PRIV { -+ * u32 total_len; -+ * u8 private_flag; -+ * //--- enc --- <- enc_old starts here -+ * u32 object_len; -+ * u8 object[object_len]; -+ * u8 sha1[20]; -+ * u8 padding[padding_len]; -+ * }; -+ */ -+static CK_RV decrypt_OBJECT_PRIV_00(unsigned char **clear, unsigned int *clear_len, -+ unsigned char *enc_old, unsigned int enc_len, -+ const CK_BYTE *masterkey_old) -+{ -+ CK_ULONG_32 obj_data_len_32; -+ CK_BYTE hash_sha[SHA1_HASH_SIZE]; -+ CK_BYTE des3_key[MAX_MASTER_KEY_SIZE]; -+ unsigned char *tmp_clear, *raw_clear; -+ CK_ULONG tmp_clear_len; -+ CK_RV ret; -+ -+ *clear = NULL; -+ *clear_len = 0; -+ -+ /* Allocate storage for clear output */ -+ tmp_clear = malloc(enc_len); -+ if (!tmp_clear) { -+ TRACE_ERROR("Cannot malloc %d bytes, errno=%s.\n", -+ enc_len, strerror(errno)); -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ /* Decrypt old object */ -+ memcpy(des3_key, masterkey_old, MAX_MASTER_KEY_SIZE); -+ ret = sw_des3_cbc_decrypt(enc_old, enc_len, tmp_clear, &tmp_clear_len, -+ (CK_BYTE *)"10293847", des3_key); -+ if (ret) { -+ TRACE_ERROR("sw_des3_cbc_decrypt failed with ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ /* Validate the length */ -+ memcpy(&obj_data_len_32, tmp_clear, sizeof(CK_ULONG_32)); -+ if (obj_data_len_32 >= enc_len) { -+ TRACE_ERROR("Decrypted object data length %d inconsistent\n", -+ obj_data_len_32); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Validate the hash */ -+ ret = compute_sha1((char *)(tmp_clear + sizeof(CK_ULONG_32)), -+ obj_data_len_32, (char *)hash_sha); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("compute_sha1 failed with ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ if (memcmp(tmp_clear + sizeof(CK_ULONG_32) + obj_data_len_32, hash_sha, -+ SHA1_HASH_SIZE) != 0) { -+ TRACE_ERROR("Stored hash does not match with newly calculated hash.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* At this point, tmp_clear points to the full decrypted obj data: -+ * | 4 bytes len | clear obj[obj_data_len_32] | 20 bytes sha | padding | -+ * But the caller only wants clear obj[obj_data_len_32]. -+ */ -+ raw_clear = malloc(obj_data_len_32); -+ if (!raw_clear) { -+ TRACE_ERROR("Cannot malloc %d bytes, errno=%s.\n", enc_len, strerror(errno)); -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ memcpy(raw_clear, tmp_clear + sizeof(CK_ULONG_32), obj_data_len_32); -+ -+ *clear = raw_clear; -+ *clear_len = (unsigned int)obj_data_len_32; -+ -+ ret = CKR_OK; -+ -+done: -+ -+ free(tmp_clear); -+ return ret; -+} -+ -+/** -+ * This function migrates the private obj to the current format. -+ */ -+static CK_RV migrate_private_token_object(const char *data_store, const char *name, -+ unsigned char *data, unsigned long len, -+ const CK_BYTE *masterkey_old, -+ const CK_BYTE *masterkey_new) -+{ -+ const char *tokobj = "TOK_OBJ"; -+ char fname[PATH_MAX + 1 + strlen(tokobj) + 1 + strlen(name) + 1]; -+ unsigned char *clear = NULL; -+ unsigned int clear_len; -+ unsigned char *obj_new = NULL; -+ unsigned int obj_new_len; -+ FILE *fp = NULL; -+ CK_RV ret; -+ -+ /* Decrypt old object */ -+ ret = decrypt_OBJECT_PRIV_00(&clear, &clear_len, data, len, masterkey_old); -+ if (ret != 0) { -+ TRACE_ERROR("Cannot decrypt old object with old masterkey, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Create new object */ -+ ret = make_OBJECT_PRIV_312(&obj_new, &obj_new_len, name, clear, clear_len, -+ masterkey_new); -+ if (ret != 0) { -+ TRACE_ERROR("make_OBJECT_PRIV_312 failed with ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Create file name for new object */ -+ sprintf(fname, "%s/%s/%s", data_store, tokobj, name); -+ fp = fopen((char *)fname, "w"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp)); -+ -+ /* Save new object */ -+ if (fwrite(obj_new, obj_new_len, 1, fp) != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) { -+ fclose(fp); -+ fp = NULL; -+ } -+ free(clear); -+ free(obj_new); -+ -+ return ret; -+} -+ -+/** -+ * Reads a format 0.0 object: -+ * -+ * struct OBJECT { -+ * u32 total_len; <- indicates old or new format -+ * u8 private_flag; -+ * u8 object; <- can be public or private -+ * }; -+ * -+ * The total_len field has been already read to decide whether this -+ * object is old or new. Its value is passed via the size parm. -+ */ -+static CK_RV read_object_00(FILE *fp, const char *name, unsigned int size, -+ unsigned char **obj, unsigned int *obj_len, -+ CK_BBOOL *obj_priv) -+{ -+ CK_BBOOL priv; -+ size_t read_size; -+ unsigned char *buf = NULL; -+ CK_RV ret; -+ -+ *obj = NULL; -+ *obj_len = 0; -+ -+ /* Check parms */ -+ if (!fp || !name) { -+ TRACE_ERROR("Arguments bad.\n"); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Read 1-char private flag */ -+ read_size = fread(&priv, sizeof(CK_BBOOL), 1, fp); -+ if (read_size != 1) { -+ TRACE_ERROR("Cannot read private flag from old object %s.\n", name); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Allocate buffer for obj */ -+ size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL); -+ buf = malloc(size); -+ if (!buf) { -+ TRACE_ERROR("Cannot malloc %d bytes for object %s.\n", size, name); -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ /* Read obj into buf */ -+ read_size = fread((char *)buf, 1, size, fp); -+ if (read_size != size) { -+ TRACE_ERROR("Cannot read old object %s.\n", name); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ *obj = buf; -+ *obj_len = size; -+ *obj_priv = priv; -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Reads the token object given by name from given data_store and returns -+ * pointers to the object, its length, and indications whether the object -+ * is in 0.0 or 3.12 format and whether it's private. -+ */ -+static CK_RV read_object(const char *data_store, const char *name, -+ unsigned char **obj, unsigned int *obj_len, -+ CK_ULONG *version, CK_BBOOL *obj_priv) -+{ -+ char fname[PATH_MAX]; -+ unsigned int size = 0; -+ size_t read_size; -+ FILE *fp; -+ CK_RV ret; -+ -+ *obj = NULL; -+ *obj_len = 0; -+ -+ /* Open token object file */ -+ snprintf((char *) fname, sizeof(fname), "%s/TOK_OBJ/", data_store); -+ strcat((char *) fname, (char *) name); -+ fp = fopen((char *) fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Read 32-bit size field */ -+ read_size = fread(&size, sizeof(CK_ULONG_32), 1, fp); -+ if (read_size != 1) { -+ TRACE_ERROR("Cannot read %ld bytes from %s, read_size = %ld. " -+ "Object probably empty or corrupted.\n", -+ sizeof(CK_ULONG_32), name, read_size); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Check if this object is old or current */ -+ if (size == TOKVERSION_312) { -+ TRACE_INFO("%s is already in current format, nothing to do.\n", name); -+ ret = CKR_OK; -+ *version = TOKVERSION_312; -+ goto done; -+ } -+ -+ /* Read old object */ -+ *version = TOKVERSION_00; -+ ret = read_object_00(fp, name, size, obj, obj_len, obj_priv); -+ if (ret != 0) { -+ TRACE_ERROR("Cannot read old object %s.\n", name); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * Migrate the token objects from old to new format. Some of the token objects -+ * may be in old and some may be in new format if a previous migration run -+ * was interrupted. -+ */ -+static CK_RV migrate_token_objects(const char *data_store, const CK_BYTE *masterkey_old, -+ const CK_BYTE *masterkey_new, -+ const CK_BYTE *so_wrap_key, -+ const CK_BYTE *user_wrap_key) -+{ -+ const char *tokobj = "TOK_OBJ"; -+ const char *objidx = "OBJ.IDX"; -+ FILE *fp = NULL; -+ unsigned char *obj = NULL; -+ unsigned int obj_len; -+ char tmp[PATH_MAX]; -+ char iname[PATH_MAX + 1 + strlen(tokobj) + 1 + strlen(objidx) + 1]; -+ CK_BBOOL priv; -+ CK_ULONG version; -+ int count = 0, scount = 0; -+ CK_RV ret; -+ -+ /* Check parms */ -+ if (!data_store || !masterkey_old || !masterkey_new || !so_wrap_key -+ || !user_wrap_key) { -+ TRACE_ERROR("Invalid parms.\n"); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Open index file OBJ.IDX */ -+ sprintf(iname, "%s/%s/%s", data_store, tokobj, objidx); -+ fp = fopen((char *)iname, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", iname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Migrate items from OBJ.IDX */ -+ while (fgets(tmp, PATH_MAX, fp)) { -+ tmp[strlen(tmp) - 1] = 0; -+ ret = read_object(data_store, tmp, &obj, &obj_len, &version, &priv); -+ if (ret == 0 && version == TOKVERSION_00) { -+ if (priv) { -+ ret = migrate_private_token_object(data_store, tmp, -+ obj, obj_len, masterkey_old, masterkey_new); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot migrate private object %s, continuing ... \n", tmp); -+ } else -+ scount++; -+ } else { -+ ret = migrate_public_token_object(data_store, tmp, -+ obj, obj_len); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot migrate public object %s, continuing ... \n", tmp); -+ } else -+ scount++; -+ } -+ } -+ -+ if (obj) { -+ free(obj); -+ obj = NULL; -+ } -+ count++; -+ } -+ -+ /* OBJ.IDX must be at eof here */ -+ if (!feof(fp)) { -+ TRACE_WARN("OBJ.IDX is not at eof after object %s, should not happen.\n", -+ tmp); -+ } -+ -+ /* Close OBJ.IDX */ -+ fclose(fp); -+ -+ ret = CKR_OK; -+ -+ TRACE_NONE("Migrated %d object(s) out of %d object(s).\n", scount, count); -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * loads the new aes256 masterkey. -+ * The new format defines the MK to be an AES-256 key. Its unencrypted format -+ * are just the 32 key bytes. Its encrypted format is a 40 byte key blob -+ */ -+static CK_RV load_masterkey_312(const char *data_store, const char *mkfile, -+ const char *pin, TOKEN_DATA *tokdata, -+ CK_BYTE *masterkey) -+{ -+ FILE *fp = NULL; -+ CK_RV ret; -+ int rc; -+ char fname[PATH_MAX]; -+ unsigned char inbuf[40]; -+ unsigned char wrap_key[32]; -+ -+ /* Open file */ -+ memset(fname, 0, PATH_MAX); -+ snprintf(fname, PATH_MAX, "%s/%s", data_store, mkfile); -+ fp = fopen(fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Read wrapped key from file */ -+ rc = fread(inbuf, sizeof(inbuf), 1, fp); -+ if (rc != 1) { -+ TRACE_ERROR("Cannot read %ld bytes from %s.\n", sizeof(inbuf), fname); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Derive wrapping key from pin and public info in TOKEN_DATA */ -+ if (strstr(mkfile,"MK_SO")) { -+ rc = PKCS5_PBKDF2_HMAC(pin, strlen(pin), -+ tokdata->dat.so_wrap_salt, 64, -+ tokdata->dat.so_wrap_it, EVP_sha512(), -+ 256 / 8, wrap_key); -+ } else { -+ rc = PKCS5_PBKDF2_HMAC(pin, strlen(pin), -+ tokdata->dat.user_wrap_salt, 64, -+ tokdata->dat.user_wrap_it, EVP_sha512(), -+ 256 / 8, wrap_key); -+ } -+ if (rc != 1) { -+ TRACE_INFO("PKCS5_PBKDF2_HMAC returned rc=%08X.\n", rc); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Decrypt buffer with pin-related wrapping key */ -+ rc = aes_256_unwrap(masterkey, inbuf, wrap_key); -+ if (rc != CKR_OK) { -+ TRACE_ERROR("aes_256_unwrap failed with rc=%08X.\n", rc); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * loads the old des3 masterkey from given file with given PIN. -+ * The format is: -+ * -+ * struct MK { -+ * u8 MK [24 or 64 (cca)]; -+ * u8 sha1 [20]; -+ * u8 padding[4]; -+ * }; -+ */ -+static CK_RV load_masterkey_00(const char *mkfile, const char *pin, -+ CK_BYTE *masterkey) -+{ -+ CK_BYTE des3_key[3 * DES_KEY_SIZE]; -+ char hash_sha[SHA1_HASH_SIZE]; -+ char pin_md5_hash[MD5_HASH_SIZE]; -+ unsigned char *cipher = NULL; -+ unsigned char *clear = NULL; -+ unsigned long cipher_len, clear_len; -+ CK_ULONG master_key_len = 0L; -+ int file_size = 0; -+ -+ CK_RV ret; -+ int rc; -+ FILE *fp = NULL; -+ -+ fp = fopen(mkfile, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", mkfile, strerror(errno)); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ /* Determine the master key length */ -+ fseek(fp, 0L, SEEK_END); -+ file_size = ftell(fp); -+ switch (file_size) { -+ case MK_FILE_SIZE_00_CCA: /* CCA token */ -+ master_key_len = MASTER_KEY_SIZE_CCA; -+ break; -+ case MK_FILE_SIZE_00: /* All other tokens */ -+ master_key_len = MASTER_KEY_SIZE; -+ break; -+ default: -+ /* Unknown MK format, should not occur. */ -+ TRACE_ERROR("%s has an unknown file size of %d bytes. Should be either 48 or 88 bytes.\n", -+ mkfile, file_size); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ rewind(fp); -+ -+ /* Read file contents */ -+ clear_len = cipher_len = -+ (master_key_len + SHA1_HASH_SIZE + -+ (DES_BLOCK_SIZE - 1)) & ~(DES_BLOCK_SIZE - 1); -+ -+ cipher = malloc(cipher_len); -+ clear = malloc(clear_len); -+ if (cipher == NULL || clear == NULL) { -+ ret = CKR_HOST_MEMORY; -+ goto done; -+ } -+ -+ rc = fread(cipher, cipher_len, 1, fp); -+ if (rc != 1) { -+ TRACE_ERROR("Cannot read %ld bytes from %s\n", cipher_len, mkfile); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Decrypt the masterkey */ -+ ret = compute_md5((char *)pin, strlen(pin), pin_md5_hash); -+ if (ret) { -+ TRACE_ERROR("Error calculating MD5 of PIN, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ memcpy(des3_key, pin_md5_hash, MD5_HASH_SIZE); -+ memcpy(des3_key + MD5_HASH_SIZE, pin_md5_hash, DES_KEY_SIZE); -+ -+ ret = sw_des3_cbc_decrypt(cipher, cipher_len, clear, -+ &clear_len, (unsigned char *) "12345678", -+ des3_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("failed to decrypt master key file after read, ret=%08lX\n", ret); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* compare the hashes to verify integrity */ -+ ret = compute_sha1((char *)clear, master_key_len, hash_sha); -+ if (ret) { -+ TRACE_ERROR("Failed to compute sha1 for masterkey, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ if (memcmp(hash_sha, clear + master_key_len, SHA1_HASH_SIZE) != 0) { -+ TRACE_ERROR("%s appears to be tampered! Cannot migrate.\n", mkfile); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ memcpy(masterkey, clear, master_key_len); -+ ret = 0; -+ -+done: -+ if (fp) -+ fclose(fp); -+ free(clear); -+ free(cipher); -+ -+ return ret; -+} -+ -+/** -+ * Remove any spaces from given string -+ */ -+static void remove_spaces(char *s) -+{ -+ int i, count = 0; -+ -+ for (i = 0; s[i]; i++) { -+ if (s[i] != ' ') -+ s[count++] = s[i]; -+ } -+ -+ s[count] = '\0'; -+} -+ -+/** -+ * gets the stdll name from the given opencryptoki.conf file. -+ */ -+static CK_RV get_stdll_name(FILE *fp, char *dll_name) -+{ -+ char line[PATH_MAX]; -+ -+ while (fgets(line, sizeof(line), fp)) { -+ remove_spaces(line); -+ if (strstr(line, "stdll=")) { -+ sscanf(line, "stdll=%s", dll_name); -+ return CKR_OK; -+ } -+ } -+ -+ return CKR_FUNCTION_FAILED; -+} -+ -+/** -+ * Check if the given conf_dir exists and contains the opencryptoki.conf. -+ */ -+static CK_BBOOL conffile_exists(const char *conf_dir) -+{ -+ char fname[PATH_MAX]; -+ struct stat statbuf; -+ DIR *dir; -+ -+ TRACE_INFO("Checking if config file exists in %s ...\n", conf_dir); -+ dir = opendir(conf_dir); -+ if (dir == NULL) { -+ TRACE_INFO("Cannot open %s.\n", conf_dir); -+ return CK_FALSE; -+ } -+ -+ /* Check if opencryptoki.conf exists */ -+ memset(fname, 0, PATH_MAX); -+ snprintf(fname, PATH_MAX, "%s/opencryptoki.conf", conf_dir); -+ if (stat(fname, &statbuf) != 0) { -+ TRACE_INFO("Cannot find %s.\n", fname); -+ closedir(dir); -+ return CK_FALSE; -+ } -+ closedir(dir); -+ -+ return CK_TRUE; -+} -+ -+/** -+ * Check if the given data_store directory exists. -+ */ -+static CK_BBOOL datastore_exists(const char *data_store) -+{ -+ DIR *dir; -+ -+ TRACE_INFO("Checking if datastore %s exists ...\n", data_store); -+ dir = opendir(data_store); -+ if (dir == NULL) { -+ TRACE_INFO("Cannot open %s.\n", data_store); -+ return CK_FALSE; -+ } -+ closedir(dir); -+ -+ return CK_TRUE; -+} -+ -+/** -+ * Check if the data store is empty, which is the case when -+ * there are no entries in OBJ.IDX. -+ */ -+static CK_BBOOL datastore_empty(const char *data_store) -+{ -+ char fname[PATH_MAX]; -+ struct stat statbuf; -+ -+ TRACE_INFO("Checking if data store is empty ...\n"); -+ -+ /* Check if OBJ.IDX exists */ -+ memset(fname, 0, PATH_MAX); -+ snprintf(fname, PATH_MAX, "%s/TOK_OBJ/OBJ.IDX", data_store); -+ if (stat(fname, &statbuf) != 0) { -+ TRACE_INFO("Cannot find %s, data store probably empty.\n", fname); -+ return CK_TRUE; -+ } -+ -+ /* Check if OBJ.IDX is empty */ -+ if (statbuf.st_size == 0) { -+ TRACE_INFO("OBJ.IDX file is empty. Thus no objects to migrate.\n"); -+ return CK_TRUE; -+ } -+ -+ return CK_FALSE; -+} -+ -+/** -+ * -+ */ -+static CK_RV load_MK_SO_00(const char *data_store, const char *sopin, -+ CK_BYTE *masterkey) -+{ -+ const char *mkso = "MK_SO"; -+ char fname[PATH_MAX + 1 + strlen(mkso) + 1]; -+ CK_RV ret; -+ -+ /* Get masterkey from MK_SO. This also verifies SO PIN is correct */ -+ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); -+ sprintf(fname, "%s/%s", data_store, mkso); -+ ret = load_masterkey_00(fname, sopin, masterkey); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load old masterkey from MK_SO, ret=%08lX.\n", ret); -+ // We cannot do anything more here, even when some objs are still old. -+ // We would need the old key in order to open an old obj. -+ } -+ -+ return ret; -+} -+ -+/** -+ * -+ */ -+static CK_RV load_MK_USER_00(const char *data_store, const char *userpin, -+ CK_BYTE *masterkey) -+{ -+ const char *mkuser = "MK_USER"; -+ char fname[PATH_MAX + 1 + strlen(mkuser) + 1]; -+ CK_RV ret; -+ -+ /* Get masterkey from MK_USER. This also verifies user PIN is correct */ -+ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); -+ sprintf(fname, "%s/%s", data_store, mkuser); -+ ret = load_masterkey_00(fname, userpin, masterkey); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load old masterkey from MK_USER, ret=%08lX.\n", ret); -+ } -+ -+ return ret; -+} -+ -+/** -+ * -+ */ -+static CK_RV load_MK_SO_312(const char *data_store, const char *sopin, -+ TOKEN_DATA *tokdata, CK_BYTE *masterkey) -+{ -+ CK_RV ret; -+ -+ /* Get masterkey from MK_SO_312. This also verifies SO PIN is correct */ -+ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); -+ ret = load_masterkey_312(data_store, "MK_SO_312", sopin, tokdata, masterkey); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load masterkey from MK_SO_312, ret=%08lX.\n", ret); -+ } -+ -+ return ret; -+} -+ -+/** -+ * -+ */ -+static CK_RV load_MK_USER_312(const char *data_store, const char *userpin, -+ TOKEN_DATA *tokdata, CK_BYTE *masterkey) -+{ -+ CK_RV ret; -+ -+ /* Get masterkey from MK_USER_312. This also verifies user PIN is correct */ -+ memset(masterkey, 0, MAX_MASTER_KEY_SIZE); -+ ret = load_masterkey_312(data_store, "MK_USER_312", userpin, tokdata, masterkey); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load masterkey from MK_USER_312, ret=%08lX.\n", ret); -+ } -+ -+ return ret; -+} -+ -+/** -+ * Loads the NVTOK.DAT and returns the TOKEN_DATA struct. -+ */ -+static CK_RV load_NVTOK_DAT(const char *data_store, const char *nvtok_name, -+ TOKEN_DATA *td) -+{ -+ char fname[PATH_MAX]; -+ struct stat stbuf; -+ int fd; -+ size_t tdlen; -+ FILE *fp = NULL; -+ CK_RV ret; -+ -+ /* Check parms */ -+ if (!data_store || !nvtok_name || !td) { -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Read the NVTOK.DAT */ -+ snprintf(fname, PATH_MAX, "%s/%s", data_store, nvtok_name); -+ fp = fopen((char *) fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ fd = fileno(fp); -+ if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Check if this NVTOK.DAT is old or new */ -+ if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { -+ /* old data store/pin format */ -+ tdlen = sizeof(TOKEN_DATA_OLD); -+ } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { -+ /* new data store/pin format */ -+ tdlen = sizeof(TOKEN_DATA); -+ } else { -+ TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", -+ fname, stbuf.st_size); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Read TOKEN_DATA */ -+ ret = fread(td, tdlen, 1, fp); -+ if (ret != 1) { -+ TRACE_ERROR("Cannot read %s, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * Strip trailing chars from given string. -+ */ -+static char *strip_trailing_chars(char *s, int slen, char c) -+{ -+ int i; -+ -+ if (!s || slen == 0) -+ return s; -+ -+ for (i = slen - 1; i >= 0; i--) { -+ if (s[i] == c) -+ s[i] = '\0'; -+ else -+ break; -+ } -+ -+ return s; -+} -+ -+/** -+ * Read the token info from NVTOK.DAT. -+ */ -+static CK_RV get_token_info(const char *data_store, CK_TOKEN_INFO_32 *tokinfo) -+{ -+ TOKEN_DATA tokdata; -+ CK_RV ret; -+ -+ TRACE_INFO("Reading token info from NVTOK.DAT ...\n"); -+ -+ ret = load_NVTOK_DAT(data_store, "NVTOK.DAT", &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load NVTOK.DAT, datastore inconsistent.\n"); -+ return ret; -+ } -+ -+ memcpy(tokinfo, &(tokdata.token_info), sizeof(CK_TOKEN_INFO_32)); -+ -+ return CKR_OK; -+} -+ -+/** -+ * returns true, if the given string begins with the given char, -+ * false otherwise. The string may contain leading spaces. -+ */ -+static CK_BBOOL begins_with(const char *str, const char c) -+{ -+ size_t i; -+ -+ for (i = 0; i < strlen(str); i++) { -+ if (str[i] == ' ') -+ continue; -+ else if (str[i] == c) -+ return CK_TRUE; -+ else -+ return CK_FALSE; -+ } -+ -+ return CK_FALSE; -+} -+ -+/** -+ * Identify the token that belongs to the given slot ID. -+ */ -+static CK_RV identify_token(CK_SLOT_ID slot_id, char *conf_dir, char *dll_name) -+{ -+ char conf_file[PATH_MAX]; -+ char line[80], parm[80]; -+ FILE *fp; -+ CK_RV ret; -+ -+ TRACE_INFO("Identifying the token that belongs to slot %ld ...\n", slot_id); -+ -+ /* Open conf file */ -+ snprintf(conf_file, PATH_MAX, "%s/%s", conf_dir, "opencryptoki.conf"); -+ fp = fopen(conf_file, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", conf_file, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Get stdll name */ -+ ret = CKR_FUNCTION_FAILED; -+ snprintf(parm, sizeof(parm), "slot %ld", slot_id); -+ while (fgets(line, sizeof(line), fp)) { -+ if (!begins_with(line, '#') && strstr(line, parm)) { -+ ret = get_stdll_name(fp, dll_name); -+ goto done; -+ } -+ } -+ -+done: -+ -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * derives the SO wrap key from the given SO pin and given public -+ * info in NVTOK.DAT. -+ */ -+static CK_RV derive_so_wrap_key_312(const char *sopin, TOKEN_DATA *tokdata, -+ CK_BYTE *so_wrap_key) -+{ -+ CK_RV ret; -+ -+ ret = PKCS5_PBKDF2_HMAC(sopin, strlen(sopin), -+ tokdata->dat.so_wrap_salt, 64, -+ tokdata->dat.so_wrap_it, EVP_sha512(), -+ 256 / 8, so_wrap_key); -+ if (ret != 1) { -+ TRACE_ERROR("PBKDF2 failed.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * derives the user wrap key from the given user pin and given public -+ * info in NVTOK.DAT. -+ */ -+static CK_RV derive_user_wrap_key_312(const char *userpin, TOKEN_DATA *tokdata, -+ CK_BYTE *user_wrap_key) -+{ -+ CK_RV ret; -+ -+ ret = PKCS5_PBKDF2_HMAC(userpin, strlen(userpin), -+ tokdata->dat.user_wrap_salt, 64, -+ tokdata->dat.user_wrap_it, EVP_sha512(), -+ 256 / 8, user_wrap_key); -+ if (ret != 1) { -+ TRACE_ERROR("PBKDF2 failed.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Activates the new repository by deleting the old MK_USER, MK_SO, and -+ * NVTOK.DAT, and renaming the new MK_SO_312, MK_USER_312, NVTOK.DAT_312 to -+ * their normal names. -+ */ -+static CK_RV cleanup_repository_backup(const char *data_store) -+{ -+ static char *names[] = { "MK_SO", "MK_USER", "NVTOK.DAT" }; -+ int num_names = sizeof(names) / sizeof(char *); -+ char fname1[PATH_MAX + 9 + 1]; // satisfy compiler warning -+ char fname2[PATH_MAX + 1 + 1]; // satisfy compiler warning -+ int i, rc; -+ CK_RV ret; -+ -+ /* Delete old files */ -+ for (i = 0; i < num_names; i++) { -+ snprintf(fname1, sizeof(fname1), "%s/%s", data_store, names[i]); -+ rc = remove(fname1); -+ if (rc) { -+ TRACE_ERROR("Cannot delete old file %s.\n", fname1); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ } -+ -+ /* Rename new files */ -+ for (i = 0; i < num_names; i++) { -+ snprintf(fname1, sizeof(fname1), "%s/%s_312", data_store, names[i]); -+ snprintf(fname2, sizeof(fname2), "%s/%s", data_store, names[i]); -+ rc = rename(fname1, fname2); -+ if (rc) { -+ TRACE_ERROR("Cannot rename new file %s.\n", fname1); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Migrates the repository. This process may be interrupted at any time and -+ * must be able to resume until the complete repository is successfully -+ * migrated. This especially requires to keep the old keys until -+ * everything is done. -+ */ -+static CK_RV migrate_repository(const char *data_store, const char *sopin, -+ const char *userpin) -+{ -+ CK_BYTE so_masterkey_old[MAX_MASTER_KEY_SIZE]; -+ CK_BYTE so_masterkey_new[MAX_MASTER_KEY_SIZE]; -+ CK_BYTE user_masterkey_old[MAX_MASTER_KEY_SIZE]; -+ CK_BYTE user_masterkey_new[MAX_MASTER_KEY_SIZE]; -+ CK_BYTE so_wrap_key[32]; -+ CK_BYTE user_wrap_key[32]; -+ CK_RV ret; -+ TOKEN_DATA tokdata; -+ -+ TRACE_INFO("Migrating the repository ...\n"); -+ -+ /* Load NVTOK.DAT_312, which was either created before or exists from a -+ * previous interrupted run. So tokdata definitely contains the 3.12 -+ * extension. -+ */ -+ ret = load_NVTOK_DAT(data_store, "NVTOK.DAT_312", &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load NVTOK.DAT_312, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ ret = load_MK_SO_00(data_store, sopin, so_masterkey_old); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load old masterkey, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ ret = load_MK_USER_00(data_store, userpin, user_masterkey_old); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load old masterkey, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ if (memcmp(so_masterkey_old, user_masterkey_old, MAX_MASTER_KEY_SIZE) != 0) { -+ TRACE_ERROR("MK_SO and MK_USER are inconsistent, got different MKs.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = load_MK_SO_312(data_store, sopin, &tokdata, so_masterkey_new); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load new masterkey from MK_SO_312, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ ret = load_MK_USER_312(data_store, userpin, &tokdata, user_masterkey_new); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load new masterkey from MK_USER_312, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ if (memcmp(so_masterkey_new, user_masterkey_new, MAX_MASTER_KEY_SIZE) != 0) { -+ TRACE_ERROR("MK_SO_312 and MK_USER_312 are inconsistent, got different MKs.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* This function needs a new NVTOK.DAT with the public salt and icount */ -+ ret = derive_so_wrap_key_312(sopin, &tokdata, so_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create new so_wrap_key, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* This function needs a new NVTOK.DAT with the public salt and icount */ -+ ret = derive_user_wrap_key_312(userpin, &tokdata, user_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create new user_wrap_key, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Now do the migration */ -+ ret = migrate_token_objects(data_store, so_masterkey_old, so_masterkey_new, -+ so_wrap_key, user_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Migrating token objects failed with ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Remove temp files in backup */ -+ ret = cleanup_repository_backup(data_store); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cleanup repository backup failed with ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * creates a MK_USER_312 file containing the new user MK. -+ */ -+static CK_RV create_MK_USER_312(const char *data_store, const char *userpin, -+ const CK_BYTE *masterkey, -+ TOKEN_DATA *tokdata) -+{ -+ const char *mkuser = "MK_USER_312"; -+ char fname[PATH_MAX + 1 + strlen(mkuser) + 1]; -+ CK_BYTE user_wrap_key[32]; -+ CK_BYTE outbuf[40]; -+ FILE *fp = NULL; -+ size_t rv; -+ CK_RV ret; -+ -+ /* Create user wrap key */ -+ ret = derive_user_wrap_key_312(userpin, tokdata, (unsigned char *)&user_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot derive user wrap key, ret=%08lX.\n", ret); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Wrap user MK with user_wrap_key */ -+ ret = aes_256_wrap(outbuf, masterkey, user_wrap_key); -+ if (ret != CKR_OK) -+ goto done; -+ -+ /* Create file MK_USER_312 */ -+ sprintf(fname, "%s/%s", data_store, mkuser); -+ fp = fopen(fname, "w"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp)); -+ -+ rv = fwrite(outbuf, sizeof(outbuf), 1, fp); -+ if (rv != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * creates a MK_SO_312 file containing the new SO MK. -+ */ -+static CK_RV create_MK_SO_312(const char *data_store, const char *sopin, -+ const CK_BYTE *masterkey, -+ TOKEN_DATA *tokdata) -+{ -+ const char *mkso = "MK_SO_312"; -+ char fname[PATH_MAX + 1 + strlen(mkso) + 1]; -+ CK_BYTE outbuf[40]; -+ CK_BYTE so_wrap_key[32]; -+ FILE *fp = NULL; -+ size_t rv; -+ CK_RV ret; -+ -+ /* Derive so wrap key from sopin and tokdata */ -+ ret = derive_so_wrap_key_312(sopin, tokdata, so_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot derive new so wrap key, ret=%08lX.\n", ret); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Wrap masterkey with SO_wrap_key */ -+ ret = aes_256_wrap(outbuf, masterkey, so_wrap_key); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot wrap masterkey with so wrap key, ret=%08lX.\n", ret); -+ goto done; -+ } -+ -+ /* Create file MK_SO_312 */ -+ sprintf(fname, "%s/%s", data_store, mkso); -+ fp = fopen(fname, "w"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ rv = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp)); -+ -+ rv = fwrite(outbuf, sizeof(outbuf), 1, fp); -+ if (rv != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * reads the old NVTOK.DAT and returns its contents: -+ */ -+static CK_RV read_NVTOK_DAT_00(const char *data_store, TOKEN_DATA *tokdata) -+{ -+ FILE *fp; -+ const char *nvtok = "NVTOK.DAT"; -+ char fname[PATH_MAX + 1 + strlen(nvtok) + 1]; -+ struct stat stbuf; -+ int fd; -+ CK_RV ret; -+ -+ /* Check parms */ -+ if (!data_store || !tokdata) { -+ return CKR_ARGUMENTS_BAD; -+ } -+ -+ /* Read the old NVTOK.DAT */ -+ sprintf(fname, "%s/%s", data_store, nvtok); -+ fp = fopen((char *) fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ fd = fileno(fp); -+ if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Ensure that this NVTOK.DAT is in fact old */ -+ if (stbuf.st_size != sizeof(TOKEN_DATA_OLD)) { -+ TRACE_ERROR("%s has an invalid size of %ld bytes.\n", fname, stbuf.st_size); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Read TOKEN_DATA_OLD */ -+ ret = fread(tokdata, sizeof(TOKEN_DATA_OLD), 1, fp); -+ if (ret != 1) { -+ TRACE_ERROR("Cannot read %s, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * creates the additions for new format. -+ */ -+static CK_RV create_TOKEN_DATA_VERSION(const char *sopin, const char *userpin, -+ TOKEN_DATA *tokdata) -+{ -+ CK_RV ret; -+ int rc; -+ -+ tokdata->dat.version = TOKVERSION_312; -+ -+ tokdata->dat.so_login_it = SO_KDF_LOGIN_IT; -+ memcpy(tokdata->dat.so_login_salt, SO_KDF_LOGIN_PURPOSE, 32); -+ ret = local_rng(tokdata->dat.so_login_salt + 32, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("local_rng returned %lX\n", ret); -+ goto done; -+ } -+ rc = PKCS5_PBKDF2_HMAC(sopin, strlen(sopin), -+ tokdata->dat.so_login_salt, 64, -+ tokdata->dat.so_login_it, EVP_sha512(), -+ 256 / 8, tokdata->dat.so_login_key); -+ if (rc != 1) { -+ TRACE_ERROR("Error: PKCS5_PBKDF2_HMAC\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ tokdata->dat.so_wrap_it = SO_KDF_WRAP_IT; -+ memcpy(tokdata->dat.so_wrap_salt, SO_KDF_WRAP_PURPOSE, 32); -+ ret = local_rng(tokdata->dat.so_wrap_salt + 32, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("local_rng returned %lX\n", ret); -+ goto done; -+ } -+ -+ tokdata->dat.user_login_it = USER_KDF_LOGIN_IT; -+ memcpy(tokdata->dat.user_login_salt, USER_KDF_LOGIN_PURPOSE, 32); -+ ret = local_rng(tokdata->dat.user_login_salt + 32, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("local_rng returned %lX\n", ret); -+ goto done; -+ } -+ rc = PKCS5_PBKDF2_HMAC(userpin, strlen(userpin), -+ tokdata->dat.user_login_salt, 64, -+ tokdata->dat.user_login_it, EVP_sha512(), -+ 256 / 8, tokdata->dat.user_login_key); -+ if (rc != 1) { -+ TRACE_ERROR("Error: PKCS5_PBKDF2_HMAC\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ tokdata->dat.user_wrap_it = USER_KDF_WRAP_IT; -+ memcpy(tokdata->dat.user_wrap_salt, USER_KDF_WRAP_PURPOSE, 32); -+ ret = local_rng(tokdata->dat.user_wrap_salt + 32, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("local_rng returned %lX\n", ret); -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Creates the new NVTOK.DAT which now contains the public salt and iteration -+ * count values that are necessary for re-deriving the pin-related -+ * wrapping keys. -+ */ -+static CK_RV create_NVTOK_DAT_312(const char *data_store, const char *sopin, -+ const char *userpin, TOKEN_DATA *tokdata) -+{ -+ const char *nvtok = "NVTOK.DAT_312"; -+ char fname[PATH_MAX + 1 + strlen(nvtok) + 1]; -+ FILE *fp = NULL; -+ CK_RV ret; -+ size_t rc; -+ -+ /* Check parms */ -+ if (!data_store || !sopin || !userpin || !tokdata) { -+ TRACE_ERROR("invalid parms.\n"); -+ ret = CKR_ARGUMENTS_BAD; -+ goto done; -+ } -+ -+ /* Create new file NVTOK.DAT_312 */ -+ sprintf(fname, "%s/%s", data_store, nvtok); -+ fp = fopen(fname, "w"); -+ if (!fp) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp)); -+ -+ /* Get contents from old NVTOK.DAT */ -+ ret = read_NVTOK_DAT_00(data_store, tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot read old NVTOK.DAT, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ /* Write old part into NVTOK.DAT_312 */ -+ rc = fwrite(tokdata, sizeof(TOKEN_DATA_OLD), 1, fp); -+ if (rc != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Create additions for new format */ -+ ret = create_TOKEN_DATA_VERSION(sopin, userpin, tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create TOKEN_DATA_VERSION struct, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ /* Append TOKEN_DATA_VERSION to NVTOK.DAT_312 */ -+ rc = fwrite(&(tokdata->dat), sizeof(TOKEN_DATA_VERSION), 1, fp); -+ if (rc != 1) { -+ TRACE_ERROR("fwrite(%s) failed, errno=%s.\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp) -+ fclose(fp); -+ -+ return ret; -+} -+ -+/** -+ * Creates new token keys MK_USER_312 and MK_SO_312. The old keys in -+ * MK_USER and MK_SO are kept until the migration is fully completed. -+ * Then the old keys are deleted and the new keys are renamed. -+ */ -+static CK_RV create_token_keys_312(const char *data_store, const char *sopin, -+ const char *userpin) -+{ -+ unsigned char masterkey[32]; -+ TOKEN_DATA tokdata; -+ CK_RV ret = CKR_OK; -+ -+ TRACE_INFO("Creating new v3.12 MK_SO, MK_USER, and NVTOK.DAT ...\n"); -+ -+ /* Create master key */ -+ ret = local_rng(masterkey, 32); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create master key, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ ret = create_NVTOK_DAT_312(data_store, sopin, userpin, &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create NVTOK.DAT_312, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ ret = create_MK_SO_312(data_store, sopin, masterkey, &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create MK_SO_312, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ ret = create_MK_USER_312(data_store, userpin, masterkey, &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot create MK_USER_312, ret=%08lX\n", ret); -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Count the objs in the data_store and return the number of total objs -+ * and number of old objs. -+ */ -+static CK_RV count_objects(const char *data_store, unsigned int *num_objs, -+ unsigned int *num_old_objs) -+{ -+ char tmp[PATH_MAX], iname[PATH_MAX]; -+ unsigned char *obj = NULL; -+ unsigned int obj_len; -+ CK_ULONG version; -+ CK_BBOOL priv; -+ FILE *fp; -+ CK_RV ret; -+ -+ *num_objs = 0; -+ *num_old_objs = 0; -+ -+ /* Open index file OBJ.IDX */ -+ snprintf(iname, sizeof(iname), "%s/TOK_OBJ/OBJ.IDX", data_store); -+ fp = fopen((char *) iname, "r"); -+ if (!fp) { -+ TRACE_INFO("Cannot open %s, datastore probably empty.\n", iname); -+ ret = CKR_OK; -+ goto done; -+ } -+ -+ /* Count objects and old objects */ -+ while (fgets(tmp, PATH_MAX, fp)) { -+ tmp[strlen(tmp) - 1] = 0; -+ (*num_objs)++; -+ ret = read_object(data_store, tmp, &obj, &obj_len, &version, &priv); -+ if (ret == 0 && version == TOKVERSION_00) -+ (*num_old_objs)++; -+ if (obj) { -+ free(obj); -+ obj = NULL; -+ } -+ } -+ -+ /* OBJ.IDX must be at eof here */ -+ if (!feof(fp)) { -+ TRACE_WARN("OBJ.IDX is not at eof after object %s, should not happen.\n", -+ tmp); -+ } -+ -+ fclose(fp); -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Set parameter "*new" to true if the NVTOK.DAT in the given data store -+ * is on 3.12 level, or false otherwise. -+ */ -+static CK_RV NVTOK_DAT_is_312(const char *data_store, CK_BBOOL *new) -+{ -+ CK_RV ret; -+ char fname[PATH_MAX]; -+ struct stat stbuf; -+ int fd; -+ FILE *fp = NULL; -+ -+ *new = CK_FALSE; -+ -+ /* Read the NVTOK.DAT */ -+ snprintf(fname, PATH_MAX, "%s/NVTOK.DAT", data_store); -+ fp = fopen((char *)fname, "r"); -+ if (!fp) { -+ TRACE_ERROR("Cannot open %s, errno=%s\n", fname, strerror(errno)); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ fd = fileno(fp); -+ if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Check if this NVTOK.DAT is old or new */ -+ if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { -+ *new = CK_FALSE; -+ } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { -+ *new = CK_TRUE; -+ } else { -+ TRACE_ERROR("%s has an invalid size of %ld bytes. Neither old nor new token format.\n", -+ fname, stbuf.st_size); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Check if the data store is in 3.12 format. -+ */ -+static CK_RV datastore_is_312(const char *data_store, const char *sopin, -+ const char *userpin, CK_BBOOL *new) -+{ -+ CK_RV ret; -+ CK_BYTE masterkey_so[32]; -+ CK_BYTE masterkey_user[32]; -+ unsigned int num_objs = 0, num_old_objs = 0; -+ TOKEN_DATA tokdata; -+ -+ *new = CK_FALSE; -+ -+ TRACE_INFO("Checking if data store is already in 3.12 format ...\n"); -+ -+ /* Check if NVTOK.DAT is new */ -+ ret = NVTOK_DAT_is_312(data_store, new); -+ if (ret != CKR_OK) { -+ warnx("Cannot determine if NVTOK.DAT has an old or new format."); -+ warnx("Note that generic token formats cannot be migrated."); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ if (*new == CK_FALSE) { -+ ret = CKR_OK; -+ goto done; -+ } -+ -+ /* NVTOK.DAT is already new, now check if we can read the keys */ -+ ret = load_NVTOK_DAT(data_store, "NVTOK.DAT", &tokdata); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot load NVTOK.DAT, datastore inconsistent, ret=%08lX\n", ret); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = load_masterkey_312(data_store, "MK_SO", sopin, &tokdata, masterkey_so); -+ if (ret != CKR_OK) { -+ TRACE_INFO("Cannot load new MK from MK_SO, datastore probably old.\n"); -+ goto done; -+ } -+ -+ ret = load_masterkey_312(data_store, "MK_USER", userpin, &tokdata, masterkey_user); -+ if (ret != CKR_OK) { -+ TRACE_INFO("Cannot load new MK from MK_USER, datastore probably old.\n"); -+ goto done; -+ } -+ -+ if (memcmp(masterkey_so, masterkey_user, 32) != 0) { -+ TRACE_ERROR("MKs from MK_SO and MK_USER don't match, datastore inconsistent.\n"); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = count_objects(data_store, &num_objs, &num_old_objs); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("cannot count objects in %s.\n", data_store); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ TRACE_INFO("Found %d objects total, %d old objects.\n", num_objs, num_old_objs); -+ if (num_old_objs > 0) -+ TRACE_WARN("Note that the old objects are not usable anymore, because " -+ "we don't have the corresponding old masterkey!\n"); -+ -+ if (num_objs > 0 && num_old_objs == 0) -+ *new = CK_TRUE; -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Switch to new repository by deleting the old repository and renaming -+ * the backup folder to the original data store name. -+ */ -+static CK_RV switch_to_new_repository(const char *data_store_old, -+ const char *data_store_new) -+{ -+ char fname1[PATH_MAX]; -+ CK_RV ret; -+ int rc = -1; -+ -+ TRACE_INFO("Switching to new repository ...\n"); -+ -+ /* Rename original repository folder */ -+ snprintf(fname1, sizeof(fname1), "%s_BAK", data_store_old); -+ rc = rename(data_store_old, fname1); -+ if (rc) { -+ TRACE_ERROR("Cannot rename %s, errno=%s.\n", data_store_old, strerror(rc)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Rename backup folder */ -+ rc = rename(data_store_new, data_store_old); -+ if (rc) { -+ TRACE_ERROR("Cannot rename %s, errno=%s.\n", data_store_new, strerror(rc)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Inserts the new tokversion parm in the token's slot configuration, e.g. -+ * -+ * slot 2 -+ * { -+ * stdll = libpkcs11_cca.so -+ * tokversion = 3.12 -+ * } -+ */ -+static CK_RV update_opencryptoki_conf(CK_SLOT_ID slot_id, char *location) -+{ -+ const char *parm = "tokversion = 3.12\n"; -+ char dst_file[PATH_MAX], src_file[PATH_MAX], fname[PATH_MAX+20], line[PATH_MAX]; -+ char slot[32]; -+ FILE *fp_r = NULL, *fp_w = NULL; -+ CK_RV ret; -+ int rc; -+ -+ TRACE_INFO("Updating config file ...\n"); -+ -+ /* Open current conf file for read */ -+ snprintf(src_file, PATH_MAX, "%s/%s", location, "opencryptoki.conf"); -+ fp_r = fopen(src_file, "r"); -+ if (!fp_r) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", src_file, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Open new conf file for write */ -+ snprintf(dst_file, PATH_MAX, "%s/%s", location, "opencryptoki.conf_new"); -+ fp_w = fopen(dst_file, "w"); -+ if (!fp_w) { -+ TRACE_ERROR("fopen(%s) failed, errno=%s\n", dst_file, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp_w)); -+ -+ /* Insert/replace tokversion parm in new file */ -+ snprintf(slot, sizeof(slot), "slot %ld", slot_id); -+ while (fgets(line, sizeof(line), fp_r)) { -+ if (!begins_with(line, '#') && strstr(line, slot)) { -+ fputs(line, fp_w); // write "slot n" -+ /* insert tokversion before '}' */ -+ while (fgets(line, sizeof(line), fp_r)) { -+ if (strstr(line, "}")) { -+ fputs(parm, fp_w); -+ fputs(line, fp_w); -+ break; -+ } -+ /* Don't write existing tokversion to new file */ -+ if (!strstr(line, "tokversion")) -+ fputs(line, fp_w); -+ } -+ } else -+ fputs(line, fp_w); -+ } -+ -+ fclose(fp_r); -+ fclose(fp_w); -+ fp_r = NULL; -+ fp_w = NULL; -+ -+ /* Rename old conf file */ -+ snprintf(fname, sizeof(fname), "%s_BAK", src_file); -+ rc = rename(src_file, fname); -+ if (rc) { -+ TRACE_ERROR("Cannot rename %s\n", src_file); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Rename new file */ -+ rc = rename(dst_file, src_file); -+ if (rc) { -+ TRACE_ERROR("Cannot rename %s.\n", dst_file); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ if (fp_r) -+ fclose(fp_r); -+ if (fp_w) -+ fclose(fp_w); -+ -+ return ret; -+ -+} -+ -+/** -+ * Copy a file given by name from a src folder to a dst folder. -+ */ -+static CK_RV file_copy(char *dst, const char *src, const char *name) -+{ -+ char dst_file[PATH_MAX], src_file[PATH_MAX], buf[4096]; -+ FILE *fp_r = NULL, *fp_w = NULL; -+ size_t written; -+ CK_RV ret; -+ -+ snprintf(dst_file, PATH_MAX, "%s/%s", dst, name); -+ snprintf(src_file, PATH_MAX, "%s/%s", src, name); -+ -+ fp_r = fopen(src_file, "r"); -+ if (!fp_r) { -+ warnx("fopen(%s) failed, errno=%s", src_file, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ fp_w = fopen(dst_file, "w"); -+ if (!fp_w) { -+ warnx("fopen(%s) failed, errno=%s", dst_file, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ set_perm(fileno(fp_w)); -+ -+ while (!feof(fp_r)) { -+ size_t bytes = fread(buf, 1, sizeof(buf), fp_r); -+ if (bytes) { // can be zero, if file empty -+ written = fwrite(buf, 1, bytes, fp_w); -+ if (written != bytes) { -+ warnx("fwrite(%s) failed, errno=%s", dst_file, -+ strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ } -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ if (fp_r) -+ fclose(fp_r); -+ if (fp_w) -+ fclose(fp_w); -+ -+ return ret; -+} -+ -+/** -+ * Change the group owner of the given directory to 'pkcs11'. -+ */ -+static CK_RV change_owner(char *dir) -+{ -+ struct group* grp; -+ CK_RV ret; -+ -+ /* Set group owner */ -+ grp = getgrnam("pkcs11"); -+ if (grp) { -+ if (chown(dir, -1, grp->gr_gid)) { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ } else { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Fix group permissions (see man 2 mkdir for details) */ -+ if (chmod(dir, 0770)) { -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ return ret; -+} -+ -+/** -+ * Copy the given src folder to the given dst folder including all -+ * subdirectories and files. -+ */ -+static CK_RV folder_copy(char *dst, const char *src) -+{ -+ char d[PATH_MAX], s[PATH_MAX]; -+ struct dirent *entry; -+ CK_RV ret; -+ DIR *dir; -+ -+ /* Open src */ -+ dir = opendir(src); -+ if (dir == NULL) { -+ TRACE_ERROR("Cannot open %s\n", src); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ /* Create dst */ -+ if (mkdir(dst, 0) != 0) { -+ TRACE_ERROR("Cannot create %s\n", dst); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Change group owner and set permissions */ -+ ret = change_owner(dst); -+ if (ret != CKR_OK) { -+ TRACE_ERROR("Cannot change owner and permissions for %s\n", dst); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Copy folder recursively, skip the "." and ".." entries */ -+ while ((entry = readdir(dir)) != NULL) { -+ if (entry->d_type == DT_DIR) { -+ if (strncmp(entry->d_name, ".", 1) != 0) { -+ snprintf(d, PATH_MAX, "%s/%s", dst, entry->d_name); -+ snprintf(s, PATH_MAX, "%s/%s", src, entry->d_name); -+ ret = folder_copy(d, s); -+ if (ret != CKR_OK) -+ goto done; -+ } -+ } else { -+ ret = file_copy(dst, src, entry->d_name); -+ if (ret != CKR_OK) -+ goto done; -+ } -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ closedir(dir); -+ -+ return ret; -+} -+ -+/** -+ * Remove the given folder and all of its contents. -+ */ -+static CK_RV folder_delete(const char *folder) -+{ -+ DIR *dir; -+ char fname[PATH_MAX]; -+ size_t len, path_len; -+ struct stat statbuf; -+ struct dirent *ent; -+ CK_RV ret = CKR_OK; -+ -+ dir = opendir(folder); -+ if (!dir) { -+ TRACE_INFO("Folder %s doesn't exist.\n", folder); -+ return CKR_OK; -+ } -+ -+ path_len = strlen(folder); -+ while (!ret && (ent = readdir(dir))) { -+ if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) -+ continue; -+ len = path_len + strlen(ent->d_name) + 2; -+ snprintf(fname, len, "%s/%s", folder, ent->d_name); -+ if (!stat(fname, &statbuf)) { -+ if (S_ISDIR(statbuf.st_mode)) { -+ ret = folder_delete(fname); -+ if (ret != CKR_OK) -+ goto done; -+ } else { -+ ret = remove(fname); -+ if (ret != CKR_OK) -+ goto done; -+ } -+ } else { -+ /* stat failed */ -+ TRACE_ERROR("Cannot stat %s, errno=%s.\n", fname, strerror(errno)); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ } -+ -+ ret = CKR_OK; -+ -+done: -+ -+ closedir(dir); -+ if (ret == CKR_OK) -+ rmdir(folder); -+ -+ return ret; -+} -+ -+/** -+ * Backs up the given data_store to data_store_PKCSTOK_MIGRATE_TMP. -+ * All folders and files are recursively created and copied. -+ * Remove the backup if it already exists so that we always have -+ * a clean backup. -+ * The calling routine ensures that data_store does not end with a '/' ! -+ */ -+static CK_RV backup_repository(const char *data_store) -+{ -+ char dst[PATH_MAX]; -+ CK_RV ret = CKR_OK; -+ -+ TRACE_INFO("Creating data store backup ...\n"); -+ -+ memset(dst, 0, PATH_MAX); -+ snprintf(dst, PATH_MAX, "%s_PKCSTOK_MIGRATE_TMP", data_store); -+ ret = folder_delete(dst); -+ if (ret != CKR_OK) { -+ warnx("Fatal error: cannot delete old backup: %s", dst); -+ return CKR_FUNCTION_FAILED; -+ } -+ -+ return folder_copy(dst, data_store); -+} -+ -+/** -+ * Checks if the pkcsslotd is running. -+ */ -+static CK_BBOOL pkcsslotd_running(void) -+{ -+ DIR *dir; -+ FILE *fp; -+ struct dirent* ent; -+ char* endptr; -+ char buf[PATH_MAX]; -+ char fname[PATH_MAX]; -+ -+ TRACE_INFO("Checking if pkcsslotd is running ...\n"); -+ if (!(dir = opendir("/proc"))) { -+ TRACE_WARN("Cannot open /proc, i.e. cannot check if pkcsslotd is running.\n"); -+ return CK_TRUE; -+ } -+ -+ while ((ent = readdir(dir)) != NULL) { -+ /* if endptr is not a null character, the directory is not -+ * entirely numeric, so ignore it */ -+ long lpid = strtol(ent->d_name, &endptr, 10); -+ if (*endptr != '\0') { -+ continue; -+ } -+ -+ /* try to open the cmdline file */ -+ snprintf(fname, sizeof(fname), "/proc/%ld/cmdline", lpid); -+ fp = fopen(fname, "r"); -+ if (!fp) { -+ warnx("fopen(%s) failed, errno=%s", fname, strerror(errno)); -+ return CK_TRUE; -+ } -+ -+ /* check the first token in the file: the program pathname */ -+ if (fgets(buf, sizeof(buf), fp) != NULL) { -+ char* first = strtok(buf, " "); -+ if (!first) { -+ TRACE_WARN("Cannot read program name from %s, i.e. cannot check if pkcsslotd is running.\n", -+ fname); -+ return CK_TRUE; -+ } -+ if (strstr(first, "pkcsslotd") != NULL) { -+ fclose(fp); -+ closedir(dir); -+ return CK_TRUE; -+ } -+ } -+ fclose(fp); -+ } -+ -+ closedir(dir); -+ return CK_FALSE; -+} -+ -+/** -+ * -+ */ -+static CK_BBOOL token_invalid(const char *dll) -+{ -+ if (strcmp(dll, INVALID_TOKEN) == 0) -+ return CK_TRUE; -+ else -+ return CK_FALSE; -+} -+ -+/** -+ * returns the token name related to the given stdll name for the -+ * 4 supported tokens. -+ */ -+static const char *dll2name(const char *dll) -+{ -+ static char *dlls[] = { -+ "libpkcs11_ica.so", "libpkcs11_cca.so", -+ "libpkcs11_sw.so", "libpkcs11_ep11.so" -+ }; -+ static char *names[] = { -+ "ICA", "CCA", "Soft", "EP11" -+ }; -+ int i, num_tokens = sizeof(names) / sizeof(char *); -+ -+ for (i = 0; i < num_tokens; i++) { -+ if (strcmp(dll, dlls[i]) == 0) -+ return names[i]; -+ } -+ -+ return INVALID_TOKEN; -+} -+ -+/** -+ * translates the given verbose level string into a numeric verbose level. -+ * Returns -1 if the string is invalid. -+ */ -+static int verbose_str2level(char *str) -+{ -+ const char *tlevel[] = {"none", "error", "warn", "info", "devel", "debug"}; -+ const int num = sizeof(tlevel) / sizeof(char *); -+ int i; -+ -+ for (i = 0; i < num; i++) { -+ if (strcmp(str, tlevel[i]) == 0) { -+ return i; -+ } -+ } -+ -+ return -1; -+} -+ -+static void usage(char *progname) -+{ -+ printf(" Help:\t\t\t\t%s -h\n", progname); -+ printf(" -h, --help \t\t\tShow this help\n\n"); -+ printf(" Options:\n"); -+ printf(" -s, --slotid SLOTID\t\tPKCS slot number (required)\n"); -+ printf(" -d, --datastore DATASTORE\ttoken datastore location (required)\n"); -+ printf(" -c, --confdir CONFDIR\t\tlocation of opencryptoki.conf (required)\n"); -+ printf(" -u, --userpin USERPIN\t\ttoken user pin (prompted if not specified)\n"); -+ printf(" -p, --sopin SOPIN\t\ttoken SO pin (prompted if not specified)\n"); -+ printf(" -v, --verbose LEVEL\t\tset verbose level (optional):\n"); -+ printf("\t\t\t\tnone (default), error, warn, info, devel, debug\n"); -+ return; -+} -+ -+int main(int argc, char **argv) -+{ -+ CK_RV ret = 0; -+ int opt = 0, vlevel = -1; -+ CK_SLOT_ID slot_id = 0; -+ CK_BBOOL slot_id_specified = CK_FALSE; -+ size_t sopinlen, userpinlen, buflen = 0; -+ ssize_t num_chars; -+ char *data_store = NULL, *data_store_old = NULL, *conf_dir = NULL; -+ char *sopin = NULL, *userpin = NULL, *verbose = NULL; -+ char *buff = NULL; -+ char dll_name[PATH_MAX]; -+ CK_TOKEN_INFO_32 tokinfo; -+ CK_BBOOL new; -+ -+ static const struct option long_opts[] = { -+ {"datastore", required_argument, NULL, 'd'}, -+ {"confdir", required_argument, NULL, 'c'}, -+ {"slotid", required_argument, NULL, 's'}, -+ {"userpin", required_argument, NULL, 'u'}, -+ {"sopin", required_argument, NULL, 'p'}, -+ {"verbose", required_argument, NULL, 'v'}, -+ {"help", no_argument, NULL, 'h'}, -+ {0, 0, 0, 0} -+ }; -+ -+ while ((opt = getopt_long(argc, argv, "d:c:s:u:p:v:h", long_opts, NULL)) != -1) { -+ switch (opt) { -+ case 'd': -+ data_store = strdup(optarg); -+ break; -+ case 'c': -+ conf_dir = strdup(optarg); -+ break; -+ case 's': -+ slot_id = atoi(optarg); -+ slot_id_specified = CK_TRUE; -+ break; -+ case 'u': -+ userpin = strdup(optarg); -+ userpinlen = strlen(userpin); -+ break; -+ case 'p': -+ sopin = strdup(optarg); -+ sopinlen = strlen(sopin); -+ break; -+ case 'v': -+ verbose = strdup(optarg); -+ vlevel = verbose_str2level(verbose); -+ if (vlevel < 0) { -+ warnx("Invalid verbose level '%s' specified.", verbose); -+ usage(argv[0]); -+ exit(1); -+ } -+ break; -+ case 'h': -+ usage(argv[0]); -+ exit(0); -+ default: -+ warnx("pkcstok_migrate: Parameters are required."); -+ usage(argv[0]); -+ exit(1); -+ } -+ } -+ -+ if (argc == 1) { -+ usage(argv[0]); -+ exit(1); -+ } -+ -+ printf("\npkcstok_migrate:\n"); -+ printf("Summary of input parameters:\n"); -+ if (data_store) { -+ strip_trailing_chars(data_store, strlen(data_store), '/'); -+ printf(" datastore = %s \n", data_store); -+ } -+ if (conf_dir) { -+ strip_trailing_chars(conf_dir, strlen(conf_dir), '/'); -+ printf(" confdir = %s \n", conf_dir); -+ } -+ if (slot_id_specified) -+ printf(" slot ID = %ld\n", slot_id); -+ if (userpin) -+ printf(" user PIN specified\n"); -+ if (sopin) -+ printf(" SO PIN specified\n"); -+ if (vlevel >= 0) { -+ trace_level = vlevel; -+ printf(" verbose level = %s\n", verbose); -+ } -+ printf("\n"); -+ -+ /* Slot ID must be given */ -+ if (!slot_id_specified) { -+ warnx("Slot ID must be specified."); -+ goto done; -+ } -+ -+ /* Datastore must be given */ -+ if (data_store == NULL) { -+ warnx("Data store path must be specified."); -+ goto done; -+ } -+ -+ /* Limit datastore path length because of appended suffixes */ -+ if (strlen(data_store) > PKCSTOK_MIGRATE_MAX_PATH_LEN) { -+ warnx("Datastore path (%ld characters) is too long (max = %d).\n", -+ strlen(data_store), PKCSTOK_MIGRATE_MAX_PATH_LEN); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Location of opencryptoki.conf must be specified. */ -+ if (conf_dir == NULL) { -+ warnx("Location of opencryptoki.conf must be specified."); -+ goto done; -+ } -+ -+ /* Limit path to config file because of appended suffixes */ -+ if (strlen(conf_dir) > PKCSTOK_MIGRATE_MAX_PATH_LEN) { -+ warnx("Path to config file (%ld characters) is too long (max = %d).\n", -+ strlen(conf_dir), PKCSTOK_MIGRATE_MAX_PATH_LEN); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Check if given data_store exists */ -+ if (!datastore_exists(data_store)) { -+ ret = CKR_FUNCTION_FAILED; -+ warnx("Datastore %s does not exist.", data_store); -+ goto done; -+ } -+ -+ /* Check if given conf_dir exists and contains opencryptoki.conf */ -+ if (!conffile_exists(conf_dir)) { -+ ret = CKR_FUNCTION_FAILED; -+ warnx("%s does not exist or does not contain opencryptoki.conf", conf_dir); -+ goto done; -+ } -+ -+ /* Check if pkcsslotd is running */ -+ if (pkcsslotd_running()) { -+ warnx("Please stop pkcsslotd before running this utility."); -+ ret = CKR_FUNCTION_FAILED; -+ goto done; -+ } -+ -+ /* Identify token related to given slot ID */ -+ ret = identify_token(slot_id, conf_dir, dll_name); -+ if (ret != CKR_OK) { -+ warnx("Cannot identify a token related to given slot ID %ld", slot_id); -+ goto done; -+ } -+ -+ /* Check if DLL name from conf file is a known and migratable token */ -+ printf("Slot ID %ld points to DLL name %s, which is a %s token.\n", -+ slot_id, dll_name, dll2name(dll_name)); -+ if (token_invalid(dll2name(dll_name))) { -+ warnx("Please check your input."); -+ goto done; -+ } -+ -+ /* Check if there are token objects to migrate */ -+ if (datastore_empty(data_store)) { -+ ret = CKR_OK; -+ warnx("Datastore %s is empty, no objects to migrate.", data_store); -+ goto done; -+ } -+ -+ /* Get token info from NVTOK.DAT */ -+ ret = get_token_info(data_store, &tokinfo); -+ if (ret != CKR_OK) { -+ warnx("Cannot get the token label from NVTOK.DAT"); -+ goto done; -+ } -+ -+ /* Check with user if ok to migrate this token, or quit if token not migratable */ -+ printf("Data store %s points to this token info:\n", data_store); -+ printf(" label : %.*s\n", 32, tokinfo.label); -+ printf(" manufacturerID : %.*s\n", 32, tokinfo.manufacturerID); -+ printf(" model : %.*s\n", 16, tokinfo.model); -+ printf(" serialNumber : %.*s\n", 16, tokinfo.serialNumber); -+ printf(" hardwareVersion : %i.%i\n", tokinfo.hardwareVersion.major, tokinfo.hardwareVersion.minor); -+ printf(" firmwareVersion : %i.%i\n", tokinfo.firmwareVersion.major, tokinfo.firmwareVersion.minor); -+ printf("Migrate this token with given slot ID? y/n\n"); -+ num_chars = getline(&buff, &buflen, stdin); -+ if (num_chars < 0 || strncmp(buff, "y", 1) != 0) { -+ printf("ok, let's quit.\n"); -+ goto done; -+ } -+ -+ /* Get the SO pin to authorize migration */ -+ if (!sopin) { -+ printf("Enter the SO PIN: "); -+ fflush(stdout); -+ ret = get_pin(&sopin, &sopinlen); -+ if (ret != 0) { -+ warnx("Could not get SO PIN."); -+ goto done; -+ } -+ } -+ -+ /* Get the USER pin to authorize migration */ -+ if (!userpin) { -+ printf("Enter the USER PIN: "); -+ fflush(stdout); -+ ret = get_pin(&userpin, &userpinlen); -+ if (ret != 0) { -+ warnx("Could not get USER PIN."); -+ goto done; -+ } -+ } -+ -+ /* Verify the SO and USER PINs entered against NVTOK.DAT. */ -+ ret = verify_pins(data_store, sopin, sopinlen, userpin, userpinlen); -+ if (ret) { -+ warnx("Could not verify pins."); -+ goto done; -+ } -+ -+ /* Check if data store is already new */ -+ ret = datastore_is_312(data_store, sopin, userpin, &new); -+ if (ret == 0 && new) { -+ printf("Data store %s is already in new format.\n", data_store); -+ ret = update_opencryptoki_conf(slot_id, conf_dir); -+ if (ret != CKR_OK) -+ warnx("Failed to update opencryptoki.conf, you must do this manually."); -+ goto done; -+ } -+ -+ /* Backup repository if not already done */ -+ ret = backup_repository(data_store); -+ if (ret != CKR_OK) { -+ warnx("Failed to create backup."); -+ goto done; -+ } -+ -+ /* Perform all actions on the backup */ -+ char data_store_new[PATH_MAX]; -+ data_store_old = data_store; -+ snprintf(data_store_new, PATH_MAX, "%s_PKCSTOK_MIGRATE_TMP", data_store_old); -+ -+ /* Create new temp token keys, which exist in parallel to the old ones -+ * until the migration is fully completed. */ -+ ret = create_token_keys_312(data_store_new, sopin, userpin); -+ if (ret != CKR_OK) { -+ warnx("Failed to create new token keys."); -+ goto done; -+ } -+ -+ /* Migrate repository */ -+ ret = migrate_repository(data_store_new, sopin, userpin); -+ if (ret != CKR_OK) { -+ warnx("Failed to migrate repository."); -+ goto done; -+ } -+ -+ /* Switch to new repository */ -+ ret = switch_to_new_repository(data_store_old, data_store_new); -+ if (ret != CKR_OK) { -+ warnx("Switch to new repository failed."); -+ goto done; -+ } -+ -+ /* Now insert new 'tokversion=3.12' parm in opencryptoki.conf */ -+ ret = update_opencryptoki_conf(slot_id, conf_dir); -+ if (ret != CKR_OK) { -+ warnx("Failed to update opencryptoki.conf, you must do this manually."); -+ goto done; -+ } -+ -+ printf("Pre-migration data backed up at '%s_BAK'\n", data_store_old); -+ printf("Config file backed up at '%s/opencryptoki.conf_BAK'\n", conf_dir); -+ printf("Remove these backups manually after testing the new repository.\n"); -+ -+ ret = CKR_OK; -+ -+done: -+ -+ free(buff); -+ free(sopin); -+ free(userpin); -+ free(data_store); -+ free(conf_dir); -+ free(verbose); -+ -+ if (ret == CKR_OK) { -+ printf("pkcstok_migrate finished successfully.\n"); -+ return EXIT_SUCCESS; -+ } else { -+ printf("pkcstok_migrate finished with warnings/errors.\n"); -+ return EXIT_FAILURE; -+ } -+} -diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk b/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -new file mode 100644 -index 00000000..dc4582e5 ---- /dev/null -+++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -@@ -0,0 +1,22 @@ -+sbin_PROGRAMS += usr/sbin/pkcstok_migrate/pkcstok_migrate -+noinst_HEADERS += misc/mech_types.h -+noinst_HEADERS += usr/lib/common/defs.h -+noinst_HEADERS += usr/lib/common/host_defs.h -+noinst_HEADERS += usr/include/local_types.h -+noinst_HEADERS += usr/lib/common/h_extern.h -+noinst_HEADERS += usr/lib/common/pkcs_utils.h -+ -+usr_sbin_pkcstok_migrate_pkcstok_migrate_LDFLAGS = -lcrypto -ldl -+ -+usr_sbin_pkcstok_migrate_pkcstok_migrate_CFLAGS = \ -+ -DSTDLL_NAME=\"pkcstok_migrate\" \ -+ -I${srcdir}/usr/include \ -+ -I${srcdir}/usr/lib/common \ -+ -I${srcdir}/usr/sbin/pkcstok_migrate -+ -+usr_sbin_pkcstok_migrate_pkcstok_migrate_SOURCES = \ -+ usr/lib/common/p11util.c \ -+ usr/lib/common/sw_crypt.c \ -+ usr/lib/common/trace.c \ -+ usr/lib/common/pkcs_utils.c \ -+ usr/sbin/pkcstok_migrate/pkcstok_migrate.c -diff --git a/usr/sbin/sbin.mk b/usr/sbin/sbin.mk -index 640308f5..01e152df 100644 ---- a/usr/sbin/sbin.mk -+++ b/usr/sbin/sbin.mk -@@ -13,6 +13,9 @@ endif - if ENABLE_P11SAK - include usr/sbin/p11sak/p11sak.mk - endif -+if ENABLE_PKCSTOK_MIGRATE -+include usr/sbin/pkcstok_migrate/pkcstok_migrate.mk -+endif - - include usr/sbin/pkcsslotd/pkcsslotd.mk - include usr/sbin/pkcsconf/pkcsconf.mk diff --git a/opencryptoki-3.14.0-crash-in-c_setpin.patch b/opencryptoki-3.14.0-crash-in-c_setpin.patch deleted file mode 100644 index 0ea8ccd..0000000 --- a/opencryptoki-3.14.0-crash-in-c_setpin.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff -up opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_openssl.c.me opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_openssl.c ---- opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_openssl.c.me 2020-05-26 08:51:32.714189399 -0400 -+++ opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_openssl.c 2020-05-26 08:52:16.429412060 -0400 -@@ -57,7 +57,7 @@ void openssl_print_errors() - } - #endif - --RSA *openssl_gen_key() -+RSA *openssl_gen_key(STDLL_TokData_t *tokdata) - { - RSA *rsa; - int rc, counter = 0; -@@ -66,7 +66,7 @@ RSA *openssl_gen_key() - BIGNUM *bne; - #endif - -- token_specific_rng(NULL, (CK_BYTE *) buf, 32); -+ token_specific_rng(tokdata, (CK_BYTE *) buf, 32); - RAND_seed(buf, 32); - - regen_rsa_key: -diff -up opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.c.me opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.c ---- opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.c.me 2020-05-26 08:52:26.351235628 -0400 -+++ opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.c 2020-05-26 08:53:15.928354051 -0400 -@@ -159,8 +159,6 @@ CK_RV token_specific_rng(STDLL_TokData_t - TSS_HTPM hTPM; - BYTE *random_bytes = NULL; - -- UNUSED(tokdata); -- - rc = Tspi_Context_GetTpmObject(tpm_data->tspContext, &hTPM); - if (rc) { - TRACE_ERROR("Tspi_Context_GetTpmObject: %x\n", rc); -@@ -1389,7 +1387,7 @@ CK_RV token_create_private_tree(STDLL_To - unsigned char n[256], p[256]; - - /* all sw generated keys are 2048 bits */ -- if ((rsa = openssl_gen_key()) == NULL) -+ if ((rsa = openssl_gen_key(tokdata)) == NULL) - return CKR_HOST_MEMORY; - - if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) { -@@ -1467,7 +1465,7 @@ CK_RV token_create_public_tree(STDLL_Tok - unsigned char n[256], p[256]; - - /* all sw generated keys are 2048 bits */ -- if ((rsa = openssl_gen_key()) == NULL) -+ if ((rsa = openssl_gen_key(tokdata)) == NULL) - return CKR_HOST_MEMORY; - - if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) { -diff -up opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.h.me opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.h ---- opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.h.me 2020-05-26 08:53:20.281276648 -0400 -+++ opencryptoki-3.14.0/usr/lib/tpm_stdll/tpm_specific.h 2020-05-26 08:54:08.356421779 -0400 -@@ -56,7 +56,7 @@ - /* retry count for generating software RSA keys */ - #define KEYGEN_RETRY 5 - --RSA *openssl_gen_key(); -+RSA *openssl_gen_key(STDLL_TokData_t *); - int openssl_write_key(STDLL_TokData_t *, RSA *, char *, CK_BYTE *); - CK_RV openssl_read_key(STDLL_TokData_t *, char *, CK_BYTE *, RSA **); - int openssl_get_modulus_and_prime(RSA *, unsigned int *, unsigned char *, diff --git a/opencryptoki-3.14.0-early-error-in-c-initialize.patch b/opencryptoki-3.14.0-early-error-in-c-initialize.patch deleted file mode 100644 index fe2b277..0000000 --- a/opencryptoki-3.14.0-early-error-in-c-initialize.patch +++ /dev/null @@ -1,85 +0,0 @@ -commit 2585fc1a52afdfc6ec119e6a27d7c5d52c06d4e2 -Author: Alexander Scheel -Date: Wed Jul 1 08:23:42 2020 -0400 - - Handle early error cases in C_Initialize - - When C_Initialize errors prior to the bt_init call, bt_destroy will be - called on garbage memory because Anchor hasn't yet been zeroed. This - gives a stack trace such as: - - Stack trace of thread 27740: - #0 0x00007fce91552b05 raise (libc.so.6 + 0x3cb05) - #1 0x00007fce9153b8a4 abort (libc.so.6 + 0x258a4) - #2 0x00007fce908db2e1 _ZN2os5abortEb.cold (libjvm.so + 0x20f2e1) - #3 0x00007fce911f76c2 _ZN7VMError14report_and_dieEv (libjvm.so + 0xb2b6c2) - #4 0x00007fce90fe7a24 JVM_handle_linux_signal (libjvm.so + 0x91ba24) - #5 0x00007fce90fdaa9c _Z13signalHandleriP9siginfo_tPv (libjvm.so + 0x90ea9c) - #6 0x00007fce91552b90 __restore_rt (libc.so.6 + 0x3cb90) - #7 0x00007fce7a262550 bt_destroy (libopencryptoki.so + 0x11550) - #8 0x00007fce7a2600d6 C_Initialize (libopencryptoki.so + 0xf0d6) - #9 0x00007fce7a6c8234 initialize_module_inlock_reentrant (p11-kit-proxy.so + 0x2d234) - #10 0x00007fce7a6c8383 managed_C_Initialize (p11-kit-proxy.so + 0x2d383) - #11 0x00007fce7a6cabe0 p11_kit_modules_initialize (p11-kit-proxy.so + 0x2fbe0) - #12 0x00007fce7a6cea97 proxy_C_Initialize (p11-kit-proxy.so + 0x33a97) - #13 0x00007fce7aaaa6f2 secmod_ModuleInit (libnss3.so + 0x486f2) - #14 0x00007fce7aaaae4a secmod_LoadPKCS11Module (libnss3.so + 0x48e4a) - #15 0x00007fce7aab800d SECMOD_LoadModule (libnss3.so + 0x5600d) - #16 0x00007fce7aab8148 SECMOD_LoadModule (libnss3.so + 0x56148) - #17 0x00007fce7aa80dc1 nss_Init (libnss3.so + 0x1edc1) - #18 0x00007fce7aa8124d NSS_InitReadWrite (libnss3.so + 0x1f24d) - #19 0x00007fce7ac47a29 Java_org_mozilla_jss_CryptoManager_initializeAllNative2 (libjss4.so + 0x15a29) - #20 0x00007fce7c8133c7 n/a (n/a + 0x0) - #21 0x00007fce7c802ffd n/a (n/a + 0x0) - #22 0x00007fce7c802ffd n/a (n/a + 0x0) - #23 0x00007fce7c802ffd n/a (n/a + 0x0) - #24 0x00007fce7c802ffd n/a (n/a + 0x0) - #25 0x00007fce7c802ffd n/a (n/a + 0x0) - #26 0x00007fce7c802ffd n/a (n/a + 0x0) - #27 0x00007fce7c802ffd n/a (n/a + 0x0) - #28 0x00007fce7c802ffd n/a (n/a + 0x0) - #29 0x00007fce7c802ffd n/a (n/a + 0x0) - #30 0x00007fce7c7fb4e7 n/a (n/a + 0x0) - #31 0x00007fce90d60e45 _ZN9JavaCalls11call_helperEP9JavaValueP12methodHandleP17JavaCallArgumentsP6Thread (libjvm.so + 0x694e45) - #32 0x00007fce90d8488d _ZL17jni_invoke_staticP7JNIEnv_P9JavaValueP8_jobject11JNICallTypeP10_jmethodIDP18JNI_ArgumentPusherP6Thread.constprop.1 (libjvm.so + 0x6b888d) - #33 0x00007fce90d87996 jni_CallStaticVoidMethod (libjvm.so + 0x6bb996) - #34 0x00007fce916ee877 JavaMain (libjli.so + 0x4877) - #35 0x00007fce914dc3f9 start_thread (libpthread.so.0 + 0x93f9) - #36 0x00007fce916183b3 __clone (libc.so.6 + 0x1023b3) - - Fixing this requires zeroing Anchor earlier, making t->size 0 and - allowing bt_destroy to exit with accessing uninitialized memory. - - Resolves: #304 - - Signed-off-by: Alexander Scheel - -diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c -index 51ab30fe..f61f2368 100644 ---- a/usr/lib/api/api_interface.c -+++ b/usr/lib/api/api_interface.c -@@ -2557,6 +2557,11 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) - // Clear out the load list - memset(slot_loaded, 0, sizeof(int) * NUMBER_SLOTS_MANAGED); - -+ // Zero out API_Proc_Struct -+ // This must be done prior to all goto error calls, else bt_destroy() -+ // will fail because it accesses uninitialized memory when t->size > 0. -+ memset(Anchor, 0, sizeof(API_Proc_Struct_t)); -+ - TRACE_DEBUG("Anchor allocated at %s\n", (char *) Anchor); - - // Validation of the parameters passed -@@ -2653,12 +2658,10 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) - rc = CKR_FUNCTION_FAILED; - goto error; - } -- //Zero out API_Proc_Struct - //Map Shared Memory Region - //if ( Shared Memory Mapped not Successful ) - // Free allocated Memory - // Return CKR_HOST_MEMORY -- memset((char *) Anchor, 0, sizeof(API_Proc_Struct_t)); - bt_init(&Anchor->sess_btree, free); - Anchor->Pid = getpid(); - diff --git a/opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch b/opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch deleted file mode 100644 index 5c7bddf..0000000 --- a/opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch +++ /dev/null @@ -1,22 +0,0 @@ -commit a94436937b6364c53219fb3c7922439f403e8d5e -Author: Harald Freudenberger -Date: Wed May 27 07:30:33 2020 +0200 - - Fix missing entries for p11sak tool in template spec file - - Signed-off-by: Harald Freudenberger - -diff --git a/rpm/opencryptoki.spec b/rpm/opencryptoki.spec -index fa4b9899..ae563406 100644 ---- a/rpm/opencryptoki.spec -+++ b/rpm/opencryptoki.spec -@@ -238,7 +238,9 @@ exit 0 - %{_unitdir}/pkcsslotd.service - %{_sbindir}/pkcsconf - %{_sbindir}/pkcsslotd -+%{_sbindir}/p11sak - %{_mandir}/man1/pkcsconf.1* -+%{_mandir}/man1/p11sak.1* - %{_mandir}/man5/%{name}.conf.5* - %{_mandir}/man7/%{name}.7* - %{_mandir}/man8/pkcsslotd.8* diff --git a/opencryptoki-3.15.0-timeb.patch b/opencryptoki-3.15.0-timeb.patch new file mode 100644 index 0000000..9b30e44 --- /dev/null +++ b/opencryptoki-3.15.0-timeb.patch @@ -0,0 +1,183 @@ +From 456570f5d4f8d7e9ce75c62ace1a9f79e25b6ee5 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Tue, 20 Oct 2020 08:47:24 +0200 +Subject: [PATCH] Remove now unused header timeb.h + +Since ef62794ca1d065ea20b207990956f93ab2cc6e3b timeb.h is no longer used. +Remove it from the testcases that still include it, and also do not +check for it in configure.ac. + +Signed-off-by: Ingo Franzki +--- + configure.ac | 2 +- + testcases/login/digest_init.c | 1 - + testcases/login/init_pin.c | 1 - + testcases/login/login.c | 1 - + testcases/login/set_pin.c | 1 - + testcases/misc_tests/fork.c | 1 - + testcases/misc_tests/multi_instance.c | 1 - + testcases/misc_tests/obj_lock.c | 1 - + testcases/misc_tests/reencrypt.c | 1 - + testcases/misc_tests/speed.c | 1 - + testcases/misc_tests/tok2tok_transport.c | 1 - + testcases/misc_tests/tok_des.c | 1 - + testcases/misc_tests/tok_rsa.c | 1 - + 13 files changed, 1 insertion(+), 13 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 43349169..851f5e00 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -16,7 +16,7 @@ AC_HEADER_STDC + AC_CHECK_HEADER_STDBOOL + AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h locale.h malloc.h \ + nl_types.h stddef.h sys/file.h sys/socket.h sys/time.h \ +- sys/timeb.h syslog.h termios.h]) ++ syslog.h termios.h]) + + dnl Checks for typedefs, structures, and compiler characteristics. + AC_C_INLINE +diff --git a/testcases/login/digest_init.c b/testcases/login/digest_init.c +index 9998447f..875d8ed8 100644 +--- a/testcases/login/digest_init.c ++++ b/testcases/login/digest_init.c +@@ -14,7 +14,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + +diff --git a/testcases/login/init_pin.c b/testcases/login/init_pin.c +index 62b6f984..c03b57ab 100644 +--- a/testcases/login/init_pin.c ++++ b/testcases/login/init_pin.c +@@ -14,7 +14,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + +diff --git a/testcases/login/login.c b/testcases/login/login.c +index 79ca419a..3081b3e3 100644 +--- a/testcases/login/login.c ++++ b/testcases/login/login.c +@@ -14,7 +14,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + #include "regress.h" +diff --git a/testcases/login/set_pin.c b/testcases/login/set_pin.c +index f72ac7bf..b82d99ac 100644 +--- a/testcases/login/set_pin.c ++++ b/testcases/login/set_pin.c +@@ -15,7 +15,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + +diff --git a/testcases/misc_tests/fork.c b/testcases/misc_tests/fork.c +index b11f2035..fc3f4af8 100644 +--- a/testcases/misc_tests/fork.c ++++ b/testcases/misc_tests/fork.c +@@ -20,7 +20,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/testcases/misc_tests/multi_instance.c b/testcases/misc_tests/multi_instance.c +index e9b9df4a..40638fcb 100644 +--- a/testcases/misc_tests/multi_instance.c ++++ b/testcases/misc_tests/multi_instance.c +@@ -20,7 +20,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/testcases/misc_tests/obj_lock.c b/testcases/misc_tests/obj_lock.c +index c5bbc870..229aa054 100644 +--- a/testcases/misc_tests/obj_lock.c ++++ b/testcases/misc_tests/obj_lock.c +@@ -21,7 +21,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/testcases/misc_tests/reencrypt.c b/testcases/misc_tests/reencrypt.c +index c427f8f6..fa9633f5 100644 +--- a/testcases/misc_tests/reencrypt.c ++++ b/testcases/misc_tests/reencrypt.c +@@ -20,7 +20,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/testcases/misc_tests/speed.c b/testcases/misc_tests/speed.c +index ac803c08..8f5426be 100644 +--- a/testcases/misc_tests/speed.c ++++ b/testcases/misc_tests/speed.c +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + + #include "pkcs11types.h" + #include "regress.h" +diff --git a/testcases/misc_tests/tok2tok_transport.c b/testcases/misc_tests/tok2tok_transport.c +index f9e88561..1c482c27 100644 +--- a/testcases/misc_tests/tok2tok_transport.c ++++ b/testcases/misc_tests/tok2tok_transport.c +@@ -20,7 +20,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/testcases/misc_tests/tok_des.c b/testcases/misc_tests/tok_des.c +index d881c827..2a0e186e 100644 +--- a/testcases/misc_tests/tok_des.c ++++ b/testcases/misc_tests/tok_des.c +@@ -19,7 +19,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + #include "regress.h" +diff --git a/testcases/misc_tests/tok_rsa.c b/testcases/misc_tests/tok_rsa.c +index 52068561..07e24ec2 100644 +--- a/testcases/misc_tests/tok_rsa.c ++++ b/testcases/misc_tests/tok_rsa.c +@@ -19,7 +19,6 @@ + #include + + #include +-#include + + #include "pkcs11types.h" + #include "regress.h" diff --git a/opencryptoki.spec b/opencryptoki.spec index 355b726..49a6684 100644 --- a/opencryptoki.spec +++ b/opencryptoki.spec @@ -1,7 +1,7 @@ Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v2.11 -Version: 3.14.0 -Release: 6%{?dist} +Version: 3.15.0 +Release: 1%{?dist} License: CPL URL: https://github.com/opencryptoki/opencryptoki Source0: https://github.com/opencryptoki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz @@ -12,22 +12,8 @@ Patch0: opencryptoki-3.11.0-group.patch # bz#1373833, change tmpfiles snippets from /var/lock/* to /run/lock/* Patch1: opencryptoki-3.11.0-lockdir.patch -# upstream fix, regression - segfault in C_SetPin -Patch2: opencryptoki-3.14.0-crash-in-c_setpin.patch - -# upstream fix, handle early error cases in C_Initialize -Patch3: opencryptoki-3.14.0-early-error-in-c-initialize.patch - -# Fix missing entries for p11sak tool in template spec file -Patch4: opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch - -# PIN conversion tool -Patch5: opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch -Patch6: 0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch -Patch7: 0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch -Patch8: 0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch -Patch9: 0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch -Patch10: 0005-Fix-storing-of-public-token-objects-in-new-data-form.patch +# https://github.com/opencryptoki/opencryptoki/issues/330 +Patch2: opencryptoki-3.15.0-timeb.patch # Use --no-undefined to debug missing symbols #Patch100: %%{name}-3.2-no-undefined.patch @@ -326,6 +312,9 @@ fi %changelog +* Mon Oct 19 2020 Dan HorĂ¡k - 3.15.0-1 +- Rebase to 3.15.0 + * Tue Jul 28 2020 Fedora Release Engineering - 3.14.0-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild diff --git a/sources b/sources index 13985ac..6e7b91c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (opencryptoki-3.14.0.tar.gz) = 62928f30e3aed7adaafcbe90d1b65ae56dbf10308c0c2a0e6860c266fc68de44d7bfac5c5f7f302e88a032f5360452cdc1185dfd63c26ec1c1ebda0d8324df2b +SHA512 (opencryptoki-3.15.0.tar.gz) = 23ff42245dee95fa3ea123fbf4faf620a10c13bb5d0f86470aa5e5c17b933fc528b77019d740a114ad86a706a60019c59b2d95bb612e7fad4d186bdd0428a72e