diff --git a/.gitignore b/.gitignore index 7229299..f3abbac 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/opencryptoki-3.14.0.tar.gz +SOURCES/opencryptoki-3.15.1.tar.gz diff --git a/.opencryptoki.metadata b/.opencryptoki.metadata index 9259d12..1799171 100644 --- a/.opencryptoki.metadata +++ b/.opencryptoki.metadata @@ -1 +1 @@ -9ddd1bbe34992707b20b314645fd92d35cb298ef SOURCES/opencryptoki-3.14.0.tar.gz +66baf9c90f144bb273964270a39f23fadd86143d SOURCES/opencryptoki-3.15.1.tar.gz diff --git a/SOURCES/0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch b/SOURCES/0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch deleted file mode 100644 index e51b2ea..0000000 --- a/SOURCES/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/SOURCES/0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch b/SOURCES/0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch deleted file mode 100644 index 6954bf2..0000000 --- a/SOURCES/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/SOURCES/0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch b/SOURCES/0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch deleted file mode 100644 index 331d09b..0000000 --- a/SOURCES/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/SOURCES/0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch b/SOURCES/0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch deleted file mode 100644 index 4520992..0000000 --- a/SOURCES/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/SOURCES/0005-Fix-storing-of-public-token-objects-in-new-data-form.patch b/SOURCES/0005-Fix-storing-of-public-token-objects-in-new-data-form.patch deleted file mode 100644 index a014b41..0000000 --- a/SOURCES/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/SOURCES/opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch b/SOURCES/opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch deleted file mode 100644 index ef02e85..0000000 --- a/SOURCES/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/SOURCES/opencryptoki-3.14.0-crash-in-c_setpin.patch b/SOURCES/opencryptoki-3.14.0-crash-in-c_setpin.patch deleted file mode 100644 index 0ea8ccd..0000000 --- a/SOURCES/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/SOURCES/opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch b/SOURCES/opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch deleted file mode 100644 index 5c7bddf..0000000 --- a/SOURCES/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/SOURCES/opencryptoki.module b/SOURCES/opencryptoki.module new file mode 100644 index 0000000..4720c04 --- /dev/null +++ b/SOURCES/opencryptoki.module @@ -0,0 +1,8 @@ +# This file describes how to load the opensc module +# See: http://p11-glue.freedesktop.org/doc/p11-kit/config.html + +# This is a relative path, which means it will be loaded from +# the p11-kit default path which is usually $(libdir)/pkcs11. +# Doing it this way allows for packagers to package opensc for +# 32-bit and 64-bit and make them parallel installable +module: libopencryptoki.so diff --git a/SPECS/opencryptoki.spec b/SPECS/opencryptoki.spec index 68b80e9..6bdfe74 100644 --- a/SPECS/opencryptoki.spec +++ b/SPECS/opencryptoki.spec @@ -1,27 +1,18 @@ Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v2.11 -Version: 3.14.0 -Release: 5%{?dist} +Version: 3.15.1 +Release: 1%{?dist} License: CPL Group: System Environment/Base URL: https://github.com/opencryptoki/opencryptoki Source0: https://github.com/opencryptoki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz +Source1: opencryptoki.module # https://bugzilla.redhat.com/show_bug.cgi?id=732756 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 -# bz#1780293, fix regression, segfault in C_SetPin -Patch2: opencryptoki-3.14.0-crash-in-c_setpin.patch -# Fix missing entries for p11sak tool in template spec file -Patch3: opencryptoki-3.14.0-missing-p11sak-tool-a94436937b6364c53219fb3c7922439f403e8d5e.patch -# bz#1780294, PIN conversion tool -Patch4: opencryptoki-3.14.0-cd40f4b7cb1b502ca754b9bfb307d934285709a9-PIN-conversion-tool.patch -# bz#1853420, endian issue -Patch5: 0001-pkcstok_migrate-Fix-NVTOK.DAT-conversion-on-little-e.patch -Patch6: 0002-pkcstok_migrate-Fix-private-token-object-conversion-.patch -Patch7: 0003-pkcstok_migrate-Fix-public-token-object-conversion-o.patch -Patch8: 0004-pkcstok_migrate-Remove-the-token-s-shared-memory-seg.patch -Patch9: 0005-Fix-storing-of-public-token-objects-in-new-data-form.patch +# upstream fixes + Requires(pre): coreutils BuildRequires: gcc BuildRequires: openssl-devel @@ -204,6 +195,7 @@ make %{?_smp_mflags} CHGRP=/bin/true %install make install DESTDIR=$RPM_BUILD_ROOT CHGRP=/bin/true +install -Dpm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/p11-kit/modules/opencryptoki.module # Remove unwanted cruft rm -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/*.la @@ -286,6 +278,10 @@ fi %{_libdir}/pkcs11/libopencryptoki.so %{_libdir}/pkcs11/PKCS11_API.so %{_libdir}/pkcs11/stdll +# Co-owned with p11-kit +%dir %{_datadir}/p11-kit/ +%dir %{_datadir}/p11-kit/modules/ +%{_datadir}/p11-kit/modules/opencryptoki.module %files devel %{_includedir}/%{name}/ @@ -342,6 +338,23 @@ fi %changelog +* Mon Nov 02 2020 Than Ngo - 3.15.1-1 +- Related: #1847433 + upstream fixes: + - Free generated key in all error cases + - CCA: Zeroize key buffer to avoid CCA 8/32 error + - Do not delete the map-btree entry if destroying an object is not allowed + - Remove now unused header timeb.h + - TESTCASES: Use FIPS conforming keys for 3DES CBC-MAC test vectors + - Fix buffer overrun in C_CopyObject + - TPM: Fix double free in openssl_gen_key + +* Mon Oct 19 2020 Than Ngo - 3.15.0-1 +- Resolves: #1847433, rebase to 3.15.0 +- Resolves: #1851105, PKCS #11 3.0 - baseline provider support +- Resolves: #1851108, openCryptoki ep11 token: enhanced functionality +- Resolves: #1851109, openCryptoki key management tool: key deletion function + * Mon Jul 06 2020 Than Ngo - 3.14.0-5 - Related: #1853420, more fixes