diff -Nru opencryptoki-3.20.0+dfsg/ChangeLog opencryptoki-3.21.0+dfsg/ChangeLog --- opencryptoki-3.20.0+dfsg/ChangeLog 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/ChangeLog 2023-05-15 14:42:55.000000000 +0200 @@ -1,3 +1,17 @@ ++ openCryptoki 3.21 +- EP11 and CCA: Support concurrent HSM master key changes +- CCA: protected-key option +- pkcsslotd: no longer run as root user and further hardening +- p11sak: Add support for additional key types (DH, DSA, generic secret) +- p11sak: Allow wildcards in label filter +- p11sak: Allow to specify hex value for CKA_ID attribute +- p11sak: Support sorting when listing keys +- p11sak: New commands: set-key-attr, copy-key to modify and copy keys +- p11sak: New commands: import-key, export-key to import and export keys +- Remove support for --disable-locks (transactional memory) +- Updates to harden against RSA timing attacks +- Bug fixes + + openCryptoki 3.20 - Soft/ICA: add support for the AES-XTS key type (PKCS#11 v3.0) - ICSF: add support for ECDH and additional SHA variants diff -Nru opencryptoki-3.20.0+dfsg/configure.ac opencryptoki-3.21.0+dfsg/configure.ac --- opencryptoki-3.20.0+dfsg/configure.ac 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/configure.ac 2023-05-15 14:42:55.000000000 +0200 @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([openCryptoki],[3.20.0],[https://github.com/opencryptoki/opencryptoki/issues],[],[https://github.com/opencryptoki/opencryptoki]) +AC_INIT([openCryptoki],[3.21.0],[https://github.com/opencryptoki/opencryptoki/issues],[],[https://github.com/opencryptoki/opencryptoki]) AC_CONFIG_SRCDIR([testcases/common/common.c]) dnl Needed for $target! @@ -50,9 +50,11 @@ AC_PATH_PROG([ID], [id], [/us/bin/id]) AC_PATH_PROG([USERMOD], [usermod], [/usr/sbin/usermod]) AC_PATH_PROG([GROUPADD], [groupadd], [/usr/sbin/groupadd]) +AC_PATH_PROG([USERADD], [useradd], [/usr/sbin/useradd]) AC_PATH_PROG([CAT], [cat], [/bin/cat]) AC_PATH_PROG([CHMOD], [chmod], [/bin/chmod]) AC_PATH_PROG([CHGRP], [chgrp], [/bin/chgrp]) +AC_PATH_PROG([CHOWN], [chown], [/bin/chown]) AC_PROG_AWK AC_PROG_INSTALL AC_PROG_LN_S @@ -68,7 +70,10 @@ AC_MSG_ERROR(['bison' program is missing on your system. Please install 'bison'.]) fi -AC_CHECK_LIB([itm], [_ITM_commitTransaction], [itm=yes], [itm=no]) +LIBCAP_LIBS= +AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP_LIBS="-lcap"], + [AC_MSG_ERROR(['libcap' library is missing on your system. Please install 'libcap-devel'.])]) +AC_SUBST([LIBCAP_LIBS]) OPENLDAP_LIBS= AC_CHECK_HEADERS([lber.h ldap.h], @@ -176,7 +181,7 @@ dnl --- locking support AC_ARG_ENABLE([locks], - AS_HELP_STRING([--disable-locks],[build opencryptoki with transactional memory instead of locks])) + AS_HELP_STRING([--disable-locks],[This option is no longer supported, ignored if specified.])) dnl --- p11sak tool AC_ARG_ENABLE([p11sak], @@ -199,6 +204,12 @@ dnl --- support for MD2 AC_ARG_ENABLE([md2], AS_HELP_STRING([--enable-md2],[build opencryptoki with support for MD2])) + +dnl --- pkcshsm_mk_change +AC_ARG_ENABLE([pkcshsm_mk_change], + AS_HELP_STRING([--enable-pkcshsm_mk_change],[build pkcshsm_mk_change tool @<:@default=enabled@:>@]), + [], + [enable_pkcshsm_mk_change=yes]) dnl --- dnl --- Check for external software @@ -224,9 +235,10 @@ dnl --- systemd system unit files location AC_ARG_WITH([systemd], - AS_HELP_STRING([--with-systemd@<:@=DIR@:>@],[systemd system unit files location]), + AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], + [Build a systemd service unit file for pkcsslotd (default yes), and optionally specify the systemd system unit files location. Specify '--without-systemd' to build an init-d script instead]), [], - [with_systemd=no]) + [with_systemd=yes]) dnl --- libudev development files AC_ARG_WITH([libudev], @@ -234,23 +246,44 @@ [], [with_libudev=check]) +dnl --- pkcsslotd user +AC_ARG_WITH([pkcsslotd-user], + AS_HELP_STRING([--with-pkcsslotd-user=USER],[set the user under which pkcsslotd runs (default: pkcsslotd)]), + [pkcsslotd_user=$withval], + [pkcsslotd_user=pkcsslotd]) + +dnl --- pkcs group +AC_ARG_WITH([pkcs-group], + AS_HELP_STRING([--with-pkcs-group=GROUP],[set the group that all openCryptoki applications must belong to (default: pkcs11)]), + [pkcs_group=$withval], + [pkcs_group=pkcs11]) + dnl --- dnl --- dnl --- Now that we have all the options, let's check for a valid build dnl --- +dnl --- enable_pkey +enable_pkey=no + case $target in *s390x*) + enable_pkey=yes ;; *s390*) - CFLAGS="$CFLAGS -m31" + CFLAGS="$CFLAGS -m31 -DNO_PKEY" ;; *ppc64* | *x86_64*) + CFLAGS="$CFLAGS -DNO_PKEY" ;; *ppc* | i*86*) - CFLAGS="$CFLAGS -m32" + CFLAGS="$CFLAGS -m32 -DNO_PKEY" + ;; + *) + CFLAGS="$CFLAGS -DNO_PKEY" ;; esac +AM_CONDITIONAL([NO_PKEY], [test "x$enable_pkey" != "xyes"]) dnl --- enable_debug if test "x$enable_debug" = "xyes"; then @@ -275,6 +308,25 @@ AC_CHECK_HEADER([openssl/evp.h], [], [ AC_MSG_ERROR([OpenSSL 1.1.1 or later is required but OpenSSL headers couldn't be found]) ]) + AC_MSG_CHECKING([whether OpenSSL has alternate fix for CVE 2022-4304]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[ + #include + #if OPENSSL_VERSION_NUMBER < 0x1010115fL + #error "< OpenSSl 1.1.1u" + #endif + #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x30000090L + #error "< OpenSSl 3.0.9" + #endif + #if OPENSSL_VERSION_NUMBER >= 0x30100000L && OPENSSL_VERSION_NUMBER < 0x30100010L + #error "< OpenSSl 3.1.1" + #endif + ]],[[int dummy;]])], + [have_alt_fix_for_cve_2022_4304=yes + CFLAGS="$CFLAGS -DHAVE_ALT_FIX_FOR_CVE2022_4304" + AC_MSG_RESULT([yes])], + [have_alt_fix_for_cve_2022_4304=no + AC_MSG_RESULT([no])]) if test "x$with_openssl" != "xno"; then AC_CHECK_LIB([crypto], [EVP_sha3_256], [ OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto" @@ -292,6 +344,7 @@ fi AC_SUBST([OPENSSL_CFLAGS]) AC_SUBST([OPENSSL_LIBS]) +AM_CONDITIONAL([HAVE_ALT_FIX_FOR_CVE_2022_4304], [test "x$have_alt_fix_for_cve_2022_4304" = "xyes"]) dnl --- with_libica LIBICA_CFLAGS= @@ -465,6 +518,21 @@ AM_CONDITIONAL([ENABLE_ICATOK], [test "x$enable_icatok" = "xyes"]) dnl --- enable_ccatok +if test "x$enable_ccatok" = "xyes" -a "x$enable_pkey" = "xyes"; then + AC_CHECK_HEADER([asm/pkey.h], [], [ + AC_MSG_ERROR([cca token build requested but Kernel's pkey header couldn't be found]) + ]) +fi +if test "x$enable_ccatok" != "xno"; then + enable_ccatok=yes + if test "x$enable_pkey" = "xyes"; then + AC_CHECK_HEADER([asm/pkey.h], [], [ + enable_ccatok=no + ]) + fi +else + enable_ccatok=no +fi AM_CONDITIONAL([ENABLE_CCATOK], [test "x$enable_ccatok" = "xyes"]) dnl --- enable_swtok @@ -571,21 +639,13 @@ dnl --- enable_pkcsstats AM_CONDITIONAL([ENABLE_PKCSSTATS], [test "x$enable_pkcsstats" = "xyes"]) +dnl --- enable_pkcshsm_mk_change +AM_CONDITIONAL([ENABLE_PKCSHSM_MK_CHANGE], [test "x$enable_pkcshsm_mk_change" = "xyes"]) + dnl --- enable_locks -if test "x$enable_locks" != "xno"; then - enable_locks=yes - CFLAGS="$CFLAGS -DENABLE_LOCKS" -else - enable_locks=no - CFLAGS="$CFLAGS -fgnu-tm" -fi if test "x$enable_locks" = "xno"; then - if test "x$itm" != "xyes"; then - AC_MSG_ERROR([in order to build opencryptoki with transactional memory, -libitm and gcc>=4.7 is required]) - fi + AC_MSG_WARN([The --disable-locks option is no longer supported, it is ignored.]) fi -AM_CONDITIONAL([ENABLE_LOCKS], [test "x$enable_locks" = "xyes"]) dnl --- enable_md2 if test "x$enable_md2" = "xyes"; then @@ -596,9 +656,13 @@ fi AM_CONDITIONAL([ENABLE_MD2], [test "x$enable_md2" = "xyes"]) +AC_SUBST([pkcsslotd_user]) +AC_SUBST([pkcs_group]) + CFLAGS="$CFLAGS -DPKCS64 -D_XOPEN_SOURCE=600 -Wall -Wextra" CFLAGS+=' -DCONFIG_PATH=\"$(localstatedir)/lib/opencryptoki\" -DSBIN_PATH=\"$(sbindir)\" -DLIB_PATH=\"$(libdir)\" -DLOCKDIR_PATH=\"$(lockdir)\" -DOCK_CONFDIR=\"$(sysconfdir)/opencryptoki\" -DOCK_LOGDIR=\"$(logdir)\"' +CFLAGS+=' -DPKCSSLOTD_USER=\"$(pkcsslotd_user)\" -DPKCS_GROUP=\"$(pkcs_group)\"' CFLAGS+=" -std=c99 -Werror=implicit-int -Werror=implicit-function-declaration -Werror=int-conversion -Werror=strict-prototypes -Werror=old-style-definition -pedantic" # At this point, CFLAGS is set to something sensible @@ -628,6 +692,7 @@ man/man1/pkcsep11_session.1 \ man/man1/pkcstok_migrate.1 \ man/man1/pkcsstats.1 \ + man/man1/pkcshsm_mk_change.1 \ man/man5/opencryptoki.conf.5 \ man/man5/p11sak_defined_attrs.conf.5 \ man/man5/strength.conf.5 \ @@ -643,11 +708,11 @@ echo " Daemon build: $enable_daemon" echo " Library build: $enable_library" echo " Systemd service: $enable_systemd" -echo " Build with locks: $enable_locks" echo " Build with libudev: $with_libudev" echo " Build p11sak tool: $enable_p11sak" echo " token migrate tool: $enable_pkcstok_migrate" echo " statistics tool: $enable_pkcsstats" +echo " HSM MK change tool: $enable_pkcshsm_mk_change" echo echo "Enabled token types:" echo " ICA token: $enable_icatok" @@ -661,5 +726,8 @@ echo " pkcsep11migrate build: $enable_pkcsep11_migrate" echo " pkcsep11session build: $enable_pkcsep11_session" echo +echo "pkcsslotd user: $pkcsslotd_user" +echo "pkcs group: $pkcs_group" +echo echo "CFLAGS=$CFLAGS" echo diff -Nru opencryptoki-3.20.0+dfsg/COPYRIGHTS opencryptoki-3.21.0+dfsg/COPYRIGHTS --- opencryptoki-3.20.0+dfsg/COPYRIGHTS 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/COPYRIGHTS 2023-05-15 14:42:55.000000000 +0200 @@ -1,9 +1,34 @@ Base openCryptoki Code and IBM submissions -(C) COPYRIGHT International Business Machines Corp. 2001, 2022 +(C) COPYRIGHT International Business Machines Corp. 2001, 2023 +For code originating from OpenSSL: + + * - usr/lib/ica_s390_stdll/rsa_sup_mul.c: Copied from OpenSSL from + * crypto/bn/rsa_sup_mul.c and modified to fit to the OpenCrptoki environment. + * See comment in usr/lib/ica_s390_stdll/rsa_sup_mul.c for a list of changes. + * Note that in OpenSSL the file crypto/bn/rsa_sup_mul.c does no longer + * exist, it was removed with commit https://github.com/openssl/openssl/commit/4209ce68d8fe8b1506494efa03d378d05baf9ff8 + * - usr/lib/common/constant_time.h: Copied unchanged from OpenSSL from + include/internal/constant_time.h + * - The implementation of function rsa_parse_block_type_2() in + * usr/lib/common/mech_rsa.c is copied from OpenSSL's function + * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c + * and is slightly modified to fit to the OpenCryptoki environment. + * See comment in function rsa_parse_block_type_2() for a list of changes. + * - The implementation of function decode_eme_oaep() in + * usr/lib/common/mech_rsa.c is copied from OpenSSL's function + * RSA_padding_check_PKCS1_OAEP_mgf1() in crypto/rsa/rsa_oaep.c and is + * slightly modified to fit to the OpenCryptoki environment. See comment in + * function decode_eme_oaep() for a list of changes. + * + * Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * The OpenSSL code is licensed under the Apache License 2.0 (the "License"). + * You can obtain a copy in the file LICENSE in the OpenSSL source distribution + * or at https://www.openssl.org/source/license.html diff -Nru opencryptoki-3.20.0+dfsg/debian/changelog opencryptoki-3.21.0+dfsg/debian/changelog --- opencryptoki-3.20.0+dfsg/debian/changelog 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/changelog 2023-07-07 12:15:35.000000000 +0200 @@ -1,3 +1,42 @@ +opencryptoki (3.21.0+dfsg-0ubuntu1) mantic; urgency=medium + + * New upstream release (LP: #2026732), incl. support for: + - concurrent MK rotation for ep11 token (LP: #2025917) + - concurrent MK rotation for cca token (LP: #2025926) + - cca token: protected key support (LP: #2025923) + - pkcsslotd hardening (LP: #2025922) + Required modifications: + - add libcap-dev to Build-Depends + - adjust and refresh d/p/01-disable-testcases.patch due to changed context + - adjust and refresh d/p/04-pkcsslotd-cmdline-args.patch due to changed + context and fuzz + - adjust, expand and refresh + d/p/lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch + due to changed context and changes around pkcsslotd, which req. folders + added to d/opencryptoki.dirs and modifications in d/opencryptoki.postinst + and d/opencryptoki.postrm to work properly. + Fix selected issues on top of v3.21 and add: + - d/p/lp-2026732-common-Correctly-set-default-attributes-for-certific.patch + - d/p/lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch + - d/p/lp-2026732-pkcsstats-Fix-handling-of-user-name.patch + - d/p/lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch + - d/p/lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch + - d/p/lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch + * According to LP: #2022088 comment #4, revert d/rules, d/triggers + d/libopencryptoki0.{install,links} back, but do not instead add + d/p/lp-2022088-fix-p11sak-failure-to-find-libopencryptoki.so.patch + to fix 'failure that p11sak is not able to find libopencryptoki', + since the p11sak code was refactored and changed significantly in v3.21. + To fix this now expand d/p/03-dlopen-soname.patch with hunks for + usr/sbin/p11sak/p11sak.h, usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c, + usr/sbin/pkcsstats/pkcsstats.c, testcases/common/common.c and + testcases/policy/policytest.c + * d/libopencryptoki0.links{.s390x} Merge files, since the content of the + s390x version of this file applies to all platforms. + * d/*: changes due to wrap-and-sort run + + -- Frank Heimes Fri, 07 Jul 2023 12:15:35 +0200 + opencryptoki (3.20.0+dfsg-0ubuntu2) mantic; urgency=medium * d/rules, d/triggers, d/libopencryptoki0.install: keep tmp/etc/ld.so.conf.d diff -Nru opencryptoki-3.20.0+dfsg/debian/control opencryptoki-3.21.0+dfsg/debian/control --- opencryptoki-3.20.0+dfsg/debian/control 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/control 2023-07-07 12:15:35.000000000 +0200 @@ -3,28 +3,31 @@ Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Paulo Vital -Build-Depends: autoconf, +Build-Depends: + autoconf, automake, + bison, debhelper (>= 13~), debhelper-compat (= 13), - libtool, - libtspi-dev, - bison, flex, - libitm1 [!armhf], + libcap-dev, libica-dev [s390x], + libitm1 [!armhf], libldap2-dev, + libtool, + libtspi-dev, libudev-dev Standards-Version: 4.6.1.0 Homepage: https://github.com/opencryptoki/opencryptoki Package: opencryptoki Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libopencryptoki0 (= ${binary:Version}), +Depends: adduser, - lsb-base (>= 3.0-6) + libopencryptoki0 (= ${binary:Version}), + lsb-base (>= 3.0-6), + ${misc:Depends}, + ${shlibs:Depends} Multi-Arch: foreign Description: PKCS#11 implementation (daemon) openCryptoki is a PKCS#11 Cryptographic Token Interface Standard @@ -37,8 +40,7 @@ Package: libopencryptoki0 Section: libs Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same Description: PKCS#11 implementation (library) openCryptoki is a PKCS#11 Cryptographic Token Interface Standard @@ -51,8 +53,7 @@ Package: libopencryptoki-dev Section: libdevel Architecture: any -Depends: ${misc:Depends}, - libopencryptoki0 (= ${binary:Version}) +Depends: libopencryptoki0 (= ${binary:Version}), ${misc:Depends} Multi-Arch: same Description: PKCS#11 implementation (development) openCryptoki is a PKCS#11 Cryptographic Token Interface Standard diff -Nru opencryptoki-3.20.0+dfsg/debian/copyright opencryptoki-3.21.0+dfsg/debian/copyright --- opencryptoki-3.20.0+dfsg/debian/copyright 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/copyright 2023-07-07 12:15:35.000000000 +0200 @@ -2,7 +2,7 @@ Author: Kent Yoder Download: http://opencryptoki.sourceforge.net/ Files-Excluded: - doc/README.* + doc/README.* Files: * Copyright: diff -Nru opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.install opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.install --- opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.install 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.install 2023-07-07 12:15:35.000000000 +0200 @@ -4,4 +4,3 @@ usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/stdll/*.so.* usr/lib/${DEB_HOST_MULTIARCH}/pkcs11/methods usr/lib/${DEB_HOST_MULTIARCH}/pkcs11/stdll -etc/ld.so.conf.d/opencryptoki-${DEB_HOST_GNU_CPU}.conf diff -Nru opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.links opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.links --- opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.links 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.links 2023-07-07 12:15:35.000000000 +0200 @@ -1,4 +1,6 @@ +usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so +usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ep11.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ep11.so +usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ica.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ica.so +usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_icsf.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_icsf.so usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_sw.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_sw.so usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_tpm.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_tpm.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so -usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/libopencryptoki.so.0 usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/stdll/libopencryptoki.so diff -Nru opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.links.s390x opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.links.s390x --- opencryptoki-3.20.0+dfsg/debian/libopencryptoki0.links.s390x 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/libopencryptoki0.links.s390x 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_sw.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_sw.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_tpm.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_tpm.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_cca.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ep11.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ep11.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ica.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_ica.so -usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_icsf.so.0 usr/lib/${DEB_HOST_MULTIARCH}/libpkcs11_icsf.so -usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/libopencryptoki.so.0 usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/stdll/libopencryptoki.so diff -Nru opencryptoki-3.20.0+dfsg/debian/libopencryptoki-dev.install opencryptoki-3.21.0+dfsg/debian/libopencryptoki-dev.install --- opencryptoki-3.20.0+dfsg/debian/libopencryptoki-dev.install 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/libopencryptoki-dev.install 2023-07-07 12:15:35.000000000 +0200 @@ -2,4 +2,3 @@ usr/include/opencryptoki/* usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/*.so usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig/*.pc - diff -Nru opencryptoki-3.20.0+dfsg/debian/opencryptoki.dirs opencryptoki-3.21.0+dfsg/debian/opencryptoki.dirs --- opencryptoki-3.20.0+dfsg/debian/opencryptoki.dirs 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/opencryptoki.dirs 2023-07-07 12:15:35.000000000 +0200 @@ -1,12 +1,14 @@ /var/lib/opencryptoki -/var/lib/opencryptoki/icsf -/var/lib/opencryptoki/swtok -/var/lib/opencryptoki/tpm -/var/lib/opencryptoki/lite /var/lib/opencryptoki/ccatok +/var/lib/opencryptoki/ccatok/TOK_OBJ /var/lib/opencryptoki/ep11tok +/var/lib/opencryptoki/ep11tok/TOK_OBJ +/var/lib/opencryptoki/icsf /var/lib/opencryptoki/icsf/TOK_OBJ -/var/lib/opencryptoki/swtok/TOK_OBJ +/var/lib/opencryptoki/lite /var/lib/opencryptoki/lite/TOK_OBJ -/var/lib/opencryptoki/ccatok/TOK_OBJ -/var/lib/opencryptoki/ep11tok/TOK_OBJ +/var/lib/opencryptoki/swtok +/var/lib/opencryptoki/swtok/TOK_OBJ +/var/lib/opencryptoki/tpm +/var/lock/opencryptoki +/var/log/opencryptoki diff -Nru opencryptoki-3.20.0+dfsg/debian/opencryptoki.install opencryptoki-3.21.0+dfsg/debian/opencryptoki.install --- opencryptoki-3.20.0+dfsg/debian/opencryptoki.install 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/opencryptoki.install 2023-07-07 12:15:35.000000000 +0200 @@ -1,8 +1,8 @@ -usr/sbin -usr/share/man -usr/share/doc/opencryptoki/*-example.conf +etc/opencryptoki +lib/systemd/system/pkcsslotd.service usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/stdll/*.so usr/lib/tmpfiles.d/opencryptoki.conf +usr/sbin +usr/share/doc/opencryptoki/*-example.conf +usr/share/man var/lib/opencryptoki -etc/opencryptoki -lib/systemd/system/pkcsslotd.service diff -Nru opencryptoki-3.20.0+dfsg/debian/opencryptoki.links opencryptoki-3.21.0+dfsg/debian/opencryptoki.links --- opencryptoki-3.20.0+dfsg/debian/opencryptoki.links 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/opencryptoki.links 2023-07-07 12:15:35.000000000 +0200 @@ -1,2 +1,2 @@ -usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/libopencryptoki.so.0 usr/lib/${DEB_HOST_MULTIARCH}/pkcs11/libopencryptoki.so usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/libopencryptoki.so.0 usr/lib/${DEB_HOST_MULTIARCH}/pkcs11/PKCS11_API.so +usr/lib/${DEB_HOST_MULTIARCH}/opencryptoki/libopencryptoki.so.0 usr/lib/${DEB_HOST_MULTIARCH}/pkcs11/libopencryptoki.so diff -Nru opencryptoki-3.20.0+dfsg/debian/opencryptoki.postinst opencryptoki-3.21.0+dfsg/debian/opencryptoki.postinst --- opencryptoki-3.20.0+dfsg/debian/opencryptoki.postinst 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/opencryptoki.postinst 2023-07-07 12:15:35.000000000 +0200 @@ -5,15 +5,26 @@ case "${1}" in configure) addgroup --system pkcs11 - adduser root pkcs11 + adduser --system --ingroup pkcs11 --home /run/opencryptoki --shell /usr/sbin/nologin --comment "Opencryptoki pkcsslotd user" pkcsslotd + adduser root pkcs11 chown root:pkcs11 /var/lib/opencryptoki - chmod 0775 /var/lib/opencryptoki chown root:pkcs11 /etc/opencryptoki/p11sak_defined_attrs.conf chown root:pkcs11 /etc/opencryptoki/strength.conf - chmod 640 /etc/opencryptoki/strength.conf + + chown pkcsslotd:pkcs11 /run/opencryptoki + chgrp pkcs11 /run/opencryptoki + chmod 0710 /run/opencryptoki + chgrp pkcs11 /var/lock/opencryptoki + chmod 0770 /var/lock/opencryptoki + chgrp pkcs11 /var/log/opencryptoki + chmod 0770 /var/log/opencryptoki + + chgrp pkcs11 /var/lib/opencryptoki + chmod 0770 /var/lib/opencryptoki + ;; abort-upgrade|abort-remove|abort-deconfigure) diff -Nru opencryptoki-3.20.0+dfsg/debian/opencryptoki.postrm opencryptoki-3.21.0+dfsg/debian/opencryptoki.postrm --- opencryptoki-3.20.0+dfsg/debian/opencryptoki.postrm 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/opencryptoki.postrm 2023-07-07 12:15:35.000000000 +0200 @@ -3,6 +3,7 @@ set -e if [ "remove" = "${1}" ]; then + deluser root pkcs11 || true deluser --group --only-if-empty pkcs11 || true fi diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/01-disable-testcases.patch opencryptoki-3.21.0+dfsg/debian/patches/01-disable-testcases.patch --- opencryptoki-3.20.0+dfsg/debian/patches/01-disable-testcases.patch 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/01-disable-testcases.patch 2023-07-07 12:15:35.000000000 +0200 @@ -8,7 +8,7 @@ @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) - AC_INIT([openCryptoki],[3.20.0],[https://github.com/opencryptoki/opencryptoki/issues],[],[https://github.com/opencryptoki/opencryptoki]) + AC_INIT([openCryptoki],[3.21.0],[https://github.com/opencryptoki/opencryptoki/issues],[],[https://github.com/opencryptoki/opencryptoki]) -AC_CONFIG_SRCDIR([testcases/common/common.c]) +AC_CONFIG_SRCDIR([usr/include/pkcs11.h]) @@ -18,7 +18,7 @@ =================================================================== --- opencryptoki-3.14.0+dfsg.orig/Makefile.am +++ opencryptoki-3.14.0+dfsg/Makefile.am -@@ -22,9 +22,6 @@ if ENABLE_DAEMON +@@ -28,9 +28,6 @@ if ENABLE_DAEMON include misc/misc.mk endif endif diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/03-dlopen-soname.patch opencryptoki-3.21.0+dfsg/debian/patches/03-dlopen-soname.patch --- opencryptoki-3.20.0+dfsg/debian/patches/03-dlopen-soname.patch 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/03-dlopen-soname.patch 2023-07-07 12:15:35.000000000 +0200 @@ -1,6 +1,18 @@ -Author: Daniel Baumann Description: Opening libopencryptoki correctly with soname major (Closes: #463593). + While working on (LP: #2026732) I've added adjustments for the soname + major of libopencryptoki also for: + testcases/common/common.c + testcases/policy/policytest.c + usr/sbin/p11sak/p11sak.h + usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c + usr/sbin/pkcsstats/pkcsstats.c +Author: Daniel Baumann +Author: Frank Heimes +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1982842 +Forwarded: no +Reviewed-by: Frank Heimes +Last-Update: 2023-07-11 --- a/usr/sbin/pkcscca/pkcscca.c +++ b/usr/sbin/pkcscca/pkcscca.c @@ -15,7 +27,7 @@ --- a/usr/sbin/pkcsconf/pkcsconf.c +++ b/usr/sbin/pkcsconf/pkcsconf.c -@@ -969,7 +969,7 @@ +@@ -975,7 +975,7 @@ * error */ /* The host machine should have the right library in the * LD_LIBRARY_PATH */ @@ -46,3 +58,58 @@ evar = secure_getenv("PKCSLIB"); if (evar == NULL) +--- a/testcases/common/common.c ++++ b/testcases/common/common.c +@@ -1392,7 +1392,7 @@ + CK_RV(*getinterface)(CK_UTF8CHAR_PTR name, CK_VERSION_PTR version, + CK_INTERFACE_PTR_PTR interface, CK_FLAGS flags); + char *e; +- char *f = "libopencryptoki.so"; ++ char *f = "libopencryptoki.so.0"; + CK_ULONG nmemb = 0; + + rv = FALSE; +--- a/testcases/policy/policytest.c ++++ b/testcases/policy/policytest.c +@@ -117,7 +117,7 @@ + + static int doLoadLib(void) + { +- const char *lib = "libopencryptoki.so"; ++ const char *lib = "libopencryptoki.so.0"; + const char *envlib; + CK_RV (*pGetFuncList)(CK_FUNCTION_LIST **); + CK_RV rc; +--- a/usr/sbin/p11sak/p11sak.h ++++ b/usr/sbin/p11sak/p11sak.h +@@ -14,7 +14,7 @@ + #include "pkcs11types.h" + #include "ec_curves.h" + +-#define P11SAK_DEFAULT_PKCS11_LIB "libopencryptoki.so"; ++#define P11SAK_DEFAULT_PKCS11_LIB "libopencryptoki.so.0"; + #define P11SAK_PKCSLIB_ENV_NAME "PKCSLIB" + #define PKCS11_USER_PIN_ENV_NAME "PKCS11_USER_PIN" + #define PKCS11_PEM_PASSWORD_ENV_NAME "PKCS11_PEM_PASSWORD" +--- a/usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c ++++ b/usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change.c +@@ -1315,7 +1315,7 @@ + void (*sym_ptr)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); + CK_RV rc; + +- dll = dlopen("libopencryptoki.so", RTLD_NOW); ++ dll = dlopen("libopencryptoki.so.0", RTLD_NOW); + if (dll == NULL) { + warnx("Error loading PKCS#11 library: dlopen: %s", dlerror()); + return ELIBACC; +--- a/usr/sbin/pkcsstats/pkcsstats.c ++++ b/usr/sbin/pkcsstats/pkcsstats.c +@@ -713,7 +713,7 @@ + void (*sym_ptr)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); + CK_RV rc; + +- *dll = dlopen("libopencryptoki.so", RTLD_NOW); ++ *dll = dlopen("libopencryptoki.so.0", RTLD_NOW); + if (*dll == NULL) { + warnx("Error loading PKCS#11 library: dlopen: %s", dlerror()); + return 1; diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/04-pkcsslotd-cmdline-args.patch opencryptoki-3.21.0+dfsg/debian/patches/04-pkcsslotd-cmdline-args.patch --- opencryptoki-3.20.0+dfsg/debian/patches/04-pkcsslotd-cmdline-args.patch 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/04-pkcsslotd-cmdline-args.patch 2023-07-07 12:15:35.000000000 +0200 @@ -89,11 +89,11 @@ +#define _GNU_SOURCE + + #define _DEFAULT_SOURCE #include #include - #include -@@ -49,6 +51,9 @@ - int mode; +@@ -54,6 +56,9 @@ + int owner_pkcsslotd; }; +/* for getopt via unitstd */ @@ -102,7 +102,7 @@ /* We make main() able to modify Daemon so that we can daemonize or not based on a command-line argument -@@ -605,6 +610,23 @@ +@@ -723,6 +728,23 @@ } /***************************************** @@ -126,7 +126,7 @@ * main() - * You know what main does. * Comment block for ease of spotting -@@ -615,6 +637,7 @@ +@@ -733,6 +755,7 @@ int main(int argc, char *argv[], char *envp[]) { int ret, i; @@ -134,7 +134,7 @@ /**********************************/ /* Read in command-line arguments */ -@@ -624,9 +647,42 @@ +@@ -742,9 +765,42 @@ /* FIXME: Argument for debug level */ /* FIXME: Arguments affecting the log files, whether to use syslog, etc. * (Read conf file?) */ diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch 2023-07-07 12:15:35.000000000 +0200 @@ -5,37 +5,46 @@ This quilt patch removes the pkcs11 group assignements from Makefile.am. The pkcs11 group assignments are now done instead at in debian/opencryptoki.postinst. + Now extended to cover useradd of pkcsslotd user; again removed from + Makefile.am and now done in debian/opencryptoki.postinst. Author: Frank Heimes Bug-Ubuntu: https://bugs.launchpad.net/bugs/1982842 Forwarded: no Reviewed-by: Frank Heimes -Last-Update: 2022-08-17 +Last-Update: 2023-07-10 --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ --- a/Makefile.am +++ b/Makefile.am -@@ -36,7 +36,6 @@ +@@ -36,14 +36,9 @@ include doc/doc.mk install-data-hook: -- getent group pkcs11 > /dev/null || $(GROUPADD) -r pkcs11 +- getent group $(pkcs_group) > /dev/null || $(GROUPADD) -r $(pkcs_group) +- getent passwd $(pkcsslotd_user) >/dev/null || $(USERADD) -r -g $(pkcs_group) -d /run/opencryptoki -s /sbin/nologin -c "Opencryptoki pkcsslotd user" $(pkcsslotd_user) + $(MKDIR_P) $(DESTDIR)/run/opencryptoki/ +- $(CHOWN) $(pkcsslotd_user):$(pkcs_group) $(DESTDIR)/run/opencryptoki/ +- $(CHGRP) $(pkcs_group) $(DESTDIR)/run/opencryptoki/ + $(CHMOD) 0710 $(DESTDIR)/run/opencryptoki/ + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki +- $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki + $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki if ENABLE_LIBRARY $(MKDIR_P) $(DESTDIR)$(libdir)/opencryptoki/stdll - $(MKDIR_P) $(DESTDIR)$(libdir)/pkcs11 -@@ -84,7 +83,7 @@ +@@ -97,7 +92,7 @@ endif if ENABLE_P11SAK test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true -- test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -g pkcs11 -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true +- test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -g $(pkcs_group) -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true + test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true endif if ENABLE_ICATOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ -@@ -135,7 +134,7 @@ +@@ -148,7 +143,7 @@ if ENABLE_DAEMON test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || $(INSTALL) -m 644 $(srcdir)/usr/sbin/pkcsslotd/opencryptoki.conf $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || true -- test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -g pkcs11 -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true +- test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -g $(pkcs_group) -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true + test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true endif $(MKDIR_P) $(DESTDIR)/etc/ld.so.conf.d diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-common-Correctly-set-default-attributes-for-certific.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-common-Correctly-set-default-attributes-for-certific.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-common-Correctly-set-default-attributes-for-certific.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-common-Correctly-set-default-attributes-for-certific.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,56 @@ +From eeed5b5ef4cd41560be0d889032fb22b1bc8ab92 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Tue, 16 May 2023 15:38:43 +0200 +Subject: [PATCH] common: Correctly set default attributes for certificates + +The code did not set a default value for CKA_JAVA_MIDP_SECURITY_DOMAIN, but +incorrectly set CKA_TRUSTED twice. + +Similar CKA_NAME_HASH_ALGORITHM was not set, but CKA_CERTIFICATE_CATEGORY +was set twice, and with a wrong size. + +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptokieeed5b5ef4cd41560be0d889032fb22b1bc8ab92 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/lib/common/cert.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/usr/lib/common/cert.c b/usr/lib/common/cert.c +index 09d95673..7daea60c 100644 +--- a/usr/lib/common/cert.c ++++ b/usr/lib/common/cert.c +@@ -105,7 +105,7 @@ CK_RV cert_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) + *(CK_BBOOL *) trusted_attr->pValue = FALSE; + + category_attr->type = CKA_CERTIFICATE_CATEGORY; +- category_attr->ulValueLen = sizeof(CK_BBOOL); ++ category_attr->ulValueLen = sizeof(CK_CERTIFICATE_CATEGORY); + category_attr->pValue = (CK_BYTE *)category_attr + sizeof(CK_ATTRIBUTE); + *(CK_CERTIFICATE_CATEGORY *) category_attr->pValue = + CK_CERTIFICATE_CATEGORY_UNSPECIFIED; +@@ -363,14 +363,14 @@ CK_RV cert_x509_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) + issuer_hash_attr->ulValueLen = 0; // empty byte array + issuer_hash_attr->pValue = NULL; + +- sec_domain_attr->type = CKA_TRUSTED; +- sec_domain_attr->ulValueLen = sizeof(CK_BBOOL); ++ sec_domain_attr->type = CKA_JAVA_MIDP_SECURITY_DOMAIN; ++ sec_domain_attr->ulValueLen = sizeof(CK_JAVA_MIDP_SECURITY_DOMAIN); + sec_domain_attr->pValue = (CK_BYTE *)sec_domain_attr + sizeof(CK_ATTRIBUTE); + *(CK_JAVA_MIDP_SECURITY_DOMAIN *) sec_domain_attr->pValue = + CK_SECURITY_DOMAIN_UNSPECIFIED; + +- hash_mech_attr->type = CKA_CERTIFICATE_CATEGORY; +- hash_mech_attr->ulValueLen = sizeof(CK_BBOOL); ++ hash_mech_attr->type = CKA_NAME_HASH_ALGORITHM; ++ hash_mech_attr->ulValueLen = sizeof(CK_MECHANISM_TYPE); + hash_mech_attr->pValue = (CK_BYTE *)hash_mech_attr + sizeof(CK_ATTRIBUTE); + *(CK_MECHANISM_TYPE *) hash_mech_attr->pValue = CKM_SHA_1; + +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,122 @@ +From f71f3d2515f71c2c2031fbcdd10cbdaddc7b21cd Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Thu, 1 Jun 2023 12:07:03 +0200 +Subject: [PATCH] p11sak: fix length handling when importing and exporting an + EC public key + +A 521-bit EC key has a public key length of 133 bytes. Here, the BER encoding +of the EC-point needs a full byte for the length, and thus must use the long +form length with a 1 byte length field. This needs 3 bytes for the BER encoding. + +Reported-by: Joerg Schmidbauer +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptokif71f3d2515f71c2c2031fbcdd10cbdaddc7b21cd +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/sbin/p11sak/p11sak.c | 47 +++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 17 deletions(-) + +diff --git a/usr/sbin/p11sak/p11sak.c b/usr/sbin/p11sak/p11sak.c +index 3baae560..a6213720 100644 +--- a/usr/sbin/p11sak/p11sak.c ++++ b/usr/sbin/p11sak/p11sak.c +@@ -5455,6 +5455,7 @@ static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + const EC_POINT *ec_point = NULL; + unsigned char *point = NULL; + #endif ++ unsigned char *point_ptr; + size_t point_len = 0; + ASN1_OBJECT *obj = NULL; + unsigned char *ec_params = NULL; +@@ -5469,10 +5470,10 @@ static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + #if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, + group, sizeof(group), NULL) || +- (!private && /* leave 2 bytes space for DER encoding */ ++ (!private && /* leave 3 bytes space for DER encoding */ + !EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, +- point + 2, sizeof(point) - 2, ++ point + 3, sizeof(point) - 3, + &point_len)) || + (private && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { +@@ -5522,8 +5523,8 @@ static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + goto done; + } + +- /* Leave 2 bytes space for DER encoding of OCTET-STRING */ +- point = calloc(2 + point_len, 1); ++ /* Leave 3 bytes space for DER encoding of OCTET-STRING */ ++ point = calloc(3 + point_len, 1); + if (point == NULL) { + warnx("Failed to allocate buffer for EC point."); + rc = CKR_HOST_MEMORY; +@@ -5532,7 +5533,7 @@ static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + + if (EC_POINT_point2oct(ec_group, ec_point, + POINT_CONVERSION_UNCOMPRESSED, +- point + 2, point_len, NULL) != point_len) { ++ point + 3, point_len, NULL) != point_len) { + warnx("EC_POINT_point2oct failed."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; +@@ -5570,19 +5571,24 @@ static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + goto done; + } else { + /* CKA_EC_POINT needs DER encoded EC point */ +- if (!private) { +- if (point_len >= 0x80) { +- warnx("EC point is too long."); +- rc = CKR_FUNCTION_FAILED; +- goto done; +- } +- ++ if (point_len < 0x80) { ++ point[1] = 0x04; /* OCTET-STRING */ ++ point[2] = point_len & 0x7f; ++ point_len += 2; ++ point_ptr = &point[1]; ++ } else if (point_len < 0x0100) { + point[0] = 0x04; /* OCTET-STRING */ +- point[1] = point_len & 0x7f; ++ point[1] = 0x81; /* 1 byte length field */ ++ point[2] = point_len & 0xff; ++ point_len += 3; ++ point_ptr = &point[0]; ++ } else { ++ warnx("EC point is too long."); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; + } +- point_len += 2; + +- rc = add_attribute(CKA_EC_POINT, point, point_len, attrs, num_attrs); ++ rc = add_attribute(CKA_EC_POINT, point_ptr, point_len, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + } +@@ -6536,8 +6542,15 @@ static CK_RV p11sak_export_ec_pkey(const struct p11sak_keytype *keytype, + } + + /* remove octet string BER encoding */ +- ecpoint = (CK_BYTE*)ecpoint_attr.pValue + 2; +- ecpoint_len = ecpoint_attr.ulValueLen - 2; ++ ecpoint = (CK_BYTE*)ecpoint_attr.pValue; ++ ecpoint_len = ecpoint_attr.ulValueLen; ++ if ((ecpoint[1] & 0x80) == 0) { ++ ecpoint += 2; ++ ecpoint_len -= 2; ++ } else { ++ ecpoint += 2 + (ecpoint[1] & 0x7f); ++ ecpoint_len -= 3 + (ecpoint[1] & 0x7f); ++ } + } + + oid = ecparams_attr.pValue; +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,107 @@ +From 92999f344a3ad99a67a1bcfd9ad28f28c33e51bc Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Mon, 10 Jul 2023 10:19:13 +0200 +Subject: [PATCH] p11sak: Fix listing of key objects when other object types + are present + +A command like 'p11sak list-key all --slot N ...' fails with + + p11sak: Attribute CKA_KEY_TYPE is not available in key object + p11sak: Failed to iterate over key objects for key type All: 0xD0: CKR_TEMPLATE_INCOMPLETE + p11sak: Failed to perform the 'list-key' command: CKR_TEMPLATE_INCOMPLETE + +when the object repository contains other, non-key objects, e.g. certificates. + +When 'all' is used as key type, then no filter for CKA_KEY_TYPE is used +with C_FindObjects(), and thus other non-key objects also match the filter. +When a specific key type is specified, then only such objects match that +have the desired CKA_KEY_TYPE attribute value. + +Fix this by checking the object class in get_key_infos() and skip the object, +if it is not a key object. + +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptoki92999f344a3ad99a67a1bcfd9ad28f28c33e51bc +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/sbin/p11sak/p11sak.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/usr/sbin/p11sak/p11sak.c b/usr/sbin/p11sak/p11sak.c +index a6213720..6e11cb41 100644 +--- a/usr/sbin/p11sak/p11sak.c ++++ b/usr/sbin/p11sak/p11sak.c +@@ -3403,6 +3403,16 @@ static CK_RV get_key_infos(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS *class, + } + } + ++ switch (class_val) { ++ case CKO_PUBLIC_KEY: ++ case CKO_PRIVATE_KEY: ++ case CKO_SECRET_KEY: ++ break; ++ default: ++ free(attrs[0].pValue); ++ return CKR_KEY_NEEDED; ++ } ++ + for (i = 0; i < num_attrs; i++) { + if (attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + warnx("Attribute %s is not available in key object", +@@ -3614,6 +3624,10 @@ static CK_RV iterate_key_objects(const struct p11sak_keytype *keytype, + if (manual_filtering) { + rc = get_key_infos(keys[i], NULL, NULL, NULL, &label, + NULL, NULL); ++ if (rc == CKR_KEY_NEEDED) { ++ rc = CKR_OK; ++ goto next; ++ } + if (rc != CKR_OK) + break; + +@@ -3672,6 +3686,10 @@ done_find: + for (i = 0; i < num_matched_keys; i++) { + rc = get_key_infos(matched_keys[i], &class, &ktype, &keysize, + &label, &typestr, &type); ++ if (rc == CKR_KEY_NEEDED) { ++ rc = CKR_OK; ++ goto next2; ++ } + if (rc != CKR_OK) + break; + +@@ -3680,6 +3698,7 @@ done_find: + if (rc != CKR_OK) + break; + ++next2: + if (label != NULL) + free(label); + label = NULL; +@@ -4480,10 +4499,20 @@ static CK_RV p11sak_list_key_compare(CK_OBJECT_HANDLE key1, + *result = 0; + + rc = get_key_infos(key1, &class1, &ktype1, &keysize1, &label1, NULL, NULL); ++ if (rc == CKR_KEY_NEEDED) { ++ rc = CKR_OK; ++ *result = 1; /* non-key objects are always greater than key objects */ ++ goto done; ++ } + if (rc != CKR_OK) + goto done; + + rc = get_key_infos(key2, &class2, &ktype2, &keysize2, &label2, NULL, NULL); ++ if (rc == CKR_KEY_NEEDED) { ++ rc = CKR_OK; ++ *result = -1; /* key objects are always smaller than non-key objects */ ++ goto done; ++ } + if (rc != CKR_OK) + goto done; + +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,44 @@ +From 2ba0f41ef5e14d4b509c8854e27cf98e3ee89445 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Mon, 10 Jul 2023 13:22:48 +0200 +Subject: [PATCH] p11sak: Fix parsing of slot number 0 + +Running command 'p11sak list-key aes --slot 0' may result in +'p11sak: Invalid argument '0' for option '-s/--slot'' + +This is because of the error checking after strtoul() within function +process_number_argument(). In case errno is not zero, it treats a +parsed value of zero as an error. + +Under certain circumstances, errno is non-zero already before calling +strtoul(), and stays non-zero in case of strtoul() succeeds. This leads to +an incorrect error checking, and it is treated as error. + +Initialize errno to zero before calling strtoul() to avoid such false error +detection. + +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptoki2ba0f41ef5e14d4b509c8854e27cf98e3ee89445 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/sbin/p11sak/p11sak.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/usr/sbin/p11sak/p11sak.c b/usr/sbin/p11sak/p11sak.c +index 6e11cb41..38665bbd 100644 +--- a/usr/sbin/p11sak/p11sak.c ++++ b/usr/sbin/p11sak/p11sak.c +@@ -1712,6 +1712,7 @@ static CK_RV process_number_argument(const struct p11sak_arg *arg, char *val) + { + char *endptr; + ++ errno = 0; + *arg->value.number = strtoul(val, &endptr, 0); + + if ((errno == ERANGE && *arg->value.number == ULONG_MAX) || +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,63 @@ +From 43a4dc59a574bf056e6eeb96503d404e47e3d3d5 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Mon, 22 May 2023 11:40:01 +0200 +Subject: [PATCH] p11sak: Fix user confirmation prompt behavior when stdin is + closed + +Treat any error during user confirmation prompt as 'cancel' and skip all +operations. + +One can for example close stdin during a user prompt via CTRL+D. This was +erroneously treated as positive confirmation and therefore caused the +operation to be performed on the current key object and all further objects +matching the filter as well, instead of canceling the operation entirely. + +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptoki43a4dc59a574bf056e6eeb96503d404e47e3d3d5 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/sbin/p11sak/p11sak.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/usr/sbin/p11sak/p11sak.c b/usr/sbin/p11sak/p11sak.c +index d75d8343..5b54b538 100644 +--- a/usr/sbin/p11sak/p11sak.c ++++ b/usr/sbin/p11sak/p11sak.c +@@ -4736,6 +4736,7 @@ static CK_RV handle_key_remove(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + data->num_skipped++; + return CKR_OK; + case 'c': ++ case '\0': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; +@@ -4825,6 +4826,7 @@ static CK_RV handle_key_set_attr(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + data->num_skipped++; + return CKR_OK; + case 'c': ++ case '\0': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; +@@ -4974,6 +4976,7 @@ static CK_RV handle_key_copy(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + data->num_skipped++; + return CKR_OK; + case 'c': ++ case '\0': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; +@@ -6983,6 +6986,7 @@ static CK_RV handle_key_export(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + data->num_skipped++; + return CKR_OK; + case 'c': ++ case '\0': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-pkcsstats-Fix-handling-of-user-name.patch opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-pkcsstats-Fix-handling-of-user-name.patch --- opencryptoki-3.20.0+dfsg/debian/patches/lp-2026732-pkcsstats-Fix-handling-of-user-name.patch 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/lp-2026732-pkcsstats-Fix-handling-of-user-name.patch 2023-07-07 12:15:35.000000000 +0200 @@ -0,0 +1,94 @@ +From bd40bb884a6ff23b42a48237f74eb0df4d1daec1 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Mon, 22 May 2023 13:31:21 +0200 +Subject: [PATCH] pkcsstats: Fix handling of user name + +The struct passwd returned by getpwuid() is a pointer to a static area, that +may get overwritten by subsequent calls to getpwuid() or similar. +Actually, C_Initialize() itself is using getpwuid() internally, and thus will +interfere with the getpwuid() usage in pkcsstats. + +Make a copy of the returned user name before calling C_Initialize() in +init_ock() to ensure to work with the desired user name, and not with anything +left over from previous calls. + +Signed-off-by: Ingo Franzki + +Origin: upstream, https://github.com/opencryptoki/opencryptokibd40bb884a6ff23b42a48237f74eb0df4d1daec1 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2026732 +Last-Update: 2023-07-19 + +--- + usr/sbin/pkcsstats/pkcsstats.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/usr/sbin/pkcsstats/pkcsstats.c b/usr/sbin/pkcsstats/pkcsstats.c +index c2444cf5..a842a295 100644 +--- a/usr/sbin/pkcsstats/pkcsstats.c ++++ b/usr/sbin/pkcsstats/pkcsstats.c +@@ -783,6 +783,7 @@ int main(int argc, char **argv) + int opt = 0; + struct passwd *pswd = NULL; + int user_id = -1; ++ char *user_name = NULL; + bool summary = false, all_users = false, all_mechs = false; + bool reset = false, reset_all = false; + bool delete = false, delete_all = false; +@@ -903,19 +904,27 @@ int main(int argc, char **argv) + } + } + ++ user_name = strdup(pswd->pw_name); ++ if (user_name == NULL) { ++ warnx("Failed to get current user name"); ++ exit(EXIT_FAILURE); ++ } ++ + if (delete) { + if (slot_id_specified) { + warnx("Options -s/--slot and -d/--delete can not be specified together"); ++ free(user_name); + exit(EXIT_FAILURE); + } + +- rc = delete_shm(user_id, pswd->pw_name); ++ rc = delete_shm(user_id, user_name); + goto done; + } + + if (delete_all) { + if (slot_id_specified) { + warnx("Options -s/--slot and -D/--delete-all can not be specified together"); ++ free(user_name); + exit(EXIT_FAILURE); + } + +@@ -932,7 +941,7 @@ int main(int argc, char **argv) + goto done; + + if (reset) { +- rc = reset_shm(user_id, pswd->pw_name, num_slots, slots, ++ rc = reset_shm(user_id, user_name, num_slots, slots, + slot_id_specified, slot_id); + goto done; + } +@@ -968,7 +977,7 @@ int main(int argc, char **argv) + rc = display_summary(&dd); + goto done; + } else { +- rc = display_stats(user_id, pswd->pw_name, &dd); ++ rc = display_stats(user_id, user_name, &dd); + goto done; + } + +@@ -984,5 +993,7 @@ done: + dlclose(dll); + } + ++ free(user_name); ++ + return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } +-- +2.25.1 + diff -Nru opencryptoki-3.20.0+dfsg/debian/patches/series opencryptoki-3.21.0+dfsg/debian/patches/series --- opencryptoki-3.20.0+dfsg/debian/patches/series 2023-02-13 10:10:45.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/debian/patches/series 2023-07-07 12:15:35.000000000 +0200 @@ -3,3 +3,10 @@ 04-pkcsslotd-cmdline-args.patch lp-1982842-move-pkcs11-group-assigment-from-makefile-to-postinst.patch + +lp-2026732-common-Correctly-set-default-attributes-for-certific.patch +lp-2026732-p11sak-Fix-user-confirmation-prompt-behavior-when-st.patch +lp-2026732-pkcsstats-Fix-handling-of-user-name.patch +lp-2026732-p11sak-fix-length-handling-when-importing-and-export.patch +lp-2026732-p11sak-Fix-listing-of-key-objects-when-other-object-.patch +lp-2026732-p11sak-Fix-parsing-of-slot-number-0.patch diff -Nru opencryptoki-3.20.0+dfsg/debian/rules opencryptoki-3.21.0+dfsg/debian/rules --- opencryptoki-3.20.0+dfsg/debian/rules 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/rules 2023-07-07 12:15:35.000000000 +0200 @@ -31,6 +31,7 @@ libopencryptoki.so PKCS11_API.so # Removing useless files + rm -rf debian/tmp/etc/ld.so.conf.d rm -rf debian/tmp/etc/init.d rm -f debian/tmp/usr/include/Makefile* rm -f debian/tmp/usr/include/*/Makefile* diff -Nru opencryptoki-3.20.0+dfsg/debian/triggers opencryptoki-3.21.0+dfsg/debian/triggers --- opencryptoki-3.20.0+dfsg/debian/triggers 2023-05-31 21:28:48.000000000 +0200 +++ opencryptoki-3.21.0+dfsg/debian/triggers 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -activate-noawait ldconfig diff -Nru opencryptoki-3.20.0+dfsg/.gitignore opencryptoki-3.21.0+dfsg/.gitignore --- opencryptoki-3.20.0+dfsg/.gitignore 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/.gitignore 2023-05-15 14:42:55.000000000 +0200 @@ -74,6 +74,7 @@ usr/sbin/pkcstok_migrate/pkcstok_migrate usr/sbin/pkcsep11_migrate/pkcsep11_migrate usr/sbin/pkcsep11_session/pkcsep11_session +usr/sbin/pkcshsm_mk_change/pkcshsm_mk_change tools/policyexamplegen tools/tableidxgen @@ -95,6 +96,7 @@ man/man1/pkcscca.1 man/man1/pkcsconf.1 man/man1/pkcsstats.1 +man/man1/pkcshsm_mk_change.1 man/man5/policy.conf.5 man/man5/p11sak_defined_attrs.conf.5 man/man5/opencryptoki.conf.5 diff -Nru opencryptoki-3.20.0+dfsg/Makefile.am opencryptoki-3.21.0+dfsg/Makefile.am --- opencryptoki-3.20.0+dfsg/Makefile.am 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/Makefile.am 2023-05-15 14:42:55.000000000 +0200 @@ -39,7 +39,15 @@ include doc/doc.mk install-data-hook: - getent group pkcs11 > /dev/null || $(GROUPADD) -r pkcs11 + getent group $(pkcs_group) > /dev/null || $(GROUPADD) -r $(pkcs_group) + getent passwd $(pkcsslotd_user) >/dev/null || $(USERADD) -r -g $(pkcs_group) -d /run/opencryptoki -s /sbin/nologin -c "Opencryptoki pkcsslotd user" $(pkcsslotd_user) + $(MKDIR_P) $(DESTDIR)/run/opencryptoki/ + $(CHOWN) $(pkcsslotd_user):$(pkcs_group) $(DESTDIR)/run/opencryptoki/ + $(CHGRP) $(pkcs_group) $(DESTDIR)/run/opencryptoki/ + $(CHMOD) 0710 $(DESTDIR)/run/opencryptoki/ + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki + $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki if ENABLE_LIBRARY $(MKDIR_P) $(DESTDIR)$(libdir)/opencryptoki/stdll $(MKDIR_P) $(DESTDIR)$(libdir)/pkcs11 @@ -56,16 +64,21 @@ cd $(DESTDIR)$(libdir)/pkcs11 && \ ln -nfs ../opencryptoki/stdll/ stdll endif +if ENABLE_PKCSHSM_MK_CHANGE + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE + $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/HSM_MK_CHANGE +endif if ENABLE_CCATOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_cca.so PKCS11_CCA.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ccatok $(MKDIR_P) $(DESTDIR)$(lockdir)/ccatok - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/ccatok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/ccatok $(CHMOD) 0770 $(DESTDIR)$(lockdir)/ccatok test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/ccatok.conf || $(INSTALL) -m 644 $(srcdir)/usr/lib/cca_stdll/ccatok.conf $(DESTDIR)$(sysconfdir)/opencryptoki/ccatok.conf || true @@ -74,12 +87,12 @@ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_ep11.so PKCS11_EP11.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/ep11tok $(MKDIR_P) $(DESTDIR)$(lockdir)/ep11tok - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/ep11tok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/ep11tok $(CHMOD) 0770 $(DESTDIR)$(lockdir)/ep11tok test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/ep11tok.conf || $(INSTALL) -m 644 $(srcdir)/usr/lib/ep11_stdll/ep11tok.conf $(DESTDIR)$(sysconfdir)/opencryptoki/ep11tok.conf || true @@ -87,30 +100,30 @@ endif if ENABLE_P11SAK test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true - test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -g pkcs11 -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true + test -f $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || $(INSTALL) -g $(pkcs_group) -m 0640 $(srcdir)/usr/sbin/p11sak/p11sak_defined_attrs.conf $(DESTDIR)$(sysconfdir)/opencryptoki/p11sak_defined_attrs.conf || true endif if ENABLE_ICATOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_ica.so PKCS11_ICA.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/lite $(MKDIR_P) $(DESTDIR)$(lockdir)/lite - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/lite + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/lite $(CHMOD) 0770 $(DESTDIR)$(lockdir)/lite endif if ENABLE_SWTOK cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_sw.so PKCS11_SW.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok/TOK_OBJ $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/swtok $(MKDIR_P) $(DESTDIR)$(lockdir)/swtok - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/swtok + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/swtok $(CHMOD) 0770 $(DESTDIR)$(lockdir)/swtok endif if ENABLE_TPMTOK @@ -118,10 +131,10 @@ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_tpm.so PKCS11_TPM.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm $(MKDIR_P) $(DESTDIR)$(lockdir)/tpm - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/tpm + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/tpm $(CHMOD) 0770 $(DESTDIR)$(lockdir)/tpm endif if ENABLE_ICSFTOK @@ -129,16 +142,16 @@ cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ ln -fs libpkcs11_icsf.so PKCS11_ICSF.so $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf - $(CHGRP) pkcs11 $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf + $(CHGRP) $(pkcs_group) $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf $(MKDIR_P) $(DESTDIR)$(lockdir)/icsf - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/icsf + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir)/icsf $(CHMOD) 0770 $(DESTDIR)$(lockdir)/icsf endif if ENABLE_DAEMON test -f $(DESTDIR)$(sysconfdir)/opencryptoki || $(MKDIR_P) $(DESTDIR)$(sysconfdir)/opencryptoki || true test -f $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || $(INSTALL) -m 644 $(srcdir)/usr/sbin/pkcsslotd/opencryptoki.conf $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || true - test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -g pkcs11 -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true + test -f $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || $(INSTALL) -m 640 -o root -g $(pkcs_group) -T $(srcdir)/doc/strength-example.conf $(DESTDIR)$(sysconfdir)/opencryptoki/strength.conf || true endif $(MKDIR_P) $(DESTDIR)/etc/ld.so.conf.d echo "$(libdir)/opencryptoki" >\ @@ -149,7 +162,7 @@ @echo "Remember you must run ldconfig before using the above settings" @echo "--------------------------------------------------------------" $(MKDIR_P) $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) - $(CHGRP) pkcs11 $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) + $(CHGRP) $(pkcs_group) $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) $(CHMOD) 0770 $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) diff -Nru opencryptoki-3.20.0+dfsg/man/man1/man1.mk opencryptoki-3.21.0+dfsg/man/man1/man1.mk --- opencryptoki-3.20.0+dfsg/man/man1/man1.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man1/man1.mk 2023-05-15 14:42:55.000000000 +0200 @@ -1,5 +1,9 @@ man1_MANS += man/man1/pkcsconf.1 man/man1/pkcsicsf.1 +if ENABLE_PKCSHSM_MK_CHANGE +man1_MANS += man/man1/pkcshsm_mk_change.1 +endif + if ENABLE_PKCSSTATS man1_MANS += man/man1/pkcsstats.1 endif diff -Nru opencryptoki-3.20.0+dfsg/man/man1/p11sak.1.in opencryptoki-3.21.0+dfsg/man/man1/p11sak.1.in --- opencryptoki-3.20.0+dfsg/man/man1/p11sak.1.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man1/p11sak.1.in 2023-05-15 14:42:55.000000000 +0200 @@ -1,519 +1,1276 @@ .TH P11SAK 1 "May 2020" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME -p11sak \- generate and list token keys in an openCryptoki token repository. +p11sak \- Manage token keys in a PKCS\~#11 token repository. +. . . .SH SYNOPSIS .B p11sak .I command -.RI [ ARGS ] +.RB [ ARGUMENTS ] .RB [ OPTIONS ] -. .PP +. .B p11sak .BR \-\-help | \-h .br - -.SH DESCRIPTION -.B p11sak can be used to generate, list and delete the token keys in an openCryptoki token repository. -The utility provides a flexible key management tool in openCryptoki to list and generate symmetric (DES, 3DES, AES, AES-XTS) and asymmetric (RSA, EC, IBM Dilithium, IBM Kyber) keys. -This tool is especially capable of a well defined listing of keys with their PKCS #11 attributes. +.B p11sak +.BR \-\-version | \-v . . . -.SH COMMANDS -The \fBp11sak\fP tool can operate in three modes: when command -.I generate-key -is specified, it operates in the mode to generate a token key in the openCryptoki token repository. -If command -.I list-key -is given, it lists the keys specified in the arguments. -If command -.I remove-key -is given, it removes the keys specified in the arguments. -. -.PP -.SS "generate-key" -.PP -Use the -.B generate-key|gen-key|gen -command and key argument to generate a token key with the respective -.RI [ ARGS ] -and -.RB [ OPTIONS ]. -The -.BR \-\-help | \-h -option will show the arguments and options available. -. -.PP -.SS "list-key" +.SH DESCRIPTION +The \fBp11sak\fP tool can be used to manage token keys in a PKCS\~#11 token +repository. The utility provides a flexible key management tool to generate, +list, remove, update, copy, import, and export symmetric (DES, 3DES, generic, +AES, AES\-XTS) and asymmetric (RSA, DH, DSA, EC, IBM Dilithium, IBM Kyber) keys. +This tool is also capable of listing the keys with their PKCS\~#11 attributes +and its values (not all attributes may be displayed if a keys is sensitive). .PP -Use the -.B list-key|ls-key|ls -command and key argument to list token keys given the respective -.RI [ ARGS ] -and -.RB [ OPTIONS ]. +.B Note: The -.BR \-\-help | \-h -option will show the arguments and options available. +.B p11sak +tool only operates on token keys (i.e. \fBCKA_TOKEN=TRUE\fP), but not on +session keys (\fBCKA_TOKEN=FALSE\fP). Token keys are stored persistently in the +token's repository, while session keys are not stored persistently, and only +exist as long as the session is alive. Thus, session keys generated or imported +by the +.B p11sak +tool would not exist anymore when the +.B p11sak +tool has exited. +. . +. +.SH COMMANDS +The \fBp11sak\fP tool supports various commands to generate, list, remove, +update, import, and export token keys in a PKCS\~#11 token repository. .PP -.SS "remove-key" +.SS "Generating symmetric and asymmetric keys" +.B p11sak +.BR generate\-key | gen\-key | gen +.I KEYTYPE +.RB [ ARGUMENTS ] +.RB [ OPTIONS ] .PP Use the -.B remove-key|rm-key|rm -command and key argument to delete token keys given the respective -.RI [ ARGS ] +.BR generate\-key | gen\-key | gen +command to generate a token key of the specified +.I KEYTYPE +with the respective +.B ARGUMENTS and -.RB [ OPTIONS ]. -The +.BR OPTIONS . +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber . +See below for a detailed description of the arguments and options. The .BR \-\-help | \-h -option will show the arguments and options available. +option will also show the arguments and options available. . .PP .SS "Generating DES/3DES keys" . .B p11sak -.BR generate-key | gen-key | gen +.BR generate\-key | gen\-key | gen .BR des | 3des -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.I LABEL +.BR \-\-attr | \-a +.I ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key +.BR generate\-key | gen\-key | gen command with the .B des|3des -key argument to generate a DES or 3DES key. The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +.I KEYTYPE +argument to generate a DES or 3DES key (\fBCKK_DES\fP or \fBCKK_DES3\fP). The +.BR \-\-label | \-L +.I LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. +.PP +.SS "Generating generic secret keys" +. +.B p11sak +.BR generate\-key | gen\-key | gen +.BR generic +.I KEYBITS +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.I LABEL +.BR \-\-attr | \-a +.I ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] +.PP +Use the +.BR generate\-key | gen\-key | gen +.B generic +.I KEYBITS +command and +.I KEYTYPE +argument to generate a generic secret key (\fBCKK_GENERIC_SECRET\fP) with the +key size in bits as specified by the +.I KEYBITS +argument.The +.BR \-\-label | \-L +.I LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP .SS "Generating AES keys" . .B p11sak -.BR generate-key | gen-key | gen +.BR generate\-key | gen\-key | gen .BR aes .BR 128 | 192 | 256 -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.I LABEL +.BR \-\-attr | \-a +.I ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key +.BR generate\-key | gen\-key | gen .B aes .B 128|192|256 -command and key argument to generate a AES key with 128, 192 or 256 bit length, respectively. The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +command and +.I KEYTYPE +argument to generate a AES key (\fBCKK_AES\fP) with 128-, 192-, or 256-bit +length, respectively. The +.BR \-\-label | \-L +.I LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP -.SS "Generating AES-XTS keys" +.SS "Generating AES\-XTS keys" . .B p11sak -.BR generate-key | gen-key | gen -.BR aes-xts +.BR generate\-key | gen\-key | gen +.BR aes\-xts .BR 128 | 256 -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.I LABEL +.BR \-\-attr | \-a +.I ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key -.B aes-xts +.BR generate\-key | gen\-key | gen +.B aes\-xts .B 128|256 -command and key argument to generate a AES-XTS key with 128 or 256 bit length, respectively. The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +command and +.I KEYTYPE +argument to generate a AES\-XTS key (\fBCKK_AES_XTS\fP) with 128- or 256-bit +length, respectively. The +.BR \-\-label | \-L +.I LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP .SS "Generating RSA keys" . .B p11sak -.BR generate-key | gen-key | gen +.BR generate\-key | gen\-key | gen .BR rsa -.BR 1024 | 2048 | 4096 -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-exponent -.IR EXP -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR 512 | 1024 | 2048 | 4096 +.RI [ PUBL\-EXP ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key +.BR generate\-key | gen\-key | gen .B rsa .B 1024|2048|4096 -command and key argument to generate a 1024, 2048 or 4096 bit RSA key, respectively. The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). Furthermore, the -.B \-\-exponent -.IR EXP -options allows the user to specify the exponent used for generating the RSA key. The default is set to 65537 according to the PKCS #11 standard. +command and +.I KEYTYPE +argument to generate an 512-, 1024-, 2048-, or 4096-bit RSA key (\fBCKK_RSA\fP), +respectively. The +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. Furthermore, the optional +.I PUBL\-EXP +argument allows the user to specify the exponent used for generating the RSA +key. The default is set to 65537 according to the PKCS\~#11 standard. +. +.PP +.SS "Generating DH keys" +. +.B p11sak +.BR generate\-key | gen\-key | gen +.BR dh +.IR GROUP | DH\-PARAM\-PEM\-FILE +.RI [ PRIV\-BITS ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] +.PP +Use the +.BR generate\-key | gen\-key | gen +.B dh +.IR GROUP | DH\-PARAM\-PEM\-FILE +command and +.I KEYTYPE +argument to generate a DH key (\fBCKK_DH\fP), where +.I GROUP +specifies the Diffie\-Hellman FFC group name or +.I DH\-PARAM\-PEM\-FILE +specifies the name of a DH parameters PEM file. +The following arguments can be used for respective groups: +.BR ffdhe2048 | ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192 | modp1536 | \ +modp2048 | modp3072 | modp4096 | modp6144 | modp8192 +.PP +.B Note: +Not all groups are supported by all tokens and key generation will fail +when the specified +.I GROUP +is not supported. Also, not all groups are supported by all OpenSSL versions. +If the +.B p11sak +tool is compiled against an OpenSSL version that does not support certain +groups, then those groups are not accepted for the +.I GROUP +argument. +.PP +Alternatively, specify a DH parameters PEM file as +.I DH\-PARAM\-PEM\-FILE +argument. You can for example generate DH parameters using the +.B OpenSSL +command line tool as follows: '\fBopenssl dhparam \-out +\-outform PEM'\fP. See the OpenSSL man page for details about this command. +.PP +The +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. Furthermore, the optional +.I PRIV\-BITS +argument allows the user to specify the size of the private key in bits. +. +.PP +.SS "Generating DSA keys" . +.B p11sak +.BR generate\-key | gen\-key | gen +.BR dsa +.I DSA\-PARAM\-PEM\-FILE +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] +.PP +Use the +.BR generate\-key | gen\-key | gen +.B dsa +.I DSA\-PARAM\-PEM\-FILE +command and +.I KEYTYPE +argument to generate a DSA key (\fBCKK_DSA\fP), where +.I DSA\-PARAM\-PEM\-FILE +specifies the name of a DSA parameters PEM file. You can for example generate +DSA parameters using the +.B OpenSSL +command line tool as follows: '\fBopenssl dsaparam \-out +\-outform PEM'\fP. See the OpenSSL man page for details about this command. +.PP +The +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. .PP .SS "Generating EC keys" . .B p11sak -.BR generate-key | gen-key | gen +.BR generate\-key | gen\-key | gen .BR ec -.BR CURVE -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -.B \-\-help | \-h +.I CURVE +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key +.BR generate\-key | gen\-key | gen .B ec -.B CURVE -command and key argument to generate an EC key, where .I CURVE -specifies the eliptic curve used to create the EC key. The following arguments can be used for respective curves: -.B prime256v1 | prime192 | secp224 | secp384r1 | secp521r1 | secp265k1 | brainpoolP160r1 | brainpoolP160t1 -.B | brainpoolP192r1 | brainpoolP192t1 | brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 -.B | brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | brainpoolP512r1 | brainpoolP512t1 -.B | curve25519 | curve448 | ed25519 | ed448 +command and +.I KEYTYPE +argument to generate an EC key (\fBCKK_EC\fP), where +.I CURVE +specifies the elliptic curve used to create the EC key. The following arguments +can be used for respective curves: +.BR prime256v1 | prime192 | secp224 | secp384r1 | secp521r1 | secp265k1 | \ +brainpoolP160r1 | brainpoolP160t1 | brainpoolP192r1 | brainpoolP192t1 | \ +brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 | \ +brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | \ +brainpoolP512r1 | brainpoolP512t1 | curve25519 | curve448 | ed25519 | ed448 .PP .B Note: -not all curves will be supported by all tokens and key generation will fail when the specified +Not all curves will be supported by all tokens and key generation will fail +when the specified .I CURVE -is not supported. The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [P M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +is not supported. +.PP +The +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +option can be used to set the boolean attributes of the key (see below for +detailed description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP .SS "Generating IBM Dilithium keys" . .B p11sak -.BR generate-key | gen-key | gen -.BR ibm-dilithium -.BR VERSION -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.IR [M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR generate\-key | gen\-key | gen +.BR ibm\-dilithium +.I VERSION +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key -.B ibm-dilithium -.B VERSION -command and key argument to generate an IBM Dilithium key, where +.BR generate\-key | gen\-key | gen +.B ibm\-dilithium +.I VERSION +command and +.I KEYTYPE +argument to generate an IBM Dilithium key (\fBCKK_IBM_PQC_DILITHIUM\fP), where +.I VERSION +specifies the version of the IBM Dilithium keypair. The following arguments can +be used for respective keys: +.BR r2_65 | r2_87 | r2_44 | r3_65 | r3_87 +.PP +.B Note: +Not all IBM Dilithium versions will be supported by all tokens and key +generation will fail when the specified .I VERSION -specifies the version of the IBM Dilithium keypair. The following arguments can be used for respective keys: -.B r2_65 | r2_87 | r3_44 | r3_65 | r3_87 +is not supported. .PP The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.IR [M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +can be used to set the boolean attributes of the key (see below for detailed +description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP .SS "Generating IBM Kyber keys" . .B p11sak -.BR generate-key | gen-key | gen -.BR ibm-kyber -.BR VERSION -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-attr -.I [M R L S E D G V W U A X N T] -.B \-\-help | \-h +.BR generate\-key | gen\-key | gen +.BR ibm\-kyber +.I VERSION +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-help | \-h ] .PP Use the -.B generate-key -.B ibm-kyber -.B VERSION -command and key argument to generate an IBM Kyber key, where +.BR generate\-key | gen\-key | gen +.B ibm\-kyber +.I VERSION +command and +.I KEYTYPE +argument to generate an IBM Kyber key (\fBCKK_IBM_PQC_KYBER\fP), where +.I VERSION +specifies the version of the IBM Kyber keypair. The following arguments can +be used for respective keys: +.BR r2_768 | r2_1024 +.PP +.B Note: +Not all IBM Kyber versions will be supported by all tokens and key +generation will fail when the specified .I VERSION -specifies the version of the IBM Kyber keypair. The following arguments can be used for respective keys: -.B r2_768 | r2_1024 +is not supported. .PP The -.B \-\-slot -.IR SLOTID -and -.B \-\-pin -.IR PIN -options are required to set the token to -.IR SLOTID -and the token PIN. The -.B \-\-label -option allows the user to set the -.IR LABEL -attribute of the key and -.B \-\-attr -.I [M R L S E D G V W U A X N T] -can be used to set the binary attributes of the key (see below for detailed description of the attributes). +.BR \-\-label | \-L +.IR LABEL | PUB\-LABEL : PRIV\-LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +can be used to set the boolean attributes of the key (see below for detailed +description of the attributes). +Optionally, set individual key attributes for public and private key separated +by a colon (\fB:\fP). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. . .PP .SS "Listing symmetric and asymmetric keys" . .B p11sak -.BR list-key | ls-key | ls -.BR des | 3des | aes | aes-xts | rsa | ec | ibm-dilithium | ibm-kyber | public | private | secret | all -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-long | \-l -.B \-\-help | \-h +.BR list\-key | ls\-key | ls +.RI [ KEYTYPE ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.RB [ \-\-label | \-L +.IR LABEL ] +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.RB [ \-\-long | \-l ] +.RB [ \-\-detailed\-uri ] +.RB [ \-\-sort | \-S +.IR SORT-SPEC ] +.RB [ \-\-help | \-h ] .PP Use the -.B list-key | ls-key | ls -command and key argument to list DES, 3DES, AES, AES-XTS, RSA, EC, IBM Dilithium, or IBM Kyber keys, respectively. Public, private, secret, or all keys can also be listed irrespective of key type. +.BR list\-key | ls\-key | ls +command and the optional +.I KEYTYPE +argument to list symmetric or asymmetric keys. Public, private, secret, or all +keys can also be listed irrespective of the key type. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +If +.I KEYTYPE +is omitted, then all key types are listed. +.PP +Specify the +.BR \-\-label | \-L +.IR LABEL , +the +.BR \-\-id | \-i +.IR ID , +and/or the +.BR \-\-attr | \-a +.I ATTRS +options to filter the list of keys to display. You can use wildcards (\fB*\fP +and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +The +.B ID +must be specified as hex string (not prefixed with 0x) of any number of bytes. +.PP +By default, the keys are listed in a short, tabular format showing only the +boolean attributes, the key type (\fBCKA_KEY_TYPE\fP) and the key label +(\fPCKA_LABEL\fP). The attributes are denoted using the same single letters +as used with the +.BR \-\-attr | \-a +.IR ATTRS | PUB\-ATTRS : PRIV\-ATTRS +option. When option +.BR \-\-long | \-l +is specified, the keys are listed in long format, displaying the values of all +attributes defined for the key type, including non-boolean attributes. +.PP +By default, the keys are displayed in the order as they are retrieved from the +PKCS\~#11 implementation. To display the keys in a certain order, specify the +.BR \-\-sort | \-S +.I SORT-SPEC +option. You can sort the keys by label, key type, object class, and/or key size. +For details, see the description of the +.BR \-\-sort | \-S +.I SORT-SPEC +option below. . .PP .SS "Deleting symmetric and asymmetric keys" . .B p11sak -.BR remove-key | rm-key | rm -.BR des | 3des | aes | aes-xts | rsa | ec | ibm-dilithium | ibm-kyber -.B \-\-slot -.IR SLOTID -.B \-\-pin -.IR PIN -.B \-\-label -.IR LABEL -.B \-\-force | \-f -.B \-\-help | \-h +.BR remove\-key | rm\-key | rm +.RI [ KEYTYPE ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.RB [ \-\-label | \-L +.IR LABEL ] +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.RB [ \-\-long | \-l ] +.RB [ \-\-force | \-f ] +.RB [ \-\-help | \-h ] .PP Use the -.B remove-key | rm-key | rm -command and key argument to delete DES, 3DES, AES, AES-XTS, RSA, EC, IBM Dilithium, or IBM Kyber keys, respectively. All specified cipher keys will be prompted to be deleted unless -a specific key with the -.B \-\-label -.IR LABEL -argument is selected. The user will be promted to confirm the deletion of the key. To suppress the promt, use the -.B \-\-force | \-f +.BR remove\-key | rm\-key | rm +command and the optional +.I KEYTYPE +argument to remove symmetric or asymmetric keys. Public, private, secret, or all +keys can also be selected for removal irrespective of the key type. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +If +.I KEYTYPE +is omitted, then all key types are selected for removal. +.PP +Specify the +.BR \-\-label | \-L +.IR LABEL , +the +.BR \-\-id | \-i +.IR ID , +and/or the +.BR \-\-attr | \-a +.I ATTRS +options to filter the list of keys to display. You can use wildcards (\fB*\fP +and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +The +.B ID +must be specified as hex string (not prefixed with 0x) of any number of bytes. +.PP +The user will be prompted to confirm the removal of the key. To suppress the +prompt, use the +.BR \-\-force | \-f option. -. .PP . +.SS "Setting or updating boolean attributes of symmetric and asymmetric keys" . +.B p11sak +.BR set\-key\-attr | set\-key | set +.RI [ KEYTYPE ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.RB [ \-\-label | \-L +.IR LABEL ] +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.RB [ \-\-force | \-f ] +.RB [ \-\-new\-attr | \-A +.IR ATTRS ] +.RB [ \-\-new\-label | \-l +.IR LABEL ] +.RB [ \-\-new\-id | \-I +.IR ID ] +.RB [ \-\-help | \-h ] +.PP +Use the +.B set\-key\-attrs | set\-key | set +command and the optional +.I KEYTYPE +argument to set or update boolean attributes of symmetric or asymmetric keys. +Public, private, secret, or all keys can also be selected for updating +irrespective of the key type. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +If +.I KEYTYPE +is omitted, then all key types are selected for updating. +.PP +Specify the +.BR \-\-label | \-L +.IR LABEL , +the +.BR \-\-id | \-i +.IR ID , +and/or the +.BR \-\-attr | \-a +.I ATTRS +options to filter the list of keys to display. You can use wildcards (\fB*\fP +and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +The +.B ID +must be specified as hex string (not prefixed with 0x) of any number of bytes. +.PP +Use the +.BR \-\-new\-attr | \-A +.I ATTRS +option to specify the boolean attributes of the key you want to update (see +below for detailed description of the attributes). Attributes that are not +specified are not changed. Use the +.BR \-\-new\-label | \-l +.I LABEL +option to specify the new label, or the +.BR \-\-new\-id | \-I +.I ID +option to specify the new ID to set for the key. At least one of the +.BR \-\-new\-attr | \-A +.IR ATTRS , +.BR \-\-new\-label | \-l +.IR LABEL , +or +.BR \-\-new\-id | \-I +.I ID +options must be specified. +.PP +The user will be prompted to confirm the updating of the key. To suppress the +prompt, use the +.BR \-\-force | \-f +option. +.PP . -.SH ARGS +.SS "Coyping symmetric and asymmetric keys" . -.SS "des | 3des | aes | aes-xts | rsa | ec | ibm-dilithium | ibm-kyber | public | private | secret | all" - -selects the respective symmetric or asymmetric key to be generated or listed. The -.B public|private|secret|all -argument can only be used with the -.B list-key -command to list either public, private, secret, or all keys. +.B p11sak +.BR copy\-key | copy | cp +.RI [ KEYTYPE ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.RB [ \-\-label | \-L +.IR LABEL ] +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.RB [ \-\-force | \-f ] +.RB [ \-\-new\-attr | \-A +.IR ATTRS ] +.RB [ \-\-new\-label | \-l +.IR LABEL ] +.RB [ \-\-new\-id | \-I +.IR ID ] +.RB [ \-\-help | \-h ] +.PP +Use the +.B copy\-key | copy | cp +command and the optional +.I KEYTYPE +argument to copy symmetric or asymmetric keys and optionally set or change +boolean attributes, the label, or ID of the copied keys. +Public, private, secret, or all keys can also be copied irrespective of the key +type. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +If +.I KEYTYPE +is omitted, then all key types are selected for copying. +.PP +Specify the +.BR \-\-label | \-L +.IR LABEL , +the +.BR \-\-id | \-i +.IR ID , +and/or the +.BR \-\-attr | \-a +.I ATTRS +options to filter the list of keys to display. You can use wildcards (\fB*\fP +and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +The +.B ID +must be specified as hex string (not prefixed with 0x) of any number of bytes. +.PP +Use the +.BR \-\-new\-attr | \-A +.I ATTRS +option to specify the boolean attributes of the copied key you want to set or +update (see below for detailed description of the attributes). Attributes that +are not specified are not changed. Use the +.BR \-\-new\-label | \-l +.I LABEL +option to specify the new label, or the +.BR \-\-new\-id | \-I +.I ID +option to specify the new ID to set for the copied key. +.PP +The user will be prompted to confirm the copying of the key. To suppress the +prompt, use the +.BR \-\-force | \-f +option. .PP . +.SS "Importing symmetric and asymmetric keys from a file" +. +.B p11sak +.BR import\-key | import | imp +.I KEYTYPE +.RI [ KIND ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.BR \-\-label | \-L +.I LABEL +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-force | \-f ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.BR \-\-file | \-F +.I FILENAME +.RB [ \-\-pem\-password | \-P +.IR PASSWORD ] +.RB [ \-\-force\-pem\-pwd\-prompt ] +.RB [ \-\-opaque | \-o ] +.RB [ \-\-help | \-h ] +.PP +Use the +.BR import\-key | import | imp +command and +.I KEYTYPE +argument to import an symmetric or asymmetric key from a file. When importing +an asymmetric key, the +.I KIND +argument is required and specifies to either import a +.B private +or +.B public +key. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +.PP +The +.BR \-\-label | \-L +.IR LABEL +option sets the +.B CKA_LABEL +attribute of the key and the +.BR \-\-attr | \-a +.I ATTRS +can be used to set the boolean attributes of the key (see below for detailed +description of the attributes). The +.BR \-\-id | \-i +.I ID +option can be used to set the value of the +.B CKA_ID +attribute of the key. +.PP +The +.BR \-\-file | \-F +.I FILENAME +option specifies the file name of the file that contains the key to be imported. +For symmetric keys, this is a binary file containing the key material in clear. +For asymmetric keys, this is an OpenSSL PEM file containing a public or private +key. +PEM files can optionally be password protected. Specify the PEM password +with the +.BR \-\-pem\-password | \-P +.I PASSWORD +option or environment variable +.BR P11SAK_PEM_PASSWORD . +If the PEM file is password protected, but no PEM password is specified, you +will be prompted for the PEM password. +Specify the +.BR \-\-opaque | \-o +option to import an opaque secure key blob. Not all tokens support this. . +.SS "Exporting symmetric and asymmetric keys to a file" . -.SS "128|192|256" +.B p11sak +.BR export\-key | export | exp +.RI [ KEYTYPE ] +.BR \-\-slot | \-s +.I SLOTID +.RB [ \-\-pin | \-p +.IR PIN ] +.RB [ \-\-force\-pin\-prompt ] +.RB [ \-\-label | \-L +.IR LABEL ] +.RB [ \-\-id | \-i +.IR ID ] +.RB [ \-\-attr | \-a +.IR ATTRS ] +.RB [ \-\-force | \-f ] +.BR \-\-file | \-F +.I FILENAME +.RB [ \-\-opaque | \-o ] +.RB [ \-\-spki | \- S ] +.RB [ \-\-help | \-h ] +.PP +Use the +.BR export\-key | export | exp +command and the optional +.I KEYTYPE +argument to export symmetric or asymmetric keys to a file. +Public, private, secret, or all keys can also be selected for export +irrespective of the key type. +.PP +Possible values for the +.I KEYTYPE +argument are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +If +.I KEYTYPE +is omitted, then all key types are selected for export. +.PP +Specify the +.BR \-\-label | \-L +.IR LABEL , the -.B aes -argument has to be followed by either 128, 192 or 256 to set the respective key bit length of the AES key. +.BR \-\-id | \-i +.IR ID , +and/or the +.BR \-\-attr | \-a +.I ATTRS +options to filter the list of keys to display. You can use wildcards (\fB*\fP +and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +The +.B ID +must be specified as hex string (not prefixed with 0x) of any number of bytes. +.PP +The +.BR \-\-file | \-F +.I FILENAME +option specifies the file name of the file to which the keys to be exported are +written to. For symmetric keys, this is a binary file where the key material in +clear is written to. For asymmetric keys, this is an OpenSSL PEM file where the +public or private keys are written to. If multiple asymmetric keys match the +filter, the keys are appended to the PEM file specified with the +.BR \-\-file | \-F +.I FILENAME +option. If multiple symmetric keys or a mixture of asymmetric and symmetric keys +match the filter, then you are prompted to confirm to overwrite the previously +created file, unless the +.RB [ \-\-force | \-f ] +option is specified. +.PP +Specify the +.BR \-\-opaque | \-o +option to export the opaque secure key blobs of the key. Not all tokens support +this. +.PP +Specify the +.BR \-\-spki | \-S +option to export the Subject Public Key Info (SPKI) from the +.B CKA_PUBLIC_KEY_INFO +attribute of an asymmetric private key instead of its private key material. +This option can only be used with private keys. +.PP +.B Note: +Not all keys can be exported, because its attribute setting may forbid +to reveal the values of certain attributes. To allow exporting of a secret +.RB ( CKO_SECRET_KEY ) +or private +.RB ( CKO_PRIVATE_KEY ) +key, attribute +.B CKA_SENSITIVE +must be +.B CK_FALSE +and attribute +.B CKA_EXTRACTABLE +must be +.BR CK_TRUE . +Secret or private keys that contain an opaque secure key blob (attribute +.BR CKA_IBM_OPAQUE ) +can also not be +exported in clear, even if the attributes would allow it. For such keys only the +opaque secure key blob can be exported by using the +.BR \-\-opaque | \-o +option. +. +. +. +.SH ARGUMENTS +. +.SS "KEYTYPE" +. +Selects the respective symmetric or asymmetric key to be generated, imported or +selected. Possible values are: +.BR des | 3des | generic | aes | aes\-xts | rsa | dh | dsa | ec | \ +ibm\-dilithium | ibm-kyber | public | private | secret | all . +The +.BR public | private | secret | all +argument can only be used with commands that use the +.I KEYTYPE +argument as filter, such as the +.B list\-key +command, the +.B remove\-key +command, the +.B set\-key\-attrs +command, or the +.B export\-key +command. .PP . +.SS "KEYBITS" . +Specifies the size of the key in bits. For the +.B aes +key type, possible values are +.BR 128 | 192 | 256 . +For the +.B aes\-xts +key type, possible values are +.BR 128 | 256 . +For the +.B rsa +key type, possible values are +.BR 512 | 1024 | 2048 | 4096 . +.PP . -.SS "128|256" -the -.B aes-xts -argument has to be followed by either 128 or 256 to set the respective key bit length of the AES-XTS key. +.SS "PUBL\-EXP" +. +Specifies the public exponent for an RSA key. If not specified, the default is +65537 according to the PKCS\~#11 standard. .PP . +.SS "PRIV\-BITS" +. +Specifies the size of the private key in bits for an DH key. +.PP . +.SS "GROUP" . -.SS "1024|2048|4096" -the -.B rsa -argument has to be followed by either 1024, 2048 or 4096 to set the respective key bit length of the RSA key. +Specifies the Diffie\-Hellman FFC group name for an DH key. Possible values are +.BR ffdhe2048 | ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192 | modp1536 | \ +modp2048 | modp3072 | modp4096 | modp6144 | modp8192 . +.PP +.B Note: +Not all groups are supported by all tokens and key generation will fail +when the specified +.I GROUP +is not supported. Also, not all groups are supported by all OpenSSL versions. +If the +.B p11sak +tool is compiled against an OpenSSL version that does not support certain +groups, then those groups are not accepted for the +.I GROUP +argument. .PP . +.SS "DH\-PARAM\-PEM\-FILE" . +Specifies the DH parameters PEM file name. You can for example generate DH +parameters using the OpenSSL command line tool as follows: \fB'openssl dhparam + \-out \-outform PEM' \fP. See the OpenSSL man page for +details about this command. +.PP . -.SS "prime256v1 | prime192 | secp224 | secp384r1 | secp521r1 | secp265k1 | brainpoolP160r1 | brainpoolP160t1 | brainpoolP192r1 | brainpoolP192t1 | brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 | brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | brainpoolP512r1 | brainpoolP512t1 | curve25519 | curve448 | ed25519 | ed448" -the -.B ec -argument has to be followed by either of these -.I CURVE -to select the EC curve used to generate the key. +.SS "DSA\-PARAM\-PEM\-FILE" +. +Specifies the DSA parameters PEM file name. You can for example generate DSA +parameters using the OpenSSL command line tool as follows: \fB'openssl dsaparam + \-out \-outform PEM' \fP. See the OpenSSL man page for +details about this command. .PP . +.SS "CURVE" . - -.SS "r2_6|r2_87|r3_44|r3_65|r3_875" -the -.B ibm-dilithium -argument has to be followed by either of these -.I VERSION -to select the IBM dilithium version used to generate the key. +Specifies the curve for an EC key. Possible values are: +.BR prime256v1 | prime192 | secp224 | secp384r1 | secp521r1 | secp265k1 | \ +brainpoolP160r1 | brainpoolP160t1 | brainpoolP192r1 | brainpoolP192t1 | \ +brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 | \ +brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | \ +brainpoolP512r1 | brainpoolP512t1 | curve25519 | curve448 | ed25519 | ed448 . .PP . +.SS "VERSION" . +Specifies the version for an IBM Dilithium or IBM Kyber key. +For the +.B ibm\-dilithium +key type, possible values are +.BR r2_65 | r2_87 | r2_44 | r3_65 | r3_87 . +For the +.B ibm\-kyber +key type, possible values are +.BR r2_768 | r2_1024 . +.PP . -.SS "r2_768|r2_1024" -the -.B ibm-kyber -argument has to be followed by either of these -.I VERSION -to select the IBM kyber version used to generate the key. +.SS "KIND" +. +Specifies the kind of the asymmetric key to import. Possible values are +.BR public | private . .PP . . . .SH OPTIONS -.SS "\-\-slot SLOTID" -sets the token to -.IR SLOTID +.TP 8 +.BR \-\-slot | \-s\~\fISLOT\fP +Specifies the slot number of the token to use. .PP . . . -.SS "\-\-pin PIN" -sets the token PIN to -.IR PIN +.TP 8 +.BR \-\-pin | \-p\~\fIPIN\fP +Specifies the token user PIN to login with. .PP -Alternatively the PKCS11_USER_PIN environment variable may be used to -provide the token PIN. +.RS 8 +Alternatively, the +.B PKCS11_USER_PIN +environment variable may be used to provide the token user PIN. +If neither this option is specified nor the einvironment variable is set, +you are prompted for the PIN. +.RE .PP . . . -.SS "\-\-force-pin-prompt" -enforce p11sak to prompt for the token PIN (regardless if it has been -specified elsewhere) +.TP 8 +.BR \-\-force\-pin\-prompt +Enforce the +.B p11sak +tool to prompt for the token user PIN (regardless if it has been specified +elsewhere) .PP . . . -.SS "\-\-label LABEL" -sets the key label attribute to -.IR LABEL -.PP -For asymmetric keys, the specified label is appended by \fB:pub\fP and -\fB.prv\fP for the public and private key objects. Optionally, a user can set -different labels for the public and private key objects by specifying them -separated by a colon (\fB:\fP), e.g. \fBpub-label:priv-label\fP. The label +.TP 8 +.BR \-\-label | \-L\~\fILABEL\fP | \fIPUB\-LABEL\fP : \fIPRIV\-LABEL\fP +Specifies the key label attribute value (\fBCKA_LABEL\fP). +.PP +.RS 8 +For commands such as the +.B list\-key +command, the +.B remove\-key +command, the +.B set\-key\-attrs +command, and the +.B export\-key +command, specify the label to filter the list of keys to operate on. You can +use wildcards (\fB*\fP and \fB?\fP) in the +.B LABEL +specification. To specify a wildcard character that should not be treated as a +wildcard, it must be escaped using a backslash (\fB\e*\fP or \fB\e?\fP). +Also, a backslash character that should not be treated as an escape character +must be escaped (\fB\e\e\fP). +.PP +For generation of asymmetric keys, the specified label is appended by \fB:pub\fP +and \fB:prv\fP for the public and private key objects. Optionally, a user can +set different labels for the public and private key objects by specifying them +separated by a colon (\fB:\fP), e.g. \fBpub\-label:priv\-label\fP. The label string in front of the colon is used as label for the public key object, the label string after the colon is used for the private key object. -To set the public and private key label the exact same, use \fBpub-label:=\fP. +To set the public and private key label the exact same, use \fBpub\-label:=\fP. The equal sign (\fB=\fP) means to use the same label string for the private key objects as for the public key object. In case a colon character or a equal sign is supposed to appear within @@ -521,122 +1278,395 @@ \fBabc\\:xyz\fP results in \fBabx:xyz\fP where the colon is not treated as separator character. Note that the shell may interpret escape characters as well, so better quote -the \fILABEL\fP specification. +the \fILABEL\fP|\fIPUB\-LABEL\fP:\fIPRIV\-LABEL\fP specification. +.RE .PP . . . -.SS "\-\-exponent EXP" -sets the RSA exponent to -.IR EXP +.TP 8 +.BR \-\-id | \-i\~\fIID\fP +Specifies the key ID attribute value (\fBCKA_ID\fP) as hex string (not prefixed +with 0x) of any number of bytes. +.PP +.RS 8 +For commands such as the +.B list\-key +command, the +.B remove\-key +command, the +.B set\-key\-attrs +command, and the +.B export\-key +command, specify the key ID to filter the list of keys to operate on. +.PP +For generation of asymmetric keys, the same ID is set for both, the public and +the private key. +.RE .PP . . . -.SS "\-\-attr [P M R L S E D G V W U A X N T]" -sets the binary attributes of a key. +.TP 8 +.BR \-\-attr | \-a\~\fIATTRS\fP | \fIPUB\-ATTRS\fP : \fIPRIV\-ATTRS\fP +For the +.B generate\-key +command the and +.B import\-key +commands, specify the boolean attributes that are to be set for the new key(s). +For commands such as the +.B list\-key +command, the +.B remove\-key +command, the +.B set\-key\-attrs +command, and the +.B export\-key +command, specify the attribute values to filter the list of keys to operate on. .PP +.RS 8 .B Note: -not all binary attributes are applicable to all keys and will be omitted if not applicable. +Not all boolean attributes are applicable to all key types and/or commands and +will be silently ignored if not applicable. .PP -The attributes are set to -.B FALSE -by default and switched to +The respective attributes are set to .B TRUE -when the letter that is associated with the given binary attribute is specified. The following letters are associated with the respective -.B CK_ATTRIBUTE: +when the corresponding letter is specified in uppercase, or +.B FALSE +when the corresponding letter is specified in lowercase. +Attributes (except \fBCKA_TOKEN\fP and \fBCKA_SENSITIVE\fP, see below) that are +not specified get the default value as defined by the PKCS\~#11 standard or the +used PKCS\~#11 token implementation when generating keys, or are not updated +when setting the attributes of an existing key. +.PP +Attribute +.B CKA_TOKEN +is always set to \fBTRUE\fP when generating a key. The +.B p11sak +tool always generates token keys, since session keys are not persistent, and +thus would no longer exist after the session that the +.B p11sak +tool has opened for generating the key is closed when it exists. +.PP +When generating or importing a key with the +.B p11sak +tool, attribute +.B CKA_SENSITIVE +defaults to \fBTRUE\fP for secret keys or the private key of asymmetric +key pairs. However, this can be overridden by specifying the respective +uppercase or lowercase letter for the CKA_SENSITIVE attribute in the attribute +string, as desired. +.PP +.B Note: +The default setting for the +.B CKA_SENSITIVE +attribute is defined by the +.B p11sak +tool, and might be different from the default setting that would be chosen by +the used PKCS\~#11 implementation. +.PP +The following letters are associated with the respective +.BR CK_ATTRIBUTE : .IP "\(bu" 2 .B P -- CKA_PRIVATE +\- CKA_PRIVATE +.IP "\(bu" 2 +.B L +\- CKA_LOCAL (read only) .IP "\(bu" 2 .B M -- CKA_MODIFIABLE +\- CKA_MODIFIABLE .IP "\(bu" 2 -.B R -- CKA_DERIVE +.B B +\- CKA_COPYABLE .IP "\(bu" 2 -.B L -- CKA_LOCAL +.B Y +\- CKA_DESTROYABLE .IP "\(bu" 2 -.B S -- CKA_SENSITIVE +.B R +\- CKA_DERIVE .IP "\(bu" 2 .B E -- CKA_ENCRYPT +\- CKA_ENCRYPT .IP "\(bu" 2 .B D -- CKA_DECRYPT +\- CKA_DECRYPT .IP "\(bu" 2 .B G -- CKA_SIGN +\- CKA_SIGN +.IP "\(bu" 2 +.B C +\- CKA_SIGN_RECOVER .IP "\(bu" 2 .B V -- CKA_VERIFY +\- CKA_VERIFY +.IP "\(bu" 2 +.B O +\- CKA_VERIFY_RECOVER .IP "\(bu" 2 .B W -- CKA_WRAP +\- CKA_WRAP .IP "\(bu" 2 .B U -- CKA_UNWRAP +\- CKA_UNWRAP +.IP "\(bu" 2 +.B S +\- CKA_SENSITIVE .IP "\(bu" 2 .B A -- CKA_ALWAYS_SENSITIVE +\- CKA_ALWAYS_SENSITIVE (read only) .IP "\(bu" 2 .B X -- CKA_EXTRACTABLE +\- CKA_EXTRACTABLE .IP "\(bu" 2 .B N -- CKA_NEVER_EXTRACTABLE +\- CKA_NEVER_EXTRACTABLE (read only) +.IP "\(bu" 2 +.B T +\- CKA_TRUSTED (can only be set by SO user) +.IP "\(bu" 2 +.B I +\- CKA_WRAP_WITH_TRUSTED +.IP "\(bu" 2 +.B K +\- CKA_IBM_PROTKEY_EXTRACTABLE (IBM specific, not all tokens support this) +.IP "\(bu" 2 +.B Z +\- CKA_IBM_PROTKEY_NEVER_EXTRACTABLE (IBM specific, not all tokens support this, +read only) +.PP +For multiple attributes, specify a set of these letters without any blanks in +between, e. g. \fB'MlD'\fP. An uppercase letter means \fBTRUE\fP, while a +lowercase letter means \fBFALSE\fP. +From Example above, \fB'MlD'\fP corresponds to: \fBCKA_MODIFIABLE=TRUE, +CKA_LOCAL=FALSE, CKA_DECRYPT=TRUE\fP. +.PP +For generating asymmetric keys set individual key attributes for public and +private key separated by a colon (\fB:\fP). The attributes in front of the colon +are set for the public key and the attributes after the colon are set for the +private key. When no colon is used, the same attribute set is used for +both, the public and private keys. To set a configuration for only the public +key, the string must end with the colon and respectively, to use a +configuration for the private key only, the string must start with the +colon. +.PP +.RE +. +. +. +.TP 8 +.BR \-\-new\-attr | \-A\~\fIATTRS\fP +Specifies the boolean attributes to set or update for a key with the +.B set\-key\-attr +or +.B copy\-key +commands. See the description of the +.BR \-\-attr | \-a +option above for a list of letters that are associated with the respective +.BR CK_ATTRIBUTE . +. +. +. +.TP 8 +.BR \-\-new\-label | \-L\~\fILABEL\fP +Specifies the new label attribute value (\fBCKA_LABEL\fP) to set for the key. +.RE +.PP +. +. +. +.TP 8 +.BR \-\-new\-id | \-I\~\fIID\fP +Specifies the new ID attribute value (\fBCKA_ID\fP) as hex string (not prefixed +with 0x) of any number of bytes to set for the key. +.RE +.PP +. +. +. +.TP 8 +.BR \-\-long | \-l +Prints the +.B list\-key +output in long format, displaying the values of all attributes defined for the +key type, including non-boolean attributes. If the +.BR \-\-long | \-l +option is omitted, the output is in a +short, tabular format, showing only the boolean attributes, the key type +(\fBCKA_KEY_TYPE\fP) and the key label (\fBCKA_LABEL\fP). +.RE +.PP +. +. +. +.TP 8 +.B \-\-detailed\-uri +Displayes a detailed PKCS\~#11 URI. +.RE +.PP + +. +. +. +.TP 8 +.BR \-\-sort | \-S\~\fISORT-SPEC\fP +Sort the keys by label, key type, object class, and/or key size. Specify a sort +selection of up to 4 fields, each field represented by its coresponding letter, +separated by comma +.RB ( , ): +.RS 8 +.IP "\(bu" 2 +.B l +- sort by label +.RB ( CKA_LABEL ) +.IP "\(bu" 2 +.B k +- sort by key type +.RB ( CKA_KEY_TYPE ) .IP "\(bu" 2 -.B * -- if in p11sak_defined_attrs.conf additional attributes are defined. +.B c +- sort by object class +.RB ( CKA_CLASS , +secret key, private key, public key) +.IP "\(bu" 2 +.B s +- sort by key size +.RB ( CKA_VALUE_LEN , +or derived from other key type spcifi attribute) +.PP +The sort order can be appended to the field designator by a colon +.RB ( : ) +and its coressponding letter: +.IP "\(bu" 2 +.B a +- ascending order (default) +.IP "\(bu" 2 +.B d +- descending order +.PP +Example: +.B l:a,k:d +will sort by label in ascending order and then by key type in descending order. +.RE .PP -CKA_TOKEN and CKA_PRIVATE are set by default to -.B TRUE. -For multiple attributes, combine the letters in a string without white space, e. g. 'MlD'. -An uppercase letter means true, while an lowercase letter equals false. -From Example above: CKA_MODIFIABLE=true, CKA_LOCAL=false, CKA_DECRYPT=true +. +. +. +.TP 8 +.BR \-\-force | \-f +Suppress the prompt whether the user wants to remove, update, or export the keys +matching the specified \fIKEYTYPE\fP, label, and ID filter (if specified). +.RE +.PP +. +. +. +.TP 8 +.BR \-\-file | \-F\~\fIFILENAME\fP +For the +.B import\-key +command, this option specifies the file name of the file that contains the key +to be imported. For symmetric keys, this is a binary file containing the key +material in clear. For asymmetric keys, this is an OpenSSL PEM file containing +a public or private key. PEM files used for importing keys can be password +protected. Specify the PEM password with the +.BR \-\-pem\-password | \-P +.I PASSWORD +option or environment variable +.BR P11SAK_PEM_PASSWORD . +If the PEM file is password protected, but no PEM password is specified, you +will be prompted for the PEM password. .PP -For asymmetric keys a user can set different custom attributes for the public and the private key. -The separator is the symbol ":". The defined attributes in front of the separator are set for the -public key and the attributes defined after the separator are set for the private key. When the -separator is not in the string, the defined attribute set is used for public and private key. To set -a configuration for only the public key, the string has to end with the separator and respectively, -to use a configuration for the private key only, the string has to start with the separator. +.RS 8 +For the +.B export\-key +command, this option specifies the file name of the file to which the keys to +be exported are written to. For symmetric keys, this is a binary file where the +key material in clear is written to. For asymmetric keys, this is an OpenSSL +PEM file where the public or private keys are written to. If multiple asymmetric +keys match the filter, the keys are appended to the PEM file specified with this +option. If multiple symmetric keys or a mixture of asymmetric and symmetric keys +match the filter, then you are prompted to confirm to overwrite the previously +created file, unless the +.RB [ \-\-force | \-f ] +option is specified. +.RE .PP . . . -.SS "\-\-long | \-l" -prints the -.B list-key -output in long format. If omitted, the output is in a short, tabular format. +.TP 8 +.BR \-\-pem\-password | \-P\~\fIPASSWORD\fP +Specifies the password of the PEM file specified with the +.BR \-\-file | \-F +.I FILENAME +option for the +.B import\-key +command. If the PEM file is password protected, but this option is not +specified, nor environment variable +.B P11SAK_PEM_PASSWORD +is set, you will be prompted for the PEM password. +.RE .PP . . . -.SS "\-\-force | \-f" -to be used with the -.B remove-key -command to suppress the promt whether the user wants to delete the specified keys. +.TP 8 +.BR \-\-force\-pem\-pwd\-prompt +Enforce the +import\-key +command to prompt for the PEM password (regardless if it has been specified +elsewhere). +.RE .PP . . . -.SS "\-\-help | \-h" -prints help for the usage of +.TP 8 +.BR \-\-opaque +The key material in the file specified with the +.BR \-\-file | \-F +.I FILENAME +option is an opaque secure key blob. Not all tokens support this. +.RE +.PP +. +. +. +.TP 8 +.BR \-\-help | \-h +Prints help for the usage of the +.B p11sak +tool and/or the respective command and then exits. +.RE +.PP +. +. +. +.TP 8 +.BR \-\-version | \-v +Prints the version of the .B p11sak -and/or the respective command. +tool and then exits. +.RE .PP . . . .SH "FILES" - -.SS "/usr/local/etc/opencryptoki/p11sak_defined_attrs.conf" -In the output config file a user can define additional attributes, which are not -mentioned in the PKCS#11 standard. A custom filepath can be set with an environment -variable. +. +.SS "/etc/opencryptoki/p11sak_defined_attrs.conf" +.SS "~/.p11sak_defined_attrs.conf" +In the output config file a user can define additional attributes, which are not +mentioned in the PKCS#11 standard or are not known by the +.B p11sak +tool. A custom file path can be set with environment variable +\fBP11SAK_DEFAULT_CONF_FILE\fP. If the environment variable is not set, then +\fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current +user's home directory. If this is not available, the global +\fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. +If none of these files are available, a warning message is displayed, and +printing of custom attributes is not available. .PP . . @@ -644,35 +1674,86 @@ .SH "ENVIRONMENT VARIABLES" .SS "P11SAK_DEFAULT_CONF_FILE" -A custom path for p11sak_defined_attrs.conf can be set with the environment variable -P11SAK_DEFAULT_CONF_FILE. If none is set p11sak will first look for the file in the user -directory, followed by the standard installation path. +A custom path for the \fBp11sak_defined_attrs.conf\fP config file can be set +with the environment variable \fBP11SAK_DEFAULT_CONF_FILE\fP. +If the environment variable is not set, then +\fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current +user's home directory. If this is not available, the global +\fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. +If none of these files are available, a warning message is displayed, and +printing of custom attributes is not available. .PP +. .SS "PKCS11_USER_PIN" -The token PIN can be specified via the environment variable PKCS11_USER_PIN. -If nothing is set and the option -.B \-\-pin -is not specified, p11sak will prompt for the token PIN interactively. -.PP +The token user PIN can be specified via the environment variable +\fBPKCS11_USER_PIN\fP. If this environment variable is not set, and the option +.BR \-\-pin | \-p +.I PIN +is not specified, p11sak will prompt for the token user PIN interactively. +.PP +. +.SS "PKCSLIB" +An alternative PKCS\~#11 library name can be specified with the \fBPKCSLIB\fP +environment variable. If this environment variable is not set, then the default +PKCS\~#11 library \fBlibopencryptoki.so\fP is used. +.PP +. +.SS "P11SAK_PEM_PASSWORD" +PEM files used for importing keys from can be password protected. The PEM +password can be specified via the environment variable +\fBP11SAK_PEM_PASSWORD\fP. If this environment variable is not set, and the +option +.BR \-\-pem\-password | \-P +.I PASSWORD +is not specified, p11sak will prompt for the PEM password interactively. . . . .SH "EXIT STATUS" -p11sak returns various error codes on fail: +The +.B p11sak +tool returns error codes as defined by the PKCS\~#11 standard, i.e. the +\fBCKR_nnn\fP errors. On success, \fBCKR_OK\fP (which is zero) is returned. +.PP +The PKCS\~#11 error codes may originate from a PKCS\~#11 function called by the +.B p11sak +tool, or from the +.B p11sak +tool itself, like the following: + .SS CKR_ARGUMENTS_BAD (0x00000007): -The p11sak_defined_attrs.conf is not found. +An argument, option or keyword is not valid. .PP . . . .SS CKR_DATA_INVALID (0x00000020): -The p11sak_defined_attrs.conf cannot be parsed or syntax is invalid. +The \fBp11sak_defined_attrs.conf\fP cannot be parsed or its syntax is invalid. +.PP +. +. +. +.SS CKR_MECHANISM_INVALID (0x00000070): +The token does not support the key generation mechanism for the specified key +type. +.PP +. +. +. +.SS CKR_KEY_SIZE_RANGE (0x00000062): +The token does not support the key size for the specified key type. +.PP +. +. +. +.SS CKR_HOST_MEMORY (0x00000002): +Allocating memory has failed. .PP . . . -.SS CKR_ATTRIBUTE_TYPE_INVALID (0x00000012): -A given attribute type cannot be set for this key. +.SS CKR_FUNCTION_FAILED (0x00000006): +A subfunction or library call has failed. .PP . . diff -Nru opencryptoki-3.20.0+dfsg/man/man1/pkcshsm_mk_change.1.in opencryptoki-3.21.0+dfsg/man/man1/pkcshsm_mk_change.1.in --- opencryptoki-3.20.0+dfsg/man/man1/pkcshsm_mk_change.1.in 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man1/pkcshsm_mk_change.1.in 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,271 @@ +.\" pkcshsm_mk_change.1 +.\" +.\" Copyright IBM Corp. 2022 +.\" See LICENSE for details. +.\" +.TH PKCSHSM_MK_CHANGE 1 "August 2022" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcshsm_mk_change \- utility to manage and control the re-enciphering of secure +keys for a concurrent HSM master key change for openCryptoki. + +.SH SYNOPSIS +.B pkcshsm_mk_change +.I command +.RB [ OPTIONS ] +. +.PP +.B pkcshsm_mk_change +.BR \-\-help | \-h +.br + +.SH DESCRIPTION +Manages and controls the re-enciphering of secure keys for a concurrent HSM +master key change for openCryptoki. Secure keys are encrypted by the HSM master +key(s). The HSM master key(s) must be changed (rolled) from time to time, +dependent on policies defined by the HSM security officer. Whenever a HSM master +key is changed, all secure keys that are encrypted with that HSM master key must +be re-enciphered with the new to be set master key. +.PP +Changing HSM master keys needs to be coordinated between the HSM security +officer and an openCryptoki administrator. The HSM security officer performs a +master key change via the TKE (Trusted Key Entry), while the openCryptoki +administrator performs administrative steps using the \fBpkcshsm_mk_change\fP +tool to re-encipher all openCryptoki token and session key objects, as well as +currently active crypto operation states with the new master key. Applications +using those keys can continue to run, the re-enciphering process takes place +transparently to them. +.PP +A concurrent master key change works as follows: +.RS 2 +.nr step 1 1 +.IP "\n[step]." 3 +The HSM security officer loads the new master keys using the TKE into the NEW +register of the set of APQNs logically belonging together. + +.IP "\n+[step]." 3 +The HSM security officer notifies the openCryptoki administrator that new master +keys have been loaded for all the APQNs. +. +.IP "\n+[step]." 3 +The openCryptoki administrator uses the \fBpkcshsm_mk_change\fP to initiate a +master key change for openCryptoki, specifying the set of APQNs (and master key +types) that are to be changed. The \fBpkcshsm_mk_change\fP tool communicates +with running applications and performs/controls re-encipherment of the key +objects with the new master key. +. +.IP "\n+[step]." 3 +When the \fBpkcshsm_mk_change\fP tool has completed its re-encipherment +processing, the openCryptoki administrator notifies the HSM security officer +that openCryptoki is ready to set/activate the new master keys. +. +.IP "\n+[step]." 3 +The HSM security officer coordinates with other (non-openCryptoki) applications +and once all users of the APQNs are OK, he sets/activates the new master keys +on the APQNs. +. +.IP "\n+[step]." 3 +The HSM security officer notifies the openCyptoki administrator when for all +APQNs the new master key have been set/activated. +. +.IP "\n+[step]." 3 +The openCryptoki administrator uses the \fBpkcshsm_mk_change\fP tool to finalize +the master key change for openCryptoki. The tool communicates with running +applications and performs/controls finalizing the re-encipherment of the key +objects with the new master key. +. +.IP "\n+[step]." 3 +When the \fBpkcshsm_mk_change\fP tool has completed its finalizing processing, +the master key change operation is complete. +.RE +. +.PP +The whole procedure can take an arbitrary amount of time. Especially the time +between the moment when the new master key has been loaded on all APQNs, and +the moment the new master keys are set/activated can even last several days, +due to time required for coordination with other (non-openCryptoki) +applications/users of the APQNs to prepare for the master key change. +.PP +The time to perform the re-encipherment and finalization (steps 3 and 7) of all +key objects as such depends on the amount of keys and openCryptoki applications +using them, but is usually relatively short, i.e. seconds up to a few minutes. +.PP +The system where openCryptoki runs may be restarted while a master key change +is ongoing, provided that the re-encipherment and finalization steps (steps 3 +and 7) are not interrupted. +.PP +An ongoing master key change operation can be canceled using the +\fBpkcshsm_mk_change\fP tool, as long as for none of the APQNs the new master +key has been set/activated, that is up to step 5 from above. +. +.SH COMMANDS +.SS "Initiate a master key change for openCryptoki" +. +.B pkcshsm_mk_change reencipher +.RB [ \-\-apqns | \-a +.IR APQNS ] +.RB [ \-\-ep11\-wkvp | \-e +.IR WKVP ] +.RB [ \-\-cca\-sym\-mkvp | \-s +.IR MKVP ] +.RB [ \-\-cca\-asym\-mkvp | \-S +.IR MKVP ] +.RB [ \-\-cca\-aes\-mkvp | \-A +.IR MKVP ] +.RB [ \-\-cca\-apka\-mkvp | \-p +.IR MKVP ] +.RB [ \-\-verbose | \-v +.IR LEVEL ] +.PP +. +Use the \fBreencipher\fP command to initiate a master key change operation +for the specified APQNs and master key types and re-encipher all session and +token key objects of the affected tokens. For each master key type that is +changed, the verification pattern of the new, to be set master key must be +specified. +.PP +A CryptoExpress adapter in \fBCCA\fP coprocessor mode has 4 different master +keys: \fBSYM\fP, \fBASYM\fP, \fBAES\fP, and \fBAPKA\fP. The CCA token of +openCryptoki only uses SYM, AES, and APKA. Each master key type can be change +individually, or together with others. You can use the TKE or the +\fBpanel.exe\fP tool to query the master key verification patterns: +.B 'panel.exe --mk-query --mktype= --mkregister=NEW'. +For master key types \fBSYM\fP and \fBASYM\fP, use the hex string under +\fB[RND]\fP, for types \fBAES\fP and \fBAPKA\fP use the hex string under +\fB[VER]\fP. For AES and APKA you can also find the master key verification +patterns in sysfs: +.B 'cat /sys/bus/ap/devices/./mkvps'. +.PP +A CryptoExpress adapter in \fBEP11\fP coprocessor mode has only one master key, +called the EP11 wrapping key (WK). You can use the TKE or the \fBep11info\fP tool +to query the current wrapping key verification pattern (WKVP) of an EP11 APQN: +.B 'ep11info -m -d -D'. +You can also find the wrapping key verification pattern for EP11 APQNs in sysfs: +.B 'cat /sys/bus/ap/devices/./mkvps'. +.PP +the \fBpkcshsm_mk_change reencipher\fP command will query all available slots +and determine if the token in the slot is affected by the master key change, +based on the list of APQNs and master key types. For each affected slot, it +prompts for the \fBUSER pin\fP. +.PP +On successful completion, the id of the master key change operation is displayed. +This id must later be specified when finalizing or canceling the operation using +the \fBfinalize\fP or \fBcancel\fP command. +. +.SS "Finalize a master key change for openCryptoki" +. +.B pkcshsm_mk_change finalize +.RB [ \-\-id | \-i +.IR OPERATION-ID ] +.RB [ \-\-verbose | \-v +.IR LEVEL ] +.PP +. +Use the \fBfinalize\fP command to finalize a master key change operation when +the new master key has been activated on the APQNs. The id of the master key +change operation to finalize must be specified. +. +.SS "Cancel a master key change for openCryptoki" +. +.B pkcshsm_mk_change cancel +.RB [ \-\-id | \-i +.IR OPERATION-ID ] +.RB [ \-\-verbose | \-v +.IR LEVEL ] +.PP +. +Use the \fBcancel\fP command to finalize a master key change operation. +The id of the master key change operation to cancel must be specified. +A master key change operation can only be canceled as long as for none of the +APQNs the new master key have been set/activated. +. +.SS "List master key change operations" +. +.B pkcshsm_mk_change list +.RB [ \-\-id | \-i +.IR OPERATION-ID ] +.RB [ \-\-verbose | \-v +.IR LEVEL ] +.PP +. +Use the \fBlist\fP command to list currently active master key change +operations. If no operation ID is specified, all currently active master key +change operations are displayed, otherwise only the specified one is displayed. + +.SH "OPTIONS" + +.TP +.BR \-a ", " \-\-apqns\~\fIAPQNS\fP +Specifies a comma separated list of APQNs for which a master key change is to +be performed. Each APQN must be specified in the form \fB card.domain\fP, where +both \fBcard\fP and \fBdomain\fP are in hex, as displayed by the \fBlszcrypt\fP +command. Multiple APQNs are separated by a comma. +This options is only valid with the \fBreencipher\fP command. +.TP +.BR \-e ", " \-\-ep11\-wkvp\~\fIWKVP\fP +Specifies the EP11 wrapping key verification pattern (WKVP) of the new, to be +set EP11 wrapping key as a 16 bytes hex string. +This options is only valid with the \fBreencipher\fP command. +You can use the TKE or the \fBep11info\fP tool to query the current wrapping key +verification pattern (WKVP) of an EP11 APQN: +.B 'ep11info -m -d -D'. +You can also find the wrapping key verification pattern for EP11 APQNs in sysfs: +.B 'cat /sys/bus/ap/devices/./mkvps'. +.TP +.BR \-s ", " \-\-cca\-sym\-mkvp\~\fIMKVP\fP +Specifies the CCA master key verification pattern (MKVP) of the new, to be +set CCA SYM master key as a 8 bytes hex string. +This options is only valid with the \fBreencipher\fP command. +You can use the TKE or the \fBpanel.exe\fP tool to query the master key +verification patterns: +.B 'panel.exe --mk-query --mktype=SYM --mkregister=NEW'. +Use the hex string under \fB[RND]\fP. +.TP +.BR \-S ", " \-\-cca\-asym\-mkvp\~\fIMKVP\fP +Specifies the CCA master key verification pattern (MKVP) of the new, to be +set CCA ASYM master key as a 8 bytes hex string. +This options is only valid with the \fBreencipher\fP command. +You can use the TKE or the \fBpanel.exe\fP tool to query the master key +verification patterns: +.B 'panel.exe --mk-query --mktype=ASYM --mkregister=NEW'. +Use the hex string under \fB[RND]\fP. +.TP +.BR \-A ", " \-\-cca\-aes\-mkvp\~\fIMKVP\fP +Specifies the CCA master key verification pattern (MKVP) of the new, to be +set CCA AES master key as a 8 bytes hex string. +This options is only valid with the \fBreencipher\fP command. +You can use the TKE or the \fBpanel.exe\fP tool to query the master key +verification patterns: +.B 'panel.exe --mk-query --mktype=AES --mkregister=NEW'. +Use the hex string under \fB[VER]\fP. +You can also find the AES master key verification patterns in sysfs: +.B 'cat /sys/bus/ap/devices/./mkvps'. +.TP +.BR \-p ", " \-\-cca\-apka\-mkvp\~\fIMKVP\fP +Specifies the CCA master key verification pattern (MKVP) of the new, to be +set CCA APKA master key as a 8 bytes hex string. +This options is only valid with the \fBreencipher\fP command. +You can use the TKE or the \fBpanel.exe\fP tool to query the master key +verification patterns: +.B 'panel.exe --mk-query --mktype=APKA --mkregister=NEW'. +Use the hex string under \fB[VER]\fP. +You can also find the APKA master key verification patterns in sysfs: +.B 'cat /sys/bus/ap/devices/./mkvps'. +.TP +.BR \-i ", " \-\-id\~\fIOPERATION-ID\fP +Specifies the id of the master key change operation for the \fBfinalize\fP, +\fBcancel\fP, or \fBlist\fP command. On successful completion of the +\fBreencipher\fP command, the id of the master key change operation is +displayed. +.TP +.BR \-v ", " \-\-verbose\~\fILEVEL\fP +Specifies the verbose level (optional): \fBnone\fP (default), \fBerror\fP, +\fBwarn\fP, \fBinfo\fP, \fBdevel\fP, or \fBdebug\fP. +.TP +.BR \-h ", " \-\-help +Displays help text and exits. + +.SH SEE ALSO +.PD 0 +.TP +\fBopencryptoki\fP(7) +.PD \ No newline at end of file diff -Nru opencryptoki-3.20.0+dfsg/man/man5/p11sak_defined_attrs.conf.5.in opencryptoki-3.21.0+dfsg/man/man5/p11sak_defined_attrs.conf.5.in --- opencryptoki-3.20.0+dfsg/man/man5/p11sak_defined_attrs.conf.5.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man5/p11sak_defined_attrs.conf.5.in 2023-05-15 14:42:55.000000000 +0200 @@ -1,20 +1,35 @@ .TH P11SAK_DEFINED_ATTRS.CONF 5 "September 2021" "@PACKAGE_VERSION@" "openCryptoki" .SH NAME -p11sak_defined_attrs.conf \- Configuration file for p11sak list-key command. - +p11sak_defined_attrs.conf \- Configuration file for \fBp11sak list\-key\fP +command. +. +. +. .SH DESCRIPTION -p11sak uses a configuration file at /etc/opencryptoki/p11sak_defined_attrs.conf. -This configuration file path can be overwritten by the user with the environment -variable P11SAK_DEFAULT_CONF_FILE. - -This is a text file that contains information used to configure -non standard attributes that shall be printed with the p11sak list-key command. - +The +.B p11sak +tool uses the configuration files \fB~/.p11sak_defined_attrs.conf\fP and +\fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP to read information about +custom attributes that shall be printed with the \fBp11sak list\-key\fP command. +.PP +This configuration file path can be overwritten by the user with the environment +variable \fBP11SAK_DEFAULT_CONF_FILE\fP. +If the environment variable is not set, then +\fB.p11sak_defined_attrs.conf\fP is first tried to be read from the current +user's home directory. If this is not available, the global +\fB/etc/opencryptoki/p11sak_defined_attrs.conf\fP config file is read. +If none of these files are available, a warning message is displayed, and +printing of custom attributes is not available. +. +. +. .SH SYNTAX - +. .P -Each attribute description is composed of the attribute title, brackets and three key-value pairs. -e.g.: +Each attribute description is composed of the attribute title, brackets and +three key\-value pairs. +.PP +Example: attribute { @@ -23,35 +38,40 @@ type = CK_BBOOL } -All three keywords +All three keywords .B name -, +, .B id -, +, .B type are required to define an attribute. -The +The .B name -has to start with a letter followed by an arbitrary number of letters, numbers, underscores, dots, minuses, or slashes. -The +must start with a letter followed by an arbitrary number of letters, numbers, +underscores, dots, minuses, or slashes. +The .B id -is defined in the PKCS#11 standard and can be -in decimal as well as in hexadecimal, when started with 0x, format. -The only valid values for +can be in decimal as well as in hexadecimal, when started with 0x, format. +The only valid values for .B type -are +are: +.IP "\(bu" 2 .B CK_BBOOL -, -.B CK_ULONG -or -.B CK_BYTE. +.IP "\(bu" 2 +.B CK_ULONG +.IP "\(bu" 2 +.B CK_BYTE +.IP "\(bu" 2 +.B CK_DATE +.PP .SH Notes -The pound sign ('#') is used to indicate a comment up to and including the end of line. +The pound sign ('#') is used to indicate a comment up to and including the end +of line. .SH "SEE ALSO" .PD 0 .TP -\fBp11sak\fP(1), +\fBp11sak\fP(1) .PD diff -Nru opencryptoki-3.20.0+dfsg/man/man5/policy.conf.5.in opencryptoki-3.21.0+dfsg/man/man5/policy.conf.5.in --- opencryptoki-3.20.0+dfsg/man/man5/policy.conf.5.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man5/policy.conf.5.in 2023-05-15 14:42:55.000000000 +0200 @@ -161,7 +161,7 @@ .SH NOTES -The policy configuration file has to be owned by \fBroot:pkcs11\fP and +The policy configuration file has to be owned by \fBroot:@pkcs_group@\fP and have mode 0640. Otherwise, openCryptoki will return \fBCKR_FUNCTION_FAILED\fR on \fBC_Initialize\fR and log the reason into syslog. diff -Nru opencryptoki-3.20.0+dfsg/man/man5/strength.conf.5.in opencryptoki-3.21.0+dfsg/man/man5/strength.conf.5.in --- opencryptoki-3.20.0+dfsg/man/man5/strength.conf.5.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man5/strength.conf.5.in 2023-05-15 14:42:55.000000000 +0200 @@ -80,7 +80,7 @@ .SH NOTES -The strength configuration file has to be owned by \fBroot:pkcs11\fP, +The strength configuration file has to be owned by \fBroot:@pkcs_group@\fP, have mode 0640, and be parsable. Otherwise, openCryptoki will return \fBCKR_FUNCTION_FAILED\fR on \fBC_Initialize\fR and log a corresponding message to syslog detailing the reason why the strength diff -Nru opencryptoki-3.20.0+dfsg/man/man7/opencryptoki.7.in opencryptoki-3.21.0+dfsg/man/man7/opencryptoki.7.in --- opencryptoki-3.20.0+dfsg/man/man7/opencryptoki.7.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man7/opencryptoki.7.in 2023-05-15 14:42:55.000000000 +0200 @@ -18,7 +18,7 @@ .SH "SECURITY NOTE" All non-root users that require access to PKCS#11 tokens using openCryptoki -must be assigned to the \fIpkcs11\fP group to be able to communicate with +must be assigned to the \fI@pkcs_group@\fP group to be able to communicate with the \fIpkcsslotd\fP daemon. Only fully trusted users should be granted membership in the group. Group members can block other openCryptoki users from accessing PKCS#11 tokens. diff -Nru opencryptoki-3.20.0+dfsg/man/man8/pkcsslotd.8.in opencryptoki-3.21.0+dfsg/man/man8/pkcsslotd.8.in --- opencryptoki-3.20.0+dfsg/man/man8/pkcsslotd.8.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/man/man8/pkcsslotd.8.in 2023-05-15 14:42:55.000000000 +0200 @@ -19,7 +19,7 @@ \fIipcrm -M 0x6202AB38\fP The daemon creates the shared memory segment with group ownership by the -\fIpkcs11\fP group. All non-root users that should be able to use +\fI@pkcs_group@\fP group. All non-root users that should be able to use openCryptoki need to be members of the group. Only trusted users should be assigned to the group, see the "SECURITY NOTE" in the \fBopencryptoki\fP(7) manual page for details. diff -Nru opencryptoki-3.20.0+dfsg/misc/misc.mk opencryptoki-3.21.0+dfsg/misc/misc.mk --- opencryptoki-3.20.0+dfsg/misc/misc.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/misc/misc.mk 2023-05-15 14:42:55.000000000 +0200 @@ -37,13 +37,20 @@ CLEANFILES += misc/pkcsslotd.service misc/opencryptoki.conf ${srcdir}/misc/pkcsslotd.service: ${srcdir}/misc/pkcsslotd.service.in - @SED@ -e s!\@sbindir\@!"@sbindir@"!g < $< > $@-t + @SED@ -e s!\@sbindir\@!"@sbindir@"!g \ + -e s!\@localstatedir\@!$(localstatedir)!g \ + -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ + -e s!\@pkcs_group\@!$(pkcs_group)!g < $< > $@-t mv $@-t $@ ${srcdir}/misc/opencryptoki.conf: ${srcdir}/misc/tmpfiles.conf.in - @SED@ -e s!\@lockdir\@!$(lockdir)!g < $< > $@-t + @SED@ -e s!\@lockdir\@!$(lockdir)!g \ + -e s!\@logdir\@!$(logdir)!g \ + -e s!\@localstatedir\@!$(localstatedir)!g \ + -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ + -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t $(foreach TOK,$(TOKENS),\ - echo "D $(lockdir)/$(TOK) 0770 root pkcs11 -" >> $@-t;) + echo "D $(lockdir)/$(TOK) 0770 root $(pkcs_group) -" >> $@-t;) mv $@-t $@ else initddir = $(sysconfdir)/rc.d/init.d @@ -51,7 +58,9 @@ CLEANFILES += misc/pkcsslotd ${srcdir}/misc/pkcsslotd: ${srcdir}/misc/pkcsslotd.in - @SED@ -e s!\@sbindir\@!"@sbindir@"!g < $< > $@-t + @SED@ -e s!\@sbindir\@!"@sbindir@"!g \ + -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ + -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t @CHMOD@ a+x $@-t mv $@-t $@ endif diff -Nru opencryptoki-3.20.0+dfsg/misc/pkcsslotd.in opencryptoki-3.21.0+dfsg/misc/pkcsslotd.in --- opencryptoki-3.20.0+dfsg/misc/pkcsslotd.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/misc/pkcsslotd.in 2023-05-15 14:42:55.000000000 +0200 @@ -12,7 +12,8 @@ . /etc/init.d/functions -PIDFILE=/run/pkcsslotd.pid +RUNDIR=/run/opencryptoki +PIDFILE=$RUNDIR/pkcsslotd.pid LOCKFILE=/var/lock/subsys/pkcsslotd SLOTDBIN=@sbindir@/pkcsslotd @@ -22,7 +23,11 @@ echo -n $"Starting pkcsslotd: " - daemon $SLOTDBIN + mkdir -p $RUNDIR + chown @pkcsslotd_user@:@pkcs_group@ $RUNDIR + chmod 710 $RUNDIR + + daemon --user=@pkcsslotd_user@ $SLOTDBIN RETVAL=$? echo diff -Nru opencryptoki-3.20.0+dfsg/misc/pkcsslotd.service.in opencryptoki-3.21.0+dfsg/misc/pkcsslotd.service.in --- opencryptoki-3.20.0+dfsg/misc/pkcsslotd.service.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/misc/pkcsslotd.service.in 2023-05-15 14:42:55.000000000 +0200 @@ -3,9 +3,75 @@ After=local-fs.target [Service] +User=@pkcsslotd_user@ +Group=@pkcs_group@ Type=forking -PIDFile=/run/pkcsslotd.pid +PIDFile=/run/opencryptoki/pkcsslotd.pid ExecStart=@sbindir@/pkcsslotd +# Uncomment the following line to allow pkcsslotd to increase the receive buffer +# size of the UDEV monitor's netlink socket via udev_monitor_set_receive_buffer_size(): +# AmbientCapabilities=CAP_NET_ADMIN + +# Sandboxing Settings: +# Many of them are not really needed, pkcsslotd run under an unpriviledged user. +NoNewPrivileges=yes +UMask=0022 +PrivateTmp=yes +PrivateUsers=no +PrivateNetwork=no +RestrictAddressFamilies=AF_UNIX AF_NETLINK +IPAddressDeny=any +ProtectClock=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectKernelLogs=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectProc=default +ProtectSystem=strict +ReadWritePaths=@localstatedir@ +ProcSubset=all +MemoryDenyWriteExecute=yes +RestrictRealtime=yes +RestrictNamespaces=yes +PrivateDevices=yes +RestrictSUIDSGID=yes +LockPersonality=yes +RemoveIPC=yes +CapabilityBoundingSet=~CAP_SETUID CAP_SETGID CAP_SETPCAP +CapabilityBoundingSet=~CAP_SYS_ADMIN +CapabilityBoundingSet=~CAP_SYS_PTRACE +CapabilityBoundingSet=~CAP_CHOWN CAP_FSETID CAP_SETFCAP +CapabilityBoundingSet=~CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER +CapabilityBoundingSet=~CAP_SYS_MODULE +CapabilityBoundingSet=~CAP_SYS_RAWIO +CapabilityBoundingSet=~CAP_SYS_TIME +CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE +CapabilityBoundingSet=~CAP_KILL +CapabilityBoundingSet=~CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW +CapabilityBoundingSet=~CAP_SYS_NICE CAP_SYS_RESOURCE +CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE +CapabilityBoundingSet=~CAP_SYS_BOOT +CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE +CapabilityBoundingSet=~CAP_IPC_LOCK +CapabilityBoundingSet=~CAP_SYS_CHROOT +CapabilityBoundingSet=~CAP_BLOCK_SUSPEND +CapabilityBoundingSet=~CAP_LEASE +CapabilityBoundingSet=~CAP_SYS_PACCT +CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG +CapabilityBoundingSet=~CAP_PERFMON CAP_BPF CAP_CHECKPOINT_RESTORE +SystemCallFilter=~@clock +SystemCallFilter=~@debug +SystemCallFilter=~@module +SystemCallFilter=~@mount +SystemCallFilter=~@raw-io +SystemCallFilter=~@reboot +SystemCallFilter=~@swap +SystemCallFilter=~@resources +SystemCallFilter=~@cpu-emulation +SystemCallFilter=~@obsolete + [Install] WantedBy=multi-user.target diff -Nru opencryptoki-3.20.0+dfsg/misc/tmpfiles.conf.in opencryptoki-3.21.0+dfsg/misc/tmpfiles.conf.in --- opencryptoki-3.20.0+dfsg/misc/tmpfiles.conf.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/misc/tmpfiles.conf.in 2023-05-15 14:42:55.000000000 +0200 @@ -1,2 +1,5 @@ # path mode uid gid age -D @lockdir@ 0770 root pkcs11 - +D /run/opencryptoki 710 @pkcsslotd_user@ @pkcs_group@ - +d @localstatedir@/lib/opencryptoki 0770 root @pkcs_group@ - +d @logdir@ 0770 root @pkcs_group@ - +D @lockdir@ 0770 root @pkcs_group@ - diff -Nru opencryptoki-3.20.0+dfsg/README.md opencryptoki-3.21.0+dfsg/README.md --- opencryptoki-3.20.0+dfsg/README.md 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/README.md 2023-05-15 14:42:55.000000000 +0200 @@ -3,13 +3,13 @@ # openCryptoki -Package version 3.20 +Package version 3.21 Please see [ChangeLog](ChangeLog) for release specific information. ## OVERVIEW -openCryptoki version 3.20 implements the PKCS#11 specification version 3.0. +openCryptoki version 3.21 implements the PKCS#11 specification version 3.0. This package includes several cryptographic tokens: CCA, ICA, TPM , SWToken, ICSF and EP11. diff -Nru opencryptoki-3.20.0+dfsg/rpm/opencryptoki.spec opencryptoki-3.21.0+dfsg/rpm/opencryptoki.spec --- opencryptoki-3.20.0+dfsg/rpm/opencryptoki.spec 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/rpm/opencryptoki.spec 2023-05-15 14:42:55.000000000 +0200 @@ -2,7 +2,7 @@ Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v3.0 -Version: 3.20.0 +Version: 3.21.0 Release: 1%{?dist} License: CPL Group: System Environment/Base @@ -17,7 +17,7 @@ BuildRequires: autoconf automake libtool autoconf-archive BuildRequires: bison flex BuildRequires: systemd-devel -BuildRequires: libitm-devel +BuildRequires: libcap-devel BuildRequires: make %ifarch s390 s390x BuildRequires: libica-devel >= 3.3 @@ -180,6 +180,7 @@ ./bootstrap.sh %configure --with-systemd=%{_unitdir} \ + --with-pkcsslotd-user=pkcsslotd --with-pkcs-group=pkcs11 \ %ifarch s390 s390x --enable-icatok --enable-ccatok --enable-ep11tok --enable-pkcsep11_migrate %else @@ -216,8 +217,9 @@ %endif %pre libs -# Create pkcs11 group +# Create pkcs11 group and pkcsslotd user getent group pkcs11 >/dev/null || groupadd -r pkcs11 +getent passwd pkcsslotd >/dev/null || useradd -r -g pkcs11 -d /run/opencryptoki -s /sbin/nologin -c "Opencryptoki pkcsslotd user" pkcsslotd exit 0 %post @@ -247,10 +249,12 @@ %{_sbindir}/p11sak %{_sbindir}/pkcstok_migrate %{_sbindir}/pkcsstats +%{_sbindir}/pkcshsm_mk_change %{_mandir}/man1/pkcsconf.1* %{_mandir}/man1/p11sak.1* %{_mandir}/man1/pkcstok_migrate.1* %{_mandir}/man1/pkcsstats.1* +%{_mandir}/man1/pkcshsm_mk_change.1* %{_mandir}/man5/%{name}.conf.5* %{_mandir}/man5/p11sak_defined_attrs.conf.5* %{_mandir}/man5/policy.conf.5* @@ -260,8 +264,10 @@ %{_libdir}/opencryptoki/methods %{_libdir}/pkcs11/methods %dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name} +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/HSM_MK_CHANGE/ %dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name} %dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name}/* +%dir %attr(710,pkcsslotd,pkcs11) /run/%{name}/ %files libs %license LICENSE diff -Nru opencryptoki-3.20.0+dfsg/testcases/ciconfig.sh opencryptoki-3.21.0+dfsg/testcases/ciconfig.sh --- opencryptoki-3.20.0+dfsg/testcases/ciconfig.sh 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/ciconfig.sh 2023-05-15 14:42:55.000000000 +0200 @@ -4,7 +4,7 @@ EPCONFDIR="$2" CCACONFDIR="$3" -LATESTCEXP="CEX7P" +LATESTCEXP="CEX8P" CCA_SYM_MKVP="5776993D2741EB4A" CCA_AES_MKVP="E9A49A58CD039BED" @@ -55,8 +55,8 @@ return $res } -# Usage: genccamkvpcfg num -function genccamkvpcfg() { +# Usage: genccacfg num +function genccacfg() { cat < "${CCACONFDIR}/ccatok${1}.conf" version cca-0 EXPECTED_MKVPS { @@ -64,6 +64,7 @@ AES = "$CCA_AES_MKVP" APKA = "$CCA_APKA_MKVP" } +PKEY_MODE = ENABLED EOF } @@ -75,7 +76,7 @@ fi # initialize opencryptoki.conf -echo "version opencryptoki-3.20" > "${OCKCONFDIR}/opencryptoki.conf" +echo "version opencryptoki-3.21" > "${OCKCONFDIR}/opencryptoki.conf" # enable full statistics echo "statistics (on,implicit,internal)" >> "${OCKCONFDIR}/opencryptoki.conf" @@ -85,7 +86,7 @@ addslot 11 libpkcs11_ica.so ica1 # CCA token -genccamkvpcfg 20 +genccacfg 20 addslot 20 libpkcs11_cca.so cca0 ccatok20.conf addslot 21 libpkcs11_cca.so cca1 @@ -126,7 +127,7 @@ genep11cfg 44 "DIGEST_LIBICA OFF" addslot 44 libpkcs11_ep11.so ep4 ep11tok44.conf -# 5: latest (CEX7 only) +# 5: latest (CEX8 only) # PKEY_MODE ENABLE4NONEXTR if genlatestep11cfg 45 "PKEY_MODE ENABLE4NONEXTR"; then addslot 45 libpkcs11_ep11.so ep5 ep11tok45.conf diff -Nru opencryptoki-3.20.0+dfsg/testcases/common/common.c opencryptoki-3.21.0+dfsg/testcases/common/common.c --- opencryptoki-3.20.0+dfsg/testcases/common/common.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/common/common.c 2023-05-15 14:42:55.000000000 +0200 @@ -496,10 +496,12 @@ CK_RV generate_EC_KeyPair(CK_SESSION_HANDLE session, CK_BYTE* ec_params, CK_ULONG ec_params_len, CK_OBJECT_HANDLE * publ_key, - CK_OBJECT_HANDLE * priv_key) + CK_OBJECT_HANDLE * priv_key, + CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; + CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; @@ -515,6 +517,8 @@ {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, + {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, + {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate)/sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate)/sizeof(CK_ATTRIBUTE); @@ -544,6 +548,7 @@ { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_BBOOL pkeyextractable = !extractable; CK_KEY_TYPE keyType = CKK_EC; CK_UTF8CHAR label[] = "An EC private key object"; CK_BYTE subject[] = {0}; @@ -564,7 +569,8 @@ {CKA_DERIVE, &true, sizeof(true)}, {CKA_EC_PARAMS, params, params_len}, {CKA_VALUE, privatekey, privatekey_len}, - {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)} + {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, + {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; // create key diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/aes_func.c opencryptoki-3.21.0+dfsg/testcases/crypto/aes_func.c --- opencryptoki-3.20.0+dfsg/testcases/crypto/aes_func.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/aes_func.c 2023-05-15 14:42:55.000000000 +0200 @@ -53,7 +53,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -208,7 +208,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -493,7 +493,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -666,7 +666,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -880,7 +880,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -1052,7 +1052,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(tsuite->tvcount, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -1277,7 +1277,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -1565,7 +1565,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -1833,7 +1833,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -2026,7 +2026,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -2204,7 +2204,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(slot_id)) { + if (pkey && !is_ep11_token(slot_id) && !is_cca_token(SLOT_ID)) { testsuite_skip(3, "pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -2406,7 +2406,7 @@ testcase_user_login(); /* Skip tests if the slot doesn't support protected keys*/ - if (!is_ep11_token(slot_id)) { + if (!is_ep11_token(slot_id) && !is_cca_token(slot_id)) { testsuite_skip(1, "Slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -2521,7 +2521,7 @@ testcase_user_login(); /* Skip tests if the slot doesn't support protected keys*/ - if (!is_ep11_token(slot_id)) { + if (!is_ep11_token(slot_id) && !is_cca_token(slot_id)) { testsuite_skip(6, "Slot %u doesn't support protected keys", (unsigned int) slot_id); goto testcase_cleanup; @@ -2799,7 +2799,7 @@ pkey = CK_FALSE; rv = aes_funcs(); - if (is_ep11_token(SLOT_ID)) { + if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { pkey = CK_TRUE; rv += aes_funcs(); rv += aes_funcs_pkey(); diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/des3_func.c opencryptoki-3.21.0+dfsg/testcases/crypto/des3_func.c --- opencryptoki-3.20.0+dfsg/testcases/crypto/des3_func.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/des3_func.c 2023-05-15 14:42:55.000000000 +0200 @@ -1328,6 +1328,95 @@ return rc; } +CK_RV do_PBE(void) +{ + CK_SESSION_HANDLE session; + CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; + CK_FLAGS flags; + CK_RV rc = CKR_OK; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG user_pin_len; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_BYTE iv[DES3_IV_SIZE]; + CK_BYTE clear[BIG_REQUEST]; + CK_BYTE encrypted[BIG_REQUEST]; + CK_ULONG clear_len, encrypted_len; + CK_PBE_PARAMS pbe_param; + CK_MECHANISM mech = { CKM_PBE_SHA1_DES3_EDE_CBC, + &pbe_param, sizeof(pbe_param) }; + CK_MECHANISM enc_mech = { CKM_DES3_CBC, iv, sizeof(iv) }; + + testsuite_begin("PBE."); + testcase_rw_session(); + testcase_user_login(); + + /** skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (0x%x)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto testcase_cleanup; + } + if (!mech_supported(slot_id, enc_mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (0x%x)", + (unsigned int) slot_id, + mech_to_str(enc_mech.mechanism), + (unsigned int) enc_mech.mechanism); + goto testcase_cleanup; + } + + testcase_begin("PBE with %s", mech_to_str(mech.mechanism)); + testcase_new_assertion(); + + pbe_param.pInitVector = iv; + pbe_param.pPassword = (CK_BYTE *)"Password"; + pbe_param.ulPasswordLen = 4; + pbe_param.pSalt = (CK_BYTE *)"Salt"; + pbe_param.ulSaltLen = 4; + pbe_param.ulIteration = 1000; + + rc = funcs->C_GenerateKey(session, &mech, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_EncryptInit(session, &enc_mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + memset(clear, 0x55, sizeof(clear)); + clear_len = sizeof(clear); + memset(encrypted, 0x00, sizeof(encrypted)); + encrypted_len = sizeof(encrypted); + + rc = funcs->C_Encrypt(session, clear, clear_len, encrypted, &encrypted_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + testcase_pass("PBE with %s" ,mech_to_str(mech.mechanism)); + + goto testcase_cleanup; + +error: + if (h_key != CK_INVALID_HANDLE) + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_close_session(); + + return rc; +} + CK_RV des3_funcs(void) { int i; @@ -1373,6 +1462,9 @@ break; } + /* CKM_PBE_SHA1_DES3_EDE_CBC */ + rv = do_PBE(); + return rv; } diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/digest_func.c opencryptoki-3.21.0+dfsg/testcases/crypto/digest_func.c --- opencryptoki-3.20.0+dfsg/testcases/crypto/digest_func.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/digest_func.c 2023-05-15 14:42:55.000000000 +0200 @@ -1607,6 +1607,145 @@ return rc; } +CK_RV do_SHA_derive_key(void) +{ + CK_MECHANISM secret_mech = { CKM_AES_KEY_GEN, 0, 0 }; + CK_ULONG key_len; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE h_derived_key = CK_INVALID_HANDLE; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; + unsigned int i, k; + CK_BBOOL true = CK_TRUE; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_EXTRACTABLE, &true, sizeof(CK_BBOOL)}, + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, + {CKA_IBM_USE_AS_DATA, &true, sizeof(CK_BBOOL)}, + }; + CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); + CK_ATTRIBUTE derive_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, + }; + CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); + + CK_MECHANISM derive_mechs[5] = { + { CKM_SHA1_KEY_DERIVATION, 0, 0 }, + { CKM_SHA224_KEY_DERIVATION, 0, 0 }, + { CKM_SHA256_KEY_DERIVATION, 0, 0 }, + { CKM_SHA384_KEY_DERIVATION, 0, 0 }, + { CKM_SHA512_KEY_DERIVATION, 0, 0 } + }; + + struct { + CK_KEY_TYPE keytype; + CK_ULONG key_len; + } attributes[5] = { + { -1, 0 }, + { CKK_GENERIC_SECRET, 0 }, + { CKK_GENERIC_SECRET, 20 }, + { CKK_DES3, 0 }, + { CKK_AES, 16 }, + }; + + testsuite_begin("do_SHA_derive_key"); + + testcase_rw_session(); + testcase_user_login(); + + if (!mech_supported(SLOT_ID, secret_mech.mechanism)) { + testsuite_skip(1, "mechanism %lu not supported with slot %lu", + secret_mech.mechanism, slot_id); + goto testcase_cleanup; + } + + key_len = 32; + rc = funcs->C_GenerateKey(session, &secret_mech, key_gen_tmpl, + key_gen_tmpl_len, &h_key); + if (rc != CKR_OK) { + if (is_rejected_by_policy(rc, session)) { + testsuite_skip(1, "AES key generation is not allowed by policy"); + goto testcase_cleanup; + } + + testcase_error("generate_SecretKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + for (i = 0; i < sizeof(derive_mechs) / sizeof(CK_MECHANISM); i++) { + for (k = 0; k < sizeof(attributes) / sizeof(attributes[0]); k++) { + key_type = attributes[k].keytype; + key_len = attributes[k].key_len; + + /* SHA-1 can produce only 20 bytes, not sufficient for a 3DES key */ + if (key_type == CKK_DES3 && + derive_mechs[i].mechanism == CKM_SHA1_KEY_DERIVATION) + continue; + + testcase_begin("Derive key with %s keytype=0x%lx, value_len=%lu", + mech_to_str(derive_mechs[i].mechanism), + key_type, key_len); + + if (!mech_supported(SLOT_ID, derive_mechs[i].mechanism)) { + testcase_skip("mechanism %lu not supported with slot %lu", + derive_mechs[i].mechanism, slot_id); + continue; + } + + if (key_type == (CK_ULONG)-1) + derive_tmpl_len = 1; + else if (key_len == 0) + derive_tmpl_len = 2; + else + derive_tmpl_len = 3; + + rc = funcs->C_DeriveKey(session, &derive_mechs[i], + h_key, derive_tmpl, + derive_tmpl_len, &h_derived_key); + if (rc != CKR_OK) { + if (rc == CKR_POLICY_VIOLATION) { + testcase_skip("key derivation is not allowed by policy"); + continue; + } + + testcase_fail("Derive key with %s keytype=0x%lx, value_len=%lu: rc: %s", + mech_to_str(derive_mechs[i].mechanism), + key_type, key_len, p11_get_ckr(rc)); + } else { + testcase_pass("Derive key with %s keytype=0x%lx, value_len=%lu", + mech_to_str(derive_mechs[i].mechanism), + key_type, key_len); + } + + if (h_derived_key != CK_INVALID_HANDLE && + (rc = funcs->C_DestroyObject(session, h_derived_key)) != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + h_derived_key = CK_INVALID_HANDLE; + } + } + + if (h_key != CK_INVALID_HANDLE && + (rc = funcs->C_DestroyObject(session, h_key)) != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + if (h_derived_key != CK_INVALID_HANDLE && + (rc = funcs->C_DestroyObject(session, h_derived_key)) != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + if ((rc = funcs->C_CloseAllSessions(slot_id)) != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + CK_RV digest_funcs(void) { CK_RV rc; @@ -1669,6 +1808,8 @@ /* HMAC test with a generated generic secret key */ rc = do_HMAC_SignVerify_WithGenKey(); + rc = do_SHA_derive_key(); + return rc; } diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/ec_func.c opencryptoki-3.21.0+dfsg/testcases/crypto/ec_func.c --- opencryptoki-3.20.0+dfsg/testcases/crypto/ec_func.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/ec_func.c 2023-05-15 14:42:55.000000000 +0200 @@ -392,7 +392,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -926,7 +926,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -1076,11 +1076,14 @@ }; CK_ULONG secretB_tmpl_len = sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE); + CK_BBOOL extractable = !pkey; CK_ATTRIBUTE derive_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)}, {CKA_VALUE_LEN, &(ecdh_tv[i].derived_key_len), sizeof(CK_ULONG)}, {CKA_SENSITIVE, &false, sizeof(false)}, + {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, + {CKA_IBM_PROTKEY_EXTRACTABLE, &pkey, sizeof(CK_BBOOL)}, }; CK_ULONG derive_tmpl_len = sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); @@ -1536,7 +1539,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -1587,21 +1590,10 @@ } } - CK_BBOOL bextr = !pkey; - CK_ATTRIBUTE ec_priv_attr[] = { - {CKA_EXTRACTABLE, &bextr, sizeof(CK_BBOOL)}, - }; - CK_ULONG ec_priv_attr_len = sizeof(ec_priv_attr) / sizeof(CK_ATTRIBUTE); - CK_ATTRIBUTE ec_publ_attr[] = { - {CKA_ECDSA_PARAMS, (CK_VOID_PTR)der_ec_supported[i].curve, - der_ec_supported[i].size} - }; - CK_ULONG ec_publ_attr_len = sizeof(ec_publ_attr) / sizeof(CK_ATTRIBUTE); + rc = generate_EC_KeyPair(session, (CK_BYTE *)der_ec_supported[i].curve, + der_ec_supported[i].size, + &publ_key, &priv_key, !pkey); - rc = funcs->C_GenerateKeyPair(session, &mech, - ec_publ_attr, ec_publ_attr_len, - ec_priv_attr, ec_priv_attr_len, - &publ_key, &priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) { testcase_skip("EC key generation is not allowed by policy"); @@ -1615,7 +1607,7 @@ continue; } testcase_fail - ("C_GenerateKeyPair with valid input failed at i=%lu (%s), " + ("generate_EC_KeyPair with valid input failed at i=%lu (%s), " "rc=%s", i, der_ec_supported[i].name, p11_get_ckr(rc)); goto testcase_cleanup; } @@ -1642,17 +1634,13 @@ } for (i = 0; i < NUMECINVAL; i++) { - CK_ATTRIBUTE ec_attr[] = { - {CKA_ECDSA_PARAMS, (CK_VOID_PTR)der_ec_notsupported[i].curve, - der_ec_notsupported[i].size} - }; - - rc = funcs->C_GenerateKeyPair(session, &mech, ec_attr, 1, NULL, 0, - &publ_key, &priv_key); + rc = generate_EC_KeyPair(session, (CK_BYTE *)der_ec_notsupported[i].curve, + der_ec_notsupported[i].size, + &publ_key, &priv_key, !pkey); testcase_new_assertion(); if (rc == CKR_OK) { testcase_fail - ("C_GenerateKeyPair with invalid input failed at i=%lu (%s)", + ("generate_EC_KeyPair with invalid input failed at i=%lu (%s)", i, der_ec_supported[i].name); goto testcase_cleanup; } @@ -1690,7 +1678,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -1860,7 +1848,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -2207,7 +2195,11 @@ CK_MECHANISM ec_mech = {CKM_ECDSA, NULL, 0}; CK_MECHANISM ed25519_mech = {CKM_IBM_ED25519_SHA512, NULL, 0}; CK_MECHANISM ed448_mech = {CKM_IBM_ED448_SHA3, NULL, 0}; - CK_BYTE data[] = "abcdefghijklmnopqrstuvwxyz"; + CK_BYTE data[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + }; CK_BYTE *sig = NULL; CK_ULONG sig_len; unsigned int i, j; @@ -2216,7 +2208,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -2247,13 +2239,13 @@ for (j = 0; j < 2; j++) { if (j == 0) - testcase_begin("Starting Import EC private key (%s) index=%u sign via CPACF / verify via ep11 card", + testcase_begin("Starting Import EC private key (%s) index=%u sign via CPACF / verify via card", ec_tv[i].name, i); else - testcase_begin("Starting Import EC private key (%s) index=%u sign via ep11 card / verify via CPACF", + testcase_begin("Starting Import EC private key (%s) index=%u sign via card / verify via CPACF", ec_tv[i].name, i); - /* j toggles between sign via protected key / verify via ep11 card + /* j toggles between sign via protected key / verify via card * and vice versa. */ if (j == 0) { extr_priv = FALSE; @@ -2359,10 +2351,10 @@ } if (j == 0) - testcase_pass("*Import EC private key (%s) index=%u sign via CPACF / verify via ep11 card passed.", + testcase_pass("*Import EC private key (%s) index=%u sign via CPACF / verify via card passed.", ec_tv[i].name, i); else - testcase_pass("*Import EC private key (%s) index=%u sign via ep11 card / verify via CPACF passed.", + testcase_pass("*Import EC private key (%s) index=%u sign via card / verify via CPACF passed.", ec_tv[i].name, i); } } @@ -2494,7 +2486,7 @@ testcase_user_login(); /* Skip tests if pkey = true, but the slot doesn't support protected keys*/ - if (pkey && !is_ep11_token(SLOT_ID)) { + if (pkey && !is_ep11_token(SLOT_ID) && !is_cca_token(SLOT_ID)) { testcase_skip("pkey test option is true, but slot %u doesn't support protected keys", (unsigned int) SLOT_ID); goto testcase_cleanup; @@ -2786,7 +2778,7 @@ rv += run_DeriveECDHKeyKAT(); rv += run_DeriveBTC(); - if (is_ep11_token(SLOT_ID)) { + if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { pkey = CK_TRUE; rv = run_GenerateECCKeyPairSignVerify(); rv += run_ImportECCKeyPairSignVerify(); diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/kyber_func.c opencryptoki-3.21.0+dfsg/testcases/crypto/kyber_func.c --- opencryptoki-3.20.0+dfsg/testcases/crypto/kyber_func.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/kyber_func.c 2023-05-15 14:42:55.000000000 +0200 @@ -207,7 +207,7 @@ } rc = generate_EC_KeyPair(session, (CK_BYTE *)prime256v1, sizeof(prime256v1), - &publ_key, &priv_key); + &publ_key, &priv_key, CK_FALSE); if (rc != CKR_OK) { testcase_notice("generate_EC_KeyPair rc=%s", p11_get_ckr(rc)); goto error; diff -Nru opencryptoki-3.20.0+dfsg/testcases/crypto/rsa.h opencryptoki-3.21.0+dfsg/testcases/crypto/rsa.h --- opencryptoki-3.20.0+dfsg/testcases/crypto/rsa.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/crypto/rsa.h 2023-05-15 14:42:55.000000000 +0200 @@ -7655,6 +7655,226 @@ .chunks = {100, 100, 43}, .num_chunks = 3, }, + { // 44 (pC_GetAttributeValue(session1, obj_list[i], attrs, 1); if (rv != CKR_OK || - strcmp((char *)label, "RSA-1024-SLOT1") != 0) { + strcmp((char *)label, "RSA-2048-SLOT1") != 0) { num_wrong++; testcase_fail("C_FindObjects() on slot %lu found foreign object: %s\n", slot_id1, label); } @@ -329,7 +329,7 @@ memset(label, 0, sizeof(label)); rv = funcs->C_GetAttributeValue(session2, obj_list[i], attrs, 1); if (rv != CKR_OK || - strcmp((char *)label, "RSA-1024-SLOT2") != 0) { + strcmp((char *)label, "RSA-2048-SLOT2") != 0) { num_wrong++; testcase_fail("C_FindObjects() on slot %lu found foreign object: %s\n", slot_id2, label); //goto close_session; diff -Nru opencryptoki-3.20.0+dfsg/testcases/misc_tests/p11sak_test.sh opencryptoki-3.21.0+dfsg/testcases/misc_tests/p11sak_test.sh --- opencryptoki-3.20.0+dfsg/testcases/misc_tests/p11sak_test.sh 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/misc_tests/p11sak_test.sh 2023-05-15 14:42:55.000000000 +0200 @@ -12,12 +12,13 @@ # # sudo -E ./p11sak_test.sh +DIR=$(dirname "$0") + status=0 echo "** Now executing 'p11sak_test.sh'" - # tmp files P11SAK_DES_PRE=p11sak-des-pre.out @@ -26,6 +27,9 @@ P11SAK_3DES_PRE=p11sak-3des-pre.out P11SAK_3DES_LONG=p11sak-3des-long.out P11SAK_3DES_POST=p11sak-3des-post.out +P11SAK_GENERIC_PRE=p11sak-generic-pre.out +P11SAK_GENERIC_LONG=p11sak-generic-long.out +P11SAK_GENERIC_POST=p11sak-generic-post.out P11SAK_AES_PRE=p11sak-aes-pre.out P11SAK_AES_LONG=p11sak-aes-long.out P11SAK_AES_POST=p11sak-aes-post.out @@ -35,12 +39,18 @@ P11SAK_RSA_PRE=p11sak-rsa-pre.out P11SAK_RSA_LONG=p11sak-rsa-long.out P11SAK_RSA_POST=p11sak-rsa-post.out +P11SAK_DH_PRE=p11sak-dh-pre.out +P11SAK_DH_LONG=p11sak-dh-long.out +P11SAK_DH_POST=p11sak-dh-post.out +P11SAK_DSA_PRE=p11sak-dsa-pre.out +P11SAK_DSA_LONG=p11sak-dsa-long.out +P11SAK_DSA_POST=p11sak-dsa-post.out P11SAK_EC_PRE=p11sak-ec-pre.out P11SAK_EC_LONG=p11sak-ec-long.out P11SAK_EC_POST=p11sak-ec-post.out -P11SAK_IBM_DIL_PRE=p11sak-ibm-dil-pre.out -P11SAK_IBM_DIL_LONG=p11sak-ibm-dil-long.out -P11SAK_IBM_DIL_POST=p11sak-ibm-dil-post.out +P11SAK_IBM_DILITHIUM_PRE=p11sak-ibm-dilithium-pre.out +P11SAK_IBM_DILITHIUM_LONG=p11sak-ibm-dilithium-long.out +P11SAK_IBM_DILITHIUM_POST=p11sak-ibm-dilithium-post.out P11SAK_IBM_KYBER_PRE=p11sak-ibm-kyber-pre.out P11SAK_IBM_KYBER_LONG=p11sak-ibm-kyber-long.out P11SAK_IBM_KYBER_POST=p11sak-ibm-kyber-post.out @@ -51,54 +61,92 @@ echo "** Setting SLOT=30 to the Softtoken unless otherwise set - 'p11sak_test.sh'" - # setting SLOT=30 to the Softtoken SLOT=${SLOT:-30} echo "** Using Slot $SLOT with PKCS11_USER_PIN $PKCS11_USER_PIN and PKCSLIB $PKCSLIB - 'p11sak_test.sh'" -echo "** Now generating keys - 'p11sak_test.sh'" +echo "** Now generating keys - 'p11sak_test.sh'" # generate objects +RC_P11SAK_GENERATE=0 # des if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then - p11sak generate-key des --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-des + p11sak generate-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating des keys, slot does not support CKM_DES_KEY_GEN" fi # 3des -p11sak generate-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-3des +p11sak generate-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +# generic +p11sak generate-key generic 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # aes [128 | 192 | 256] -p11sak generate-key aes 128 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-128 -p11sak generate-key aes 192 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-192 -p11sak generate-key aes 256 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-256 +p11sak generate-key aes 128 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-128" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key aes 192 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-192" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key aes 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-256" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # aes-xts [128 | 256] -if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) && -z $( pkcsconf -t -c $SLOT | grep "Model: EP11") ]]; then - p11sak generate-key aes-xts 128 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-xts-128 - p11sak generate-key aes-xts 256 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-xts-256 +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) ]]; then + if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") ]]; then + # EP11 needs CKA_IBM_PROTKEY_EXTRACTABLE=TRUE and CKA_EXTRACTABLE=FALSE for AES-XTS keys + P11SAK_ATTR="--attr xK" + else + P11SAK_ATTR="" + fi + p11sak generate-key aes-xts 128 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-128" $P11SAK_ATTR + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) + p11sak generate-key aes-xts 256 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-256" $P11SAK_ATTR + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating aes-xts keys, slot does not support CKM_AES_XTS_KEY_GEN" fi # rsa [1024 | 2048 | 4096] -p11sak generate-key rsa 1024 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-1024 -p11sak generate-key rsa 2048 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-2048 -p11sak generate-key rsa 4096 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-4096 +p11sak generate-key rsa 1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key rsa 2048 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key rsa 4096 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +# dh ffdhe2048 +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DH_PKCS_KEY_PAIR_GEN) ]]; then + p11sak generate-key dh ffdhe2048 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh" + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +else + echo "Skip generating dh keys, slot does not support CKM_DH_PKCS_KEY_PAIR_GEN" +fi +# dsa dsa-param.pem +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DSA_KEY_PAIR_GEN) ]]; then + p11sak generate-key dsa dsa-param.pem --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa" + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +else + echo "Skip generating dsa keys, slot does not support CKM_DSA_KEY_PAIR_GEN" +fi # ec [prime256v1 | secp384r1 | secp521r1] -p11sak generate-key ec prime256v1 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-prime256v1 -p11sak generate-key ec secp384r1 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp384r1 -p11sak generate-key ec secp521r1 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp521r1 +p11sak generate-key ec prime256v1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key ec secp384r1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) +p11sak generate-key ec secp521r1 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1" +RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) # ibm-dilithium if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then - p11sak generate-key ibm-dilithium r2_65 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-dilithium + p11sak generate-key ibm-dilithium r2_65 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium" + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" fi # ibm-kyber if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then - p11sak generate-key ibm-kyber r2_1024 --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-kyber + p11sak generate-key ibm-kyber r2_1024 --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber" + RC_P11SAK_GENERATE=$((RC_P11SAK_GENERATE + $?)) else echo "Skip generating ibm-kyber keys, slot does not support CKM_IBM_KYBER" fi @@ -106,24 +154,55 @@ echo "** Now list keys and redirect output to pre-files - 'p11sak_test.sh'" - # list objects -p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_DES_PRE -p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_3DES_PRE -p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_AES_PRE -p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_AES_XTS_PRE -p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_RSA_PRE -p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_EC_PRE -p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_IBM_DIL_PRE - -p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_DES_LONG -p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_3DES_LONG -p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_AES_LONG -p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_AES_XTS_LONG -p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_RSA_LONG -p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_EC_LONG -p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_IBM_DIL_LONG -p11sak list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --long &> $P11SAK_IBM_KYBER_LONG +RC_P11SAK_LIST=0 +p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" &> $P11SAK_DES_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" &> $P11SAK_3DES_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" &> $P11SAK_GENERIC_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" &> $P11SAK_AES_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" &> $P11SAK_RSA_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh*" &> $P11SAK_DH_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa*" &> $P11SAK_DSA_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-*" &> $P11SAK_EC_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) +p11sak list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_PRE +RC_P11SAK_LIST=$((RC_P11SAK_LIST + $?)) + +RC_P11SAK_LIST_LONG=0 +p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-des" &> $P11SAK_DES_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-3des" &> $P11SAK_3DES_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-generic" &> $P11SAK_GENERIC_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-aes-*" &> $P11SAK_AES_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-rsa-*" &> $P11SAK_RSA_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-dh*" &> $P11SAK_DH_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-dsa*" &> $P11SAK_DSA_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ec-*" &> $P11SAK_EC_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) +p11sak list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --long --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_LONG +RC_P11SAK_LIST_LONG=$((RC_P11SAK_LIST_LONG + $?)) + p11sak list-key all --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_ALL_PINOPT RC_P11SAK_PINOPT=$? @@ -132,67 +211,302 @@ printf "${PKCS11_USER_PIN}\n" | p11sak list-key all --slot $SLOT --force-pin-prompt | tail -n +2 &> $P11SAK_ALL_PINCON RC_P11SAK_PINCON=$? -echo "** Now remove keys - 'p11sak_test.sh'" +echo "** Now updating keys - 'p11sak_test.sh'" + +RC_P11SAK_UPDATE=0 +p11sak set-key-attr aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" --new-attr "ed" --force +RC_P11SAK_UPDATE=$((RC_P11SAK_UPDATE + $?)) +p11sak set-key-attr rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" --new-id "012345" --force +RC_P11SAK_UPDATE=$((RC_P11SAK_UPDATE + $?)) + + +echo "** Now copying keys - 'p11sak_test.sh'" + +RC_P11SAK_COPY=0 +p11sak copy-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" --new-label "p11sak-aes-copied" --new-attr "ED" --force +RC_P11SAK_COPY=$((RC_P11SAK_COPY + $?)) + + +echo "** Now importing keys - 'p11sak_test.sh'" + +RC_P11SAK_IMPORT=0 +# aes +p11sak import-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file $DIR/aes.key --attr sX +RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +# rsa +p11sak import-key rsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-private" --file $DIR/rsa-key.pem --attr sX +RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +p11sak import-key rsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-public" --file $DIR/rsa-key.pem --attr sX +RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +# dsa +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DSA) ]]; then + p11sak import-key dsa private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-private" --file $DIR/dsa-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) + p11sak import-key dsa public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-public" --file $DIR/dsa-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +else + echo "Skip importing dsa keys, slot does not support CKM_DSA" +fi +# dh +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DH_PKCS_DERIVE) ]]; then + p11sak import-key dh private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-private" --file $DIR/dh-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) + p11sak import-key dh public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-public" --file $DIR/dh-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +else + echo "Skip importing dh keys, slot does not support CKM_DH_PKCS_DERIVE" +fi +# ec +p11sak import-key ec private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-private" --file $DIR/ec-key.pem --attr sX +RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +p11sak import-key ec public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-public" --file $DIR/ec-key.pem --attr sX +RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +# ibm-dilithium +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then + p11sak import-key ibm-dilithium private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-private" --file $DIR/ibm-dilithium-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) + p11sak import-key ibm-dilithium public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-public" --file $DIR/ibm-dilithium-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +else + echo "Skip importing ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" +fi +# ibm-kyber +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then + p11sak import-key ibm-kyber private --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-private" --file $DIR/ibm-kyber-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) + p11sak import-key ibm-kyber public --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-public" --file $DIR/ibm-kyber-key.pem --attr sX + RC_P11SAK_IMPORT=$((RC_P11SAK_IMPORT + $?)) +else + echo "Skip importing ibm-kyber keys, slot does not support CKM_IBM_KYBER" +fi + + +echo "** Now exporting keys - 'p11sak_test.sh'" + +RC_P11SAK_EXPORT=0 +# aes +if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-aes.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +else + p11sak export-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "import-aes" --file export-aes.key --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + diff export-aes.key $DIR/aes.key > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +fi +# rsa +if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-public" --file export-rsa-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-private" --file export-rsa-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +else + p11sak export-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-rsa-*" --file export-rsa-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + openssl pkey -in export-rsa-key.pem -check -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +fi +openssl pkey -in export-rsa-key.pem -pubin -text > /dev/null +RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +# dsa +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DSA) ]]; then + if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-public" --file export-dsa-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-private" --file export-dsa-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + else + p11sak export-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dsa-*" --file export-dsa-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + openssl pkey -in export-dsa-key.pem -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + fi + openssl pkey -in export-dsa-key.pem -pubin -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +else + echo "Skip exporting dsa keys, slot does not support CKM_DSA" +fi +# dh +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DH_PKCS_DERIVE) ]]; then + if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-public" --file export-dh-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-private" --file export-dh-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + else + p11sak export-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "import-dh-*" --file export-dh-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + openssl pkey -in export-dh-key.pem -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + fi + openssl pkey -in export-dh-key.pem -pubin -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +else + echo "Skip exporting dh keys, slot does not support CKM_DH_PKCS_DERIVE" +fi +# ec +if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-public" --file export-ec-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-private" --file export-ec-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +else + p11sak export-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ec-*" --file export-ec-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + openssl pkey -in export-ec-key.pem -check -text > /dev/null + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +fi +openssl pkey -in export-ec-key.pem -pubin -text > /dev/null +RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) +# ibm-dilithium +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then + if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-public" --file export-ibm-dilithium-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-private" --file export-ibm-dilithium-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + else + p11sak export-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-dilithium-*" --file export-ibm-dilithium-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + fi +else + echo "Skip exporting ibm-dilithium keys, slot does not support CKM_IBM_DILITHIUM" +fi +# ibm-kyber +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then + if [[ -n $( pkcsconf -t -c $SLOT | grep "Model: EP11") || -n $( pkcsconf -t -c $SLOT | grep "Model: CCA") ]]; then + p11sak export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-public" --file export-ibm-kyber-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + p11sak export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-private" --file export-ibm-kyber-key.opaque --force --opaque + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + else + p11sak export-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "import-ibm-kyber-*" --file export-ibm-kyber-key.pem --force + RC_P11SAK_EXPORT=$((RC_P11SAK_EXPORT + $?)) + fi +else + echo "Skip exporting ibm-kyber keys, slot does not support CKM_IBM_KYBER" +fi + + +echo "** Now remove keys - 'p11sak_test.sh'" # remove objects +RC_P11SAK_REMOVE=0 # des -p11sak remove-key des --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-des -f +p11sak remove-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # 3des -p11sak remove-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-3des -f -# aes [128 | 192 | 256] -p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-128 -f -p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-192 -f -p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-256 -f +p11sak remove-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# generic +p11sak remove-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# aes [128 | 192 | 256 | copied] +p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-128" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-192" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-256" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-copied" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # aes-xts [128 | 256] -p11sak remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-xts-128 -f -p11sak remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-aes-xts-256 -f +p11sak remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-128" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-256" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # rsa [1024 | 2048 | 4096] # remove public key -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-1024:pub -f -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-2048:pub -f -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-4096:pub -f +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-1024:prv -f -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-2048:prv -f -p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-rsa-4096:prv -f +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-1024:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-2048:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-4096:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# dh +# remove public key +p11sak remove-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# remove private key +p11sak remove-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# dsa +# remove public key +p11sak remove-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# remove private key +p11sak remove-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # ec [prime256v1 | secp384r1 | secp521r1] #remove public key -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-prime256v1:pub -f -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp384r1:pub -f -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp521r1:pub -f +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) # remove private key -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-prime256v1:prv -f -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp384r1:prv -f -p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ec-secp521r1:prv -f -# remove ibm dilithium keys -p11sak remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-dilithium:pub -f -p11sak remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-dilithium:prv -f -# remove ibm kyber keys -p11sak remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-kyber:pub -f -p11sak remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label p11sak-ibm-kyber:prv -f +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-prime256v1:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp384r1:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-secp521r1:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# remove ibm-dilithium keys +p11sak remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +# remove ibm-kyber keys +p11sak remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber:pub" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber:prv" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) +p11sak remove-key --slot $SLOT --pin $PKCS11_USER_PIN --label "import*" -f +RC_P11SAK_REMOVE=$((RC_P11SAK_REMOVE + $?)) -echo "** Now list keys and rediirect to post-files - 'p11sak_test.sh'" - +echo "** Now list keys and redirect to post-files - 'p11sak_test.sh'" # list objects -p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_DES_POST -p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_3DES_POST -p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_AES_POST -p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_AES_XTS_POST -p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_RSA_POST -p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_EC_POST -p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_IBM_DIL_POST -p11sak list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN &> $P11SAK_IBM_KYBER_POST +RC_P11SAK_LIST_POST=0 +p11sak list-key des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-des" &> $P11SAK_DES_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key 3des --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-3des" &> $P11SAK_3DES_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key generic --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-generic" &> $P11SAK_GENERIC_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key aes --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-*" &> $P11SAK_AES_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key aes-xts --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-aes-xts-*" &> $P11SAK_AES_XTS_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key rsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-rsa-*" &> $P11SAK_RSA_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key dh --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dh*" &> $P11SAK_DH_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key dsa --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-dsa*" &> $P11SAK_DSA_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key ec --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ec-*" &> $P11SAK_EC_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key ibm-dilithium --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-dilithium*" &> $P11SAK_IBM_DILITHIUM_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) +p11sak list-key ibm-kyber --slot $SLOT --pin $PKCS11_USER_PIN --label "p11sak-ibm-kyber*" &> $P11SAK_IBM_KYBER_POST +RC_P11SAK_LIST_POST=$((RC_P11SAK_LIST_POST + $?)) echo "** Now checking output files to determine PASS/FAIL of tests - 'p11sak_test.sh'" - if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then # check DES - grep -q 'p11sak-des' $P11SAK_DES_PRE + grep -q "p11sak-des" $P11SAK_DES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key des PASS Generated random DES key" @@ -200,7 +514,7 @@ echo "* TESTCASE generate-key des FAIL Failed to generate DES key" status=1 fi - grep -v -q 'p11sak-des' $P11SAK_DES_POST + grep -v -q "p11sak-des" $P11SAK_DES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key des PASS Deleted generated DES key" @@ -215,43 +529,43 @@ if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DES_KEY_GEN) ]]; then # CK_BBOOL - if [[ $(grep -A 20 'p11sak-des' $P11SAK_DES_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "1" ]]; then - echo "* TESTCASE list-key des PASS Listed random des public keys CK_BBOOL attribute" + if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_DES_LONG) == "1" ]]; then + echo "* TESTCASE list-key des PASS Listed random des keys CK_BBOOL attribute" else - echo "* TESTCASE list-key des FAIL Failed to list des public keys CK_BBOOL attribute" + echo "* TESTCASE list-key des FAIL Failed to list des keys CK_BBOOL attribute" status=1 fi # CK_ULONG - if [[ $(grep -A 20 'p11sak-des' $P11SAK_DES_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key des PASS Listed random des public keys CK_ULONG attribute" + if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_DES_LONG) == "0" ]]; then + echo "* TESTCASE list-key des PASS Listed random des keys CK_ULONG attribute" else - echo "* TESTCASE list-key des FAIL Failed to list des public keys CK_ULONG attribute" + echo "* TESTCASE list-key des FAIL Failed to list des keys CK_ULONG attribute" status=1 fi # CK_BYTE - if [[ $(grep -A 20 'p11sak-des' $P11SAK_DES_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key des PASS Listed random des public keys CK_BYTE attribute" + if [[ $(grep -c "CKA_VALUE:" $P11SAK_DES_LONG) == "1" ]]; then + echo "* TESTCASE list-key des PASS Listed random des keys CK_BYTE attribute" else - echo "* TESTCASE list-key des FAIL Failed to list des public keys CK_BYTE attribute" + echo "* TESTCASE list-key des FAIL Failed to list des keys CK_BYTE attribute" status=1 fi # URI - if [[ $(grep -A 20 'p11sak-des' $P11SAK_DES_LONG | grep -c 'URI: pkcs11:.*type=secret-key') == "1" ]]; then + if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_DES_LONG) == "1" ]]; then echo "* TESTCASE list-key des PASS list des key pkcs#11 URI" else echo "* TESTCASE list-key des FAIL list des key pkcs#11 URI" status=1 fi else - echo "* TESTCASE list-key des SKIP Listed random des public keys CK_BBOOL attribute" - echo "* TESTCASE list-key des SKIP Listed random des public keys CK_ULONG attribute" - echo "* TESTCASE list-key des SKIP Listed random des public keys CK_BYTE attribute" + echo "* TESTCASE list-key des SKIP Listed random des keys CK_BBOOL attribute" + echo "* TESTCASE list-key des SKIP Listed random des keys CK_ULONG attribute" + echo "* TESTCASE list-key des SKIP Listed random des keys CK_BYTE attribute" echo "* TESTCASE list-key des SKIP list des key pkcs#11 URI" fi # check 3DES -grep -q 'p11sak-3des' $P11SAK_3DES_PRE +grep -q "p11sak-3des" $P11SAK_3DES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key 3des PASS Generated random 3DES key" @@ -259,7 +573,7 @@ echo "* TESTCASE generate-key 3des FAIL Failed to generate 3DES key" status=1 fi -grep -v -q 'p11sak-3des' $P11SAK_3DES_POST +grep -v -q "p11sak-3des" $P11SAK_3DES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key 3des PASS Deleted generated 3DES key" @@ -270,28 +584,28 @@ # CK_BBOOL -if [[ $(grep -A 23 'p11sak-3des' $P11SAK_3DES_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "1" ]]; then - echo "* TESTCASE list-key 3des PASS Listed random 3des public keys CK_BBOOL attribute" +if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_3DES_LONG) == "1" ]]; then + echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_BBOOL attribute" else - echo "* TESTCASE list-key 3des FAIL Failed to list 3des public keys CK_BBOOL attribute" + echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_BBOOL attribute" status=1 fi # CK_ULONG -if [[ $(grep -A 23 'p11sak-3des' $P11SAK_3DES_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key 3des PASS Listed random 3des public keys CK_ULONG attribute" +if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_3DES_LONG) == "0" ]]; then + echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_ULONG attribute" else - echo "* TESTCASE list-key 3des FAIL Failed to list 3des public keys CK_ULONG attribute" + echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_ULONG attribute" status=1 fi # CK_BYTE -if [[ $(grep -A 23 'p11sak-3des' $P11SAK_3DES_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key 3des PASS Listed random 3des public keys CK_BYTE attribute" +if [[ $(grep -c "CKA_VALUE:" $P11SAK_3DES_LONG) == "1" ]]; then + echo "* TESTCASE list-key 3des PASS Listed random 3des keys CK_BYTE attribute" else - echo "* TESTCASE list-key 3des FAIL Failed to list 3des public keys CK_BYTE attribute" + echo "* TESTCASE list-key 3des FAIL Failed to list 3des keys CK_BYTE attribute" status=1 fi # URI -if [[ $(grep -A 23 'p11sak-3des' $P11SAK_3DES_LONG | grep -c 'URI: pkcs11:.*type=secret-key') == "1" ]]; then +if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_3DES_LONG) == "1" ]]; then echo "* TESTCASE list-key 3des PASS list 3des key pkcs#11 URI" else echo "* TESTCASE list-key 3des FAIL list 3des key pkcs#11 URI" @@ -299,8 +613,57 @@ fi +# check generic +grep -q "p11sak-generic" $P11SAK_GENERIC_PRE +rc=$? +if [ $rc = 0 ]; then + echo "* TESTCASE generate-key generic PASS Generated random GENERIC key" +else + echo "* TESTCASE generate-key generic FAIL Failed to generate GENERIC key" + status=1 +fi +grep -v -q "p11sak-generic" $P11SAK_GENERIC_POST +rc=$? +if [ $rc = 0 ]; then + echo "* TESTCASE remove-key generic PASS Deleted generated GENERIC key" +else + echo "* TESTCASE remove-key generic FAIL Failed to delete generated GENERIC key" + status=1 +fi + + +# CK_BBOOL +if [[ $(grep -c "CKA_SIGN: CK_TRUE" $P11SAK_GENERIC_LONG) == "1" ]]; then + echo "* TESTCASE list-key generic PASS Listed random generic keys CK_BBOOL attribute" +else + echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_BBOOL attribute" + status=1 +fi +# CK_ULONG +if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_GENERIC_LONG) == "0" ]]; then + echo "* TESTCASE list-key generic PASS Listed random generic keys CK_ULONG attribute" +else + echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_ULONG attribute" + status=1 +fi +# CK_BYTE +if [[ $(grep -c "CKA_VALUE:" $P11SAK_GENERIC_LONG) == "1" ]]; then + echo "* TESTCASE list-key generic PASS Listed random generic keys CK_BYTE attribute" +else + echo "* TESTCASE list-key generic FAIL Failed to list generic keys CK_BYTE attribute" + status=1 +fi +# URI +if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_GENERIC_LONG) == "1" ]]; then + echo "* TESTCASE list-key generic PASS list generic key pkcs#11 URI" +else + echo "* TESTCASE list-key generic FAIL list generic key pkcs#11 URI" + status=1 +fi + + # check AES 128 -grep -q 'p11sak-aes-128' $P11SAK_AES_PRE +grep -q "p11sak-aes-128" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-128 PASS Generated random AES 128 key" @@ -308,7 +671,7 @@ echo "* TESTCASE generate-key aes-128 FAIL Failed to generate AES 128 key" status=1 fi -grep -v -q 'p11sak-aes-128' $P11SAK_AES_POST +grep -v -q "p11sak-aes-128" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-128 PASS Deleted generated AES 128 key" @@ -319,7 +682,7 @@ # check AES 192 -grep -q 'p11sak-aes-192' $P11SAK_AES_PRE +grep -q "p11sak-aes-192" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-192 PASS Generated random AES 192 key" @@ -327,7 +690,7 @@ echo "* TESTCASE generate-key aes-192 FAIL Failed to generate AES 192 key" status=1 fi -grep -v -q 'p11sak-aes-192' $P11SAK_AES_POST +grep -v -q "p11sak-aes-192" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-192 PASS Deleted generated AES 192 key" @@ -338,7 +701,7 @@ # check AES 256 -grep -q 'p11sak-aes-256' $P11SAK_AES_PRE +grep -q "p11sak-aes-256" $P11SAK_AES_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-256 PASS Generated random AES 256 key" @@ -346,7 +709,7 @@ echo "* TESTCASE generate-key aes-256 FAIL Failed to generate AES 256 key" status=1 fi -grep -v -q 'p11sak-aes-256' $P11SAK_AES_POST +grep -v -q "p11sak-aes-256" $P11SAK_AES_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-256 PASS Deleted generated AES 256 key" @@ -357,37 +720,37 @@ # CK_BBOOL -if [[ $(grep -A 69 'p11sak-aes-128' $P11SAK_AES_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "3" ]]; then - echo "* TESTCASE list-key aes PASS Listed random aes public keys CK_BBOOL attribute" +if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_AES_LONG) == "3" ]]; then + echo "* TESTCASE list-key aes PASS Listed random aes keys CK_BBOOL attribute" else - echo "* TESTCASE list-key aes FAIL Failed to list aes public keys CK_BBOOL attribute" + echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_BBOOL attribute" status=1 fi # CK_ULONG -if [[ $(grep -A 69 'p11sak-aes-128' $P11SAK_AES_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key aes PASS Listed random aes public keys CK_ULONG attribute" +if [[ $(grep -c "CKA_VALUE_LEN:" $P11SAK_AES_LONG) == "3" ]]; then + echo "* TESTCASE list-key aes PASS Listed random aes keys CK_ULONG attribute" else - echo "* TESTCASE list-key aes FAIL Failed to list aes public keys CK_ULONG attribute" + echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_ULONG attribute" status=1 fi # CK_BYTE -if [[ $(grep -A 69 'p11sak-aes-128' $P11SAK_AES_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key aes PASS Listed random aes public keys CK_BYTE attribute" +if [[ $(grep -c "CKA_VALUE:" $P11SAK_AES_LONG) == "3" ]]; then + echo "* TESTCASE list-key aes PASS Listed random aes keys CK_BYTE attribute" else - echo "* TESTCASE list-key aes FAIL Failed to list aes public keys CK_BYTE attribute" + echo "* TESTCASE list-key aes FAIL Failed to list aes keys CK_BYTE attribute" status=1 fi # URI -if [[ $(grep -A 69 'p11sak-aes-128' $P11SAK_AES_LONG | grep -c 'URI: pkcs11:.*type=secret-key') == "3" ]]; then +if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_AES_LONG) == "3" ]]; then echo "* TESTCASE list-key aes PASS list aes key pkcs#11 URI" else echo "* TESTCASE list-key aes FAIL list aes key pkcs#11 URI" status=1 fi -if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) && -z $( pkcsconf -t -c $SLOT | grep "Model: EP11") ]]; then +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_AES_XTS_KEY_GEN) ]]; then # check AES-XTS 128 - grep -q 'p11sak-aes-xts-128' $P11SAK_AES_XTS_PRE + grep -q "p11sak-aes-xts-128" $P11SAK_AES_XTS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-xts-128 PASS Generated random AES-XTS 128 key" @@ -395,7 +758,7 @@ echo "* TESTCASE generate-key aes-xts-128 FAIL Failed to generate AES-XTS 128 key" status=1 fi - grep -v -q 'p11sak-aes-xts-128' $P11SAK_AES_XTS_POST + grep -v -q "p11sak-aes-xts-128" $P11SAK_AES_XTS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-xts-128 PASS Deleted generated AES-XTS 128 key" @@ -405,7 +768,7 @@ fi # check AES-XTS 256 - grep -q 'p11sak-aes-xts-256' $P11SAK_AES_XTS_PRE + grep -q "p11sak-aes-xts-256" $P11SAK_AES_XTS_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key aes-xts-256 PASS Generated random AES-XTS 256 key" @@ -413,7 +776,7 @@ echo "* TESTCASE generate-key aes-xts-256 FAIL Failed to generate AES-XTS 256 key" status=1 fi - grep -v -q 'p11sak-aes-xts-256' $P11SAK_AES_XTS_POST + grep -v -q "p11sak-aes-xts-256" $P11SAK_AES_XTS_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key aes-xts-256 PASS Deleted generated AES-XTS 256 key" @@ -423,28 +786,28 @@ fi # CK_BBOOL - if [[ $(grep -A 69 'p11sak-aes-xts-128' $P11SAK_AES_XTS_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "2" ]]; then - echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts public keys CK_BBOOL attribute" + if [[ $(grep -c "CKA_ENCRYPT: CK_TRUE" $P11SAK_AES_XTS_LONG) == "2" ]]; then + echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_BBOOL attribute" else - echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts public keys CK_BBOOL attribute" + echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_BBOOL attribute" status=1 fi # CK_ULONG - if [[ $(grep -A 69 'p11sak-aes-xts-128' $P11SAK_AES_XTS_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts public keys CK_ULONG attribute" + if [[ $(grep -c "CKA_VALUE_LEN:" $P11SAK_AES_XTS_LONG) == "2" ]]; then + echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_ULONG attribute" else - echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts public keys CK_ULONG attribute" + echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_ULONG attribute" status=1 fi # CK_BYTE - if [[ $(grep -A 69 'p11sak-aes-xts-128' $P11SAK_AES_XTS_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts public keys CK_BYTE attribute" + if [[ $(grep -c "CKA_VALUE:" $P11SAK_AES_XTS_LONG) == "2" ]]; then + echo "* TESTCASE list-key aes-xts PASS Listed random aes-xts keys CK_BYTE attribute" else - echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts public keys CK_BYTE attribute" + echo "* TESTCASE list-key aes-xts FAIL Failed to list aes-xts keys CK_BYTE attribute" status=1 fi # URI - if [[ $(grep -A 69 'p11sak-aes-xts-128' $P11SAK_AES_XTS_LONG | grep -c 'URI: pkcs11:.*type=secret-key') == "2" ]]; then + if [[ $(grep -c "URI: pkcs11:.*type=secret-key" $P11SAK_AES_XTS_LONG) == "2" ]]; then echo "* TESTCASE list-key aes-xts PASS list aes-xts key pkcs#11 URI" else echo "* TESTCASE list-key aes-xts FAIL list aes-xts key pkcs#11 URI" @@ -455,14 +818,14 @@ echo "* TESTCASE remove-key aes-xts-128 SKIP Deleted generated AES-XTS 128 key" echo "* TESTCASE generate-key aes-xst-256 SKIP Generated random AES-XTS 256 key" echo "* TESTCASE remove-key aes-xts-256 SKIP Deleted generated AES-XTS 256 key" - echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts public keys CK_BBOOL attribute" - echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts public keys CK_ULONG attribute" - echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts public keys CK_BYTE attribute" + echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_BBOOL attribute" + echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_ULONG attribute" + echo "* TESTCASE list-key aes-xts SKIP Listed random aes-xts keys CK_BYTE attribute" echo "* TESTCASE list-key aes-xts SKIP list aes-xts key pkcs#11 URI" fi # check RSA 1024 public key -grep -q 'p11sak-rsa-1024:pub' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-1024:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 1024 PASS Generated random rsa 1024 public key" @@ -470,7 +833,7 @@ echo "* TESTCASE generate-key rsa 1024 FAIL Failed to generate rsa 1024 public key" status=1 fi -grep -v -q 'p11sak-rsa-1024:pub' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-1024:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 1024 public key" @@ -481,7 +844,7 @@ # check RSA 2048 public key -grep -q 'p11sak-rsa-2048:pub' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-2048:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 2048 PASS Generated random rsa 2048 public key" @@ -489,7 +852,7 @@ echo "* TESTCASE generate-key rsa 2048 FAIL Failed to generate rsa 2048 public key" status=1 fi -grep -v -q 'p11sak-rsa-2048:pub' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-2048:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 2048 public key" @@ -500,7 +863,7 @@ # check RSA 4096 public key -grep -q 'p11sak-rsa-4096:pub' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-4096:pub" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 4096 PASS Generated random rsa 4096 public key" @@ -508,7 +871,7 @@ echo "* TESTCASE generate-key rsa 4096 FAIL Failed to generate rsa 4096 public key" status=1 fi -grep -v -q 'p11sak-rsa-4096:pub' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-4096:pub" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 4096 public key" @@ -519,7 +882,7 @@ # check RSA 1024 private key -grep -q 'p11sak-rsa-1024:prv' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-1024:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 1024 PASS Generated random rsa 1024 private key" @@ -527,7 +890,7 @@ echo "* TESTCASE generate-key rsa 1024 FAIL Failed to generate rsa 1024 private key" status=1 fi -grep -v -q 'p11sak-rsa-1024:prv' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-1024:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 1024 private key" @@ -538,7 +901,7 @@ # check RSA 2048 private key -grep -q 'p11sak-rsa-2048:prv' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-2048:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 2048 PASS Generated random rsa 2048 private key" @@ -546,7 +909,7 @@ echo "* TESTCASE generate-key rsa 2048 FAIL Failed to generate rsa 2048 private key" status=1 fi -grep -v -q 'p11sak-rsa-2048:prv' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-2048:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 2048 private key" @@ -557,7 +920,7 @@ # check RSA 4096 private key -grep -q 'p11sak-rsa-4096:prv' $P11SAK_RSA_PRE +grep -q "p11sak-rsa-4096:prv" $P11SAK_RSA_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key rsa 4096 PASS Generated random rsa 4096 private key" @@ -565,7 +928,7 @@ echo "* TESTCASE generate-key rsa 4096 FAIL Failed to generate rsa 4096 private key" status=1 fi -grep -v -q 'p11sak-rsa-4096:prv' $P11SAK_RSA_POST +grep -v -q "p11sak-rsa-4096:prv" $P11SAK_RSA_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key rsa PASS Deleted generated rsa 4096 private key" @@ -576,37 +939,191 @@ # CK_BBOOL -if [[ $(grep -A 211 'p11sak-rsa-1024:pub' $P11SAK_RSA_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "6" ]]; then - echo "* TESTCASE list-key rsa PASS Listed random rsa public keys CK_BBOOL attribute" +if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_RSA_LONG) == "6" ]]; then + echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_BBOOL attribute" else - echo "* TESTCASE list-key rsa FAIL Failed to list rsa public keys CK_BBOOL attribute" + echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_BBOOL attribute" status=1 fi # CK_ULONG -if [[ $(grep -A 211 'p11sak-rsa-1024:pub' $P11SAK_RSA_LONG | grep -c 'CKA_MODULUS_BITS:') == "3" ]]; then - echo "* TESTCASE list-key rsa PASS Listed random rsa public keys CK_ULONG attribute" +if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_RSA_LONG) == "3" ]]; then + echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_ULONG attribute" else - echo "* TESTCASE list-key rsa FAIL Failed to list rsa public keys CK_ULONG attribute" + echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_ULONG attribute" status=1 fi # CK_BYTE -if [[ $(grep -A 211 'p11sak-rsa-1024:pub' $P11SAK_RSA_LONG | grep -c 'CKA_MODULUS:') == "6" ]]; then - echo "* TESTCASE list-key rsa PASS Listed random rsa public keys CK_BYTE attribute" +if [[ $(grep -c "CKA_MODULUS:" $P11SAK_RSA_LONG) == "6" ]]; then + echo "* TESTCASE list-key rsa PASS Listed random rsa keys CK_BYTE attribute" else - echo "* TESTCASE list-key rsa FAIL Failed to list rsa public keys CK_BYTE attribute" + echo "* TESTCASE list-key rsa FAIL Failed to list rsa keys CK_BYTE attribute" status=1 fi # URI -if [[ $(grep -A 211 'p11sak-rsa-1024:pub' $P11SAK_RSA_LONG | grep -c 'URI: pkcs11:.*type=public') == "3" ]]; then +if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_RSA_LONG) == "3" ]]; then echo "* TESTCASE list-key rsa PASS list rsa public key pkcs#11 URI" else echo "* TESTCASE list-key rsa FAIL list rsa public key pkcs#11 URI" status=1 fi +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DH_PKCS_KEY_PAIR_GEN) ]]; then + # check DH public key + grep -q "p11sak-dh:pub" $P11SAK_DH_PRE + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE generate-key dh PASS Generated random dh public key" + else + echo "* TESTCASE generate-key dh FAIL Failed to generate dh public key" + status=1 + fi + grep -v -q "p11sak-dh:pub" $P11SAK_DH_POST + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE remove-key dh PASS Deleted generated dh public key" + else + echo "* TESTCASE remove-key dh FAIL Failed to delete generated dh public key" + status=1 + fi + + # check DH private key + grep -q "p11sak-dh:prv" $P11SAK_DH_PRE + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE generate-key dh PASS Generated random dh private key" + else + echo "* TESTCASE generate-key dh FAIL Failed to generate dh private key" + status=1 + fi + grep -v -q "p11sak-dh:prv" $P11SAK_DH_POST + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE remove-key dh PASS Deleted generated dh private key" + else + echo "* TESTCASE remove-key dh FAIL Failed to delete generated dh private key" + status=1 + fi + + + # CK_BBOOL + if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_DH_LONG) == "2" ]]; then + echo "* TESTCASE list-key dh PASS Listed random dh keys CK_BBOOL attribute" + else + echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_BBOOL attribute" + status=1 + fi + # CK_ULONG + if [[ $(grep -c "CKA_VALUE_BITS:" $P11SAK_DH_LONG) == "1" ]]; then + echo "* TESTCASE list-key dh PASS Listed random dh keys CK_ULONG attribute" + else + echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_ULONG attribute" + status=1 + fi + # CK_BYTE + if [[ $(grep -c "CKA_PRIME:" $P11SAK_DH_LONG) == "2" ]]; then + echo "* TESTCASE list-key dh PASS Listed random dh keys CK_BYTE attribute" + else + echo "* TESTCASE list-key dh FAIL Failed to list dh keys CK_BYTE attribute" + status=1 + fi + # URI + if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_DH_LONG) == "1" ]]; then + echo "* TESTCASE list-key dh PASS list dh public key pkcs#11 URI" + else + echo "* TESTCASE list-key dh FAIL list dh public key pkcs#11 URI" + status=1 + fi +else + echo "* TESTCASE generate-key dh SKIP Failed to generate dh public key" + echo "* TESTCASE remove-key dh SKIP Failed to delete generated dh public key" + echo "* TESTCASE generate-key dh SKIP Failed to generate dh private key" + echo "* TESTCASE remove-key dh SKIP Failed to delete generated dh private key" + echo "* TESTCASE list-key dh SKIP Failed to list dh keys CK_BBOOL attribute" + echo "* TESTCASE list-key dh SKIP Failed to list dh keys CK_ULONG attribute" + echo "* TESTCASE list-key dh SKIP Failed to list dh keys CK_BYTE attribute" + echo "* TESTCASE list-key dh SKIP list dh public key pkcs#11 URI" +fi + + +if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_DSA_KEY_PAIR_GEN) ]]; then + # check DSA public key + grep -q "p11sak-dsa:pub" $P11SAK_DSA_PRE + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE generate-key dsa PASS Generated random dsa public key" + else + echo "* TESTCASE generate-key dsa FAIL Failed to generate dsa public key" + status=1 + fi + grep -v -q "p11sak-dsa:pub" $P11SAK_DSA_POST + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE remove-key dsa PASS Deleted generated dsa public key" + else + echo "* TESTCASE remove-key dsa FAIL Failed to delete generated dsa public key" + status=1 + fi + + # check DSA private key + grep -q "p11sak-dsa:prv" $P11SAK_DSA_PRE + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE generate-key dsa PASS Generated random dsa private key" + else + echo "* TESTCASE generate-key dsa FAIL Failed to generate dsa private key" + status=1 + fi + grep -v -q "p11sak-dsa:prv" $P11SAK_DSA_POST + rc=$? + if [ $rc = 0 ]; then + echo "* TESTCASE remove-key dsa PASS Deleted generated dsa private key" + else + echo "* TESTCASE remove-key dsa FAIL Failed to delete generated dsa private key" + status=1 + fi + + + # CK_BBOOL + if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_DSA_LONG) == "2" ]]; then + echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_BBOOL attribute" + else + echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_BBOOL attribute" + status=1 + fi + # CK_ULONG + if [[ $(grep -c "CKA_VALUE_BITS:" $P11SAK_DSA_LONG) == "0" ]]; then + echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_ULONG attribute" + else + echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_ULONG attribute" + status=1 + fi + # CK_BYTE + if [[ $(grep -c "CKA_PRIME:" $P11SAK_DSA_LONG) == "2" ]]; then + echo "* TESTCASE list-key dsa PASS Listed random dsa keys CK_BYTE attribute" + else + echo "* TESTCASE list-key dsa FAIL Failed to list dsa keys CK_BYTE attribute" + status=1 + fi + # URI + if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_DSA_LONG) == "1" ]]; then + echo "* TESTCASE list-key dsa PASS list dsa public key pkcs#11 URI" + else + echo "* TESTCASE list-key dsa FAIL list dsa public key pkcs#11 URI" + status=1 + fi +else + echo "* TESTCASE generate-key dsa SKIP Failed to generate dsa public key" + echo "* TESTCASE remove-key dsa SKIP Failed to delete generated dsa public key" + echo "* TESTCASE generate-key dsa SKIP Failed to generate dsa private key" + echo "* TESTCASE remove-key dsa SKIP Failed to delete generated dsa private key" + echo "* TESTCASE list-key dsa SKIP Failed to list dsa keys CK_BBOOL attribute" + echo "* TESTCASE list-key dsa SKIP Failed to list dsa keys CK_ULONG attribute" + echo "* TESTCASE list-key dsa SKIP Failed to list dsa keys CK_BYTE attribute" + echo "* TESTCASE list-key dsa SKIP list dsa public key pkcs#11 URI" +fi # check EC prime256v1 public key -grep -q 'p11sak-ec-prime256v1:pub' $P11SAK_EC_PRE +grep -q "p11sak-ec-prime256v1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec prime256v1 PASS Generated random ec prime256v1 public key" @@ -614,7 +1131,7 @@ echo "* TESTCASE generate-key ec prime256v1 FAIL Failed to generate ec prime256v1 public key" status=1 fi -grep -v -q 'p11sak-ec-prime256v1:pub' $P11SAK_EC_POST +grep -v -q "p11sak-ec-prime256v1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec prime256v1 PASS Deleted generated ec prime256v1 public key" @@ -625,7 +1142,7 @@ # check EC secp384r1 public key -grep -q 'p11sak-ec-secp384r1:pub' $P11SAK_EC_PRE +grep -q "p11sak-ec-secp384r1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp384r1 PASS Generated random ec secp384r1 public key" @@ -633,7 +1150,7 @@ echo "* TESTCASE generate-key ec secp384r1 FAIL Failed to generate ec secp384r1 public key" status=1 fi -grep -v -q 'p11sak-ec-secp384r1:pub' $P11SAK_EC_POST +grep -v -q "p11sak-ec-secp384r1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp384r1 PASS Deleted generated ec secp384r1 public key" @@ -644,7 +1161,7 @@ # check EC secp521r1 public key -grep -q 'p11sak-ec-secp521r1:pub' $P11SAK_EC_PRE +grep -q "p11sak-ec-secp521r1:pub" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp521r1 PASS Generated random ec secp521r1 public key" @@ -652,7 +1169,7 @@ echo "* TESTCASE generate-key ec secp521r1 FAIL Failed to generate ec secp521r1 public key" status=1 fi -grep -v -q 'p11sak-ec-secp521r1:pub' $P11SAK_EC_POST +grep -v -q "p11sak-ec-secp521r1:pub" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp521r1 PASS Deleted generated ec secp521r1 public key" @@ -663,7 +1180,7 @@ # check EC prime256v1 private key -grep -q 'p11sak-ec-prime256v1:prv' $P11SAK_EC_PRE +grep -q "p11sak-ec-prime256v1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec prime256v1 PASS Generated random ec prime256v1 private key" @@ -671,7 +1188,7 @@ echo "* TESTCASE generate-key ec prime256v1 FAIL Failed to generate ec prime256v1 private key" status=1 fi -grep -v -q 'p11sak-ec-prime256v1:prv' $P11SAK_EC_POST +grep -v -q "p11sak-ec-prime256v1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec prime256v1 PASS Deleted generated ec prime256v1 private key" @@ -682,7 +1199,7 @@ # check EC secp384r1 private key -grep -q 'p11sak-ec-secp384r1:prv' $P11SAK_EC_PRE +grep -q "p11sak-ec-secp384r1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp384r1 PASS Generated random ec secp384r1 private key" @@ -690,7 +1207,7 @@ echo "* TESTCASE generate-key ec secp384r1 FAIL Failed to generate ec secp384r1 private key" status=1 fi -grep -v -q 'p11sak-ec-secp384r1:prv' $P11SAK_EC_POST +grep -v -q "p11sak-ec-secp384r1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp384r1 PASS Deleted generated ec secp384r1 private key" @@ -701,7 +1218,7 @@ # check EC secp521r1 private key -grep -q 'p11sak-ec-secp521r1:prv' $P11SAK_EC_PRE +grep -q "p11sak-ec-secp521r1:prv" $P11SAK_EC_PRE rc=$? if [ $rc = 0 ]; then echo "* TESTCASE generate-key ec secp521r1 PASS Generated random ec secp521r1 private key" @@ -709,7 +1226,7 @@ echo "* TESTCASE generate-key ec secp521r1 FAIL Failed to generate ec secp521r1 private key" status=1 fi -grep -v -q 'p11sak-ec-secp521r1:prv' $P11SAK_EC_POST +grep -v -q "p11sak-ec-secp521r1:prv" $P11SAK_EC_POST rc=$? if [ $rc = 0 ]; then echo "* TESTCASE remove-key ec secp521r1 PASS Deleted generated ec secp521r1 private key" @@ -720,28 +1237,28 @@ # CK_BBOOL -if [[ $(grep -A 99 'p11sak-ec-prime256v1:pub' $P11SAK_EC_LONG | grep -c 'CKA_IBM_PROTKEY_EXTRACTABLE: CK_FALSE') == "6" ]]; then - echo "* TESTCASE list-key ec PASS Listed random ec public keys CK_BBOOL attribute" +if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_EC_LONG) == "6" ]]; then + echo "* TESTCASE list-key ec PASS Listed random ec keys CK_BBOOL attribute" else - echo "* TESTCASE list-key ec FAIL Failed to list ec public keys CK_BBOOL attribute" + echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_BBOOL attribute" status=1 fi # CK_ULONG -if [[ $(grep -A 99 'p11sak-ec-prime256v1:pub' $P11SAK_EC_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key ec PASS Listed random ec public keys CK_ULONG attribute" +if [[ $(grep -c "CKA_MODULUS_BITS:" $P11SAK_EC_LONG) == "0" ]]; then + echo "* TESTCASE list-key ec PASS Listed random ec keys CK_ULONG attribute" else - echo "* TESTCASE list-key ec FAIL Failed to list ec public keys CK_ULONG attribute" + echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_ULONG attribute" status=1 fi # CK_BYTE -if [[ $(grep -A 99 'p11sak-ec-prime256v1:pub' $P11SAK_EC_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key ec PASS Listed random ec public keys CK_BYTE attribute" +if [[ $(grep -c "CKA_EC_POINT:" $P11SAK_EC_LONG) == "3" ]]; then + echo "* TESTCASE list-key ec PASS Listed random ec keys CK_BYTE attribute" else - echo "* TESTCASE list-key ec FAIL Failed to list ec public keys CK_BYTE attribute" + echo "* TESTCASE list-key ec FAIL Failed to list ec keys CK_BYTE attribute" status=1 fi # URI -if [[ $(grep -A 99 'p11sak-ec-prime256v1:pub' $P11SAK_EC_LONG | grep -c 'URI: pkcs11:.*type=public') == "3" ]]; then +if [[ $(grep -c "URI: pkcs11:.*type=public" $P11SAK_EC_LONG) == "3" ]]; then echo "* TESTCASE list-key ec PASS list ec public key pkcs#11 URI" else echo "* TESTCASE list-key ec FAIL list ec public key pkcs#11 URI" @@ -751,93 +1268,165 @@ if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_DILITHIUM) ]]; then # CK_BBOOL - if [[ $(grep -A 35 'p11sak-ibm-dilithium' $P11SAK_IBM_DIL_LONG | grep -c 'CK_TRUE') == "12" ]]; then - echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium public keys CK_BBOOL attribute" + if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_BBOOL attribute" else - echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium public keys CK_BBOOL attribute" + echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_BBOOL attribute" status=1 fi # CK_ULONG - if [[ $(grep -A 35 'p11sak-ibm-dilithium' $P11SAK_IBM_DIL_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium public keys CK_ULONG attribute" + if [[ $(grep -c "CKA_IBM_DILITHIUM_KEYFORM:" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_ULONG attribute" else - echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium public keys CK_ULONG attribute" + echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_ULONG attribute" status=1 fi # CK_BYTE - if [[ $(grep -A 35 'p11sak-ibm-dilithium' $P11SAK_IBM_DIL_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium public keys CK_BYTE attribute" + if [[ $(grep -c "CKA_IBM_DILITHIUM_RHO:" $P11SAK_IBM_DILITHIUM_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-dilithium PASS Listed random ibm-dilithium keys CK_BYTE attribute" else - echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium public keys CK_BYTE attribute" + echo "* TESTCASE list-key ibm-dilithium FAIL Failed to list ibm-dilithium keys CK_BYTE attribute" status=1 fi else - echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium public keys CK_BBOOL attribute" - echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium public keys CK_ULONG attribute" - echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium public keys CK_BYTE attribute" + echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_BBOOL attribute" + echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_ULONG attribute" + echo "* TESTCASE list-key ibm-dilithium SKIP Listed random ibm-dilithium keys CK_BYTE attribute" fi + if [[ -n $( pkcsconf -m -c $SLOT | grep CKM_IBM_KYBER) ]]; then # CK_BBOOL - if [[ $(grep -A 35 'p11sak-ibm-kyber' $P11SAK_IBM_KYBER_LONG | grep -c 'CK_TRUE') == "12" ]]; then - echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber public keys CK_BBOOL attribute" + if [[ $(grep -c "CKA_MODIFIABLE: CK_TRUE" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_BBOOL attribute" else - echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber public keys CK_BBOOL attribute" + echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_BBOOL attribute" status=1 fi # CK_ULONG - if [[ $(grep -A 35 'p11sak-ibm-kyber' $P11SAK_IBM_KYBER_LONG | grep -c 'CKA_MODULUS_BITS:') == "0" ]]; then - echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber public keys CK_ULONG attribute" + if [[ $(grep -c "CKA_IBM_KYBER_KEYFORM:" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_ULONG attribute" else - echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber public keys CK_ULONG attribute" + echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_ULONG attribute" status=1 fi # CK_BYTE - if [[ $(grep -A 35 'p11sak-ibm-kyber' $P11SAK_IBM_KYBER_LONG | grep -c 'CKA_MODULUS:') == "0" ]]; then - echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber public keys CK_BYTE attribute" + if [[ $(grep -c "CKA_IBM_KYBER_PK:" $P11SAK_IBM_KYBER_LONG) == "2" ]]; then + echo "* TESTCASE list-key ibm-kyber PASS Listed random ibm-kyber keys CK_BYTE attribute" else - echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber public keys CK_BYTE attribute" + echo "* TESTCASE list-key ibm-kyber FAIL Failed to list ibm-kyber keys CK_BYTE attribute" status=1 fi else - echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber public keys CK_BBOOL attribute" - echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber public keys CK_ULONG attribute" - echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber public keys CK_BYTE attribute" + echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_BBOOL attribute" + echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_ULONG attribute" + echo "* TESTCASE list-key ibm-kyber SKIP Listed random ibm-kyber keys CK_BYTE attribute" +fi + + +# check return codes +if [ $RC_P11SAK_GENERATE = 0 ]; then + echo "* TESTCASE generate-key PASS return code check" +else + echo "* TESTCASE generate-key FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_LIST = 0 ]; then + echo "* TESTCASE list-key short PASS return code check" +else + echo "* TESTCASE list-key short FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_LIST_LONG = 0 ]; then + echo "* TESTCASE list-key long PASS return code check" +else + echo "* TESTCASE list-key long FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_LIST_POST = 0 ]; then + echo "* TESTCASE list-key post PASS return code check" +else + echo "* TESTCASE list-key post FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_UPDATE = 0 ]; then + echo "* TESTCASE set-key-attr PASS return code check" +else + echo "* TESTCASE set-key-attr FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_COPY = 0 ]; then + echo "* TESTCASE copy-key PASS return code check" +else + echo "* TESTCASE copy-key FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_IMPORT = 0 ]; then + echo "* TESTCASE import-key PASS return code check" +else + echo "* TESTCASE import-key FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_EXPORT = 0 ]; then + echo "* TESTCASE export-key PASS return code check" +else + echo "* TESTCASE export-key FAIL return code check" + status=1 +fi + +if [ $RC_P11SAK_REMOVE = 0 ]; then + echo "* TESTCASE remove-key PASS return code check" +else + echo "* TESTCASE remove-key FAIL return code check" + status=1 fi + # check token pin handling if [ $RC_P11SAK_PINOPT = 0 ]; then echo "* TESTCASE list-key pin-opt PASS Token pin handling (opt)" else echo "* TESTCASE list-key pin-option FAIL Token pin handling (opt)" + status=1 fi if [ $RC_P11SAK_PINENV = 0 ]; then echo "* TESTCASE list-key pin-env PASS Token pin handling (env)" else echo "* TESTCASE list-key pin-env FAIL Token pin handling (env)" + status=1 fi if [ $RC_P11SAK_PINCON = 0 ]; then echo "* TESTCASE list-key pin-prompt PASS Token pin handling (prompt)" else echo "* TESTCASE list-key pin-prompt FAIL Token pin handling (prompt)" + status=1 fi if diff -q $P11SAK_ALL_PINOPT $P11SAK_ALL_PINENV ; then echo "* TESTCASE list-key pin-opt-env PASS Token pin opt/env output compare" else echo "* TESTCASE list-key pin-opt-env FAIL Token pin opt/env output compare" + status=1 fi if diff -q $P11SAK_ALL_PINOPT $P11SAK_ALL_PINCON ; then echo "* TESTCASE list-key pin-opt-prompt PASS Token pin opt/prompt output compare" else echo "* TESTCASE list-key pin-opt-prompt FAIL Token pin opt/prompt output compare" + status=1 fi -echo "** Now remove temporary output files - 'p11sak_test.sh'" +echo "** Now remove temporary output files - "p11sak_test.sh"" rm -f $P11SAK_DES_PRE @@ -846,6 +1435,9 @@ rm -f $P11SAK_3DES_PRE rm -f $P11SAK_3DES_LONG rm -f $P11SAK_3DES_POST +rm -f $P11SAK_GENERIC_PRE +rm -f $P11SAK_GENERIC_LONG +rm -f $P11SAK_GENERIC_POST rm -f $P11SAK_AES_PRE rm -f $P11SAK_AES_LONG rm -f $P11SAK_AES_POST @@ -855,18 +1447,27 @@ rm -f $P11SAK_RSA_PRE rm -f $P11SAK_RSA_LONG rm -f $P11SAK_RSA_POST +rm -f $P11SAK_DH_PRE +rm -f $P11SAK_DH_LONG +rm -f $P11SAK_DH_POST +rm -f $P11SAK_DSA_PRE +rm -f $P11SAK_DSA_LONG +rm -f $P11SAK_DSA_POST rm -f $P11SAK_EC_PRE rm -f $P11SAK_EC_LONG rm -f $P11SAK_EC_POST -rm -f $P11SAK_IBM_DIL_PRE -rm -f $P11SAK_IBM_DIL_LONG -rm -f $P11SAK_IBM_DIL_POST +rm -f $P11SAK_IBM_DILITHIUM_PRE +rm -f $P11SAK_IBM_DILITHIUM_LONG +rm -f $P11SAK_IBM_DILITHIUM_POST rm -f $P11SAK_IBM_KYBER_PRE rm -f $P11SAK_IBM_KYBER_LONG rm -f $P11SAK_IBM_KYBER_POST rm -f $P11SAK_ALL_PINOPT rm -f $P11SAK_ALL_PINENV rm -f $P11SAK_ALL_PINCON +rm -f export-aes.key +rm -f export-*.pem +rm -f export-*.opaque echo "** Now DONE testing - 'p11sak_test.sh' - rc = $status" diff -Nru opencryptoki-3.20.0+dfsg/testcases/misc_tests/rsa-key.pem opencryptoki-3.21.0+dfsg/testcases/misc_tests/rsa-key.pem --- opencryptoki-3.20.0+dfsg/testcases/misc_tests/rsa-key.pem 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/misc_tests/rsa-key.pem 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,36 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAt7QmlNEerbJO19BfRF9oZ4AL7D9p+U60vj1Vs9N9UrA5RBGm +n4+EdCqrLyIKtCqCplyXIY2AScB6axLWCh0+9g/kkQDkgD3JQDi/7TMyRwZAUrdG +4d5IfLPNkzIiaahyP1IbedhU9xYNRPx3jMfFc5S+XyZIY2f0xxeYFCLMC3OtM/8D +Pr7QSZskKLiyGfP26G9ZbEHKJcmMcswuW0HxE6ReLI6v57OxqR/Tqpb1uLNC4KC/ +7VkggyUF2N/w7pssVb+bZSvix3flBTUaJ3XwrGyydgAVOI1GLq219KlcmPLo4d/j +XDz41eQKFlMi8etqr5b32uVfoj+W5ukLz5H+kQIDAQABAoIBAALTUoSXctFZHL1V +ByIWFZUB8yz/DLI48665YsgRSKws6bSSUO3DV1YyEc/3xhJfVQMaCXkKpB5+R2O+ +NmyRZpaCSBGy4dDXInFKbilH0E4nWnXrO7vdn1/LpC3PZ5gYbylqKeIF4cirHikh +ePVBXVgZwZPVEuf0gV9OjZhBsMG8Tw4p4u5WDx00LmL5I9Iy1ozH9VrYGQ6lUl/1 +K3KdKynx5L0cQDad6jgOfNojHUHqH98TwyMNsGl4UHp8wQ0iHOGw0hyzEL8bB2e3 +jM1hX2kzEIKyyA8QxW12tIsmeg8Ijmzk2CsbHEEffFQTqMaaQtiLxLuL1rnQ6GBC +qk0GjMECgYEA57QSVnjf+waLbPdfzxTw+GEm3YmzANTSSniVSK/8RlCs0tLWIGgQ +q6oSztVhUn2+IXLhbmsCl0ni+lZvRYEW2vg2gxuwVhaMloyLYdL1VBt49EtgCYtr +s5jmPjFGGtUgSqnQaWBGGAfthlGLNUcz3bbIvAt+vTAY5VDNmbjAhSsCgYEAyveO +78OWVncMxaE2p0BF2g3B2KIwVdNoxrtYkmwhqPR56RBTpya3IOyV7lMvsjUE7lRx +jLsEYtWEmQUsuSuyiUnNNVx8Mr4uu3z959b/ZQ5KrHLulV2up1nPFcSnA2nDAmwO +MNqfrO+Ngt0qQGTdyTYcIZJNrTNClNhh6AJI5TMCgYA0OrYrgeHTXx1MudKCBpFv +G887/w83r8GbgeT81pbCbusWNuqHsY2YdKT6tMTUaH3UYmYIktypp8Efdx5sB3ZU +c8Et+q7cKQcV5KaCraAZjnvMbbU/UYs8l8nG2SqZX9OAoRjWuBn0zsyvC3Ca2OsL +HmnPYbP3B4GFJ5rA/RGAswKBgQCcK+38yNcVwta9/nTqLkdRKAK+6NUeROQ6/g6B +49fmg+6GCX0EgYKpP8GBttpdWfRoWethKMmQLtCvWU73UAs5HeNbKsWZ2cJlmyBX +UpQDMwL8PBceMQ5hUHZKPp1vv+JAK9qjdqUkUNLnHbwT/ki1OQBeSI+iNG4Hz5NO +DOwABwKBgBqqyBRVNN9qZIzdI2PVmLeRTKMm5QJUrs5xZ+WAqMSUq5SlwJ0WtHLF +ngpHzzaCvTwLmhk/CZgX6BAFDWBXOhBvFzoBtEveojTRgncJK3go1lvto1OOnK5g +qXOL4QhACnthj0rmE6lLzwyu3jYSxp/0M6G4u8zIqM0yQGabhCj1 +-----END RSA PRIVATE KEY----- +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt7QmlNEerbJO19BfRF9o +Z4AL7D9p+U60vj1Vs9N9UrA5RBGmn4+EdCqrLyIKtCqCplyXIY2AScB6axLWCh0+ +9g/kkQDkgD3JQDi/7TMyRwZAUrdG4d5IfLPNkzIiaahyP1IbedhU9xYNRPx3jMfF +c5S+XyZIY2f0xxeYFCLMC3OtM/8DPr7QSZskKLiyGfP26G9ZbEHKJcmMcswuW0Hx +E6ReLI6v57OxqR/Tqpb1uLNC4KC/7VkggyUF2N/w7pssVb+bZSvix3flBTUaJ3Xw +rGyydgAVOI1GLq219KlcmPLo4d/jXDz41eQKFlMi8etqr5b32uVfoj+W5ukLz5H+ +kQIDAQAB +-----END PUBLIC KEY----- diff -Nru opencryptoki-3.20.0+dfsg/testcases/misc_tests/tok2tok_transport.c opencryptoki-3.21.0+dfsg/testcases/misc_tests/tok2tok_transport.c --- opencryptoki-3.20.0+dfsg/testcases/misc_tests/tok2tok_transport.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/misc_tests/tok2tok_transport.c 2023-05-15 14:42:55.000000000 +0200 @@ -688,7 +688,8 @@ case CKM_EC_KEY_PAIR_GEN: rc = generate_EC_KeyPair(session1, tsuite->ec_params, - tsuite->ec_params_len, &publ_key, &priv_key); + tsuite->ec_params_len, &publ_key, &priv_key, + CK_TRUE); // must be extractable for Wrap/Unwrap break; default: diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/attribute.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/attribute.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/attribute.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/attribute.c 2023-05-15 14:42:55.000000000 +0200 @@ -237,7 +237,7 @@ update_label, 1); if (rc == CKR_ACTION_PROHIBITED) testcase_pass("C_SetAttributeValue() did not update the object rc = %s " - "(as ecpected)", p11_get_ckr(rc)); + "(as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ACTION_PROHIBITED, but got " @@ -254,7 +254,7 @@ update_modifiable_false, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_MODIFIABLE to " - "FALSE rc = %s (as ecpected)", p11_get_ckr(rc)); + "FALSE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ATTRIBUTE_READ_ONLY, but got " @@ -266,7 +266,7 @@ update_modifiable_true, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_MODIFIABLE to " - "TRUE rc = %s (as ecpected)", p11_get_ckr(rc)); + "TRUE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_MODIFIABLE should " "have failed with CKR_ATTRIBUTE_READ_ONLY, but got" @@ -292,7 +292,7 @@ update_copyable_true, 1); if (rc == CKR_ATTRIBUTE_READ_ONLY) testcase_pass("C_SetAttributeValue() did not update CKA_COPYABLE to " - "TRUE rc = %s (as ecpected)", p11_get_ckr(rc)); + "TRUE rc = %s (as expected)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_COPYABLE back to " "TRUE should have failed with CKR_ATTRIBUTE_READ_ONLY, " @@ -333,7 +333,7 @@ update_trusted_true, 1); if (rc == CKR_USER_NOT_LOGGED_IN) testcase_pass("C_SetAttributeValue() did not update CKA_TRUSTED to " - "TRUE rc = %s (as ecpected, because only SO can set " + "TRUE rc = %s (as expected, because only SO can set " "CKA_TRUSTED to TRUE)", p11_get_ckr(rc)); else testcase_fail("C_SetAttributeValue() to update CKA_TRUSTED should " diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/gen_purpose.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/gen_purpose.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/gen_purpose.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/gen_purpose.c 2023-05-15 14:42:55.000000000 +0200 @@ -385,7 +385,7 @@ goto testcase_cleanup; } - testcase_pass("C_InitToken correctly return CKR_ARGUMENS_BAD."); + testcase_pass("C_InitToken correctly returned CKR_ARGUMENS_BAD."); /* test with invalid slot id */ testcase_new_assertion(); @@ -537,7 +537,7 @@ goto testcase_cleanup; } - testcase_pass("C_SetPIN successful in pubic session."); + testcase_pass("C_SetPIN successful in public session."); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) { @@ -562,7 +562,7 @@ goto testcase_cleanup; } - testcase_pass("C_SetPIN successful in r/w pubic session."); + testcase_pass("C_SetPIN successful in r/w public session."); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) { @@ -603,7 +603,7 @@ rc = funcs->C_Logout(session); if (rc != CKR_OK) { - testcase_error("C_Logout #1 falied: rc=%s", p11_get_ckr(rc)); + testcase_error("C_Logout #1 failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } @@ -619,7 +619,7 @@ rc = funcs->C_Login(session, CKU_SO, old_pin, old_len); if (rc != CKR_OK) { - testcase_error("C_Login #3failed: rc=%s", p11_get_ckr(rc)); + testcase_error("C_Login #3 failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/getobjectsize.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/getobjectsize.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/getobjectsize.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/getobjectsize.c 2023-05-15 14:42:55.000000000 +0200 @@ -58,6 +58,8 @@ testcase_rw_session(); testcase_user_login(); + testcase_new_assertion(); + // Create an AES Key Object. rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj); if (rc != CKR_OK) { @@ -93,7 +95,7 @@ return rc; } - printf("C_GetObjectSize test passed\n"); + testcase_pass("C_GetObjectSize test passed"); testcase_cleanup: funcs->C_DestroyObject(session, keyobj); @@ -142,7 +144,9 @@ return rv; } + testcase_setup(); rv = do_GetObjectSize(); + testcase_print_result(); funcs->C_Finalize(NULL); diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/hw_fn.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/hw_fn.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/hw_fn.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/hw_fn.c 2023-05-15 14:42:55.000000000 +0200 @@ -131,34 +131,37 @@ {CKA_CLASS, &counter1_class, sizeof(counter1_class)} }; + testcase_begin("do_HW_Feature_Search"); + testcase_new_assertion(); + /* Create the 5 test objects */ rc = funcs->C_CreateObject(sess, obj1_template, 4, &h_obj1); if (rc != CKR_OK) { - show_error("C_CreateObject #1", rc); + testcase_fail("C_CreateObject #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CreateObject(sess, obj2_template, 5, &h_obj2); if (rc != CKR_OK) { - show_error("C_CreateObject #2", rc); + testcase_fail("C_CreateObject #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_1; } rc = funcs->C_CreateObject(sess, counter1_template, 6, &h_counter1); if (rc != CKR_ATTRIBUTE_READ_ONLY) { - show_error("C_CreateObject #3", rc); + testcase_fail("C_CreateObject #3, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_2; } rc = funcs->C_CreateObject(sess, counter2_template, 6, &h_counter2); if (rc != CKR_ATTRIBUTE_READ_ONLY) { - show_error("C_CreateObject #4", rc); + testcase_fail("C_CreateObject #4, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_3; } rc = funcs->C_CreateObject(sess, clock_template, 4, &h_clock); if (rc != CKR_OK) { - show_error("C_CreateObject #5", rc); + testcase_fail("C_CreateObject #5, rc=%lx, %s", rc, p11_get_ckr(rc)); goto destroy_4; } @@ -170,13 +173,13 @@ */ rc = funcs->C_FindObjectsInit(sess, NULL, 0); if (rc != CKR_OK) { - show_error(" C_FindObjectsInit #1", rc); + testcase_fail("C_FindObjectsInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); if (rc != CKR_OK) { - show_error(" C_FindObjects #1", rc); + testcase_fail("C_FindObjects #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } @@ -185,22 +188,22 @@ * feature object. */ if (find_count != 2) { - printf("%s:%d ERROR: C_FindObjects #1 should have found 2 objects!\n" - " It found %lu objects\n", __FILE__, __LINE__, + testcase_error("%s:%d ERROR: C_FindObjects #1 should have found 2 objects!\n" + " It found %lu objects", __FILE__, __LINE__, find_count); rc = -1; goto done; } if (obj_list[0] != h_obj1 && obj_list[0] != h_obj2) { - printf("%s:%d ERROR: C_FindObjects #1 found the wrong objects!\n", + testcase_error("%s:%d ERROR: C_FindObjects #1 found the wrong objects!", __FILE__, __LINE__); rc = -1; goto done; } if (obj_list[1] != h_obj1 && obj_list[1] != h_obj2) { - printf("%s:%d ERROR: C_FindObjects #1 found the wrong objects!\n", + testcase_error("%s:%d ERROR: C_FindObjects #1 found the wrong objects!", __FILE__, __LINE__); rc = -1; goto done; @@ -208,7 +211,7 @@ rc = funcs->C_FindObjectsFinal(sess); if (rc != CKR_OK) { - show_error(" C_FindObjectsFinal #1", rc); + testcase_fail("C_FindObjectsFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } @@ -218,18 +221,18 @@ */ rc = funcs->C_FindObjectsInit(sess, find_tmpl, 1); if (rc != CKR_OK) { - show_error(" C_FindObjectsInit #2", rc); + testcase_fail("C_FindObjectsInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); if (rc != CKR_OK) { - show_error(" C_FindObjects #2", rc); + testcase_fail("C_FindObjects #2, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } if (find_count != 1) { - printf("%s:%d ERROR: C_FindObjects #2 should have found 1 object!\n" + testcase_error("%s:%d ERROR: C_FindObjects #2 should have found 1 object!" " It found %lu objects\n", __FILE__, __LINE__, find_count); funcs->C_FindObjectsFinal(sess); @@ -242,7 +245,7 @@ if (obj_list[i] != h_counter1 && obj_list[i] != h_counter2 && obj_list[i] != h_clock) { - printf("%s:%d ERROR: C_FindObjects #2 found the wrong\n" + testcase_error("%s:%d ERROR: C_FindObjects #2 found the wrong\n" " objects!", __FILE__, __LINE__); rc = -1; } @@ -250,7 +253,7 @@ rc = funcs->C_FindObjectsFinal(sess); if (rc != CKR_OK) { - show_error(" C_FindObjectsFinal #2", rc); + testcase_fail("C_FindObjectsFinal #2, rc=%lx, %s", rc, p11_get_ckr(rc)); } done: @@ -265,6 +268,11 @@ destroy_1: funcs->C_DestroyObject(sess, h_obj1); + if (t_errors > 0) + testcase_notice("do_HW_Feature_Search ended with %ld error(s)", t_errors); + else + testcase_pass("do_HW_Feature_Search passed"); + return rc; } @@ -302,7 +310,7 @@ rc = funcs->C_Initialize(&initialize_args); if (rc != CKR_OK) { - show_error("C_Initialize", rc); + testcase_fail("C_Initialize, rc=%lx, %s", rc, p11_get_ckr(rc)); return -1; } @@ -311,7 +319,7 @@ NULL_PTR, NULL_PTR, &sess); /* Open a session with the token */ if (rc != CKR_OK) { - show_error("C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto done; } @@ -323,30 +331,29 @@ // Login correctly rc = funcs->C_Login(sess, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error("C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); goto session_close; } - printf("do_HW_Feature_Search...\n"); + testcase_setup(); rc = do_HW_Feature_Search(); if (rc) goto logout; - printf("Hardware Feature tests succeeded.\n"); - logout: rc = funcs->C_Logout(sess); if (rc != CKR_OK) - show_error("C_Logout #1", rc); + testcase_fail("C_Logout #1, rc=%lx, %s", rc, p11_get_ckr(rc)); session_close: rc = funcs->C_CloseSession(sess); /* Close the session */ if (rc != CKR_OK) - show_error("C_CloseSession", rc); + testcase_fail("C_CloseSession, rc=%lx, %s", rc, p11_get_ckr(rc)); done: /* Call C_Finalize and dlclose the library */ + testcase_print_result(); return clean_up(); } @@ -356,7 +363,7 @@ rc = funcs->C_Finalize(NULL); if (rc != CKR_OK) - show_error("C_Finalize", rc); + testcase_fail("C_Finalize, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/sess_mgmt.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/sess_mgmt.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/sess_mgmt.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/sess_mgmt.c 2023-05-15 14:42:55.000000000 +0200 @@ -55,24 +55,25 @@ CK_SESSION_HANDLE handle; CK_RV rc; - printf("do_OpenSession...\n"); + testcase_begin("do_OpenSession"); + testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &handle); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(handle); if (rc != CKR_OK) { - show_error(" C_CloseSession #1", rc); + testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_OpenSession passed"); return rc; } @@ -84,37 +85,38 @@ CK_SESSION_HANDLE h1, h2; CK_RV rc; - printf("do_OpenSession2...\n"); + testcase_begin("do_OpenSession2"); + testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(h1); if (rc != CKR_OK) { - show_error(" C_CloseSession #1", rc); + testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(h2); if (rc != CKR_OK) { - show_error(" C_CloseSession #2", rc); + testcase_fail("C_CloseSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_OpenSession2 passed"); return rc; } @@ -126,38 +128,39 @@ CK_SESSION_HANDLE h1, h2, h3; CK_RV rc; - printf("do_CloseAllSessions...\n"); + testcase_begin("do_CloseAllSessions"); + testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { - show_error(" C_OpenSession #3", rc); + testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { - show_error(" C_CloseAllSessions", rc); + testcase_fail("C_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_CloseAllSessions passed"); return rc; } @@ -170,34 +173,35 @@ CK_SESSION_INFO info; CK_RV rc; - printf("do_GetSessionInfo...\n"); + testcase_begin("do_GetSessionInfo"); + testcase_new_assertion(); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION; // read-only session rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { - show_error(" C_OpenSession #3", rc); + testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #1", rc); + testcase_fail("C_GetSessionInfo #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -205,7 +209,7 @@ rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #2", rc); + testcase_fail("C_GetSessionInfo #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -213,7 +217,7 @@ rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #3", rc); + testcase_fail("C_GetSessionInfo #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -221,11 +225,11 @@ rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { - show_error(" C_CloseAllSessions", rc); + testcase_fail("C_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_GetSessionInfo passed"); return rc; } @@ -258,7 +262,8 @@ CK_BYTE so_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG so_pin_len; - printf("do_LoginLogout...\n"); + testcase_begin("do_LoginLogout"); + testcase_new_assertion(); if (get_user_pin(user_pin)) return CKR_FUNCTION_FAILED; @@ -276,34 +281,34 @@ // create 3 sessions. 1 RO, two RW rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { - show_error(" C_OpenSession #3", rc); + testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // log the first session in. all sessions should become USER sessions rc = funcs->C_Login(h1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #1", rc); + testcase_fail("C_GetSessionInfo #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -311,7 +316,7 @@ rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #2", rc); + testcase_fail("C_GetSessionInfo #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -319,7 +324,7 @@ rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #3", rc); + testcase_fail("C_GetSessionInfo #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -328,7 +333,7 @@ // now, try to log in session #2. this should fail (already logged in) rc = funcs->C_Login(h2, CKU_USER, user_pin, user_pin_len); if (rc != CKR_USER_ALREADY_LOGGED_IN) { - show_error(" C_Login #2", rc); + testcase_fail("C_Login #2, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_USER_ALREADY_LOGGED_IN\n"); return -1; } @@ -336,13 +341,13 @@ // now, try to logout twice rc = funcs->C_Logout(h1); if (rc != CKR_OK) { - show_error(" C_Logout #1", rc); + testcase_fail("C_Logout #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_Logout(h2); if (rc != CKR_USER_NOT_LOGGED_IN) { - show_error(" C_Logout #2", rc); + testcase_fail("C_Logout #2, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_USER_NOT_LOGGED_IN\n"); return rc; } @@ -350,14 +355,14 @@ // now, try to log the SO in. this should fail since H1 is a RO session rc = funcs->C_Login(h1, CKU_SO, so_pin, so_pin_len); if (rc != CKR_SESSION_READ_ONLY_EXISTS) { - show_error(" C_Login #4", rc); + testcase_fail("C_Login #4, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_SESSION_READ_ONLY_EXISTS\n"); return -1; } rc = funcs->C_Login(h2, CKU_SO, so_pin, so_pin_len); if (rc != CKR_SESSION_READ_ONLY_EXISTS) { - show_error(" C_Login #5", rc); + testcase_fail("C_Login #5, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_SESSION_READ_ONLY_EXISTS\n"); return -1; } @@ -365,7 +370,7 @@ // log completely out rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { - show_error(" C_CloseAllSessions #1", rc); + testcase_fail("C_CloseAllSessions #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -373,27 +378,27 @@ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h1); if (rc != CKR_OK) { - show_error(" C_OpenSession #4", rc); + testcase_fail("C_OpenSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h2); if (rc != CKR_OK) { - show_error(" C_OpenSession #5", rc); + testcase_fail("C_OpenSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, try to log the SO in. this should work rc = funcs->C_Login(h1, CKU_SO, so_pin, so_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #6", rc); + testcase_fail("C_Login #6, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h1, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #4", rc); + testcase_fail("C_GetSessionInfo #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -401,7 +406,7 @@ rc = funcs->C_GetSessionInfo(h2, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #5", rc); + testcase_fail("C_GetSessionInfo #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -412,13 +417,13 @@ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h3); if (rc != CKR_OK) { - show_error(" C_OpenSession #6", rc); + testcase_fail("C_OpenSession #6, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetSessionInfo(h3, &info); if (rc != CKR_OK) { - show_error(" C_GetSessionInfo #6", rc); + testcase_fail("C_GetSessionInfo #6, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -428,7 +433,7 @@ flags = CKF_SERIAL_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h4); if (rc != CKR_SESSION_READ_WRITE_SO_EXISTS) { - show_error(" C_OpenSession #6", rc); + testcase_fail("C_OpenSession #6, rc=%lx, %s", rc, p11_get_ckr(rc)); PRINT_ERR(" Expected CKR_SESSION_READ_WRITE_SO_EXISTS\n"); return -1; } @@ -436,11 +441,11 @@ // we're done...close all sessions rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { - show_error(" C_CloseAllSessions #2: %d", rc); + testcase_fail("C_CloseAllSessions #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_LoginLogout passed"); return rc; } @@ -475,7 +480,8 @@ CK_OBJECT_HANDLE h_key; - printf("do_OperationState1...\n"); + testcase_begin("do_OperationState1"); + testcase_new_assertion(); slot_id = SLOT_ID; // @@ -495,13 +501,13 @@ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -512,7 +518,7 @@ rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -529,7 +535,7 @@ mech.pParameter = NULL; if (!mech_supported(slot_id, mech.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); @@ -538,7 +544,7 @@ rc = funcs->C_GenerateKey(session1, &mech, key_gen_tmpl, 1, &h_key); if (rc != CKR_OK) { - show_error(" C_GenerateKey #1", rc); + testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now encrypt the original data all at once using CBC @@ -548,21 +554,21 @@ rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { - show_error(" C_EncryptInit #1", rc); + testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt1_len = sizeof(crypt1); rc = funcs->C_Encrypt(session1, original, orig_len, crypt1, &crypt1_len); if (rc != CKR_OK) { - show_error(" C_Encrypt #1", rc); + testcase_fail("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, begin encrypting multipart rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { - show_error(" C_EncryptInit #2", rc); + testcase_fail("C_EncryptInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -570,7 +576,7 @@ rc = funcs->C_EncryptUpdate(session1, original, orig_len / 2, crypt2, &crypt2_len); if (rc != CKR_OK) { - show_error(" C_EncryptUpdate #1", rc); + testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -578,25 +584,25 @@ rc = funcs->C_GetOperationState(session1, NULL, &op_state_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { - printf("Session state not savable for mechanism %s. (skipped)\n", + testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); return 0; } - show_error(" C_GetOperationState #1", rc); + testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state = (CK_BYTE *) malloc(op_state_len); if (!op_state) { - show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state, &op_state_len); if (rc != CKR_OK) { - show_error(" C_GetOperationState #1", rc); + testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -606,7 +612,7 @@ rc = funcs->C_EncryptUpdate(session1, trash1, trash1_len, trash2, &trash2_len); if (rc != CKR_OK) { - show_error(" C_EncryptUpdate #2", rc); + testcase_fail("C_EncryptUpdate #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -614,7 +620,7 @@ // into session #2 and continue with the encryption rc = funcs->C_SetOperationState(session2, op_state, op_state_len, h_key, 0); if (rc != CKR_OK) { - show_error(" C_SetOperationState #1", rc); + testcase_fail("C_SetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -627,7 +633,7 @@ original + orig_len / 2, orig_len / 2, crypt2 + i, &crypt2_len); if (rc != CKR_OK) { - show_error(" C_EncryptUpdate #3", rc); + testcase_fail("C_EncryptUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -636,33 +642,33 @@ trash2_len = sizeof(trash2); rc = funcs->C_EncryptFinal(session2, trash2, &trash2_len); if (rc != CKR_OK) { - show_error(" C_EncryptFinal #1", rc); + testcase_fail("C_EncryptFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } if (crypt2_len != crypt1_len) { - PRINT_ERR(" ERROR: Lengths don't match\n"); + testcase_error("ERROR: Lengths don't match"); return -1; } if (memcmp(crypt1, crypt2, crypt1_len) != 0) { - PRINT_ERR(" ERROR: crypt1 != crypt2\n"); + testcase_error("ERROR: crypt1 != crypt2"); return -1; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { - show_error(" C_CloseSession #1", rc); + testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { - show_error(" C_CloseSession #2", rc); + testcase_fail("C_CloseSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_OperationState1 passed"); return rc; } @@ -693,7 +699,8 @@ CK_MECHANISM mech; - printf("do_OperationState2...\n"); + testcase_begin("do_OperationState2"); + testcase_new_assertion(); slot_id = SLOT_ID; // @@ -715,19 +722,19 @@ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); if (rc != CKR_OK) { - show_error(" C_OpenSession #3", rc); + testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -738,7 +745,7 @@ rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -751,7 +758,7 @@ mech.ulParameterLen = 0; if (!mech_supported(slot_id, mech.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); @@ -761,31 +768,31 @@ rc = funcs->C_DigestInit(session1, &mech); if (rc != CKR_OK) { - show_error(" C_DigestInit #1", rc); + testcase_fail("C_DigestInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session2, &mech); if (rc != CKR_OK) { - show_error(" C_DigestInit #2", rc); + testcase_fail("C_DigestInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session3, &mech); if (rc != CKR_OK) { - show_error(" C_DigestInit #3", rc); + testcase_fail("C_DigestInit #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session1, original, 499); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #1", rc); + testcase_fail("C_DigestUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original, 27); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #2", rc); + testcase_fail("C_DigestUpdate #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -793,7 +800,7 @@ digest3_len = sizeof(digest3); rc = funcs->C_Digest(session3, original, orig_len, digest3, &digest3_len); if (rc != CKR_OK) { - show_error(" C_Digest #1", rc); + testcase_fail("C_Digest #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -801,92 +808,92 @@ rc = funcs->C_GetOperationState(session1, NULL, &op_state1_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { - printf("Session state not savable for mechanism %s. (skipped)\n", + testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } - show_error(" C_GetOperationState #1", rc); + testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state1 = (CK_BYTE *) malloc(op_state1_len); if (!op_state1) { - show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session1, op_state1, &op_state1_len); if (rc != CKR_OK) { - show_error(" C_GetOperationState #2", rc); + testcase_fail("C_GetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { - printf("Session state not savable for mechanism %s. (skipped)\n", + testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } - show_error(" C_GetOperationState #3", rc); + testcase_fail("C_GetOperationState #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state2 = (CK_BYTE *) malloc(op_state2_len); if (!op_state2) { - show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + testcase_fail("HOST MEMORY ERROR"); return -1; } rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); if (rc != CKR_OK) { - show_error(" C_GetOperationState #4", rc); + testcase_fail("C_GetOperationState #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // switch the states rc = funcs->C_SetOperationState(session1, op_state2, op_state2_len, 0, 0); if (rc != CKR_OK) { - show_error(" C_SetOperationState #2", rc); + testcase_fail("C_SetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_SetOperationState(session2, op_state1, op_state1_len, 0, 0); if (rc != CKR_OK) { - show_error(" C_SetOperationState #3", rc); + testcase_fail("C_SetOperationState #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, finish the digest operations rc = funcs->C_DigestUpdate(session2, original + 499, (orig_len - 499)); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #3", rc); + testcase_fail("C_DigestUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session1, original + 27, orig_len - 27); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #4", rc); + testcase_fail("C_DigestUpdate #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session1, digest1, &digest1_len); if (rc != CKR_OK) { - show_error(" C_DigestFinal #1", rc); + testcase_fail("C_DigestFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); if (rc != CKR_OK) { - show_error(" C_DigestFinal #2", rc); + testcase_fail("C_DigestFinal #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -907,23 +914,23 @@ rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { - show_error(" C_CloseSession #3", rc); + testcase_fail("C_CloseSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { - show_error(" C_CloseSession #4", rc); + testcase_fail("C_CloseSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session3); if (rc != CKR_OK) { - show_error(" C_CloseSession #5", rc); + testcase_fail("C_CloseSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_OperationState2 passed"); free(op_state1); free(op_state2); @@ -962,7 +969,8 @@ CK_OBJECT_HANDLE key; - printf("do_OperationState3...\n"); + testcase_begin("do_OperationState3"); + testcase_new_assertion(); slot_id = SLOT_ID; // @@ -982,19 +990,19 @@ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); if (rc != CKR_OK) { - show_error(" C_OpenSession #2", rc); + testcase_fail("C_OpenSession #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); if (rc != CKR_OK) { - show_error(" C_OpenSession #3", rc); + testcase_fail("C_OpenSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1005,7 +1013,7 @@ rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1018,7 +1026,7 @@ mech1.ulParameterLen = 0; if (!mech_supported(slot_id, mech1.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech1.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); @@ -1028,7 +1036,7 @@ rc = funcs->C_GenerateKey(session1, &mech1, key_gen_tmpl, 1, &key); if (rc != CKR_OK) { - show_error(" C_GenerateKey #1", rc); + testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1037,7 +1045,7 @@ mech1.ulParameterLen = 0; if (!mech_supported(slot_id, mech1.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech1.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); @@ -1047,7 +1055,7 @@ rc = funcs->C_EncryptInit(session1, &mech1, key); if (rc != CKR_OK) { - show_error(" C_EncryptInit #1", rc); + testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1056,7 +1064,7 @@ mech2.ulParameterLen = 0; if (!mech_supported(slot_id, mech2.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech2.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); @@ -1066,19 +1074,19 @@ rc = funcs->C_DigestInit(session2, &mech2); if (rc != CKR_OK) { - show_error(" C_DigestInit #1", rc); + testcase_fail("C_DigestInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestInit(session3, &mech2); if (rc != CKR_OK) { - show_error(" C_DigestInit #2", rc); + testcase_fail("C_DigestInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original, 499); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #1", rc); + testcase_fail("C_DigestUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1086,39 +1094,39 @@ digest3_len = sizeof(digest3); rc = funcs->C_Digest(session3, original, orig_len, digest3, &digest3_len); if (rc != CKR_OK) { - show_error(" C_Digest #1", rc); + testcase_fail("C_Digest #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); if (rc != CKR_OK) { if (rc == CKR_STATE_UNSAVEABLE) { - printf("Session state not savable for mechanism %s. (skipped)\n", + testcase_skip("Session state not savable for mechanism %s. (skipped)", mech_to_str(mech2.mechanism)); funcs->C_CloseSession(session1); funcs->C_CloseSession(session2); funcs->C_CloseSession(session3); return 0; } - show_error(" C_GetOperationState #1", rc); + testcase_fail("C_GetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } op_state2 = (CK_BYTE *) malloc(op_state2_len); if (!op_state2) { - show_error(" HOST MEMORY ERROR #1", (CK_ULONG) CKR_HOST_MEMORY); + testcase_error("HOST MEMORY ERROR #1"); return -1; } rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); if (rc != CKR_OK) { - show_error(" C_GetOperationState #2", rc); + testcase_fail("C_GetOperationState #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_SetOperationState(session1, op_state2, op_state2_len, 0, 0); if (rc != CKR_OK) { - show_error(" C_SetOperationState #1", rc); + testcase_fail("C_SetOperationState #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1126,72 +1134,72 @@ junk_len = sizeof(junk); rc = funcs->C_EncryptUpdate(session1, original, 499, junk, &junk_len); if (rc != CKR_OPERATION_NOT_INITIALIZED) { - show_error(" C_EncryptUpdate #1", rc); - PRINT_ERR(" Expected CKR_OPERATION_NOT_INITIALIZED\n"); + testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); + testcase_error("Expected CKR_OPERATION_NOT_INITIALIZED"); return -1; } // now, finish the digest operations rc = funcs->C_DigestUpdate(session1, original + 499, (orig_len - 499)); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #2", rc); + testcase_fail("C_DigestUpdate #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_DigestUpdate(session2, original + 499, (orig_len - 499)); if (rc != CKR_OK) { - show_error(" C_DigestUpdate #3", rc); + testcase_fail("C_DigestUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest1_len = sizeof(digest1); rc = funcs->C_DigestFinal(session1, digest1, &digest1_len); if (rc != CKR_OK) { - show_error(" C_DigestFinal #1", rc); + testcase_fail("C_DigestFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } digest2_len = sizeof(digest2); rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); if (rc != CKR_OK) { - show_error(" C_DigestFinal #2", rc); + testcase_fail("C_DigestFinal #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } if (digest1_len != digest2_len || digest1_len != digest3_len) { - PRINT_ERR(" ERROR: digested lengths don't match\n"); + testcase_error("ERROR: digested lengths don't match"); return -1; } if (memcmp(digest1, digest2, digest1_len) != 0) { - PRINT_ERR(" ERROR: digest1 != digest2\n"); + testcase_error("ERROR: digest1 != digest2"); return -1; } if (memcmp(digest1, digest3, digest1_len) != 0) { - PRINT_ERR(" ERROR: digest1 != digest3\n"); + testcase_error("ERROR: digest1 != digest3"); return -1; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { - show_error(" C_CloseSession #3", rc); + testcase_fail("C_CloseSession #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session2); if (rc != CKR_OK) { - show_error(" C_CloseSession #4", rc); + testcase_fail("C_CloseSession #4, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session3); if (rc != CKR_OK) { - show_error(" C_CloseSession #5", rc); + testcase_fail("C_CloseSession #5, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_OperationState3 passed"); free(op_state2); return rc; @@ -1223,14 +1231,15 @@ CK_MECHANISM mech; CK_OBJECT_HANDLE h_key; - printf("do_SessionCancel...\n"); + testcase_begin("do_SessionCancel"); + testcase_new_assertion(); slot_id = SLOT_ID; // create two USER RW sessions flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session1); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_fail("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1241,7 +1250,7 @@ rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { - show_error(" C_Login #1", rc); + testcase_fail("C_Login #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1258,7 +1267,7 @@ mech.pParameter = NULL; if (!mech_supported(slot_id, mech.mechanism)) { - printf("Mechanism %s not supported. (skipped)\n", + testcase_skip("Mechanism %s not supported. (skipped)", mech_to_str(mech.mechanism)); funcs->C_CloseSession(session1); return 0; @@ -1266,7 +1275,7 @@ rc = funcs->C_GenerateKey(session1, &mech, key_gen_tmpl, 1, &h_key); if (rc != CKR_OK) { - show_error(" C_GenerateKey #1", rc); + testcase_fail("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now encrypt the original data all at once using CBC @@ -1276,35 +1285,35 @@ rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { - show_error(" C_EncryptInit #1", rc); + testcase_fail("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel the encrypt session rc = funcs3->C_SessionCancel(session1, CKF_ENCRYPT); if (rc != CKR_OK) { - show_error(" C_SessionCancel #1", rc); + testcase_fail("C_SessionCancel #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } crypt1_len = sizeof(crypt1); rc = funcs->C_Encrypt(session1, original, orig_len, crypt1, &crypt1_len); if (rc != CKR_OPERATION_NOT_INITIALIZED) { - show_error(" C_Encrypt #1", rc); + testcase_fail("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // now, begin encrypting multipart rc = funcs->C_EncryptInit(session1, &mech, h_key); if (rc != CKR_OK) { - show_error(" C_EncryptInit #2", rc); + testcase_fail("C_EncryptInit #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel non existing sign session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_SIGN); if (rc != CKR_OK) { - show_error(" C_SessionCancel #2", rc); + testcase_fail("C_SessionCancel #2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1312,14 +1321,14 @@ rc = funcs->C_EncryptUpdate(session1, original, orig_len / 2, crypt2, &crypt2_len); if (rc != CKR_OK) { - show_error(" C_EncryptUpdate #1", rc); + testcase_fail("C_EncryptUpdate #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } // cancel non existing decrypt session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_DECRYPT); if (rc != CKR_OK) { - show_error(" C_SessionCancel #3", rc); + testcase_fail("C_SessionCancel #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1330,7 +1339,7 @@ original + orig_len / 2, orig_len / 2, crypt2 + i, &crypt2_len); if (rc != CKR_OK) { - show_error(" C_EncryptUpdate #3", rc); + testcase_fail("C_EncryptUpdate #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } @@ -1339,24 +1348,24 @@ // cancel non existing find session (no effect expected) rc = funcs3->C_SessionCancel(session1, CKF_FIND_OBJECTS); if (rc != CKR_OK) { - show_error(" C_SessionCancel #3", rc); + testcase_fail("C_SessionCancel #3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } trash2_len = sizeof(trash2); rc = funcs->C_EncryptFinal(session1, trash2, &trash2_len); if (rc != CKR_OK) { - show_error(" C_EncryptFinal #1", rc); + testcase_fail("C_EncryptFinal #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } rc = funcs->C_CloseSession(session1); if (rc != CKR_OK) { - show_error(" C_CloseSession #1", rc); + testcase_fail("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; } - printf("Looks okay...\n"); + testcase_pass("do_SessionCancel passed"); return rc; } @@ -1366,76 +1375,92 @@ SYSTEMTIME t1, t2; CK_RV rc; + testcase_begin("sess_mgmt_functions"); + testcase_new_assertion(); + GetSystemTime(&t1); rc = do_OpenSession(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_OpenSession, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_OpenSession2(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_OpenSession2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_CloseAllSessions(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_CloseAllSessions, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_GetSessionInfo(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_GetSessionInfo, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_LoginLogout(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_LoginLogout, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_OperationState1(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_OperationState1, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_OperationState2(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_OperationState2, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); - GetSystemTime(&t1); rc = do_OperationState3(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_OperationState3, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); GetSystemTime(&t1); rc = do_SessionCancel(); - if (rc && !no_stop) + if (rc && !no_stop) { + testcase_fail("do_SessionCancel, rc=%lx, %s", rc, p11_get_ckr(rc)); return rc; + } GetSystemTime(&t2); process_time(t1, t2); + testcase_pass("sess_mgmt_functions passed"); + return rc; } @@ -1475,10 +1500,11 @@ rc = funcs->C_CancelFunction(hsess); if (rc != CKR_FUNCTION_NOT_PARALLEL) return rc; - } + testcase_setup(); rv = sess_mgmt_functions(); + testcase_print_result(); /* make sure we return non-zero if rv is non-zero */ return ((rv == 0) || (rv % 256) ? (int)rv : -1); diff -Nru opencryptoki-3.20.0+dfsg/testcases/pkcs11/sess_perf.c opencryptoki-3.21.0+dfsg/testcases/pkcs11/sess_perf.c --- opencryptoki-3.20.0+dfsg/testcases/pkcs11/sess_perf.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/pkcs11/sess_perf.c 2023-05-15 14:42:55.000000000 +0200 @@ -56,7 +56,7 @@ printf(" ulDeviceError: %lu\n", info->ulDeviceError); } -int create_des_encrypt_context(CK_SESSION_HANDLE_PTR hsess, +int create_aes_encrypt_context(CK_SESSION_HANDLE_PTR hsess, CK_OBJECT_HANDLE_PTR hkey) { CK_SLOT_ID slot_id; @@ -72,7 +72,7 @@ rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, hsess); if (rc != CKR_OK) { - show_error(" C_OpenSession #1", rc); + testcase_error("C_OpenSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } @@ -83,7 +83,7 @@ rc = funcs->C_GenerateKey(*hsess, &mech, &tkey, 1, hkey); if (rc != CKR_OK) { - show_error(" C_GenerateKey #1", rc); + testcase_error("C_GenerateKey #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } @@ -95,7 +95,7 @@ /* Create encryption context using this session and key */ rc = funcs->C_EncryptInit(*hsess, &mech, *hkey); if (rc != CKR_OK) { - show_error(" C_EncryptInit #1", rc); + testcase_error("C_EncryptInit #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } @@ -115,7 +115,7 @@ rc = funcs->C_EncryptUpdate(hsess, (CK_BYTE_PTR) (DATA + i), blocklen, (CK_BYTE_PTR) (DUMP + i), &outlen); if (rc != CKR_OK) { - show_error("C_Encrypt #1", rc); + testcase_error("C_Encrypt #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } } @@ -124,20 +124,20 @@ } -int finalize_des_encrypt_context(CK_SESSION_HANDLE hsess) +int finalize_aes_encrypt_context(CK_SESSION_HANDLE hsess) { CK_RV rc; CK_ULONG outlen = DATALEN; rc = funcs->C_EncryptFinal(hsess, DUMP, &outlen); if (rc != CKR_OK) { - show_error("C_EncryptFinal#1", rc); + testcase_error("C_EncryptFinal#1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } rc = funcs->C_CloseSession(hsess); if (rc != CKR_OK) { - show_error("C_CloseSession #1", rc); + testcase_error("C_CloseSession #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } @@ -153,7 +153,7 @@ rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) { - show_error("C_CloseAllSessions #1", rc); + testcase_error("C_CloseAllSessions #1, rc=%lx, %s", rc, p11_get_ckr(rc)); return FALSE; } @@ -168,21 +168,21 @@ context_table_t *t = NULL; if (count == 0) { - show_error("do_SessionPerformance: zero session count", (CK_RV) 0); + testcase_error("do_SessionPerformance: zero session count"); return FALSE; } t = (context_table_t *) calloc(count, sizeof(context_table_t)); if (t == NULL) { - show_error("do_SessionPerformance: insuficient memory", (CK_RV) 0); + testcase_error("do_SessionPerformance: insufficient memory"); return FALSE; } /* create encryption contexts */ for (i = 0; i < count; i++) { - rc = create_des_encrypt_context(&(t[i].hsess), &(t[i].hkey)); + rc = create_aes_encrypt_context(&(t[i].hsess), &(t[i].hkey)); if (rc == FALSE) { - show_error("create_aes_encrypt_context", (CK_RV) 0); + testcase_error("create_aes_encrypt_context"); goto ret; } } @@ -191,22 +191,22 @@ GetSystemTime(&t1); rc = encrypt_DATA(t[0].hsess, t[0].hkey, 16); if (rc == FALSE) { - show_error("encrypt_DATA #1", (CK_RV) 0); + testcase_error("encrypt_DATA #1"); goto ret; } rc = encrypt_DATA(t[count - 1].hsess, t[count - 1].hkey, 16); if (rc == FALSE) { - show_error("encrypt_DATA #2", (CK_RV) 0); + testcase_error("encrypt_DATA #2"); goto ret; } GetSystemTime(&t2); process_time(t1, t2); for (i = 0; i < count; i++) { - rc = finalize_des_encrypt_context(t[i].hsess); + rc = finalize_aes_encrypt_context(t[i].hsess); if (rc == FALSE) { - show_error("finalize_aes_encrypt_context", (CK_RV) 0); + testcase_error("finalize_aes_encrypt_context"); goto ret; } } @@ -254,13 +254,23 @@ rc = funcs->C_CancelFunction(hsess); if (rc != CKR_FUNCTION_NOT_PARALLEL) return rc; - } + testcase_setup(); + testcase_begin("do_SessionPerformance"); + testcase_new_assertion(); + for (i = 100; i < 50000; i = 1.2 * i) { printf("timing do_SessionPerformance(%d)\n", i); do_SessionPerformance(i); } + if (t_errors > 0) + testcase_notice("do_SessionPerformance ran with %ld error(s)", t_errors); + else + testcase_pass("do_SessionPerformance passed"); + + testcase_print_result(); + return 0; } diff -Nru opencryptoki-3.20.0+dfsg/testcases/policy/policy.mk opencryptoki-3.21.0+dfsg/testcases/policy/policy.mk --- opencryptoki-3.20.0+dfsg/testcases/policy/policy.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/policy/policy.mk 2023-05-15 14:42:55.000000000 +0200 @@ -11,6 +11,8 @@ testcases/policy/policytest.sh: testcases/policy/policytest.sh.in $(AM_V_GEN)@SED@ -e s!\@sysconfdir\@!"@sysconfdir@"!g \ -e s!\@sbindir\@!"@sbindir@"!g \ - -e s!\@libdir\@!"@libdir@"!g < $< > $@-t && \ + -e s!\@libdir\@!"@libdir@"!g \ + -e s!\@pkcsslotd_user\@!$(pkcsslotd_user)!g \ + -e s!\@pkcs_group\@!$(pkcs_group)!g< $< > $@-t && \ @CHMOD@ a+x $@-t && \ $(am__mv) $@-t $@ diff -Nru opencryptoki-3.20.0+dfsg/testcases/policy/policytest.sh.in opencryptoki-3.21.0+dfsg/testcases/policy/policytest.sh.in --- opencryptoki-3.20.0+dfsg/testcases/policy/policytest.sh.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/policy/policytest.sh.in 2023-05-15 14:42:55.000000000 +0200 @@ -13,13 +13,13 @@ if test -e @sysconfdir@/opencryptoki/strength.conf.ptbak; then rm -f @sysconfdir@/opencryptoki/strength.conf mv @sysconfdir@/opencryptoki/strength.conf.ptbak @sysconfdir@/opencryptoki/strength.conf - chown root:pkcs11 @sysconfdir@/opencryptoki/strength.conf + chown root:@pkcs_group@ @sysconfdir@/opencryptoki/strength.conf chmod 0640 @sysconfdir@/opencryptoki/strength.conf fi if test -e @sysconfdir@/opencryptoki/policy.conf.ptbak; then rm -f @sysconfdir@/opencryptoki/policy.conf mv @sysconfdir@/opencryptoki/policy.conf.ptbak @sysconfdir@/opencryptoki/policy.conf - chown root:pkcs11 @sysconfdir@/opencryptoki/policy.conf + chown root:@pkcs_group@ @sysconfdir@/opencryptoki/policy.conf chmod 0640 @sysconfdir@/opencryptoki/policy.conf fi } @@ -67,7 +67,7 @@ signature = 256 } EOF - chown root:pkcs11 @sysconfdir@/opencryptoki/strength.conf + chown root:@pkcs_group@ @sysconfdir@/opencryptoki/strength.conf chmod 0640 @sysconfdir@/opencryptoki/strength.conf } @@ -77,7 +77,7 @@ version policy-0 strength = $1 EOF - chown root:pkcs11 @sysconfdir@/opencryptoki/policy.conf + chown root:@pkcs_group@ @sysconfdir@/opencryptoki/policy.conf chmod 0640 @sysconfdir@/opencryptoki/policy.conf } diff -Nru opencryptoki-3.20.0+dfsg/testcases/README opencryptoki-3.21.0+dfsg/testcases/README --- opencryptoki-3.20.0+dfsg/testcases/README 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/testcases/README 2023-05-15 14:42:55.000000000 +0200 @@ -36,10 +36,27 @@ This directory contains build tests: a failed test is indicated by a build break. +policy +------ +This directory contains policy related tests. Test results are dependent on the +current policy and strength settings. + +unit +---- +This directory contains unit tests that are run via 'make check'. + ock_test.sh ----------- -This driver runs the various testcases on various tokens. -TODO: Needs to be modified and tested for new testcase structure. +This driver runs the various testcases on all tokens currently configured, +unless the '-s SLOT' option is specified. It initializes the tokens and sets +SO and USER pins, if the tokens are not already initialized. Set environment +variables PKCS11_SO_PIN and PKCS11_USER_PIN to the pins to use. + +ciconfig.sh +----------- +This script sets up the openCryptoki tokens for a run in the CI. It creates +an opencryptoki.conf config file together with several token specific config +files. The CI run is started via 'make ci-installcheck'. Do NOT run this outside +of the CI, it may destroy your openCryptoki setup, tokens, and objects! -For help, send mail to the openCryptoki mailing list at -opencryptoki-users@lists.sourceforge.net +For help, open an issue at https://github.com/opencryptoki/opencryptoki/issues diff -Nru opencryptoki-3.20.0+dfsg/tools/policyexamplegen.c opencryptoki-3.21.0+dfsg/tools/policyexamplegen.c --- opencryptoki-3.20.0+dfsg/tools/policyexamplegen.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/tools/policyexamplegen.c 2023-05-15 14:42:55.000000000 +0200 @@ -21,10 +21,10 @@ puts("# OpenCryptoki policy example"); puts("# Move/copy to /etc/opencryptoki/policy.conf to use it with opencryptoki."); - puts("# Then chown it to root:pkcs11 and chmod it to 0640."); + puts("# Then chown it to root:" PKCS_GROUP " and chmod it to 0640."); puts("# Also create a /etc/opencryptoki/strength.conf since this is a prerequisite"); puts("# for policies. You could just copy the strength-example.conf from this"); - puts("# folder, chown it to root:pkcs11 and chmod it to 0640."); + puts("# folder, chown it to root:" PKCS_GROUP " and chmod it to 0640."); puts(""); puts("version policy-0"); puts(""); diff -Nru opencryptoki-3.20.0+dfsg/.travis.yml opencryptoki-3.21.0+dfsg/.travis.yml --- opencryptoki-3.20.0+dfsg/.travis.yml 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/.travis.yml 2023-05-15 14:42:55.000000000 +0200 @@ -1,61 +1,56 @@ -sudo: required +os: linux dist: focal language: c before_install: - sudo apt-get -qq update - - sudo apt-get install -y expect libldap2-dev wget libudev-dev autoconf-archive + - sudo apt-get install -y expect libldap2-dev wget libudev-dev autoconf-archive libcap-dev - if [ "$TRAVIS_CPU_ARCH" != "amd64" ]; then sudo apt-get install -y trousers libtspi-dev; fi - - sudo wget https://launchpad.net/ubuntu/+archive/primary/+files/libica3_3.4.0-0ubuntu1_s390x.deb - - sudo wget https://launchpad.net/ubuntu/+archive/primary/+files/libica-dev_3.4.0-0ubuntu1_s390x.deb - - sudo dpkg -i libica3_3.4.0-0ubuntu1_s390x.deb || true # icatok needs libica >= 3.3 - - sudo dpkg -i libica-dev_3.4.0-0ubuntu1_s390x.deb || true # but install otherwise fails for non-s390x + - if [ "$TRAVIS_CPU_ARCH" = "s390x" ]; then sudo apt-get install -y libica3 libica-dev; fi -matrix: +jobs: include: - # TODO: Appease -Wclobbered in tm builds. - - name: "linux-x86-clang-locks" + - name: "linux-x86-clang" os: linux compiler: clang - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --enable-locks --with-systemd" CFLAGS="-O3 -Werror -DDEBUG" - - name: "linux-x86-gcc-tm" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -DDEBUG" + - name: "linux-x86-gcc" os: linux compiler: gcc - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --disable-locks --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" - - name: "linux-ppc64le-clang-locks" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" + - name: "linux-ppc64le-clang" os: linux arch: ppc64le compiler: clang - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --enable-locks --with-systemd" CFLAGS="-O3 -Werror" - - name: "linux-ppc64le-gcc-tm" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror" + - name: "linux-ppc64le-gcc" os: linux arch: ppc64le compiler: gcc - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --disable-locks --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" - - name: "linux-s390x-clang-locks" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" + - name: "linux-s390x-clang" os: linux arch: s390x compiler: clang - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --enable-locks --with-systemd" CFLAGS="-O3 -Werror -DDEBUG" - - name: "linux-s390x-gcc-tm" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror -DDEBUG" + - name: "linux-s390x-gcc" os: linux arch: s390x compiler: gcc - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --disable-locks --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" - - name: "linux-arm64-clang-locks" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror" + - name: "linux-arm64-clang" os: linux arch: arm64 compiler: clang - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --enable-locks --with-systemd" CFLAGS="-O3 -Werror" - - name: "linux-arm64-gcc-tm" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Werror" + - name: "linux-arm64-gcc" os: linux arch: arm64 compiler: gcc - env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --disable-locks --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --with-systemd" CFLAGS="-O3 -Wno-clobbered -Werror -DDEBUG" before_script: - - sudo groupadd pkcs11 - ./bootstrap.sh script: diff -Nru opencryptoki-3.20.0+dfsg/usr/include/apictl.h opencryptoki-3.21.0+dfsg/usr/include/apictl.h --- opencryptoki-3.20.0+dfsg/usr/include/apictl.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/include/apictl.h 2023-05-15 14:42:55.000000000 +0200 @@ -23,6 +23,29 @@ #include #endif +#define BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) \ + do { \ + if ((sltp)->TokData->hsm_mk_change_supported) { \ + if (pthread_rwlock_rdlock( \ + &(sltp)->TokData->hsm_mk_change_rwlock) != 0) { \ + TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); \ + (rv) = CKR_CANT_LOCK; \ + break; \ + } \ + } + +#define END_HSM_MK_CHANGE_LOCK(sltp, rv) \ + if ((sltp)->TokData->hsm_mk_change_supported) { \ + if (pthread_rwlock_unlock( \ + &(sltp)->TokData->hsm_mk_change_rwlock) != 0) { \ + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); \ + if ((rv) == CKR_OK) \ + (rv) = CKR_CANT_LOCK; \ + break; \ + } \ + } \ + } while (0); + // SAB Add a linked list of STDLL's loaded to // only load and get list once, but let multiple slots us it. diff -Nru opencryptoki-3.20.0+dfsg/usr/include/events.h opencryptoki-3.21.0+dfsg/usr/include/events.h --- opencryptoki-3.20.0+dfsg/usr/include/events.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/include/events.h 2023-05-15 14:42:55.000000000 +0200 @@ -48,11 +48,19 @@ #define EVENT_CLASS_MASK 0xffff0000 #define EVENT_CLASS_UDEV 0x00010000 #define EVENT_CLASS_ADMIN 0x00020000 +#define EVENT_CLASS_MK_CHANGE 0x00040000 /* Event types */ #define EVENT_TYPE_APQN_ADD EVENT_CLASS_UDEV + 0x00000001 #define EVENT_TYPE_APQN_REMOVE EVENT_CLASS_UDEV + 0x00000002 +#define EVENT_TYPE_MK_CHANGE_INITIATE_QUERY EVENT_CLASS_MK_CHANGE + 0x00000001 +#define EVENT_TYPE_MK_CHANGE_REENCIPHER EVENT_CLASS_MK_CHANGE + 0x00000002 +#define EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY EVENT_CLASS_MK_CHANGE + 0x00000003 +#define EVENT_TYPE_MK_CHANGE_FINALIZE EVENT_CLASS_MK_CHANGE + 0x00000004 +#define EVENT_TYPE_MK_CHANGE_CANCEL_QUERY EVENT_CLASS_MK_CHANGE + 0x00000005 +#define EVENT_TYPE_MK_CHANGE_CANCEL EVENT_CLASS_MK_CHANGE + 0x00000006 + /* Event flags */ #define EVENT_FLAGS_NONE 0x00000000 #define EVENT_FLAGS_REPLY_REQ 0x00000001 @@ -80,4 +88,16 @@ #define AP_DEVICE_TYPE_CEX6 12 #define AP_DEVICE_TYPE_CEX7 13 +/* Event payload for EVENT_TYPE_MK_CHANGE_xxx events */ +typedef struct { + char id[8]; + pid_t tool_pid; + unsigned int flags; + /* Followed by flattened struct hsm_mk_change_info */ +} event_mk_change_data_t; + +#define EVENT_MK_CHANGE_FLAGS_NONE 0x00000000 +#define EVENT_MK_CHANGE_FLAGS_TOK_OBJS 0x00000001 +#define EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL 0x00000002 + #endif diff -Nru opencryptoki-3.20.0+dfsg/usr/include/local_types.h opencryptoki-3.21.0+dfsg/usr/include/local_types.h --- opencryptoki-3.20.0+dfsg/usr/include/local_types.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/include/local_types.h 2023-05-15 14:42:55.000000000 +0200 @@ -24,11 +24,7 @@ /* Each node value must start with struct bt_ref_hdr */ struct bt_ref_hdr { -#ifdef ENABLE_LOCKS volatile unsigned long ref; -#else - unsigned long ref; -#endif }; #define BT_FLAG_FREE 1 @@ -51,9 +47,7 @@ struct btnode *top; unsigned long size; unsigned long free_nodes; -#ifdef ENABLE_LOCKS pthread_mutex_t mutex; -#endif void (*delete_func)(void *); }; @@ -73,6 +67,6 @@ void *bt_node_free(struct btree *t, unsigned long node_num, int call_delete_func); void bt_destroy(struct btree *t); -void bt_init(struct btree *t, void (*delete_func)(void *)); +CK_RV bt_init(struct btree *t, void (*delete_func)(void *)); #endif diff -Nru opencryptoki-3.20.0+dfsg/usr/include/pkcs11types.h opencryptoki-3.21.0+dfsg/usr/include/pkcs11types.h --- opencryptoki-3.20.0+dfsg/usr/include/pkcs11types.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/include/pkcs11types.h 2023-05-15 14:42:55.000000000 +0200 @@ -585,6 +585,8 @@ * opaque attribute. Support has been added to use this attribute * in key objects only. */ #define CKA_IBM_OPAQUE CKA_VENDOR_DEFINED + 1 +#define CKA_IBM_OPAQUE_REENC CKA_VENDOR_DEFINED + 3 +#define CKA_IBM_OPAQUE_OLD CKA_VENDOR_DEFINED + 4 #define CKA_IBM_RESTRICTABLE (CKA_VENDOR_DEFINED +0x10001) #define CKA_IBM_NEVER_MODIFIABLE (CKA_VENDOR_DEFINED +0x10002) diff -Nru opencryptoki-3.20.0+dfsg/usr/include/slotmgr.h opencryptoki-3.21.0+dfsg/usr/include/slotmgr.h --- opencryptoki-3.20.0+dfsg/usr/include/slotmgr.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/include/slotmgr.h 2023-05-15 14:42:55.000000000 +0200 @@ -30,13 +30,23 @@ #define TOK_PATH SBIN_PATH "/pkcsslotd" #define OCK_API_LOCK_FILE LOCKDIR_PATH "/LCK..APIlock" +#define OCK_HSM_MK_CHANGE_PATH CONFIG_PATH "/HSM_MK_CHANGE" +#define OCK_HSM_MK_CHANGE_LOCK_FILE LOCKDIR_PATH "/LCK..HSM_MK_CHANGElock" -#define PROC_SOCKET_FILE_PATH "/run/pkcsslotd.socket" -#define ADMIN_SOCKET_FILE_PATH "/run/pkcsslotd.admin.socket" +#define PROC_SOCKET_FILE_PATH "/run/opencryptoki/pkcsslotd.socket" +#define ADMIN_SOCKET_FILE_PATH "/run/opencryptoki/pkcsslotd.admin.socket" -#define PID_FILE_PATH "/run/pkcsslotd.pid" +#define PID_FILE_PATH "/run/opencryptoki/pkcsslotd.pid" #define OCK_CONFIG OCK_CONFDIR "/opencryptoki.conf" +#ifndef PKCSSLOTD_USER +#error "PKCSSLOTD_USER is not defined" +#endif + +#ifndef PKCS_GROUP +#error "PKCS_GROUP is not defined" +#endif + #ifndef CK_BOOL #define CK_BOOL CK_BBOOL #endif /* CK_BOOL */ diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/api_interface.c opencryptoki-3.21.0+dfsg/usr/lib/api/api_interface.c --- opencryptoki-3.20.0+dfsg/usr/lib/api/api_interface.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/api_interface.c 2023-05-15 14:42:55.000000000 +0200 @@ -384,7 +384,7 @@ * when forked). So we need to get the group information. * Really need to take the uid and map it to a name. */ - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp == NULL) { OCK_SYSLOG(LOG_ERR, "getgrnam() failed: %s\n", strerror(errno)); goto error; @@ -506,9 +506,11 @@ } if (fcn->ST_CloseSession) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CloseSession(sltp->TokData, &rSession, FALSE); TRACE_DEVEL("Called STDLL rv = 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) // If the STDLL successfully closed the session @@ -589,10 +591,12 @@ } if (fcn->ST_CopyObject) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CopyObject(sltp->TokData, &rSession, hObject, pTemplate, ulCount, phNewObject); TRACE_DEVEL("fcn->ST_CopyObject returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -662,10 +666,12 @@ } if (fcn->ST_CreateObject) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_CreateObject(sltp->TokData, &rSession, pTemplate, ulCount, phObject); TRACE_DEVEL("fcn->ST_CreateObject returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -717,9 +723,11 @@ } if (fcn->ST_Decrypt) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Decrypt(sltp->TokData, &rSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); + END_HSM_MK_CHANGE_LOCK(sltp, rv) TRACE_DEVEL("fcn->ST_Decrypt returned:0x%lx\n", rv); END_OPENSSL_LIBCTX(rv) } else { @@ -769,11 +777,13 @@ } if (fcn->ST_DecryptDigestUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptDigestUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptDigestUpdate returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -824,10 +834,12 @@ } if (fcn->ST_DecryptFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptFinal(sltp->TokData, &rSession, pLastPart, pulLastPartLen); TRACE_DEVEL("fcn->ST_DecryptFinal returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -883,9 +895,11 @@ } if (fcn->ST_DecryptInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_DecryptInit returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -937,11 +951,13 @@ } if (fcn->ST_DecryptUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptUpdate:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -989,11 +1005,13 @@ } if (fcn->ST_DecryptVerifyUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DecryptVerifyUpdate(sltp->TokData, &rSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); TRACE_DEVEL("fcn->ST_DecryptVerifyUpdate returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1059,10 +1077,12 @@ } if (fcn->ST_DeriveKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DeriveKey(sltp->TokData, &rSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey); TRACE_DEVEL("fcn->ST_DeriveKey returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1112,9 +1132,11 @@ } if (fcn->ST_DestroyObject) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DestroyObject(sltp->TokData, &rSession, hObject); TRACE_DEVEL("fcn->ST_DestroyObject returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1162,10 +1184,12 @@ } if (fcn->ST_Digest) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Digest(sltp->TokData, &rSession, pData, ulDataLen, pDigest, pulDigestLen); TRACE_DEVEL("fcn->ST_Digest:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1215,11 +1239,13 @@ } if (fcn->ST_DigestEncryptUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestEncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_DigestEncryptUpdate returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1265,10 +1291,12 @@ } if (fcn->ST_DigestFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestFinal(sltp->TokData, &rSession, pDigest, pulDigestLen); TRACE_DEVEL("fcn->ST_DigestFinal returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1317,9 +1345,11 @@ } if (fcn->ST_DigestInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestInit(sltp->TokData, &rSession, pMechanism); TRACE_DEVEL("fcn->ST_DigestInit returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1364,9 +1394,11 @@ } if (fcn->ST_DigestKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestKey(sltp->TokData, &rSession, hKey); TRACE_DEBUG("fcn->ST_DigestKey returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1412,9 +1444,11 @@ } if (fcn->ST_DigestUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_DigestUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_DigestUpdate returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1462,10 +1496,12 @@ } if (fcn->ST_Encrypt) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Encrypt(sltp->TokData, &rSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); TRACE_DEVEL("fcn->ST_Encrypt returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1512,10 +1548,12 @@ } if (fcn->ST_EncryptFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptFinal(sltp->TokData, &rSession, pLastEncryptedPart, pulLastEncryptedPartLen); TRACE_DEVEL("fcn->ST_EncryptFinal: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1565,9 +1603,11 @@ } if (fcn->ST_EncryptInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_INFO("fcn->ST_EncryptInit returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1616,11 +1656,13 @@ } if (fcn->ST_EncryptUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_EncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_EncryptUpdate returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1804,10 +1846,12 @@ } if (fcn->ST_FindObjects) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjects(sltp->TokData, &rSession, phObject, ulMaxObjectCount, pulObjectCount); TRACE_DEVEL("fcn->ST_FindObjects returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1857,9 +1901,11 @@ } if (fcn->ST_FindObjectsFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjectsFinal(sltp->TokData, &rSession); TRACE_DEVEL("fcn->ST_FindObjectsFinal returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1912,10 +1958,12 @@ } if (fcn->ST_FindObjectsInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_FindObjectsInit(sltp->TokData, &rSession, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_FindObjectsInit returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -1972,10 +2020,12 @@ } if (fcn->ST_GenerateKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateKey(sltp->TokData, &rSession, pMechanism, pTemplate, ulCount, phKey); TRACE_DEVEL("fcn->ST_GenerateKey returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2041,6 +2091,7 @@ } if (fcn->ST_GenerateKeyPair) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateKeyPair(sltp->TokData, &rSession, pMechanism, @@ -2050,6 +2101,7 @@ ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); TRACE_DEVEL("fcn->ST_GenerateKeyPair returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2099,10 +2151,12 @@ } if (fcn->ST_GenerateRandom) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GenerateRandom(sltp->TokData, &rSession, RandomData, ulRandomLen); TRACE_DEVEL("fcn->ST_GenerateRandom returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2161,10 +2215,12 @@ } if (fcn->ST_GetAttributeValue) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetAttributeValue(sltp->TokData, &rSession, hObject, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_GetAttributeValue returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2284,8 +2340,10 @@ } if (fcn->ST_GetMechanismInfo) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetMechanismInfo(sltp->TokData, slotID, type, pInfo); TRACE_DEVEL("fcn->ST_GetMechanismInfo returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2344,9 +2402,11 @@ } if (fcn->ST_GetMechanismList) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetMechanismList(sltp->TokData, slotID, pMechanismList, pulCount); TRACE_DEVEL("fcn->ST_GetMechanismList returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2410,9 +2470,11 @@ } if (fcn->ST_GetObjectSize) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetObjectSize(sltp->TokData, &rSession, hObject, pulSize); TRACE_DEVEL("fcn->ST_GetObjectSize retuned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2464,10 +2526,12 @@ } if (fcn->ST_GetOperationState) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetOperationState(sltp->TokData, &rSession, pOperationState, pulOperationStateLen); TRACE_DEVEL("fcn->ST_GetOperationState returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -2522,6 +2586,7 @@ } if (fcn->ST_GetSessionInfo) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_GetSessionInfo(sltp->TokData, &rSession, pInfo); @@ -2529,6 +2594,7 @@ TRACE_DEVEL("Slot %lu State %lx Flags %lx DevErr %lx\n", pInfo->slotID, pInfo->state, pInfo->flags, pInfo->ulDeviceError); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { @@ -2846,12 +2912,14 @@ } if (fcn->ST_GetTokenInfo) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_GetTokenInfo(sltp->TokData, slotID, pInfo); if (rv == CKR_OK) { get_sess_counts(slotID, &pInfo->ulSessionCount, &pInfo->ulRwSessionCount); } TRACE_DEVEL("rv %lu CK_TOKEN_INFO Flags %lx\n", rv, pInfo->flags); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3017,7 +3085,11 @@ //if ( Shared Memory Mapped not Successful ) // Free allocated Memory // Return CKR_HOST_MEMORY - bt_init(&Anchor->sess_btree, free); + if (bt_init(&Anchor->sess_btree, free) != CKR_OK) { + TRACE_ERROR("Btree init Failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } #if OPENSSL_VERSION_PREREQ(3, 0) /* @@ -3268,9 +3340,11 @@ } if (fcn->ST_InitPIN) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_InitPIN(sltp->TokData, &rSession, pPin, ulPinLen); TRACE_DEVEL("fcn->ST_InitPIN returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3338,8 +3412,10 @@ } if (fcn->ST_InitToken) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_InitToken(sltp->TokData, slotID, pPin, ulPinLen, pLabel); TRACE_DEVEL("fcn->ST_InitToken returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3395,9 +3471,11 @@ } if (fcn->ST_Login) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Login(sltp->TokData, &rSession, userType, pPin, ulPinLen); TRACE_DEVEL("fcn->ST_Login returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3447,9 +3525,11 @@ } if (fcn->ST_Logout) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Logout(sltp->TokData, &rSession); TRACE_DEVEL("fcn->ST_Logout returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3525,9 +3605,11 @@ if (fcn->ST_OpenSession) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_OpenSession(sltp->TokData, slotID, flags, &(apiSessp->sessionh)); TRACE_DEVEL("fcn->ST_OpenSession returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) // If the session allocation is successful, then we need to @@ -3541,10 +3623,12 @@ *phSession = AddToSessionList(apiSessp); if (*phSession == 0) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) /* failed to add the object to the API-level tree, close the * STDLL-level session and return failure */ fcn->ST_CloseSession(sltp->TokData, apiSessp, FALSE); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) free(apiSessp); rv = CKR_HOST_MEMORY; @@ -3617,9 +3701,11 @@ } if (fcn->ST_SeedRandom) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SeedRandom(sltp->TokData, &rSession, pSeed, ulSeedLen); TRACE_DEVEL("fcn->ST_SeedRandom returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3680,10 +3766,12 @@ } if (fcn->ST_SetAttributeValue) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetAttributeValue(sltp->TokData, &rSession, hObject, pTemplate, ulCount); TRACE_DEVEL("fcn->ST_SetAttributeValue returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3737,12 +3825,14 @@ } if (fcn->ST_SetOperationState) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetOperationState(sltp->TokData, &rSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey); TRACE_DEVEL("fcn->ST_SetOperationState returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3799,10 +3889,12 @@ } if (fcn->ST_SetPIN) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SetPIN(sltp->TokData, &rSession, pOldPin, ulOldLen, pNewPin, ulNewLen); TRACE_DEVEL("fcn->ST_SetPIN returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3855,10 +3947,12 @@ } if (fcn->ST_Sign) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Sign(sltp->TokData, &rSession, pData, ulDataLen, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_Sign returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3907,11 +4001,13 @@ } if (fcn->ST_SignEncryptUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignEncryptUpdate(sltp->TokData, &rSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); TRACE_DEVEL("fcn->ST_SignEncryptUpdate return: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -3961,10 +4057,12 @@ } if (fcn->ST_SignFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignFinal(sltp->TokData, &rSession, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_SignFinal returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4018,9 +4116,11 @@ } if (fcn->ST_SignInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_SignInit returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4068,10 +4168,12 @@ } if (fcn->ST_SignRecover) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignRecover(sltp->TokData, &rSession, pData, ulDataLen, pSignature, pulSignatureLen); TRACE_DEVEL("fcn->ST_SignRecover returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4121,10 +4223,12 @@ } if (fcn->ST_SignRecoverInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignRecoverInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_SignRecoverInit returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4174,9 +4278,11 @@ } if (fcn->ST_SignUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_SignUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_SignUpdate returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4239,12 +4345,14 @@ } if (fcn->ST_UnwrapKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_UnwrapKey(sltp->TokData, &rSession, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, phKey); TRACE_DEVEL("fcn->ST_UnwrapKey returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4293,10 +4401,12 @@ } if (fcn->ST_Verify) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_Verify(sltp->TokData, &rSession, pData, ulDataLen, pSignature, ulSignatureLen); TRACE_DEVEL("fcn->ST_Verify returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4342,10 +4452,12 @@ } if (fcn->ST_VerifyFinal) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyFinal(sltp->TokData, &rSession, pSignature, ulSignatureLen); TRACE_DEVEL("fcn->ST_VerifyFinal returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4395,9 +4507,11 @@ } if (fcn->ST_VerifyInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_VerifyInit returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4446,10 +4560,12 @@ } if (fcn->ST_VerifyRecover) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyRecover(sltp->TokData, &rSession, pSignature, ulSignatureLen, pData, pulDataLen); TRACE_DEVEL("fcn->ST_VerifyRecover returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4499,10 +4615,12 @@ } if (fcn->ST_VerifyRecoverInit) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyRecoverInit(sltp->TokData, &rSession, pMechanism, hKey); TRACE_DEVEL("fcn->ST_VerifyRecoverInit returned:0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4548,9 +4666,11 @@ } if (fcn->ST_VerifyUpdate) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_VerifyUpdate(sltp->TokData, &rSession, pPart, ulPartLen); TRACE_DEVEL("fcn->ST_VerifyUpdate returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -4750,10 +4870,12 @@ } if (fcn->ST_WrapKey) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_WrapKey(sltp->TokData, &rSession, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen); TRACE_DEVEL("fcn->ST_WrapKey returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); @@ -5477,6 +5599,7 @@ } if (fcn->ST_IBM_ReencryptSingle) { BEGIN_OPENSSL_LIBCTX(Anchor->openssl_libctx, rv) + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) // Map the Session to the slot session rv = fcn->ST_IBM_ReencryptSingle(sltp->TokData, &rSession, pDecrMech, hDecrKey, pEncrMech, hEncrKey, @@ -5484,6 +5607,7 @@ pReencryptedData, pulReencryptedDataLen); TRACE_DEVEL("fcn->ST_IBM_ReencryptSingle returned: 0x%lx\n", rv); + END_HSM_MK_CHANGE_LOCK(sltp, rv) END_OPENSSL_LIBCTX(rv) } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/api.mk opencryptoki-3.21.0+dfsg/usr/lib/api/api.mk --- opencryptoki-3.20.0+dfsg/usr/lib/api/api.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/api.mk 2023-05-15 14:42:55.000000000 +0200 @@ -31,20 +31,12 @@ usr/lib/common/mgf_translation.c \ usr/lib/api/supportedstrengths.c \ usr/lib/common/pqc_supported.c \ - usr/lib/config/cfgparse.y usr/lib/config/cfglex.l + usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ + usr/lib/common/btree.c nodist_opencryptoki_libopencryptoki_la_SOURCES = \ usr/lib/api/mechtable.c -if ENABLE_LOCKS -opencryptoki_libopencryptoki_la_SOURCES += \ - usr/lib/common/lock_btree.c -else -opencryptoki_libopencryptoki_la_SOURCES += \ - usr/lib/common/btree.c -opencryptoki_libopencryptoki_la_LDFLAGS += -litm -endif - usr/lib/api/mechtable.c usr/lib/api/mechtable-gen.h: tools/tableidxgen $(AM_V_GEN)$(MKDIR_P) usr/lib/api && ${abs_builddir}/tools/tableidxgen -c usr/lib/api/mechtable.c -d usr/lib/api/mechtable-gen.h -l usr/lib/api/mechtable.log diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/apiutil.c opencryptoki-3.21.0+dfsg/usr/lib/api/apiutil.c --- opencryptoki-3.20.0+dfsg/usr/lib/api/apiutil.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/apiutil.c 2023-05-15 14:42:55.000000000 +0200 @@ -153,8 +153,10 @@ * validity, since if we're here, they must already have been valid */ sltp = &(Anchor->SltList[closeme_arg->slot_id]); fcn = sltp->FcnList; + BEGIN_HSM_MK_CHANGE_LOCK(sltp, rv) rv = fcn->ST_CloseSession(sltp->TokData, s, closeme_arg->in_fork_initializer); + END_HSM_MK_CHANGE_LOCK(sltp, rv) if (rv == CKR_OK) { decr_sess_counts(closeme_arg->slot_id, s->rw_session); bt_node_free(&(Anchor->sess_btree), node_handle, TRUE); @@ -462,10 +464,10 @@ #endif if (sltp->TokData) { -#ifdef ENABLE_LOCKS pthread_rwlock_destroy(&sltp->TokData->sess_list_rwlock); -#endif pthread_mutex_destroy(&sltp->TokData->login_mutex); + if (sltp->TokData->hsm_mk_change_supported) + pthread_rwlock_destroy(&sltp->TokData->hsm_mk_change_rwlock); free(sltp->TokData); sltp->TokData = NULL; } @@ -609,10 +611,20 @@ sltp->TokData->real_gid = Anchor->ClientCred.real_gid; sltp->TokData->ro_session_count = 0; sltp->TokData->global_login_state = CKS_RO_PUBLIC_SESSION; -#ifdef ENABLE_LOCKS - pthread_rwlock_init(&sltp->TokData->sess_list_rwlock, NULL); -#endif - pthread_mutex_init(&sltp->TokData->login_mutex, NULL); + sltp->TokData->spinxplfd = -1; + sltp->TokData->spinxplfd_count = 0; + if (pthread_rwlock_init(&sltp->TokData->sess_list_rwlock, NULL) != 0) { + TRACE_ERROR("Initializing session list lock failed.\n"); + free(sltp->TokData); + sltp->TokData = NULL; + return FALSE; + } + if (pthread_mutex_init(&sltp->TokData->login_mutex, NULL) != 0) { + TRACE_ERROR("Initializing login mutex failed.\n"); + free(sltp->TokData); + sltp->TokData = NULL; + return FALSE; + } sltp->TokData->policy = policy; sltp->TokData->mechtable_funcs = &mechtable_funcs; sltp->TokData->statistics = statistics; @@ -631,6 +643,8 @@ DL_Load(sinfp, sltp, dllload); } } else { + free(sltp->TokData); + sltp->TokData = NULL; return FALSE; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/policy.c opencryptoki-3.21.0+dfsg/usr/lib/api/policy.c --- opencryptoki-3.20.0+dfsg/usr/lib/api/policy.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/policy.c 2023-05-15 14:42:55.000000000 +0200 @@ -1330,10 +1330,11 @@ struct group *grp = NULL; int err; - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (!grp) { - TRACE_ERROR("Could not retrieve \"pkcs11\" group!"); - OCK_SYSLOG(LOG_ERR, "POLICY: Could not retrieve \"pkcs11\" group!"); + TRACE_ERROR("Could not retrieve \"%s\" group!", PKCS_GROUP); + OCK_SYSLOG(LOG_ERR, "POLICY: Could not retrieve \"%s\" group!", + PKCS_GROUP); return CKR_GENERAL_ERROR; } if (fstat(fileno(fp), &statbuf)) { @@ -1352,10 +1353,10 @@ return CKR_GENERAL_ERROR; } if (statbuf.st_gid != grp->gr_gid) { - TRACE_ERROR("Policy configuration file %s should have group \"pkcs11\"!\n", - name); - OCK_SYSLOG(LOG_ERR, "POLICY: Configuration file %s should have group \"pkcs11\"!\n", - name); + TRACE_ERROR("Policy configuration file %s should have group \"%s\"!\n", + name, PKCS_GROUP); + OCK_SYSLOG(LOG_ERR, "POLICY: Configuration file %s should have group \"%s\"!\n", + name, PKCS_GROUP); return CKR_GENERAL_ERROR; } if ((statbuf.st_mode & ~S_IFMT) != OCK_POLICY_PERMS) { diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/shrd_mem.c.in opencryptoki-3.21.0+dfsg/usr/lib/api/shrd_mem.c.in --- opencryptoki-3.20.0+dfsg/usr/lib/api/shrd_mem.c.in 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/shrd_mem.c.in 2023-05-15 14:42:55.000000000 +0200 @@ -74,7 +74,7 @@ // only check group membership if not root user if (uid != 0 && euid != 0) { int i, member = 0; - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (!grp) { // group pkcs11 not known to the system return NULL; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/api/socket_client.c opencryptoki-3.21.0+dfsg/usr/lib/api/socket_client.c --- opencryptoki-3.20.0+dfsg/usr/lib/api/socket_client.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/api/socket_client.c 2023-05-15 14:42:55.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ struct sockaddr_un daemon_address; struct stat file_info; struct group *grp; + struct passwd *pwd; if (stat(file_path, &file_info)) { OCK_SYSLOG(LOG_ERR, @@ -49,15 +51,23 @@ return -1; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (!grp) { OCK_SYSLOG(LOG_ERR, - "connect_socket: pkcs11 group does not exist, errno=%d", - errno); + "connect_socket: %s group does not exist, errno=%d", + PKCS_GROUP, errno); + return -1; + } + + pwd = getpwnam(PKCSSLOTD_USER); + if (!pwd) { + OCK_SYSLOG(LOG_ERR, + "connect_socket: %s user does not exist, errno=%d", + PKCSSLOTD_USER, errno); return -1; } - if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid) { + if (file_info.st_uid != pwd->pw_uid || file_info.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, "connect_socket: incorrect permissions on socket file"); return -1; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_func.h opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_func.h --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_func.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_func.h 2023-05-15 14:42:55.000000000 +0200 @@ -288,6 +288,16 @@ unsigned char *rule_array, unsigned char *key_identifier); +/* Key Token Change 2 */ +typedef void (*CSNBKTC2_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_identifier_length, + unsigned char *key_identifier); + /* Key Translate */ typedef void (*CSNBKTR_t) (long *return_code, long *reason_code, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_specific.c opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -15,6 +15,7 @@ * */ +#define _GNU_SOURCE #include #include #include @@ -29,6 +30,13 @@ #include #include #include +#include +#include +#include +#ifndef NO_PKEY +#include +#include +#endif #include "cca_stdll.h" #include "pkcs11types.h" #include "p11util.h" @@ -45,7 +53,13 @@ #include "cfgparser.h" #include "configuration.h" #include "events.h" +#include "hsm_mk_change.h" +#include "constant_time.h" #include +#include +#ifndef NO_PKEY +#include "pkey_utils.h" +#endif /** * EC definitions @@ -105,6 +119,7 @@ static CSNBKYT_t dll_CSNBKYT; static CSNBKYTX_t dll_CSNBKYTX; static CSNBKTC_t dll_CSNBKTC; +static CSNBKTC2_t dll_CSNBKTC2; static CSNBKTR_t dll_CSNBKTR; static CSNBRNG_t dll_CSNBRNG; static CSNBRNGL_t dll_CSNBRNGL; @@ -176,6 +191,20 @@ static CSNBCTT2_t dll_CSNBCTT2; static CSUACFV_t dll_CSUACFV; +/* + * The CCA adapter lock is shared between all CCA token instances within the + * same process. Users of the CCA adapter(s) should obtain a READ lock, to + * be sure that no CCA adapter and/or domain selection is done concurrently. + * Whenever a CCA adapter and/or domain selection is performed, a WRITE lock + * must be obtained. This blocks all users until the selection processing is + * finished. + * While CCA device selection has thread scope, domain selection seems to have + * process scope. Thus, domain selection influences not only the current thread, + * but all threads of the process. + */ +static pthread_rwlock_t cca_adapter_rwlock; +static unsigned long cca_adapter_rwlock_ref_count = 0; + /* mechanisms provided by this token */ static const MECH_LIST_ELEMENT cca_mech_list[] = { {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, @@ -257,14 +286,37 @@ sec_ecc_publ_key }; +struct cca_mk_change_op { + volatile int mk_change_active; + char mk_change_op[8]; /* set if mk_change_active = 1 */ + unsigned char new_sym_mkvp[CCA_MKVP_LENGTH]; + unsigned char new_aes_mkvp[CCA_MKVP_LENGTH]; + unsigned char new_apka_mkvp[CCA_MKVP_LENGTH]; + CK_BBOOL new_sym_mkvp_set; + CK_BBOOL new_aes_mkvp_set; + CK_BBOOL new_apka_mkvp_set; + struct apqn *apqns; + unsigned int num_apqns; +}; + /* CCA token private data */ +#define PKEY_MK_VP_LENGTH 32 + +#define PKEY_MODE_DISABLED 0 +#define PKEY_MODE_DEFAULT 1 +#define PKEY_MODE_ENABLED 2 + +struct cca_version { + unsigned int ver; + unsigned int rel; + unsigned int mod; +}; + struct cca_private_data { void *lib_csulcca; - struct { - unsigned int ver; - unsigned int rel; - unsigned int mod; - } version; + struct cca_version cca_lib_version; + struct cca_version min_card_version; + pthread_rwlock_t min_card_version_rwlock; unsigned char expected_sym_mkvp[CCA_MKVP_LENGTH]; unsigned char expected_aes_mkvp[CCA_MKVP_LENGTH]; unsigned char expected_apka_mkvp[CCA_MKVP_LENGTH]; @@ -278,7 +330,14 @@ unsigned int num_usagedoms; unsigned short usage_domains[256]; CK_BBOOL inconsistent; - char serialno[9]; + char serialno[CCA_SERIALNO_LENGTH + 1]; + struct cca_mk_change_op mk_change_ops[CCA_NUM_MK_TYPES]; + char token_config_filename[PATH_MAX]; + int pkey_mode; + int pkey_wrap_supported; + char pkey_mk_vp[PKEY_MK_VP_LENGTH]; + int pkeyfd; + int msa_level; }; #define CCA_CFG_EXPECTED_MKVPS "EXPECTED_MKVPS" @@ -286,11 +345,168 @@ #define CCA_CFG_AES_MKVP "AES" #define CCA_CFG_APKA_MKVP "APKA" +#define SYSFS_BUS_AP "/sys/bus/ap/" #define SYSFS_DEVICES_AP "/sys/devices/ap/" +#define REGEX_CARD_PATTERN "card[0-9a-fA-F]+" #define MASK_COPRO 0x10000000 +/* + * Macros to enclose CCA verbs that use a secure key blob. + * If the CCA verb fails with return code 8 reason code 48 "One or more keys + * has a master key verification pattern that is not valid.", check if the + * secure key bob is enciphered with the new MK already. If so, and if a + * MK change operation for that master key type is currently active, select + * a single APQN that has the new MK set/activated. Wait in case no APQN is + * currently available. Once a single APQN has been selected, retry the CCA + * verb on the now selected single APQN. + */ +#define RETRY_NEW_MK_BLOB_START() \ + do { \ + int single_selected = 0; \ + char serialno[CCA_SERIALNO_LENGTH + 1]; \ + do { + +#define RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, \ + blob, bloblen) \ + RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, \ + blob, bloblen, NULL, 0) + +#define RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, \ + blob1, bloblen1, blob2, bloblen2) \ + if ((return_code) == 8 && (reason_code) == 48) { \ + TRACE_DEVEL("%s MKVP mismatch\n", __func__); \ + if (!single_selected && \ + cca_check_blob_select_single_apqn((tokdata), \ + (blob1), (bloblen1), \ + (blob2), (bloblen2), \ + serialno)) { \ + single_selected = 1; \ + continue; \ + } \ + } \ + if (single_selected) { \ + if (cca_deselect_single_apqn((tokdata), \ + serialno) != CKR_OK) { \ + TRACE_ERROR("%s Failed to de-select single " \ + "APQN\n", __func__); \ + (return_code) = 16; \ + (reason_code) = 336; \ + } \ + } \ + break; \ + } while (1); \ + } while (0); + +/* + * Macros to enclose any usage of CCA verbs. + * Obtains a READ lock on the CCA adapter lock, if a DOM-ANY configuration is + * used. This prevents CCA adapter usage concurrent to another thread performing + * Domain selection processing. Domain selection works on process scope, so + * it would influence all threads that currently use CCA verbs. + */ +#define USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) \ + do { \ + if (((struct cca_private_data *) \ + (tokdata)->private_data)->dom_any) { \ + if (pthread_rwlock_rdlock(&cca_adapter_rwlock) \ + != 0) { \ + TRACE_ERROR("CCA adapter RD-Lock failed.\n"); \ + (return_code) = 16; \ + (reason_code) = 336; \ + break; \ + } \ + } + +#define USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) \ + if (((struct cca_private_data *) \ + (tokdata)->private_data)->dom_any) { \ + if (pthread_rwlock_unlock(&cca_adapter_rwlock) \ + != 0) { \ + TRACE_ERROR("CCA adapter Unlock failed.\n"); \ + (return_code) = 16; \ + (reason_code) = 336; \ + break; \ + } \ + } \ + } while (0); + + const unsigned char cca_zero_mkvp[CCA_MKVP_LENGTH] = { 0 }; +static CK_RV file_fgets(const char *fname, char *buf, size_t buflen); +static CK_RV cca_mk_change_check_pending_ops(STDLL_TokData_t *tokdata); +static unsigned char *cca_mk_change_find_mkvp_in_ops(STDLL_TokData_t *tokdata, + enum cca_mk_type mk_type, + unsigned int *idx); +static CK_RV cca_reencipher_sec_key(STDLL_TokData_t *tokdata, + struct cca_mk_change_op *mk_change_op, + CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, CK_BBOOL from_old); + +static CK_RV init_cca_adapter_lock(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_private = tokdata->private_data; + pthread_rwlockattr_t attr; + unsigned long cnt; + + /* + * Only for DOM-ANY, we will perform domain selections. Thus, we only need + * to use the CCA adapter lock for for DOM-ANY configurations. + */ + if (!cca_private->dom_any) + return CKR_OK; + + cnt = __sync_add_and_fetch(&cca_adapter_rwlock_ref_count, 1); + if (cnt > 1) + return CKR_OK; + + if (pthread_rwlockattr_init(&attr) != 0) { + TRACE_ERROR("pthread_rwlockattr_init failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", + __func__); + return CKR_CANT_LOCK; + } + + if (pthread_rwlockattr_setkind_np(&attr, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) != 0) { + TRACE_ERROR("pthread_rwlockattr_setkind_np failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", + __func__); + pthread_rwlockattr_destroy(&attr); + return CKR_CANT_LOCK; + } + + if (pthread_rwlock_init(&cca_adapter_rwlock, &attr) != 0) { + TRACE_ERROR("pthread_rwlock_init failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the CCA adapter lock\n", + __func__); + pthread_rwlockattr_destroy(&attr); + return CKR_CANT_LOCK; + } + + pthread_rwlockattr_destroy(&attr); + + return CKR_OK; +} + +static void destroy_cca_adapter_lock(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned long cnt; + + /* + * Only for DOM-ANY, we will perform domain selections. Thus, we only need + * to use the CCA adapter lock for for DOM-ANY configurations. + */ + if (!cca_private->dom_any) + return; + + cnt = __sync_sub_and_fetch(&cca_adapter_rwlock_ref_count, 1); + + if (cnt == 0) + pthread_rwlock_destroy(&cca_adapter_rwlock); +} + /* * Helper function: Analyse given CCA token. * returns TRUE and keytype, keybitsize, and MKVP address if token is known @@ -452,15 +668,19 @@ static CK_RV check_expected_mkvp(STDLL_TokData_t *tokdata, enum cca_token_type keytype, - const CK_BYTE *mkvp) + const CK_BYTE *mkvp, CK_BBOOL *new_mk) { struct cca_private_data *cca_private = tokdata->private_data; const char *mktype; - const CK_BYTE *expected_mkvp; + const CK_BYTE *expected_mkvp, *new_mkvp; + + if (new_mk != NULL) + *new_mk = FALSE; switch (keytype) { case sec_des_data_key: expected_mkvp = cca_private->expected_sym_mkvp; + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, NULL); mktype = "SYM"; break; @@ -468,12 +688,14 @@ case sec_aes_cipher_key: case sec_hmac_key: expected_mkvp = cca_private->expected_aes_mkvp; + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, NULL); mktype = "AES"; break; case sec_rsa_priv_key: case sec_ecc_priv_key: expected_mkvp = cca_private->expected_apka_mkvp; + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, NULL); mktype = "APKA"; break; @@ -488,6 +710,15 @@ } if (memcmp(mkvp, expected_mkvp, CCA_MKVP_LENGTH) != 0) { + /* If an MK change operation is active, also allow the new MK */ + if (new_mkvp != NULL && + memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) == 0) { + TRACE_DEVEL("The key is wrapped by the new MK\n"); + if (new_mk != NULL) + *new_mk = TRUE; + return CKR_OK; + } + TRACE_ERROR("The key's master key verification pattern does not " "match the expected CCA %s master key\n", mktype); TRACE_DEBUG_DUMP("MKVP of key: ", (CK_BYTE *)mkvp, CCA_MKVP_LENGTH); @@ -540,12 +771,14 @@ if (num_bytes > 8192) num_bytes = 8192; - dll_CSNBRNGL(&return_code, - &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &zero, NULL, - (long *)&num_bytes, output + bytes_so_far); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBRNGL(&return_code, + &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &zero, NULL, + (long *)&num_bytes, output + bytes_so_far); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBRNGL failed. return:%ld, reason:%ld\n", @@ -592,6 +825,7 @@ *(void **)(&dll_CSNBKYT) = dlsym(hdl, "CSNBKYT"); *(void **)(&dll_CSNBKYTX) = dlsym(hdl, "CSNBKYTX"); *(void **)(&dll_CSNBKTC) = dlsym(hdl, "CSNBKTC"); + *(void **)(&dll_CSNBKTC2) = dlsym(hdl, "CSNBKTC2"); *(void **)(&dll_CSNBKTR) = dlsym(hdl, "CSNBKTR"); *(void **)(&dll_CSNBRNG) = dlsym(hdl, "CSNBRNG"); *(void **)(&dll_CSNBRNGL) = dlsym(hdl, "CSNBRNGL"); @@ -672,6 +906,7 @@ return CKR_OK; } +/* Called during token_specific_init() , no need to obtain CCA adapter lock */ static CK_RV cca_get_version(STDLL_TokData_t *tokdata) { struct cca_private_data *cca_private = tokdata->private_data; @@ -697,66 +932,40 @@ TRACE_DEVEL("CCA Version string: %s\n", version_data); if (sscanf((char *)version_data, "%u.%u.%uz%s", - &cca_private->version.ver, - &cca_private->version.rel, - &cca_private->version.mod, date) != 4) { + &cca_private->cca_lib_version.ver, + &cca_private->cca_lib_version.rel, + &cca_private->cca_lib_version.mod, date) != 4) { TRACE_ERROR("CCA library version is invalid: %s\n", version_data); return CKR_FUNCTION_FAILED; } - if (cca_private->version.ver < CCA_MIN_VERSION || - (cca_private->version.ver == CCA_MIN_VERSION && - cca_private->version.rel < CCA_MIN_RELEASE)) { + if (cca_private->cca_lib_version.ver < CCA_MIN_VERSION || + (cca_private->cca_lib_version.ver == CCA_MIN_VERSION && + cca_private->cca_lib_version.rel < CCA_MIN_RELEASE)) { TRACE_ERROR("The CCA host library version is too old: %u.%u.%u, " "required: %u.%u or later\n", - cca_private->version.ver, cca_private->version.rel, - cca_private->version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); + cca_private->cca_lib_version.ver, cca_private->cca_lib_version.rel, + cca_private->cca_lib_version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); OCK_SYSLOG(LOG_ERR,"The CCA host library version is too old: %u.%u.%u, " "required: %u.%u or later\n", - cca_private->version.ver, cca_private->version.rel, - cca_private->version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); + cca_private->cca_lib_version.ver, cca_private->cca_lib_version.rel, + cca_private->cca_lib_version.mod, CCA_MIN_VERSION, CCA_MIN_RELEASE); return CKR_DEVICE_ERROR; } return CKR_OK; } -static CK_RV cca_cmp_mkvp(unsigned char mkvp[CCA_MKVP_LENGTH], - unsigned char exp_mkvp[CCA_MKVP_LENGTH], - const char *mktype, const char *adapter, - const char *domain, CK_BBOOL expected_mkvps_set) -{ - if (expected_mkvps_set == FALSE && - memcmp(exp_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { - /* zero expected MKVP, copy current one */ - memcpy(exp_mkvp, mkvp, CCA_MKVP_LENGTH); - } else { - if (memcmp(mkvp, exp_mkvp, CCA_MKVP_LENGTH) != 0) { - TRACE_ERROR("CCA %s master key on adapter %s domain %s does not " - "match the %s master key\n", mktype, adapter, - domain, expected_mkvps_set ? "expected" : "other APQN's"); - OCK_SYSLOG(LOG_ERR, "CCA %s master key on adapter %s domain %s does " - "not match the %s master key\n", mktype, adapter, - domain, expected_mkvps_set ? "expected" : "other APQN's"); - return CKR_DEVICE_ERROR; - } - } - - return CKR_OK; -} - -static CK_RV cca_get_and_check_mkvps(STDLL_TokData_t *tokdata, - const char *adapter, const char *domain) +/* + * Called from within cca_iterate_adapters() handler function, thus no need to + * obtain CCA adapter lock + */ +static CK_RV cca_get_adapter_serial_number(char *serialno) { - struct cca_private_data *cca_private = tokdata->private_data; - unsigned char rule_array[256] = { 0, }; - unsigned char verb_data[256] = { 0, }; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; - unsigned short *id; - CK_RV rc; - /* Get current adapter serial number */ - memcpy(rule_array, "STATCRD2", 8); + memcpy(rule_array, "STATCRD2", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, @@ -765,42 +974,47 @@ &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACFQ (STATCRD2) failed for %s/%s. return:%ld, reason:%ld\n", - adapter, domain, return_code, reason_code); + TRACE_ERROR("CSUACFQ (STATCRD2) failed. return:%ld, reason:%ld\n", + return_code, reason_code); return CKR_FUNCTION_FAILED; } - TRACE_DEVEL("%s serialno: %.8s\n", adapter, &rule_array[14 * 8]); + memcpy(serialno, &rule_array[CCA_STATCRD2_SERIAL_NUMBER_OFFSET], + CCA_SERIALNO_LENGTH); + serialno[CCA_SERIALNO_LENGTH] = '\0'; - /* Get status of AES master key (DES, 3DES keys) */ - memcpy(rule_array, "STATCCAE", 8); - rule_array_count = 1; - verb_data_length = 0; - dll_CSUACFQ(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &verb_data_length, NULL); + return CKR_OK; +} - if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACFQ (STATCCAE) failed for %s/%s. return:%ld, reason:%ld\n", - adapter, domain, return_code, reason_code); - return CKR_FUNCTION_FAILED; - } +/* + * Called from within cca_iterate_adapters() handler function, thus no need to + * obtain CCA adapter lock + */ +static CK_RV cca_get_mk_state(enum cca_mk_type mk_type, + enum cca_cmk_state *cur, + enum cca_nmk_state *new) +{ + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, verb_data_length; + char *cmk, *nmk; - /* This value should be 2 if the master key is set in the card */ - if (memcmp(&rule_array[CCA_STATCCAE_CMK_OFFSET], "2 ", 8)) { - TRACE_ERROR("CCA SYM master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - OCK_SYSLOG(LOG_ERR, - "CCA SYM master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - return CKR_DEVICE_ERROR; + switch (mk_type) { + case CCA_MK_SYM: + memcpy(rule_array, "STATCCAE", CCA_KEYWORD_SIZE); + rule_array_count = 1; + break; + case CCA_MK_AES: + memcpy(rule_array, "STATAES ", CCA_KEYWORD_SIZE); + rule_array_count = 1; + break; + case CCA_MK_APKA: + memcpy(rule_array, "STATAPKA", CCA_KEYWORD_SIZE); + rule_array_count = 1; + break; + default: + return CKR_ARGUMENTS_BAD; } - /* Get status of AES master key (AES, HMAC keys) */ - memset(rule_array, 0, sizeof(rule_array)); - memcpy(rule_array, "STATAES ", 8); - rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, @@ -808,49 +1022,64 @@ &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACFQ (STATAES) failed for %s/%s. return:%ld, reason:%ld\n", - adapter, domain, return_code, reason_code); + TRACE_ERROR("CSUACFQ (%s) failed. return:%ld, reason:%ld\n", + rule_array, return_code, reason_code); return CKR_FUNCTION_FAILED; } - /* This value should be 2 if the master key is set in the card */ - if (memcmp(&rule_array[CCA_STATAES_CMK_OFFSET], "2 ", 8)) { - TRACE_ERROR("CCA AES master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - OCK_SYSLOG(LOG_ERR, - "CCA AES master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - return CKR_DEVICE_ERROR; + switch (mk_type) { + case CCA_MK_SYM: + cmk = (char *)&rule_array[CCA_STATCCAE_SYM_CMK_OFFSET]; + nmk = (char *)&rule_array[CCA_STATCCAE_SYM_NMK_OFFSET]; + break; + case CCA_MK_AES: + cmk = (char *)&rule_array[CCA_STATAES_AES_CMK_OFFSET]; + nmk = (char *)&rule_array[CCA_STATAES_AES_NMK_OFFSET]; + break; + case CCA_MK_APKA: + cmk = (char *)&rule_array[CCA_STATAPKA_APKA_CMK_OFFSET]; + nmk = (char *)&rule_array[CCA_STATAPKA_APKA_NMK_OFFSET]; + break; + default: + return CKR_ARGUMENTS_BAD; } - /* Get status of APKA master key (RSA and ECC keys) */ - memset(rule_array, 0, sizeof(rule_array)); - memcpy(rule_array, "STATAPKA", 8); - rule_array_count = 1; - verb_data_length = 0; - dll_CSUACFQ(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &verb_data_length, NULL); + cmk[1] = '\0'; + nmk[1] = '\0'; - if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACFQ (STATAPKA) failed for %s/%s. return:%ld, reason:%ld\n", - adapter, domain, return_code, reason_code); - return CKR_FUNCTION_FAILED; + if (cur != NULL) { + if (sscanf(cmk, "%d", (int *)cur) != 1) { + TRACE_ERROR("Bad CMK status '%s'\n", cmk); + return CKR_FUNCTION_FAILED; + } } - if (memcmp(&rule_array[CCA_STATAPKA_CMK_OFFSET], "2 ", 8)) { - TRACE_ERROR("CCA APKA master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - OCK_SYSLOG(LOG_ERR, - "CCA APKA master key is not yet loaded on adapter %s domain %s\n", - adapter, domain); - return CKR_DEVICE_ERROR; - } + if (new != NULL) { + if (sscanf(nmk, "%d", (int *)new) != 1) { + TRACE_ERROR("Bad CMK status '%s'\n", nmk); + return CKR_FUNCTION_FAILED; + } + } + + return CKR_OK; +} + +/* + * Called from within cca_iterate_adapters() handler function, thus no need to + * obtain CCA adapter lock + */ +static CK_RV cca_get_mkvps(unsigned char *cur_sym, unsigned char *new_sym, + unsigned char *cur_aes, unsigned char *new_aes, + unsigned char *cur_apka, unsigned char *new_apka) +{ + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + unsigned char verb_data[256] = { 0, }; + long return_code, reason_code, rule_array_count, verb_data_length; + unsigned short *id; /* Get master key verification patterns */ memset(rule_array, 0, sizeof(rule_array)); - memcpy(rule_array, "STATICSB", 8); + memcpy(rule_array, "STATICSB", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(verb_data); dll_CSUACFQ(&return_code, &reason_code, @@ -859,97 +1088,523 @@ &verb_data_length, verb_data); if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACFQ (STATICSB) failed for %s/%s. return:%ld, reason:%ld\n", - adapter, domain, return_code, reason_code); + TRACE_ERROR("CSUACFQ (STATICSB) failed . return:%ld, reason:%ld\n", + return_code, reason_code); return CKR_FUNCTION_FAILED; } - id = (unsigned short *)(verb_data + CCA_STATICSB_SYM_CMK_ID_OFFSET); - if (*id != CCA_STATICSB_SYM_CMK_ID) { - TRACE_ERROR("CSUACFQ (STATICSB) SYM MKVP not available for %s/%s\n", - adapter, domain); - return CKR_FUNCTION_FAILED; + if (cur_sym != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_SYM_CMK_ID_OFFSET); + if (*id != CCA_STATICSB_SYM_CMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) current SYM MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(cur_sym, verb_data + CCA_STATICSB_SYM_CMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); } - id = (unsigned short *)(verb_data + CCA_STATICSB_AES_CMK_ID_OFFSET); - if (*id != CCA_STATICSB_AES_CMK_ID) { - TRACE_ERROR("CSUACFQ (STATICSB) AES MKVP not available for %s/%s\n", - adapter, domain); - return CKR_FUNCTION_FAILED; + if (new_sym != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_SYM_NMK_ID_OFFSET); + if (*id != CCA_STATICSB_SYM_NMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) new SYM MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(new_sym, verb_data + CCA_STATICSB_SYM_NMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); } - id = (unsigned short *)(verb_data + CCA_STATICSB_APKA_CMK_ID_OFFSET); - if (*id != CCA_STATICSB_APKA_CMK_ID) { - TRACE_ERROR("CSUACFQ (STATICSB) APKA MKVP not available for %s/%s\n", - adapter, domain); - return CKR_FUNCTION_FAILED; + if (cur_aes != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_AES_CMK_ID_OFFSET); + if (*id != CCA_STATICSB_AES_CMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) current AES MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(cur_aes, verb_data + CCA_STATICSB_AES_CMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); + } + + if (new_aes != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_AES_NMK_ID_OFFSET); + if (*id != CCA_STATICSB_AES_NMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) new AES MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(new_aes, verb_data + CCA_STATICSB_AES_NMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); + } + + if (cur_apka != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_APKA_CMK_ID_OFFSET); + if (*id != CCA_STATICSB_APKA_CMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) current APKA MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(cur_apka, verb_data + CCA_STATICSB_APKA_CMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); + } + + if (new_apka != NULL) { + id = (unsigned short *)(verb_data + CCA_STATICSB_APKA_NMK_ID_OFFSET); + if (*id != CCA_STATICSB_APKA_NMK_ID) { + TRACE_ERROR("CSUACFQ (STATICSB) new APKA MKVP not available\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(new_apka, verb_data + CCA_STATICSB_APKA_NMK_MKVP_OFFSET, + CCA_MKVP_LENGTH); + } + + return CKR_OK; +} + +static CK_RV cca_cmp_mkvp(unsigned char mkvp[CCA_MKVP_LENGTH], + unsigned char exp_mkvp[CCA_MKVP_LENGTH], + unsigned char *new_mkvp, + const char *mktype, const char *adapter, + unsigned short card, unsigned short domain, + CK_BBOOL expected_mkvps_set) +{ + /* + * If an MK change operation is pending, the current MK may already + * be the new MK of the operation. + */ + if (new_mkvp != NULL && + memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) == 0) { + TRACE_DEVEL("CCA %s master key on adapter %s (%02X.%04X) has " + "the new MK\n", mktype, adapter, card, domain); + return CKR_OK; + } + + if (expected_mkvps_set == FALSE && + memcmp(exp_mkvp, cca_zero_mkvp, CCA_MKVP_LENGTH) == 0) { + /* zero expected MKVP, copy current one */ + memcpy(exp_mkvp, mkvp, CCA_MKVP_LENGTH); + } else { + if (memcmp(mkvp, exp_mkvp, CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("CCA %s master key on adapter %s (%02X.%04X) does not " + "match the %s master key\n", mktype, adapter, card, + domain, expected_mkvps_set ? "expected" : "other APQN's"); + OCK_SYSLOG(LOG_ERR, "CCA %s master key on adapter %s (%02X.%04X) does " + "not match the %s master key\n", mktype, adapter, card, + domain, expected_mkvps_set ? "expected" : "other APQN's"); + return CKR_DEVICE_ERROR; + } + } + + return CKR_OK; +} + +static CK_RV cca_get_and_check_mkvps(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private) +{ + struct cca_private_data *cca_private = tokdata->private_data; + char serialno[CCA_SERIALNO_LENGTH + 1]; + unsigned char sym_mkvp[CCA_MKVP_LENGTH]; + unsigned char sym_new_mkvp[CCA_MKVP_LENGTH]; + unsigned char aes_mkvp[CCA_MKVP_LENGTH]; + unsigned char aes_new_mkvp[CCA_MKVP_LENGTH]; + unsigned char apka_mkvp[CCA_MKVP_LENGTH]; + unsigned char apka_new_mkvp[CCA_MKVP_LENGTH]; + unsigned char *op_sym_mkvp, *op_aes_mkvp, *op_apka_mkvp; + unsigned int sym_op_idx = 0, aes_op_idx = 0, apka_op_idx = 0; + enum cca_cmk_state mk_state; + enum cca_nmk_state sym_new_state, aes_new_state, apka_new_state; + CK_RV rc, rc2 = CKR_OK; + + UNUSED(private); + + /* Get current adapter serial number */ + rc = cca_get_adapter_serial_number(serialno); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_adapter_serial_number failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } + TRACE_DEVEL("%s (%02X.%04X) serialno: %s\n", adapter, card, domain, + serialno); + + /* Get status of SYM master key (DES, 3DES keys) */ + rc = cca_get_mk_state(CCA_MK_SYM, &mk_state, &sym_new_state); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mk_state (SYM) failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } + + /* Ensure the master key is set in the card */ + if (mk_state != CCA_CMK_STATUS_FULL) { + TRACE_ERROR("CCA SYM master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + OCK_SYSLOG(LOG_ERR, + "CCA SYM master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + return CKR_DEVICE_ERROR; + } + + /* Get status of AES master key (AES, HMAC keys) */ + rc = cca_get_mk_state(CCA_MK_AES, &mk_state, &aes_new_state); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mk_state (AES) failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } + + /* Ensure the master key is set in the card */ + if (mk_state != CCA_CMK_STATUS_FULL) { + TRACE_ERROR("CCA AES master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + OCK_SYSLOG(LOG_ERR, + "CCA AES master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + return CKR_DEVICE_ERROR; + } + + /* Get status of APKA master key (RSA and ECC keys) */ + rc = cca_get_mk_state(CCA_MK_APKA, &mk_state, &apka_new_state); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mk_state (APKA) failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } + + /* Ensure the master key is set in the card */ + if (mk_state != CCA_CMK_STATUS_FULL) { + TRACE_ERROR("CCA APKA master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + OCK_SYSLOG(LOG_ERR, + "CCA APKA master key is not yet loaded on adapter %s (%02X.%04X)\n", + adapter, card, domain); + return CKR_DEVICE_ERROR; } - TRACE_DEBUG("Master key verification patterns for %s/%s\n", - adapter, domain); - TRACE_DEBUG_DUMP("SYM MKVP: ", - verb_data + CCA_STATICSB_SYM_CMK_MKVP_OFFSET, - CCA_MKVP_LENGTH); - TRACE_DEBUG_DUMP("AES MKVP: ", - verb_data + CCA_STATICSB_AES_CMK_MKVP_OFFSET, - CCA_MKVP_LENGTH); - TRACE_DEBUG_DUMP("APKA MKVP: ", - verb_data + CCA_STATICSB_APKA_CMK_MKVP_OFFSET, - CCA_MKVP_LENGTH); + /* Get master key verification patterns */ + rc = cca_get_mkvps(sym_mkvp, sym_new_mkvp, aes_mkvp, aes_new_mkvp, + apka_mkvp, apka_new_mkvp); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mkvps failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } - rc = cca_cmp_mkvp(verb_data + CCA_STATICSB_SYM_CMK_MKVP_OFFSET, - cca_private->expected_sym_mkvp, - "SYM", adapter, domain, + TRACE_DEBUG("Master key verification patterns for %s (%02X.%04X)\n", + adapter, card, domain); + TRACE_DEBUG_DUMP("SYM CUR MKVP: ", sym_mkvp, CCA_MKVP_LENGTH); + if (sym_new_state == CCA_NMK_STATUS_FULL) { + TRACE_DEBUG_DUMP("SYM NEW MKVP: ", sym_new_mkvp, CCA_MKVP_LENGTH); + } + TRACE_DEBUG_DUMP("AES CUR MKVP: ", aes_mkvp, CCA_MKVP_LENGTH); + if (aes_new_state == CCA_NMK_STATUS_FULL) { + TRACE_DEBUG_DUMP("AES NEW MKVP: ", aes_new_mkvp, CCA_MKVP_LENGTH); + } + TRACE_DEBUG_DUMP("APKA CUR MKVP: ", apka_mkvp, CCA_MKVP_LENGTH); + if (apka_new_state == CCA_NMK_STATUS_FULL) { + TRACE_DEBUG_DUMP("APKA NEW MKVP: ", apka_new_mkvp, CCA_MKVP_LENGTH); + } + + op_sym_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, + &sym_op_idx); + op_aes_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, + &aes_op_idx); + op_apka_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, + &apka_op_idx); + + /* Current MK can either be expected one, or new from operation (if any) */ + rc = cca_cmp_mkvp(sym_mkvp, cca_private->expected_sym_mkvp, op_sym_mkvp, + "SYM", adapter, card, domain, cca_private->expected_sym_mkvp_set); - rc |= cca_cmp_mkvp(verb_data + CCA_STATICSB_AES_CMK_MKVP_OFFSET, - cca_private->expected_aes_mkvp, - "AES", adapter, domain, + rc |= cca_cmp_mkvp(aes_mkvp, cca_private->expected_aes_mkvp, op_aes_mkvp, + "AES", adapter, card, domain, cca_private->expected_aes_mkvp_set); - rc |= cca_cmp_mkvp(verb_data + CCA_STATICSB_APKA_CMK_MKVP_OFFSET, - cca_private->expected_apka_mkvp, - "APKA", adapter, domain, + rc |= cca_cmp_mkvp(apka_mkvp, cca_private->expected_apka_mkvp, op_apka_mkvp, + "APKA", adapter, card, domain, cca_private->expected_apka_mkvp_set); + + /* + * If new MK is set, it must be the one from the MK change operation(s). + * If new MK is not set, the current MK must be the expected new MK of + * the operation(s). For this case, report error only if not within the + * pkcshsm_mk_change tool process. Otherwise the MK change operation could + * not be canceled when the new MK register has already been cleared by + * the HSM admin. + */ + if (op_sym_mkvp != NULL) { + rc2 |= cca_cmp_mkvp(sym_new_state == CCA_NMK_STATUS_FULL ? + sym_new_mkvp : sym_mkvp, + op_sym_mkvp, NULL, + sym_new_state == CCA_NMK_STATUS_FULL ? + "SYM NEW" : "SYM CURRENT", + adapter, card, domain, TRUE); + if (sym_new_state != CCA_NMK_STATUS_FULL && + strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) + rc2 = CKR_OK; + rc |= rc2; + } + if (op_aes_mkvp != NULL) { + rc2 |= cca_cmp_mkvp(aes_new_state == CCA_NMK_STATUS_FULL ? + aes_new_mkvp : aes_mkvp, + op_aes_mkvp, NULL, + aes_new_state == CCA_NMK_STATUS_FULL ? + "AES NEW" : "AES CURRENT", + adapter, card, domain, TRUE); + if (aes_new_state != CCA_NMK_STATUS_FULL && + strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) + rc2 = CKR_OK; + rc |= rc2; + } + if (op_apka_mkvp != NULL) { + rc2 |= cca_cmp_mkvp(apka_new_state == CCA_NMK_STATUS_FULL ? + apka_new_mkvp : apka_mkvp, + op_apka_mkvp, NULL, + apka_new_state == CCA_NMK_STATUS_FULL ? + "APKA NEW" : "APKA CURRENT", + adapter, card, domain, TRUE); + if (apka_new_state != CCA_NMK_STATUS_FULL && + strcmp(program_invocation_short_name, "pkcshsm_mk_change") == 0) + rc2 = CKR_OK; + rc |= rc2; + } + + /* + * If an MK change operation is active, the current APQN must be part + * of each operation. + */ + if (op_sym_mkvp != NULL && + !hsm_mk_change_apqns_find( + cca_private->mk_change_ops[sym_op_idx].apqns, + cca_private->mk_change_ops[sym_op_idx].num_apqns, + card, domain)) { + TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " + "not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[sym_op_idx].mk_change_op); + OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " + "it is not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[sym_op_idx].mk_change_op); + rc |= CKR_DEVICE_ERROR; + } + + if (op_aes_mkvp != NULL && + !hsm_mk_change_apqns_find( + cca_private->mk_change_ops[aes_op_idx].apqns, + cca_private->mk_change_ops[aes_op_idx].num_apqns, + card, domain)) { + TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " + "not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[aes_op_idx].mk_change_op); + OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " + "it is not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[aes_op_idx].mk_change_op); + rc |= CKR_DEVICE_ERROR; + } + + if (op_apka_mkvp != NULL && + !hsm_mk_change_apqns_find( + cca_private->mk_change_ops[apka_op_idx].apqns, + cca_private->mk_change_ops[apka_op_idx].num_apqns, + card, domain)) { + TRACE_ERROR("APQN %02X.%04X is used by the CCA token, but it is " + "not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[apka_op_idx].mk_change_op); + OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the CCA token, but " + "it is not part of the active MK change operation '%s'\n", + card, domain, + cca_private->mk_change_ops[apka_op_idx].mk_change_op); + rc |= CKR_DEVICE_ERROR; + } + if (rc != CKR_OK) return CKR_DEVICE_ERROR; return CKR_OK; } -static CK_RV cca_check_mkvps_domains(STDLL_TokData_t *tokdata, - const char *device) +static CK_RV cca_get_current_domain(unsigned short *domain) +{ + const char *val; + unsigned int num; + char fname[290]; + char buf[250]; + CK_RV rc; + + val = getenv(CCA_DEFAULT_DOMAIN_ENVAR); + if (val == NULL) { + /* Get default domain from AP bus */ + sprintf(fname, "%s/ap_domain", SYSFS_BUS_AP); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "%u", &num) != 1) + return CKR_FUNCTION_FAILED; + + *domain = num; + return CKR_OK; + } + + if (strcmp(val, CCA_DOMAIN_ANY) == 0) { + /* DOM-ANY mode, can not determine single domain */ + return CKR_DEVICE_ERROR; + } + + /* domain specified */ + if (sscanf(val, "%u", &num) != 1) + return CKR_FUNCTION_FAILED; + + *domain = num; + return CKR_OK; +} + +static CK_RV cca_get_current_card(STDLL_TokData_t *tokdata, + unsigned short *card) +{ + struct cca_private_data *cca_private = tokdata->private_data; + char serialno[CCA_SERIALNO_LENGTH + 1]; + DIR *d; + struct dirent *de; + regex_t reg_buf; + regmatch_t pmatch[1]; + char fname[290]; + char buf[250]; + unsigned long val; + CK_BBOOL found = FALSE; + CK_RV rc; + + if (cca_private->dev_any) { + /* Get serial number of current adapter */ + rc = cca_get_adapter_serial_number(serialno); + if (rc != CKR_OK) + return rc; + + TRACE_DEVEL("serialno: %s\n", serialno); + } + + if (regcomp(®_buf, REGEX_CARD_PATTERN, REG_EXTENDED) != 0) { + TRACE_ERROR("Failed to compile regular expression '%s'\n", + REGEX_CARD_PATTERN); + return CKR_FUNCTION_FAILED; + } + + /* Find card with that serial number in Sysfs */ + d = opendir(SYSFS_DEVICES_AP); + if (d == NULL) { + TRACE_ERROR("Directory %s is not available\n", SYSFS_DEVICES_AP); + regfree(®_buf); + return CKR_FUNCTION_FAILED; + } + + while ((de = readdir(d)) != NULL) { + if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) { + /* Check for CCA cards only */ + sprintf(fname, "%s/%s/ap_functions", SYSFS_DEVICES_AP, de->d_name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + continue; + if (sscanf(buf, "%lx", &val) != 1) + val = 0x00000000; + if ((val & MASK_COPRO) == 0) + continue; + + sprintf(fname, "%s/%s/serialnr", SYSFS_DEVICES_AP, de->d_name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + continue; + if (strcmp(buf, cca_private->dev_any ? + serialno : cca_private->serialno) != 0) + continue; + + if (sscanf(de->d_name + 4, "%lx", &val) != 1) + continue; + + found = TRUE; + *card = val; + break; + } + } + + closedir(d); + regfree(®_buf); + + return found ? CKR_OK : CKR_DEVICE_ERROR; +} + +/* + * Must NOT hold the CCA adapter lock when called ! + * May obtain the WRITE lock during iteration processing, but returns without + * holding a lock. + * The handler function is called when a single adapter/domain is selected, + * and the WRITE lock may be held, thus the handler function must not obtain + * an CCA adapter lock. + */ +static CK_RV cca_iterate_domains(STDLL_TokData_t *tokdata, const char *device, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private), + void *cb_private) { struct cca_private_data *cca_private = tokdata->private_data; - unsigned char rule_array[256] = { 0, }; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long return_code, reason_code, rule_array_count, device_name_len; unsigned char *device_name; - char tmp_str[20]; + unsigned short card, domain = 0; unsigned int i, num_found = 0; CK_RV rc2, rc = CKR_OK; + if (cca_private->dom_any == FALSE) { + rc = cca_get_current_domain(&domain); + if (rc != CKR_OK) + return rc; + } + + if (cca_private->dev_any == FALSE) { + rc = cca_get_current_card(tokdata, &card); + if (rc != CKR_OK) + return rc; + } + + /* + * Obtain the CCA adapter WRITE lock if DOM-ANY and release it only after + * domain selection has been turned back to default. + */ + if (cca_private->dom_any) { + if (pthread_rwlock_wrlock(&cca_adapter_rwlock) != 0) { + TRACE_DEVEL("CCA adapter WR-Lock failed.\n"); + return CKR_CANT_LOCK; + } + } + for (i = 0; i < cca_private->num_usagedoms; i++) { /* Allocate the adapter based on device or serialno and domain */ if (cca_private->dev_any) { - memcpy(rule_array, "DEVICE ", 8); + memcpy(rule_array, "DEVICE ", CCA_KEYWORD_SIZE); rule_array_count = 1; device_name_len = strlen(device); device_name = (unsigned char *)device; } else { - memcpy(rule_array, "SERIAL ", 8); + memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE); rule_array_count = 1; device_name_len = strlen(cca_private->serialno); device_name = (unsigned char *)cca_private->serialno; } if (cca_private->dom_any) { - sprintf((char *)(rule_array + 8), "DOMN%04u", + sprintf((char *)(rule_array + CCA_KEYWORD_SIZE), "DOMN%04u", cca_private->usage_domains[i]); rule_array_count = 2; - snprintf(tmp_str, sizeof(tmp_str), "%u", - cca_private->usage_domains[i]); - tmp_str[sizeof(tmp_str) - 1] = '\0'; - } else { - strcpy(tmp_str, "DEFAULT"); + domain = cca_private->usage_domains[i]; } dll_CSUACRA(&return_code, &reason_code, @@ -958,21 +1613,34 @@ &device_name_len, device_name); if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACRA failed for %s/%s. return:%ld, reason:%ld\n", - device_name, tmp_str, return_code, reason_code); - return CKR_FUNCTION_FAILED; + TRACE_ERROR("CSUACRA failed for %s domain %x. return:%ld, reason:%ld\n", + device_name, domain, return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + break; + } + + if (cca_private->dev_any) { + rc2 = cca_get_current_card(tokdata, &card); + if (rc2 != CKR_OK) { + if (rc2 == CKR_FUNCTION_FAILED) /* device not avail., ignore */ + rc2 = CKR_OK; + else + rc |= rc2; + goto deallocate; + } } - rc2 = cca_get_and_check_mkvps(tokdata, device, tmp_str); + rc2 = cb(tokdata, device, card, domain, cb_private); if (rc2 == CKR_OK) num_found++; if (rc2 == CKR_FUNCTION_FAILED) /* device not available, ignore */ rc2 = CKR_OK; rc |= rc2; +deallocate: /* Deallocate the adapter */ if (cca_private->dom_any) { - memcpy(rule_array + 8, "DOMN-DEF", 8); + memcpy(rule_array + CCA_KEYWORD_SIZE, "DOMN-DEF", CCA_KEYWORD_SIZE); rule_array_count = 2; } @@ -982,15 +1650,24 @@ &device_name_len, device_name); if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSUACRA failed for %s/%s. return:%ld, reason:%ld\n", - device_name, tmp_str, return_code, reason_code); - return CKR_FUNCTION_FAILED; + TRACE_ERROR("CSUACRD failed for %s domain %x. return:%ld, reason:%ld\n", + device_name, domain, return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + break; } if (cca_private->dom_any == FALSE) break; } + /* Release the CCA adapter WRITE lock now if DOM-ANY */ + if (cca_private->dom_any) { + if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { + TRACE_DEVEL("CCA adapter Unlock failed.\n"); + return CKR_CANT_LOCK; + } + } + if (rc != CKR_OK) return CKR_DEVICE_ERROR; if (num_found == 0) /* none available */ @@ -998,19 +1675,535 @@ return CKR_OK; } -static CK_RV cca_check_mks(STDLL_TokData_t *tokdata) +/* + * Must NOT hold the CCA adapter lock when called ! + * May obtain the WRITE lock during iteration processing, but returns without + * holding a lock. + * The handler function is called when a single adapter/domain is selected, + * and the WRITE lock may be held, thus the handler function must not obtain + * an CCA adapter lock. + */ +static CK_RV cca_iterate_adapters(STDLL_TokData_t *tokdata, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private), + void *cb_private) { struct cca_private_data *cca_private = tokdata->private_data; - unsigned char rule_array[256] = { 0, }; - long return_code, reason_code, rule_array_count, verb_data_length; - unsigned int i, adapter, num_found = 0; + unsigned int adapter, num_found = 0; char device_name[9]; - const char *val; + unsigned short card, domain; + CK_RV rc, rc2; + + if (cca_private->dev_any == FALSE && cca_private->dom_any == FALSE) { + /* CCA default adapter and domain selection */ + rc = cca_get_current_card(tokdata, &card); + if (rc != CKR_OK) + return rc; + + rc = cca_get_current_domain(&domain); + if (rc != CKR_OK) + return rc; + + rc = cb(tokdata, "DEFAULT", card, domain, cb_private); + if (rc != CKR_OK) + return rc; + } else if (cca_private->dev_any == FALSE) { + /* CCA default adapter selection, but domain ANY */ + rc = cca_iterate_domains(tokdata, "DEFAULT", cb, cb_private); + if (rc != CKR_OK) + return rc; + } else { + /* Device ANY and domain ANY or default */ + for (adapter = 1, rc = CKR_OK; adapter <= cca_private->num_adapters; + adapter++) { + sprintf(device_name, "CRP%02u", adapter); + + rc2 = cca_iterate_domains(tokdata, device_name, cb, cb_private); + if (rc2 == CKR_FUNCTION_FAILED) /* adapter not available, ignore */ + rc2 = CKR_OK; + if (rc2 == CKR_OK) + num_found++; + rc |= rc2; + } + if (rc != CKR_OK) + return CKR_DEVICE_ERROR; + if (num_found == 0) + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +struct cca_select_single_data { + struct cca_mk_change_op *mk_change_op; + struct cca_mk_change_op *mk_change_op2; + CK_BBOOL prefer_new_mk; + enum cca_mk_type mk_type; + enum cca_mk_type mk_type2; + char serialno[CCA_SERIALNO_LENGTH + 1]; + unsigned short card; + unsigned short domain; + CK_BBOOL found; + CK_BBOOL preferred_found; +}; + +static CK_BBOOL cca_select_single_apqn_check_mkvp( + STDLL_TokData_t *tokdata, + const struct cca_mk_change_op *mk_change_op, + enum cca_mk_type mk_type, + CK_BBOOL prefer_new_mk, + const unsigned char *cur_sym, + const unsigned char *cur_aes, + const unsigned char *cur_apka) +{ + struct cca_private_data *cca_private = tokdata->private_data; + CK_BBOOL preferred_found = FALSE; + + switch (mk_type) { + case CCA_MK_SYM: + if (prefer_new_mk && mk_change_op->new_sym_mkvp_set && + memcmp(cur_sym, mk_change_op->new_sym_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + if (prefer_new_mk == FALSE && + memcmp(cur_sym, cca_private->expected_sym_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + break; + case CCA_MK_AES: + if (prefer_new_mk && mk_change_op->new_aes_mkvp_set && + memcmp(cur_aes, mk_change_op->new_aes_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + if (prefer_new_mk == FALSE && + memcmp(cur_aes, cca_private->expected_aes_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + break; + case CCA_MK_APKA: + if (prefer_new_mk && mk_change_op->new_apka_mkvp_set && + memcmp(cur_apka, mk_change_op->new_apka_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + if (prefer_new_mk == FALSE && + memcmp(cur_apka, cca_private->expected_apka_mkvp, + CCA_MKVP_LENGTH) == 0) + preferred_found = TRUE; + break; + default: + return FALSE; + } + + return preferred_found; +} + +static CK_RV cca_select_single_apqn_cb(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private) +{ + struct cca_select_single_data *ssd = private; + unsigned char cur_sym[CCA_MKVP_LENGTH]; + unsigned char cur_aes[CCA_MKVP_LENGTH]; + unsigned char cur_apka[CCA_MKVP_LENGTH]; + CK_RV rc; + + if (ssd->preferred_found) + return CKR_OK; + + TRACE_DEVEL("%s Adapter %s (%02X.%04X)\n", __func__, adapter, card, domain); + + rc = cca_get_mkvps(cur_sym, NULL, cur_aes, NULL, cur_apka, NULL); + if (rc != CKR_OK) + return CKR_OK; /* adapter may be offline */ + + ssd->preferred_found = + cca_select_single_apqn_check_mkvp(tokdata, ssd->mk_change_op, + ssd->mk_type, ssd->prefer_new_mk, + cur_sym, cur_aes, cur_apka); + + if (ssd->mk_change_op2 != NULL) + ssd->preferred_found &= + cca_select_single_apqn_check_mkvp(tokdata, ssd->mk_change_op2, + ssd->mk_type2, ssd->prefer_new_mk, + cur_sym, cur_aes, cur_apka); + + rc = cca_get_adapter_serial_number(ssd->serialno); + if (rc != CKR_OK) + return CKR_OK; /* adapter may be offline */ + + ssd->card = card; + ssd->domain = domain; + ssd->found = TRUE; + + return CKR_OK; +} + +static enum cca_mk_type cca_mk_type_from_key_type(enum cca_token_type keytype) +{ + switch (keytype) { + case sec_des_data_key: + return CCA_MK_SYM; + case sec_aes_data_key: + case sec_aes_cipher_key: + case sec_hmac_key: + return CCA_MK_AES; + case sec_rsa_priv_key: + case sec_ecc_priv_key: + return CCA_MK_APKA; + default: + return -1; + } +} + +static struct cca_mk_change_op *cca_mk_change_find_op_by_keytype( + STDLL_TokData_t *tokdata, + enum cca_token_type keytype) +{ + struct cca_private_data *cca_private = tokdata->private_data; + enum cca_mk_type mk_type = cca_mk_type_from_key_type(keytype); + unsigned int idx; + + if (cca_mk_change_find_mkvp_in_ops(tokdata, mk_type, &idx) == NULL) + return NULL; + + return &cca_private->mk_change_ops[idx]; +} + +/* + * Must NOT hold the CCA adapter lock when called ! + * When a single APQN was selected (rc = CKR_OK), it holds the WRITE lock on + * return. The lock must be released by the caller, once selection has been + * turned back to default by using cca_deselect_single_apqn(). + * No lock is held in case of an error. + */ +static CK_RV cca_select_single_apqn(STDLL_TokData_t *tokdata, + struct cca_mk_change_op *mk_change_op, + struct cca_mk_change_op *mk_change_op2, + CK_BBOOL prefer_new_mk, + enum cca_token_type keytype, + enum cca_token_type keytype2, + char *serialno, CK_BBOOL *preferred_selected, + CK_BBOOL wait_for_new_wk) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, device_name_len; + unsigned char *device_name; + struct cca_select_single_data ssd = { 0 }; + int retries = 0; CK_RV rc; - /* Perform basic queries only once */ - if (cca_private->num_adapters != 0) - goto iterate; +retry: + ssd.mk_change_op = mk_change_op; + ssd.mk_change_op2 = mk_change_op2; + ssd.prefer_new_mk = prefer_new_mk; + ssd.mk_type = cca_mk_type_from_key_type(keytype); + ssd.mk_type2 = cca_mk_type_from_key_type(keytype2); + + rc = cca_iterate_adapters(tokdata, cca_select_single_apqn_cb, &ssd); + if (rc != CKR_OK) + return rc; + + if (ssd.found == FALSE) { + TRACE_ERROR("No single CCA APQN found\n"); + return CKR_DEVICE_ERROR; + } + + TRACE_DEVEL("single APQN %02X.%04X (Serialno %s) selected\n", + ssd.card, ssd.domain, ssd.serialno); + TRACE_DEVEL("APQN with preferred MK found: %d\n", ssd.preferred_found); + + if (preferred_selected != NULL) + *preferred_selected = ssd.preferred_found; + + if (prefer_new_mk && wait_for_new_wk && !ssd.preferred_found) { + TRACE_DEVEL("%s no APQN with new MK set found, retry in 1 second\n", + __func__); + + retries++; + if (retries > 3600) /* Retry for max 1 hour */ + return CKR_DEVICE_ERROR; + + sleep(1); + goto retry; + } + + /* + * If neither DEV-ANY, nor DOM-ANY is specified, no need to allocate the + * adapter, it's a single adapter/domain configuration anyway. + */ + if (!cca_private->dev_any && !cca_private->dom_any) + goto done; + + /* Allocate the adapter */ + memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE ); + rule_array_count = 1; + device_name_len = strlen(ssd.serialno); + device_name = (unsigned char *)ssd.serialno; + + if (cca_private->dom_any) { + sprintf((char *)(rule_array + CCA_KEYWORD_SIZE), "DOMN%04u", ssd.domain); + rule_array_count = 2; + + if (pthread_rwlock_wrlock(&cca_adapter_rwlock) != 0) { + TRACE_DEVEL("CCA adapter WR-Lock failed.\n"); + return CKR_CANT_LOCK; + } + } + + dll_CSUACRA(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &device_name_len, device_name); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSUACRA failed. return:%ld, reason:%ld\n", + return_code, reason_code); + + if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { + TRACE_DEVEL("CCA adapter Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_FUNCTION_FAILED; + } + +done: + strncpy(serialno, ssd.serialno, CCA_SERIALNO_LENGTH + 1); + serialno[CCA_SERIALNO_LENGTH] = '\0'; + + return CKR_OK; +} + +/* Does NOT unlock the CCA adapter lock ! */ +static CK_RV cca_deselect_single_apqn(STDLL_TokData_t *tokdata, char *serialno) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, device_name_len; + unsigned char *device_name; + + /* + * If neither DEV-ANY, nor DOM-ANY is specified, no need to deallocate the + * adapter, it's a single adapter/domain configuration anyway. + */ + if (!cca_private->dev_any && !cca_private->dom_any) + return CKR_OK; + + /* Deallocate the adapter */ + memcpy(rule_array, "SERIAL ", CCA_KEYWORD_SIZE); + rule_array_count = 1; + device_name_len = strlen(serialno); + device_name = (unsigned char *)serialno; + + if (cca_private->dom_any) { + memcpy(rule_array + CCA_KEYWORD_SIZE, "DOMN-DEF", CCA_KEYWORD_SIZE); + rule_array_count = 2; + } + + dll_CSUACRD(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &device_name_len, device_name); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSUACRD failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +/* Must NOT hold the CCA adapter lock when called ! */ +static CK_RV cca_reencipher_created_key(STDLL_TokData_t *tokdata, + TEMPLATE* tmpl, CK_BYTE *sec_key, + CK_ULONG sec_key_len, CK_BBOOL new_mk, + enum cca_token_type keytype) +{ + struct cca_private_data *cca_private = tokdata->private_data; + struct cca_mk_change_op *mk_change_op; + char serialno[CCA_SERIALNO_LENGTH + 1]; + CK_BBOOL new_selected = FALSE; + CK_BYTE reenc_sec_key[CCA_KEY_TOKEN_SIZE] = { 0 }; + CK_RV rc, rc2; + CK_ULONG retries = 0; + + if (sec_key_len > sizeof(reenc_sec_key)) { + TRACE_ERROR("%s sec_key_len too large: %lu\n", __func__, sec_key_len); + return CKR_ARGUMENTS_BAD; + } + + mk_change_op = cca_mk_change_find_op_by_keytype(tokdata, keytype); + if (mk_change_op == NULL) + return CKR_OK; + + if (new_mk) { + memcpy(reenc_sec_key, sec_key, sec_key_len); + goto add_attr; + } + + /* Try to re-encipher to new MK */ + rc = cca_reencipher_sec_key(tokdata, mk_change_op, sec_key, reenc_sec_key, + sec_key_len, FALSE); + if (rc == CKR_OK) + goto add_attr; + + TRACE_ERROR("%s cca_reencipher_sec_key failed: 0x%lx\n", __func__, rc); + if (rc != CKR_DEVICE_ERROR) + return rc; + +retry: + /* Try to select a APQN with new MK set/activated */ + rc = cca_select_single_apqn(tokdata, mk_change_op, NULL, TRUE, keytype, 0, + serialno, &new_selected, FALSE); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_select_single_apqn failed: 0x%lx\n", __func__, rc); + return rc; + } + + TRACE_DEVEL("%s new_selected: %d\n", __func__, new_selected); + + /* + * Retry re-enciphering, from-OLD if APQN with new MK was selected, + * otherwise try to-NEW again. + */ + rc = cca_reencipher_sec_key(tokdata, mk_change_op, sec_key, reenc_sec_key, + sec_key_len, new_selected); + if (rc != CKR_OK) + TRACE_ERROR("%s cca_reencipher_sec_key (2) failed: 0x%lx\n", __func__, + rc); + + rc2 = cca_deselect_single_apqn(tokdata, serialno); + + /* cca_select_single_apqn() got the WRITE lock, unlock it now */ + if (cca_private->dom_any) { + if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { + TRACE_ERROR("CCA adapter Unlock failed.\n"); + return CKR_CANT_LOCK; + } + } + + if (rc2 != CKR_OK) { + TRACE_ERROR("%s cca_deselect_single_apqn failed: 0x%lx\n", __func__, + rc2); + return rc2; + } + + if (rc == CKR_OK) + goto add_attr; + + /* + * If re-enciphering to-New has failed because the selected single APQN + * with old MK set has just got the new MK set, re-select a single APQN + * (preferably with new MK set) and retry. We should then get an APQN with + * the new MK set and then perform a re-encipher from-OLD. + */ + if (new_selected == FALSE && rc == CKR_DEVICE_ERROR && retries < 2) { + retries++; + goto retry; + } + + return rc; + +add_attr: + rc = build_update_attribute(tmpl, CKA_IBM_OPAQUE_REENC, + reenc_sec_key, sec_key_len); + if (rc != CKR_OK) { + TRACE_DEVEL("build_update_attribute(CKA_IBM_OPAQUE_REENC) failed\n"); + return rc; + } + + return CKR_OK; +} + +/* Called with CCA adapter READ lock held (if DOM-ANY) */ +static CK_BBOOL cca_check_blob_select_single_apqn(STDLL_TokData_t *tokdata, + const CK_BYTE *sec_key1, + CK_ULONG sec_key1_len, + const CK_BYTE *sec_key2, + CK_ULONG sec_key2_len, + char *serialno) +{ + struct cca_private_data *cca_private = tokdata->private_data; + enum cca_token_type keytype1, keytype2 = -1; + unsigned int keybitsize1, keybitsize2; + const CK_BYTE *mkvp1, *mkvp2; + CK_BBOOL new_mk1 = FALSE, new_mk2 = FALSE, new_selected = FALSE; + struct cca_mk_change_op *mk_change_op1 = NULL, *mk_change_op2 = NULL; + + if (analyse_cca_key_token(sec_key1, sec_key1_len, &keytype1, &keybitsize1, + &mkvp1) == FALSE) + return FALSE; + + if (check_expected_mkvp(tokdata, keytype1, mkvp1, &new_mk1) != CKR_OK) + return FALSE; + + TRACE_DEVEL("%s new_mk1: %d\n", __func__, new_mk1); + + mk_change_op1 = cca_mk_change_find_op_by_keytype(tokdata, keytype1); + + if (sec_key2 != NULL) { + if (analyse_cca_key_token(sec_key2, sec_key2_len, &keytype2, &keybitsize2, + &mkvp2) == FALSE) + return FALSE; + + if (check_expected_mkvp(tokdata, keytype1, mkvp1, &new_mk1) != CKR_OK) + return FALSE; + + TRACE_DEVEL("%s new_mk1: %d\n", __func__, new_mk1); + + mk_change_op2 = cca_mk_change_find_op_by_keytype(tokdata, keytype2); + } + + if (new_mk1 == FALSE && new_mk2 == FALSE) + return FALSE; + + if (mk_change_op1 == NULL && mk_change_op2 == NULL) + return FALSE; + + /* + * Unlock CCA adapter lock (if DOM-ANY), cca_select_single_apqn() will + * get WRITE lock. + */ + if (cca_private->dom_any) { + if (pthread_rwlock_unlock(&cca_adapter_rwlock) != 0) { + TRACE_ERROR("CCA adapter Unlock failed.\n"); + return FALSE; + } + } + + /* Select a single APQN with new MK(s) set, wait if required */ + TRACE_DEVEL("%s select single APQN with new MK set, wait if needed\n", + __func__); + if (cca_select_single_apqn(tokdata, mk_change_op1, mk_change_op2, TRUE, + keytype1, keytype2, serialno, + &new_selected, TRUE) != CKR_OK) + new_selected = FALSE; + + /* Need to get RD-lock again in case no new APQN was selected */ + if (!new_selected && cca_private->dom_any) { + if (pthread_rwlock_rdlock(&cca_adapter_rwlock) != 0) { + TRACE_ERROR("CCA adapter RD-Lock failed.\n"); + return FALSE; + } + } + + return new_selected; +} + +static CK_RV cca_get_adapter_domain_selection_infos(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, verb_data_length; + unsigned int i; + const char *val; /* Check if adapter and/or domain auto-selection is used */ val = getenv(CCA_DEFAULT_ADAPTER_ENVAR); @@ -1024,7 +2217,7 @@ TRACE_DEVEL("dom_any: %d\n", cca_private->dom_any); /* Get number of adapters, current adapter serial number */ - memcpy(rule_array, "STATCRD2", 8); + memcpy(rule_array, "STATCRD2", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, @@ -1038,7 +2231,7 @@ return CKR_FUNCTION_FAILED; } - rule_array[8] = '\0'; + rule_array[CCA_KEYWORD_SIZE] = '\0'; if (sscanf((char *)rule_array, "%u", &cca_private->num_adapters) != 1) { TRACE_ERROR("Failed to parse STATCRD2 output: number of adapters: %s\n", rule_array); @@ -1046,12 +2239,14 @@ } TRACE_DEVEL("num_adapters: %u\n", cca_private->num_adapters); - memcpy(cca_private->serialno, &rule_array[14 * 8], 8); - cca_private->serialno[8] = '\0'; + memcpy(cca_private->serialno, + &rule_array[CCA_STATCRD2_SERIAL_NUMBER_OFFSET], + CCA_SERIALNO_LENGTH); + cca_private->serialno[CCA_SERIALNO_LENGTH] = '\0'; TRACE_DEVEL("serialno: %s\n", cca_private->serialno); /* Get number of domains */ - memcpy(rule_array, "DOM-NUMS", 8); + memcpy(rule_array, "DOM-NUMS", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(cca_private->num_domains); dll_CSUACFQ(&return_code, &reason_code, @@ -1067,7 +2262,7 @@ TRACE_DEVEL("num_domains: %u\n", cca_private->num_domains); /* Get usage domain mask */ - memcpy(rule_array, "DOM-USAG", 8); + memcpy(rule_array, "DOM-USAG", CCA_KEYWORD_SIZE); rule_array_count = 1; verb_data_length = sizeof(cca_private->usage_domains); dll_CSUACFQ(&return_code, &reason_code, @@ -1089,49 +2284,69 @@ cca_private->num_usagedoms = i; TRACE_DEVEL("num_usagedoms: %u\n", cca_private->num_usagedoms); -iterate: - if (cca_private->dev_any == FALSE && cca_private->dom_any == FALSE) { - /* CCA default adapter and domain selection */ - rc = cca_get_and_check_mkvps(tokdata, "DEFAULT", "DEFAULT"); - if (rc != CKR_OK) - return rc; - } else if (cca_private->dev_any == FALSE) { - /* CCA default adapter selection, but domain ANY */ - rc = cca_check_mkvps_domains(tokdata, "DEFAULT"); - if (rc != CKR_OK) - return rc; - } else { - /* Device ANY and domain ANY or default */ - for (adapter = 1, rc = CKR_OK; adapter <= cca_private->num_adapters; - adapter++) { - sprintf(device_name, "CRP%02u", adapter); + return CKR_OK; +} - rc |= cca_check_mkvps_domains(tokdata, device_name); - if (rc == CKR_FUNCTION_FAILED) /* adapter not available, ignore */ - rc = CKR_OK; - if (rc == CKR_OK) - num_found++; - } - if (rc != CKR_OK) - return CKR_DEVICE_ERROR; - if (num_found == 0) - return CKR_FUNCTION_FAILED; - } +static CK_RV cca_check_mks(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned char *new_mkvp; + CK_RV rc; + + rc = cca_iterate_adapters(tokdata, cca_get_and_check_mkvps, NULL); + if (rc != CKR_OK) + return rc; - TRACE_DEBUG("Expected master key verification patters (queried):\n"); + TRACE_DEBUG("Expected master key verification patterns (queried):\n"); if (cca_private->expected_sym_mkvp_set == FALSE) { + /* + * If a MK change operation is active, and all APQNs have the new SYM MK + * already, use the new SYM MKVP as the queried one. + */ + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, NULL); + if (new_mkvp && + memcmp(cca_private->expected_sym_mkvp, cca_zero_mkvp, + CCA_MKVP_LENGTH) == 0) { + TRACE_DEBUG("%s All APQNs already have the new SYM MK\n",__func__); + memcpy(cca_private->expected_sym_mkvp, new_mkvp, CCA_MKVP_LENGTH); + } + TRACE_DEBUG_DUMP("SYM MKVP: ", cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("SYM MKVP: specified in config\n"); } if (cca_private->expected_aes_mkvp_set == FALSE) { + /* + * If a MK change operation is active, and all APQNs have the new AES MK + * already, use the new AES MKVP as the queried one. + */ + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, NULL); + if (new_mkvp && + memcmp(cca_private->expected_aes_mkvp, cca_zero_mkvp, + CCA_MKVP_LENGTH) == 0) { + TRACE_DEBUG("%s All APQNs already have the new AES MK\n",__func__); + memcpy(cca_private->expected_aes_mkvp, new_mkvp, CCA_MKVP_LENGTH); + } + TRACE_DEBUG_DUMP("AES MKVP: ", cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("AES MKVP: specified in config\n"); } if (cca_private->expected_apka_mkvp_set == FALSE) { + /* + * If a MK change operation is active, and all APQNs have the new APKA + * MK already, use the new APKA MKVP as the queried one. + */ + new_mkvp = cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, NULL); + if (new_mkvp && + memcmp(cca_private->expected_apka_mkvp, cca_zero_mkvp, + CCA_MKVP_LENGTH) == 0) { + TRACE_DEBUG("%s All APQNs already have the new APKA MK\n",__func__); + memcpy(cca_private->expected_apka_mkvp, new_mkvp, CCA_MKVP_LENGTH); + } + TRACE_DEBUG_DUMP("APKA MKVP: ", cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH); } else { @@ -1141,7 +2356,7 @@ return CKR_OK; } -CK_RV cca_parse_hex(const char *str, unsigned char *bin, size_t size) +static CK_RV cca_parse_hex(const char *str, unsigned char *bin, size_t size) { unsigned int i, val; @@ -1159,10 +2374,36 @@ return CKR_OK; } -CK_RV cca_config_parse_exp_mkvps(STDLL_TokData_t *tokdata, char *fname, - struct ConfigStructNode *exp_mkvp_node) +static CK_RV cca_config_set_pkey_mode(struct cca_private_data *cca_data, + const char *fname, const char *strval) +{ + if (strcmp(strval, "DISABLED") == 0) + cca_data->pkey_mode = PKEY_MODE_DISABLED; +#ifndef NO_PKEY + else if (strcmp(strval, "DEFAULT") == 0) + cca_data->pkey_mode = PKEY_MODE_DEFAULT; + else if (strcmp(strval, "ENABLED") == 0) + cca_data->pkey_mode = PKEY_MODE_ENABLED; +#endif + else { + TRACE_ERROR("%s unsupported PKEY mode : '%s'\n", __func__, strval); + OCK_SYSLOG(LOG_ERR,"%s: Error: unsupported PKEY mode '%s' " + "in config file '%s'\n", __func__, strval, fname); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +static CK_RV cca_config_parse_exp_mkvps(char *fname, + struct ConfigStructNode *exp_mkvp_node, + unsigned char *expected_sym_mkvp, + CK_BBOOL *expected_sym_mkvp_set, + unsigned char *expected_aes_mkvp, + CK_BBOOL *expected_aes_mkvp_set, + unsigned char *expected_apka_mkvp, + CK_BBOOL *expected_apka_mkvp_set) { - struct cca_private_data *cca_private = tokdata->private_data; struct ConfigBaseNode *c; char *str; CK_RV rc = CKR_OK; @@ -1175,8 +2416,7 @@ if (strcasecmp(c->key, CCA_CFG_SYM_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { - rc = cca_parse_hex(str, cca_private->expected_sym_mkvp, - CCA_MKVP_LENGTH); + rc = cca_parse_hex(str, expected_sym_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, @@ -1187,15 +2427,14 @@ break; } - cca_private->expected_sym_mkvp_set = TRUE; + *expected_sym_mkvp_set = TRUE; continue; } if (strcasecmp(c->key, CCA_CFG_AES_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { - rc = cca_parse_hex(str, cca_private->expected_aes_mkvp, - CCA_MKVP_LENGTH); + rc = cca_parse_hex(str, expected_aes_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, @@ -1206,15 +2445,14 @@ break; } - cca_private->expected_aes_mkvp_set = TRUE; + *expected_aes_mkvp_set = TRUE; continue; } if (strcasecmp(c->key, CCA_CFG_APKA_MKVP) == 0 && (str = confignode_getstr(c)) != NULL) { - rc = cca_parse_hex(str, cca_private->expected_apka_mkvp, - CCA_MKVP_LENGTH); + rc = cca_parse_hex(str, expected_apka_mkvp, CCA_MKVP_LENGTH); if (rc != CKR_OK) { OCK_SYSLOG(LOG_ERR, "Error parsing config file '%s': invalid " "hex value '%s' at line %d\n", fname, @@ -1225,7 +2463,7 @@ break; } - cca_private->expected_apka_mkvp_set = TRUE; + *expected_apka_mkvp_set = TRUE; continue; } @@ -1237,18 +2475,18 @@ } TRACE_DEBUG("Expected master key verification patterns\n"); - if (cca_private->expected_sym_mkvp_set == TRUE) { - TRACE_DEBUG_DUMP("SYM MKVP: ", cca_private->expected_sym_mkvp, CCA_MKVP_LENGTH); + if (*expected_sym_mkvp_set == TRUE) { + TRACE_DEBUG_DUMP("SYM MKVP: ", expected_sym_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("SYM MKVP: not specified\n"); } - if (cca_private->expected_aes_mkvp_set == TRUE) { - TRACE_DEBUG_DUMP("AES MKVP: ", cca_private->expected_aes_mkvp, CCA_MKVP_LENGTH); + if (*expected_aes_mkvp_set == TRUE) { + TRACE_DEBUG_DUMP("AES MKVP: ", expected_aes_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("AES MKVP: not specified\n"); } - if (cca_private->expected_apka_mkvp_set == TRUE) { - TRACE_DEBUG_DUMP("APKA MKVP: ", cca_private->expected_apka_mkvp, CCA_MKVP_LENGTH); + if (*expected_apka_mkvp_set == TRUE) { + TRACE_DEBUG_DUMP("APKA MKVP: ", expected_apka_mkvp, CCA_MKVP_LENGTH); } else { TRACE_DEBUG("APKA MKVP: not specified\n"); } @@ -1266,12 +2504,14 @@ CK_RV cca_load_config_file(STDLL_TokData_t *tokdata, char *conf_name) { + struct cca_private_data *cca_private = tokdata->private_data; char fname[PATH_MAX]; FILE *file; struct ConfigBaseNode *c, *config = NULL; struct ConfigStructNode *struct_node; CK_RV rc = CKR_OK; int ret, i; + const char *strval; if (conf_name == NULL || strlen(conf_name) == 0) return CKR_OK; @@ -1300,6 +2540,17 @@ goto done; } + strncpy(cca_private->token_config_filename, fname, + sizeof(cca_private->token_config_filename)); + cca_private->token_config_filename[ + sizeof(cca_private->token_config_filename) - 1] = '\0'; + +#ifndef NO_PKEY + cca_private->pkey_mode = PKEY_MODE_DEFAULT; +#else + cca_private->pkey_mode = PKEY_MODE_DISABLED; +#endif + confignode_foreach(c, config, i) { TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", c->key, c->type, c->line); @@ -1310,10 +2561,28 @@ continue; } + if (confignode_hastype(c, CT_BAREVAL)) { + /* New style (key = value) tokens */ + strval = confignode_getstr(c); + + if (strcmp(c->key, "PKEY_MODE") == 0) { + rc = cca_config_set_pkey_mode(cca_private, fname, strval); + if (rc != CKR_OK) + break; + continue; + } + } + if (confignode_hastype(c, CT_STRUCT)) { struct_node = confignode_to_struct(c); if (strcasecmp(struct_node->base.key, CCA_CFG_EXPECTED_MKVPS) == 0) { - rc = cca_config_parse_exp_mkvps(tokdata, fname, struct_node); + rc = cca_config_parse_exp_mkvps(fname, struct_node, + cca_private->expected_sym_mkvp, + &cca_private->expected_sym_mkvp_set, + cca_private->expected_aes_mkvp, + &cca_private->expected_aes_mkvp_set, + cca_private->expected_apka_mkvp, + &cca_private->expected_apka_mkvp_set); if (rc != CKR_OK) break; continue; @@ -1342,6 +2611,959 @@ return rc; } +#ifndef NO_PKEY +static CK_RV ccatok_pkey_add_attr_to_rule_array(CK_ATTRIBUTE_TYPE type, + CK_BYTE *rule_array, + CK_ULONG rule_array_size, + CK_ULONG *rule_array_count) +{ + if ((*rule_array_count + 1) * CCA_KEYWORD_SIZE > rule_array_size) + return CKR_BUFFER_TOO_SMALL; + + switch (type) { + case CKA_IBM_PROTKEY_EXTRACTABLE: + memcpy(rule_array + (*rule_array_count * CCA_KEYWORD_SIZE), + "XPRTCPAC", CCA_KEYWORD_SIZE); + (*rule_array_count)++; + break; + default: + break; + } + + return CKR_OK; +} + +/* + * This routine checks if a given attr is applicable to pass it to the CCA + * host lib via its corresponding rule_array keyword. + */ +static CK_BBOOL ccatok_pkey_attr_applicable(STDLL_TokData_t *tokdata, + CK_ATTRIBUTE *attr, CK_KEY_TYPE ktype, + int curve_type, int curve_bitlen) +{ + struct cca_private_data *cca_data = tokdata->private_data; + + /* + * On older cards, CKA_IBM_PROTKEY_EXTRACTABLE might cause errors, so + * filter it out when the PKEY option is not supported on this system. + */ + if (attr->type == CKA_IBM_PROTKEY_EXTRACTABLE && + cca_data->pkey_wrap_supported == 0) + return CK_FALSE; + + switch (ktype) { + case CKK_AES: + /* + * The CCA token currently only supports AES internal fixed-length + * key tokens. There are no attributes that would need a rule_array + * keyword. Also, they are CPACF exportable anyway, so even when the + * template contains CKA_IBM_PROTKEY_EXTRACTABLE=true, there is no + * need to add XPRTCPAC to the rule array. + */ + break; + case CKK_EC: + /* + * There is currently only one attribute with a corresponding rule + * array keyword. + */ + switch (attr->type) { + case CKA_IBM_PROTKEY_EXTRACTABLE: + if ((*(CK_BBOOL *)attr->pValue) == CK_TRUE) { + /* + * From CCA 7.3 Application Programmer's Guide, table 282: + * Allow export to CPACF protected key format. Valid for ECC + * curves P256, P384, P521, Ed25519, and Ed448. + */ + switch (curve_type) { + case PRIME_CURVE: + if (curve_bitlen == 256 || curve_bitlen == 384 || + curve_bitlen == 521) + return CK_TRUE; + break; + case EDWARDS_CURVE: + if (curve_bitlen == 255 || curve_bitlen == 448) + return CK_TRUE; + break; + default: + break; + } + } + } + break; + default: + /* + * Any other key types (RSA, ...) are currently not handled. No + * additional rule array keywords here. + */ + break; + } + + return CK_FALSE; +} + +/* + * Add protected key related attributes to be passed to CCA via the rule_array. + */ +static CK_RV ccatok_pkey_add_attrs(STDLL_TokData_t * tokdata, TEMPLATE *template, + CK_KEY_TYPE ktype, int curve_type, int curve_bitlen, + CK_BYTE *rule_array, CK_ULONG rule_array_size, + CK_ULONG *rule_array_count) +{ + DL_NODE *node; + CK_ATTRIBUTE_PTR attr; + CK_RV ret; + + node = template->attribute_list; + while (node != NULL) { + attr = node->data; + + if (ccatok_pkey_attr_applicable(tokdata, attr, ktype, + curve_type, curve_bitlen)) { + ret = ccatok_pkey_add_attr_to_rule_array(attr->type, rule_array, + rule_array_size, rule_array_count); + if (ret != CKR_OK) + return ret; + } + + node = node->next; + } + + return CKR_OK; +} + +#define MAXECPROTKEYSIZE 112 /* max 80 + 32 bytes for p521 */ +#define PKEYDEVICE "/dev/pkey" + +typedef struct { + STDLL_TokData_t *tokdata; + CK_BBOOL wrap_was_successful; + CK_RV wrap_error; + CK_VOID_PTR secure_key; + CK_ULONG secure_key_len; + CK_BYTE *pkey_buf; + size_t *pkey_buflen_p; + enum cca_token_type keytype; +} pkey_wrap_handler_data_t; + +/* + * On older kernels, the PKEY_KBLOB2PROTK3 ioctl is not yet available, which is + * no problem at runtime: protected key support is then just not available. + * But we want that the CCA token still builds on such systems, so let's copy + * the missing #defines and structs from kernel asm/pkey.h + */ +#ifndef PKEY_KBLOB2PROTK3 + +struct pkey_kblob2pkey3 { + __u8 *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */ + __u32 apqn_entries; /* in: # of apqn target list entries */ + __u32 pkeytype; /* out: prot key type (enum pkey_key_type) */ + __u32 pkeylen; /* in/out: size of pkey buffer/actual len of pkey */ + __u8 *pkey; /* in: pkey blob buffer space ptr */ +}; +#define PKEY_KBLOB2PROTK3 _IOWR(PKEY_IOCTL_MAGIC, 0x1D, struct pkey_kblob2pkey3) + +#define PKEY_TYPE_CCA_ECC (__u32)0x1f + +#endif /* PKEY_KBLOB2PROTK3 */ + +static enum pkey_key_type ccatok_pkey_type_from_keytype(enum cca_token_type keytype) +{ + switch (keytype) { + case sec_aes_data_key: + return PKEY_TYPE_CCA_DATA; + case sec_aes_cipher_key: + return PKEY_TYPE_CCA_CIPHER; + case sec_ecc_priv_key: + return PKEY_TYPE_CCA_ECC; + default: + break; + } + + return 0; +} + +/* + * Callback function used by ccatok_pkey_skey2pkey() for creating a protected + * key using (card,domain) via the PKEY_KBLOB2PROTK3 ioctl. + * Note that the PKEY_KBLOB2PROTK3 ioctl requires kernel 5.10 or later. + * On older kernels this function fails when called at token init, trying to + * determine the wkvp from the firmware wrapping key. In this case, protected + * key support for CCA is just not available (indicated in cca_private_data). + */ +static CK_RV ccatok_pkey_sec2prot(STDLL_TokData_t *tokdata, const char *adapter, + unsigned short card, unsigned short domain, + void *handler_data) +{ + pkey_wrap_handler_data_t *data = (pkey_wrap_handler_data_t *) handler_data; + struct cca_private_data *cca_data = data->tokdata->private_data; + struct pkey_kblob2pkey3 io; + struct pkey_apqn apqn; + int rc; + + UNUSED(tokdata); + UNUSED(adapter); + + if (data->wrap_was_successful) + goto done; + + apqn.card = card; + apqn.domain = domain; + + memset(&io, 0, sizeof(io)); + io.key = data->secure_key; + io.keylen = data->secure_key_len; + io.apqns = &apqn; + io.apqn_entries = 1; + io.pkeytype = ccatok_pkey_type_from_keytype(data->keytype); + io.pkeylen = *(data->pkey_buflen_p); + io.pkey = data->pkey_buf; + + rc = ioctl(cca_data->pkeyfd, PKEY_KBLOB2PROTK3, &io); + if (rc != 0) { + data->wrap_error = CKR_FUNCTION_FAILED; + data->wrap_was_successful = CK_FALSE; + goto done; + } + + data->wrap_error = CKR_OK; + data->wrap_was_successful = CK_TRUE; + *(data->pkey_buflen_p) = io.pkeylen; + +done: + + /* + * Always return ok, calling function loops over this handler until + * data->wrap_was_successful = true, or no more APQN left. + * Pass back error in handler data anyway. + */ + return CKR_OK; +} + +/* + * Creates a protected key from the given secure key object by iterating + * over all APQNs. + */ +static CK_RV ccatok_pkey_skey2pkey(STDLL_TokData_t *tokdata, + CK_ATTRIBUTE *skey_attr, + CK_ATTRIBUTE **pkey_attr) +{ + CK_ATTRIBUTE *tmp_attr = NULL; + CK_BYTE pkey_buf[MAXECPROTKEYSIZE]; + CK_ULONG pkey_buflen = sizeof(pkey_buf); + pkey_wrap_handler_data_t pkey_wrap_handler_data; + CK_RV ret; + enum cca_token_type key_type; + unsigned int token_keybitsize; + const CK_BYTE *mkvp; + CK_BBOOL new_mk; + unsigned int num_retries = 0; + + /* Determine CCA key type */ + if (analyse_cca_key_token(skey_attr->pValue, skey_attr->ulValueLen, + &key_type, &token_keybitsize, &mkvp) != TRUE) { + TRACE_ERROR("Invalid/unknown cca token, cannot get key type\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + if (check_expected_mkvp(tokdata, key_type, mkvp, &new_mk) != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); + ret = CKR_DEVICE_ERROR; + goto done; + } + + /* Create the protected key by iterating over all APQNs */ + memset(&pkey_wrap_handler_data, 0, sizeof(pkey_wrap_handler_data_t)); + pkey_wrap_handler_data.tokdata = tokdata; + pkey_wrap_handler_data.secure_key = skey_attr->pValue; + pkey_wrap_handler_data.secure_key_len = skey_attr->ulValueLen; + pkey_wrap_handler_data.pkey_buf = (CK_BYTE *)&pkey_buf; + pkey_wrap_handler_data.pkey_buflen_p = &pkey_buflen; + pkey_wrap_handler_data.keytype = key_type; + + while (num_retries < 3600) { + ret = cca_iterate_adapters(tokdata, ccatok_pkey_sec2prot, + &pkey_wrap_handler_data); + if (ret == CKR_OK && pkey_wrap_handler_data.wrap_was_successful) + break; + + /* Retry the op if key encrypted with new MK and an MK change is active */ + if (new_mk == CK_TRUE && + cca_mk_change_find_op_by_keytype(tokdata, key_type) != NULL) { + sleep(1); + num_retries++; + } + } + + if (ret != CKR_OK || !pkey_wrap_handler_data.wrap_was_successful) { + TRACE_ERROR("cca_iterate_adapters failed or no APQN could create the pkey.\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Build new attribute for protected key */ + ret = build_attribute(CKA_IBM_OPAQUE_PKEY, pkey_buf, pkey_buflen, &tmp_attr); + if (ret != CKR_OK) { + TRACE_ERROR("build_attribute failed with rc=0x%lx\n", ret); + ret = CKR_FUNCTION_FAILED;; + goto done; + } + + ret = CKR_OK; + +done: + + *pkey_attr = tmp_attr; + + return ret; +} + +/* + * Save the current firmware wrapping key verification pattern in the tokdata: + * create a dummy test key, transform it into a protected key, and store the wk + * verification pattern in the tokdata. + */ +static CK_RV ccatok_pkey_get_firmware_wkvp(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_data = tokdata->private_data; + CK_ATTRIBUTE *pkey_attr = NULL, *sec_attr = NULL; + CK_RV ret; + long return_code = 0, reason_code = 0; + long exit_data_len = 0, clear_key_bit_length = 0; + unsigned char exit_data[4]; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; + long rule_array_count; + unsigned char *clear_key_value = NULL; + long key_name_length = 0; + unsigned char key_name[CCA_KEY_ID_SIZE] = { 0, }; + long user_data_length = 0; + unsigned char user_data[64] = { 0, }; + long token_data_length = 0; + long verb_data_length = 0; + unsigned char verb_data[64] = { 0, }; + unsigned char the_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + long the_key_token_length = sizeof(the_key_token); + unsigned char key_type_1[8] = { ' ', }; + unsigned char key_type_2[8] = { ' ', }; + long key_name_1_length = 0; + long key_name_2_length = 0; + long user_data_1_length = 0; + long user_data_2_length = 0; + long kek_identifier_1_length = 0; + long kek_identifier_2_length = 0; + long the_2nd_key_token_length = 0; + unsigned int min_card_version; + + /* Check CCA host library version: XPRTCPAC requires min 7.0.0 */ + if (cca_data->cca_lib_version.ver < 7) { + TRACE_WARNING("CCA host lib is %d.%d.%d, but pkey support requires min 7.0.0\n", + cca_data->cca_lib_version.ver,cca_data->cca_lib_version.rel, + cca_data->cca_lib_version.mod); + OCK_SYSLOG(LOG_WARNING, "CCA host lib is %d.%d.%d, but pkey support requires min 7.0.0\n", + cca_data->cca_lib_version.ver,cca_data->cca_lib_version.rel, + cca_data->cca_lib_version.mod); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Read min card version from CCA private data. Needs a read lock. */ + if (pthread_rwlock_rdlock(&cca_data->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); + return CKR_CANT_LOCK; + } + min_card_version = cca_data->min_card_version.ver; + if (pthread_rwlock_unlock(&cca_data->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + /* Check minimum card version, XPRTCPAC requires min CEX7C */ + if (min_card_version < 7) { + TRACE_WARNING("Minimum card version must be CEX7C, but we only have %d.%d.%d\n", + cca_data->min_card_version.ver,cca_data->min_card_version.rel, + cca_data->min_card_version.mod); + OCK_SYSLOG(LOG_WARNING, "Minimum card version must be CEX7C, but we only have %d.%d.%d\n", + cca_data->min_card_version.ver,cca_data->min_card_version.rel, + cca_data->min_card_version.mod); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Build CPACF-exportable AES internal cipher key token */ + rule_array_count = 5; + memcpy(rule_array, "INTERNAL" "NO-KEY " "AES " "CIPHER " "XPRTCPAC", + rule_array_count * CCA_KEYWORD_SIZE); + + dll_CSNBKTB2(&return_code, &reason_code, &exit_data_len, exit_data, + &rule_array_count, rule_array, &clear_key_bit_length, + clear_key_value, &key_name_length, key_name, &user_data_length, + user_data, &token_data_length, NULL, &verb_data_length, + verb_data, &the_key_token_length, the_key_token); + + if (return_code != 0) { + TRACE_ERROR("CSNBTKB2 (TOKEN BUILD2) failed with %ld/%ld\n", + return_code, reason_code); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Generate the key */ + memset(rule_array, 0, sizeof(rule_array)); + memcpy(rule_array, "AES " "OP ", 2 * CCA_KEYWORD_SIZE); + rule_array_count = 2; + clear_key_bit_length = 256; + memcpy(key_type_1, "TOKEN ", CCA_KEYWORD_SIZE); + the_key_token_length = sizeof(the_key_token); + + dll_CSNBKGN2(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, &clear_key_bit_length, key_type_1, key_type_2, + &key_name_1_length, NULL, &key_name_2_length, NULL, + &user_data_1_length, NULL, &user_data_2_length, NULL, + &kek_identifier_1_length, NULL, &kek_identifier_2_length, + NULL, &the_key_token_length, the_key_token, + &the_2nd_key_token_length, NULL); + + if (return_code != 0) { + TRACE_ERROR("CSNBKGN2(KEYGEN2) failed with %ld/%ld\n", + return_code, reason_code); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Build attribute for secure key token */ + ret = build_attribute(CKA_IBM_OPAQUE, (CK_BYTE *)&the_key_token, + the_key_token_length, &sec_attr); + if (ret != CKR_OK) { + TRACE_ERROR("build_attribute CKA_IBM_OPAQUE failed with ret=0x%lx\n", ret); + goto done; + } + + /* + * Create a protected key from this token to obtain the firmware wkvp. When + * this function returns ok, we have a 64 byte pkey value: 32 bytes + * encrypted key + 32 bytes vp. + */ + ret = ccatok_pkey_skey2pkey(tokdata, sec_attr, &pkey_attr); + if (ret != CKR_OK) { + TRACE_ERROR("ccatok_pkey_skey2pkey failed with ret=0x%lx\n", ret); + goto done; + } + + /* Save WKVP in token data */ + memcpy(&cca_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + AES_KEY_SIZE_256, + PKEY_MK_VP_LENGTH); + + __sync_or_and_fetch(&cca_data->pkey_wrap_supported, 1); + +done: + + if (sec_attr) + free(sec_attr); + if (pkey_attr) + free(pkey_attr); + + return ret; +} + +/* + * Return true if PKEY_MODE DISABLED is set in the token specific + * config file, false otherwise. + */ +static CK_BBOOL ccatok_pkey_option_disabled(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_data = tokdata->private_data; + + if (cca_data->pkey_mode == PKEY_MODE_DISABLED) + return CK_TRUE; + + return CK_FALSE; +} + +/** + * Return true, if the given key obj has a valid protected key, i.e. its + * verification pattern matches the one of the current master key. + */ +static CK_BBOOL ccatok_pkey_is_valid(STDLL_TokData_t *tokdata, OBJECT *key_obj) +{ + struct cca_private_data *cca_data = tokdata->private_data; + CK_ATTRIBUTE *pkey_attr = NULL; + int vp_offset; + + if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE_PKEY, + &pkey_attr) == CKR_OK) { + if (pkey_attr->ulValueLen >= AES_KEY_SIZE_128 + PKEY_MK_VP_LENGTH) { + vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; + if (memcmp((CK_BYTE *)pkey_attr->pValue + vp_offset, + &cca_data->pkey_mk_vp, + PKEY_MK_VP_LENGTH) == 0) { + return CK_TRUE; + } + } + } + + return CK_FALSE; +} + +/** + * Create a new protected key for the given key obj and update attribute + * CKA_IBM_OPAQUE with the new pkey. + */ +static CK_RV ccatok_pkey_update(STDLL_TokData_t *tokdata, OBJECT *key_obj) +{ + struct cca_private_data *cca_data = tokdata->private_data; + CK_ATTRIBUTE *skey_attr = NULL; + CK_ATTRIBUTE *pkey_attr = NULL; + CK_RV ret; + int vp_offset; + + /* Get secure key from obj */ + if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, + &skey_attr) != CKR_OK) { + TRACE_ERROR("This key has no blob: should not occur!\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Transform the secure key into a protected key */ + ret = ccatok_pkey_skey2pkey(tokdata, skey_attr, &pkey_attr); + if (ret != CKR_OK) { + TRACE_ERROR("protected key creation failed with rc=0x%lx\n",ret); + goto done; + } + + /* Check if the new pkey's verification pattern matches the one in + * cca_data. This should always be the case, because we just + * created the pkey with the current MK. */ + vp_offset = pkey_attr->ulValueLen - PKEY_MK_VP_LENGTH; + if (memcmp(&cca_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + vp_offset, + PKEY_MK_VP_LENGTH) != 0) { + TRACE_ERROR("vp of this pkey does not match with the one in cca_data (should not occur)\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Now update the key obj. If it's a token obj, it will be also updated + * in the repository. */ + ret = pkey_update_and_save(tokdata, key_obj, &pkey_attr); + if (ret != CKR_OK) { + TRACE_ERROR("pkey_update_and_save failed with rc=0x%lx\n", ret); + goto done; + } + + ret = CKR_OK; + +done: + + if (pkey_attr != NULL) + free(pkey_attr); + + return ret; +} + +/** + * Returns true if the session is ok for creating protected keys, false + * otherwise. The session must be read/write for token objects, and not public + * nor SO for private objects. + */ +static CK_BBOOL ccatok_pkey_session_ok_for_obj(SESSION *session, + OBJECT *key_obj) +{ + if (object_is_token_object(key_obj) && + (session->session_info.flags & CKF_RW_SESSION) == 0) + return CK_FALSE; + + if (object_is_private(key_obj)) { + switch (session->session_info.state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + case CKS_RW_SO_FUNCTIONS: + return CK_FALSE; + default: + break; + } + } + + return CK_TRUE; +} + +/** + * Checks if the preconditions for using the related protected key of + * the given secure key object are met. The caller of this routine must + * have a READ_LOCK on the key object. + * + * The routine internally creates a protected key and adds it to the key_obj, + * if the machine supports pkeys, the key is eligible for pkey support, does + * not already have a valid pkey, and other conditions, like r/w session, are + * fulfilled. As adding a protected key to the key_obj involves unlocking and + * re-locking, the key blob, or any other attribute of the key, that was + * retrieved via h_opaque_2_blob before calling this function might be no more + * valid in a parallel environment. + * + * Therefore, the following return codes tell the calling function how to + * proceed: + * + * @return CKR_OK: + * a protected key was possibly created successfully and everything + * is fine to use pkey support. In this case the protected key + * shall be used, but a previously obtained key blob or other attr + * might be invalid, because of a possible unlock/re-lock of the + * key_obj. + * + * CKR_FUNCTION_NOT_SUPPORTED: + * The system, session or key do not allow to use pkey support, but + * no attempt was made to create a protected key. So the key blob, + * or any other attr, is still valid and a fallback into the ep11 + * path is ok. + * + * all others: + * An internal error occurred and it was possibly attempted to create + * a protected key for the object. In this case, the key blob, or + * any other attr, might be no longer valid in a parallel environment + * and the ep11 fallback is not possible anymore. The calling + * function shall return with an error in this case. + */ +static CK_RV ccatok_pkey_check(STDLL_TokData_t *tokdata, SESSION *session, + OBJECT *key_obj, CK_MECHANISM *mech) +{ + struct cca_private_data *cca_data = tokdata->private_data; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_RV ret = CKR_FUNCTION_NOT_SUPPORTED; + + /* Check if CPACF supports the operation implied by this key and mech */ + if (!pkey_op_supported_by_cpacf(cca_data->msa_level, mech->mechanism, + key_obj->template)) { + goto done; + } + + /* Check config option */ + switch (cca_data->pkey_mode) { + case PKEY_MODE_DISABLED: + goto done; + break; + case PKEY_MODE_DEFAULT: + case PKEY_MODE_ENABLED: + /* + * Use existing pkeys, re-create invalid pkeys, and also create new + * pkeys for secret/private keys that do not already have one. EC + * public keys that are pkey-extractable, can always be used via CPACF + * as there is no protected key involved. + */ + if (pkey_is_ec_public_key(key_obj->template) && + object_is_pkey_extractable(key_obj)) { + ret = CKR_OK; + goto done; + } + + if (!object_is_pkey_extractable(key_obj) || + !cca_data->pkey_wrap_supported) { + goto done; + } + if (template_attribute_get_non_empty(key_obj->template, + CKA_IBM_OPAQUE_PKEY, + &opaque_attr) != CKR_OK || + !ccatok_pkey_is_valid(tokdata, key_obj)) { + /* + * this key has either no pkey attr, or it is not valid, + * try to create one, if the session state allows it. + */ + if (!ccatok_pkey_session_ok_for_obj(session, key_obj)) + goto done; + + ret = ccatok_pkey_update(tokdata, key_obj); + if (ret != CKR_OK) { + TRACE_ERROR("error updating the protected key, rc=0x%lx\n", ret); + if (ret == CKR_FUNCTION_NOT_SUPPORTED) + ret = CKR_FUNCTION_FAILED; + goto done; + } + } + break; + default: + /* should not occur */ + TRACE_ERROR("PKEY_MODE %i unsupported.\n", cca_data->pkey_mode); + ret = CKR_FUNCTION_FAILED; + goto done; + break; + } + + ret = CKR_OK; + +done: + + return ret; +} + +/* + * This function is called whenever a new object is created. It currently sets + * attribute CKA_IBM_PROTKEY_EXTRACTABLE according to the PKEY_MODE token + * option, but may also be used for other token options and attrs in future. + */ +CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *tokdata, + CK_OBJECT_CLASS class, + CK_ULONG mode, TEMPLATE *tmpl) +{ + struct cca_private_data *cca_data = tokdata->private_data; + CK_ATTRIBUTE *pkey_attr = NULL, *ecp_attr = NULL; + CK_BBOOL add_pkey_extractable = CK_FALSE; + CK_BBOOL btrue = CK_TRUE; + CK_RV ret; + + UNUSED(mode); + + if (class != CKO_SECRET_KEY && class != CKO_PRIVATE_KEY && + class != CKO_PUBLIC_KEY) + return CKR_OK; + + switch (cca_data->pkey_mode) { + case PKEY_MODE_DISABLED: + /* Nothing to do */ + break; + case PKEY_MODE_DEFAULT: + /* + * If the application did not specify pkey-extractable, all keys get + * pkey-extractable=false. This was already set by default, so + * nothing to do here. + */ + break; + case PKEY_MODE_ENABLED: + /* + * All secret/private keys and all EC public keys where CPACF supports + * the related curve, get pkey-extractable=true + */ + switch (class) { + case CKO_PUBLIC_KEY: + if (template_attribute_get_non_empty(tmpl, CKA_EC_PARAMS, &ecp_attr) == CKR_OK && + pkey_op_supported_by_cpacf(cca_data->msa_level, CKM_ECDSA, tmpl)) + add_pkey_extractable = CK_TRUE; + /* + * Note that the explicit parm CKM_ECDSA just tells the + * function that it's not AES here. It covers all EC mechs + */ + break; + default: + add_pkey_extractable = CK_TRUE; + break; + } + + if (add_pkey_extractable) { + if (!template_attribute_find(tmpl, CKA_IBM_PROTKEY_EXTRACTABLE, &pkey_attr)) { + ret = build_attribute(CKA_IBM_PROTKEY_EXTRACTABLE, + (CK_BBOOL *)&btrue, sizeof(CK_BBOOL), + &pkey_attr); + if (ret != CKR_OK) { + TRACE_ERROR("build_attribute failed with ret=0x%lx\n", ret); + goto done; + } + ret = template_update_attribute(tmpl, pkey_attr); + if (ret != CKR_OK) { + TRACE_ERROR("update_attribute failed with ret=0x%lx\n", ret); + free(pkey_attr); + goto done; + } + } + } + break; + default: + TRACE_ERROR("PKEY_MODE %i unsupported.\n", cca_data->pkey_mode); + ret = CKR_FUNCTION_FAILED; + goto done; + break; + } + + ret = CKR_OK; + +done: + + return ret; +} + +static CK_BBOOL ccatok_token_is_cpacf_exportable(const CK_BYTE *token, + CK_ULONG token_len) +{ + CK_BYTE keyusage = token[CCA_ECC_TOKEN_KEYUSAGE_OFFSET]; + + if (token_len < CCA_ECC_TOKEN_KEYUSAGE_OFFSET) + return CK_FALSE; + + if (keyusage & CCA_XPRTCPAC) + return CK_TRUE; + + return CK_FALSE; +} + +static CK_RV ccatok_pkey_check_attrs(STDLL_TokData_t *tokdata, + TEMPLATE * templ, CK_BYTE *sec_key, + CK_ULONG sec_len, + enum cca_token_type token_type) +{ + CK_BBOOL pkey_attr_value; + CK_RV ret; + + UNUSED(tokdata); + + ret = template_attribute_get_bool(templ, CKA_IBM_PROTKEY_EXTRACTABLE, + &pkey_attr_value); + if (ret != CKR_OK || pkey_attr_value == CK_FALSE) + return CKR_OK; + + /* + * At this point, the key has CKA_IBM_PROKEY_EXTRACTABLE = true and it has + * a secure key token, so let's check if the secure key token is + * CPACF-exportable. + */ + switch (token_type) { + case sec_aes_data_key: + /* Nothing to do: AES data keys are always CPACF-exportable */ + break; + case sec_ecc_priv_key: + /* + * From CCA 7.3 Application Programmer's Guide, table 282: + * Allow export to CPACF protected key format. Valid for ECC + * curves P256, P384, P521, Ed25519, and Ed448. + */ + if (pkey_op_ec_curve_supported_by_cpacf(templ) && + !ccatok_token_is_cpacf_exportable(sec_key, sec_len)) { + TRACE_ERROR("ECC secure key is CKA_IBM_PROTKEY_EXTRACTABLE, but token is not CPACF-exportable.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + break; + default: + break; + } + + return CKR_OK; + +} +#endif /* NO_PKEY */ + +typedef struct { + CK_BBOOL card_level_set; + struct cca_version min_card_version; +} cca_min_card_version_t; + +/* return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2 */ +static int compare_cca_version(const struct cca_version *v1, + const struct cca_version *v2) +{ + if (v1->ver < v2->ver) + return -1; + if (v1->ver > v2->ver) + return 1; + if (v1->rel < v2->rel) + return -1; + if (v1->rel > v2->rel) + return 1; + if (v1->mod < v2->mod) + return -1; + if (v1->mod > v2->mod) + return 1; + return 0; +} + +/* + * Called from within cca_iterate_adapters() handler function, thus no need to + * obtain CCA adapter lock + */ +static CK_RV cca_get_adapter_version(cca_min_card_version_t *data) +{ + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, verb_data_length; + struct cca_version adapter_version; + char ccaversion[CCA_STATCCA_CCA_VERSION_LENGTH + 1]; + + memcpy(rule_array, "STATCCA ", CCA_KEYWORD_SIZE); + rule_array_count = 1; + verb_data_length = 0; + dll_CSUACFQ(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &verb_data_length, NULL); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSUACFQ (STATCCA) failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + ccaversion[CCA_STATCCA_CCA_VERSION_LENGTH] = '\0'; + memcpy(ccaversion, &rule_array[CCA_STATCCA_CCA_VERSION_OFFSET], + CCA_STATCCA_CCA_VERSION_LENGTH); + + if (sscanf(ccaversion, "%d.%d.%02d*", (int *)&adapter_version.ver, + (int *)&adapter_version.rel, (int *)&adapter_version.mod) != 3) { + TRACE_ERROR("sscanf of string %s failed, cannot determine CCA card version\n", + ccaversion); + return CKR_FUNCTION_FAILED; + } + + if (compare_cca_version(&adapter_version, &data->min_card_version) < 0) { + data->min_card_version = adapter_version; + data->card_level_set = 1; + } + + return CKR_OK; +} + +/* + * Callback function used by cca_get_min_card_level() to determine the + * minimum CCA card level among all available APQNs. + */ +static CK_RV cca_get_card_level_handler(STDLL_TokData_t *tokdata, const char *adapter, + unsigned short card, unsigned short domain, + void *handler_data) +{ + cca_min_card_version_t *data = (cca_min_card_version_t *) handler_data; + + UNUSED(tokdata); + UNUSED(adapter); + UNUSED(card); + UNUSED(domain); + + return cca_get_adapter_version(data); +} + +/* Called during token_specific_init() , no need to obtain CCA adapter lock */ +static CK_RV cca_get_min_card_level(STDLL_TokData_t *tokdata) +{ + struct cca_private_data *cca_private = tokdata->private_data; + cca_min_card_version_t card_level_data; + CK_RV ret; + + /* Determine min card level by iterating over all APQNs */ + memset(&card_level_data, 0, sizeof(cca_min_card_version_t)); + card_level_data.min_card_version.ver = UINT_MAX; + card_level_data.min_card_version.rel = UINT_MAX; + card_level_data.min_card_version.mod = UINT_MAX; + + ret = cca_iterate_adapters(tokdata, cca_get_card_level_handler, + &card_level_data); + + if (ret != CKR_OK || card_level_data.card_level_set == 0) { + TRACE_ERROR("cca_iterate_adapters failed, could not determine min card level.\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Update min card level in cca_private_data, needs write-lock. */ + if (pthread_rwlock_wrlock(&cca_private->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RW-lock failed.\n"); + ret = CKR_CANT_LOCK; + goto done; + } + cca_private->min_card_version = card_level_data.min_card_version; + if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RW-unlock failed.\n"); + ret = CKR_CANT_LOCK; + goto done; + } + + ret = CKR_OK; + +done: + + return ret; +} + CK_RV token_specific_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { @@ -1353,6 +3575,13 @@ TRACE_INFO("cca %s slot=%lu running\n", __func__, SlotNumber); + /* Request the API layer to lock against HSM-MK-change state changes. */ + rc = init_hsm_mk_change_lock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("init_hsm_mk_change_lock failed.\n"); + return rc; + } + cca_private = calloc(1, sizeof(*cca_private)); if (cca_private == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); @@ -1360,6 +3589,7 @@ } tokdata->private_data = cca_private; + cca_private->pkeyfd = -1; rc = cca_load_config_file(tokdata, conf_name); if (rc != CKR_OK) @@ -1392,10 +3622,65 @@ if (rc != CKR_OK) goto error; + rc = cca_get_adapter_domain_selection_infos(tokdata); + if (rc != CKR_OK) + goto error; + + rc = init_cca_adapter_lock(tokdata); + if (rc != CKR_OK) + goto error; + + rc = cca_mk_change_check_pending_ops(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to check for pending HSM MK change operations " + "rc=0x%lx\n", __func__, rc); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to check for pending HSM MK " + "change operations rc=0x%lx\n", tokdata->slot_id, rc); + goto error; + } + rc = cca_check_mks(tokdata); if (rc != CKR_OK) goto error; + rc = cca_get_min_card_level(tokdata); + if (rc != CKR_OK) + goto error; + +#ifndef NO_PKEY + cca_private->msa_level = get_msa_level(); + TRACE_INFO("MSA level = %i\n", cca_private->msa_level); + + if (pthread_rwlock_init(&cca_private->min_card_version_rwlock, NULL) != 0) { + TRACE_ERROR("Initializing the min_card_version RW-Lock failed\n"); + rc = CKR_CANT_LOCK; + goto error; + } + + if (!ccatok_pkey_option_disabled(tokdata)) { + cca_private->pkeyfd = open(PKEYDEVICE, O_RDWR); + if (cca_private->pkeyfd >= 0) { + TRACE_INFO("Opened /dev/pkey: file descriptor %d", cca_private->pkeyfd); + rc = ccatok_pkey_get_firmware_wkvp(tokdata); + if (rc != CKR_OK) { + /* + * Could not save mk_vp in cca_data, pkey support not available. + * But the token should initialize ok, even if this happens. + * We are just running without protected key support, i.e. the + * pkey_wrap_supported flag in tokdata remains off. + */ + OCK_SYSLOG(LOG_WARNING, + "%s: Warning: Could not get mk_vp, protected key support not available.\n", + __func__); + TRACE_WARNING( + "Could not get mk_vp, protected key support not available.\n"); + } + } else { + TRACE_WARNING("Could not open /dev/pkey, protected key support not available.\n"); + } + } +#endif + return CKR_OK; error: @@ -1407,9 +3692,12 @@ CK_BBOOL in_fork_initializer) { struct cca_private_data *cca_private = tokdata->private_data; + CK_ULONG i; TRACE_INFO("cca %s running\n", __func__); + destroy_cca_adapter_lock(tokdata); + if (tokdata->mech_list != NULL) free(tokdata->mech_list); @@ -1418,6 +3706,19 @@ dlclose(cca_private->lib_csulcca); cca_private->lib_csulcca = NULL; + for (i = 0; i < CCA_NUM_MK_TYPES; i++) { + if (cca_private->mk_change_ops[i].mk_change_active && + cca_private->mk_change_ops[i].apqns != NULL) + free(cca_private->mk_change_ops[i].apqns); + } + +#ifndef NO_PKEY + if (cca_private->pkeyfd >= 0) + close(cca_private->pkeyfd); + + pthread_rwlock_destroy(&cca_private->min_card_version_rwlock); +#endif + free(cca_private); } tokdata->private_data = NULL; @@ -1425,7 +3726,7 @@ return CKR_OK; } -static CK_RV cca_key_gen(STDLL_TokData_t *tokdata, +static CK_RV cca_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, enum cca_key_type type, CK_BYTE * key, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size) @@ -1440,6 +3741,8 @@ enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; + CK_RV rc; if (type == CCA_DES_KEY) { switch (key_size) { @@ -1473,16 +3776,18 @@ return CKR_FUNCTION_FAILED; } - dll_CSNBKGN(&return_code, - &reason_code, - NULL, - NULL, - key_form, - key_length, - key_type_1, - key_type_2, - kek_key_identifier_1, - kek_key_identifier_2, key, generated_key_identifier_2); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKGN(&return_code, + &reason_code, + NULL, + NULL, + key_form, + key_length, + key_type_1, + key_type_2, + kek_key_identifier_1, + kek_key_identifier_2, key, generated_key_identifier_2); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN(KEYGEN) failed. return:%ld, reason:%ld\n", @@ -1497,21 +3802,30 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, keytype, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, tmpl, key, CCA_KEY_ID_SIZE, + new_mk, keytype); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + return CKR_OK; } -CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **des_key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type_1[CCA_KEYWORD_SIZE]; + UNUSED(tmpl); + if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; @@ -1526,7 +3840,7 @@ memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); memcpy(key_type_1, "DATA ", (size_t) CCA_KEYWORD_SIZE); - return cca_key_gen(tokdata, CCA_DES_KEY, *des_key, key_form, + return cca_key_gen(tokdata, tmpl, CCA_DES_KEY, *des_key, key_form, key_type_1, keysize); } @@ -1599,19 +3913,23 @@ rule_array_count = 1; memcpy(rule_array, "CBC ", (size_t) CCA_KEYWORD_SIZE); - if (encrypt) { - dll_CSNBENC(&return_code, &reason_code, NULL, NULL, attr->pValue, //id, - &length, in_data, //in, - init_v, //iv, - &rule_array_count, rule_array, &pad_character, - chaining_vector, local_out); //out_data); //out); - } else { - dll_CSNBDEC(&return_code, &reason_code, NULL, NULL, attr->pValue, //id, - &length, in_data, //in, - init_v, //iv, - &rule_array_count, rule_array, chaining_vector, local_out); - //out_data); //out); - } + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + if (encrypt) { + dll_CSNBENC(&return_code, &reason_code, NULL, NULL, attr->pValue, + &length, in_data, + init_v, + &rule_array_count, rule_array, &pad_character, + chaining_vector, local_out); + } else { + dll_CSNBDEC(&return_code, &reason_code, NULL, NULL, attr->pValue, + &length, in_data, + init_v, + &rule_array_count, rule_array, chaining_vector, local_out); + } + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) @@ -1931,6 +4249,7 @@ enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -2000,13 +4319,15 @@ private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKB(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &key_value_structure_length, key_value_structure, - &private_key_name_length, private_key_name, - 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, - &key_token_length, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &key_value_structure_length, key_value_structure, + &private_key_name_length, private_key_name, + 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, + &key_token_length, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD) failed. return:%ld," @@ -2020,13 +4341,15 @@ priv_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; - dll_CSNDPKG(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - ®eneration_data_length, regeneration_data, - &key_token_length, key_token, - transport_key_identifier, - &priv_key_token_length, priv_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKG(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + ®eneration_data_length, regeneration_data, + &key_token_length, key_token, + transport_key_identifier, + &priv_key_token_length, priv_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (RSA KEY GENERATE) failed. return:%ld," @@ -2041,22 +4364,31 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, keytype, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rv = cca_reencipher_created_key(tokdata, priv_tmpl, priv_key_token, + priv_key_token_length, new_mk, keytype); + if (rv != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rv); + return rv; + } + TRACE_DEVEL("RSA secure key token generated. size: %ld\n", priv_key_token_length); rule_array_count = 0; publ_key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKX(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &priv_key_token_length, priv_key_token, - &publ_key_token_length, publ_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKX(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &priv_key_token_length, priv_key_token, + &publ_key_token_length, publ_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKX (PUBLIC KEY TOKEN EXTRACT) failed. return:%ld," @@ -2139,19 +4471,24 @@ data_structure_length = 0; - dll_CSNDPKE(&return_code, - &reason_code, - NULL, NULL, - &rule_array_count, - rule_array, - (long *) &in_data_len, - in_data, - &data_structure_length, // must be 0 - NULL, // ignored - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) out_data_len, - out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDPKE(&return_code, + &reason_code, + NULL, NULL, + &rule_array_count, + rule_array, + (long *) &in_data_len, + in_data, + &data_structure_length, // must be 0 + NULL, // ignored + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) out_data_len, + out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", @@ -2200,31 +4537,36 @@ data_structure_length = 0; - dll_CSNDPKD(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *) &in_data_len, - in_data, - &data_structure_length, // must be 0 - NULL, // ignored - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) out_data_len, - out_data); - - if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSNDPKD (RSA DECRYPT) failed. return:%ld, reason:%ld\n", - return_code, reason_code); - return CKR_FUNCTION_FAILED; - } else if (reason_code != 0) { - TRACE_WARNING("CSNDPKD (RSA DECRYPT) succeeded, but" - " returned reason:%ld\n", reason_code); - } + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDPKD(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *) &in_data_len, + in_data, + &data_structure_length, // must be 0 + NULL, // ignored + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) out_data_len, + out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + + TRACE_DEVEL("CSNDPKD (RSA DECRYPT): return:%ld, reason:%ld\n", + return_code, reason_code); + + rc = constant_time_select(constant_time_eq(return_code, CCA_SUCCESS), + CKR_OK, CKR_FUNCTION_FAILED); + rc = constant_time_select(constant_time_eq(return_code, 8) & + constant_time_eq(reason_code, 66), + CKR_ENCRYPTED_DATA_INVALID, rc); - return CKR_OK; + return rc; } CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *tokdata, @@ -2313,19 +4655,24 @@ data_structure_length = 0; - dll_CSNDPKE(&return_code, - &reason_code, - NULL, NULL, - &rule_array_count, - rule_array, - (long *)&in_data_len, - in_data, - &data_structure_length, // must be 0 - NULL, // ignored - (long *)&(attr->ulValueLen), - attr->pValue, - (long *)out_data_len, - out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDPKE(&return_code, + &reason_code, + NULL, NULL, + &rule_array_count, + rule_array, + (long *)&in_data_len, + in_data, + &data_structure_length, // must be 0 + NULL, // ignored + (long *)&(attr->ulValueLen), + attr->pValue, + (long *)out_data_len, + out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", @@ -2430,30 +4777,34 @@ data_structure_length = 0; - dll_CSNDPKD(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *)&in_data_len, - in_data, - &data_structure_length, // must be 0 - NULL, // ignored - (long *) &(attr->ulValueLen), - attr->pValue, - (long *)out_data_len, - out_data); - - if (return_code != CCA_SUCCESS) { - TRACE_ERROR("CSNDPKD (RSA DECRYPT) failed. return:%ld, reason:%ld\n", - return_code, reason_code); - rc = CKR_FUNCTION_FAILED; - goto done; - } else if (reason_code != 0) { - TRACE_WARNING("CSNDPKD (RSA DECRYPT) succeeded, but" - " returned reason:%ld\n", reason_code); - } + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDPKD(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *)&in_data_len, + in_data, + &data_structure_length, // must be 0 + NULL, // ignored + (long *) &(attr->ulValueLen), + attr->pValue, + (long *)out_data_len, + out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + + TRACE_DEVEL("CSNDPKD (RSA DECRYPT): return:%ld, reason:%ld\n", + return_code, reason_code); + + rc = constant_time_select(constant_time_eq(return_code, CCA_SUCCESS), + CKR_OK, CKR_FUNCTION_FAILED); + rc = constant_time_select(constant_time_eq(return_code, 8) & + constant_time_eq(reason_code, 2054), + CKR_ENCRYPTED_DATA_INVALID, rc); done: object_put(tokdata, key_obj, TRUE); @@ -2499,17 +4850,22 @@ rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); - dll_CSNDDSG(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) &in_data_len, - in_data, - (long *) out_data_len, &signature_bit_length, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSG(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) &in_data_len, + in_data, + (long *) out_data_len, &signature_bit_length, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA SIGN) failed. return :%ld, reason: %ld\n", @@ -2559,16 +4915,21 @@ rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); - dll_CSNDDSV(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) &in_data_len, - in_data, (long *) &out_data_len, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSV(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) &in_data_len, + in_data, (long *) &out_data_len, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; @@ -2701,17 +5062,22 @@ break; } - dll_CSNDDSG(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *)&(attr->ulValueLen), - attr->pValue, - &message_len, - message, - (long *)out_data_len, &signature_bit_length, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSG(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *)&(attr->ulValueLen), + attr->pValue, + &message_len, + message, + (long *)out_data_len, &signature_bit_length, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA PSS SIGN) failed. return :%ld, reason: %ld\n", @@ -2839,17 +5205,22 @@ break; } - dll_CSNDDSV(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *)&(attr->ulValueLen), - attr->pValue, - &message_len, - message, - (long *)&out_data_len, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSV(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *)&(attr->ulValueLen), + attr->pValue, + &message_len, + message, + (long *)&out_data_len, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { rc = CKR_SIGNATURE_INVALID; @@ -2886,9 +5257,9 @@ return rc; } -CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **aes_key, - CK_ULONG *len, CK_ULONG key_size, - CK_BBOOL *is_opaque) +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **aes_key, CK_ULONG *len, + CK_ULONG key_size, CK_BBOOL *is_opaque) { long return_code, reason_code; unsigned char key_token[CCA_KEY_ID_SIZE] = { 0, }; @@ -2934,17 +5305,20 @@ } rule_array_count = 4; - dll_CSNBKTB(&return_code, - &reason_code, - &exit_data_len, - exit_data, - key_token, - key_type, - &rule_array_count, - rule_array, - NULL, - reserved_1, - NULL, &point_to_array_of_zeros, NULL, NULL, NULL, NULL, mkvp); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKTB(&return_code, + &reason_code, + &exit_data_len, + exit_data, + key_token, + key_type, + &rule_array_count, + rule_array, + NULL, + reserved_1, + NULL, &point_to_array_of_zeros, + NULL, NULL, NULL, NULL, mkvp); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBTKB (TOKEN BUILD) failed. return:%ld," @@ -2955,11 +5329,12 @@ memcpy(key_type, "AESTOKEN", (size_t) CCA_KEYWORD_SIZE); memcpy(*aes_key, key_token, (size_t) CCA_KEY_ID_SIZE); - return cca_key_gen(tokdata, CCA_AES_KEY, *aes_key, key_form, + return cca_key_gen(tokdata, tmpl, CCA_AES_KEY, *aes_key, key_form, key_type, key_size); } CK_RV token_specific_aes_ecb(STDLL_TokData_t * tokdata, + SESSION *session, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, @@ -2976,6 +5351,13 @@ CK_ATTRIBUTE *attr = NULL; long int key_len; CK_RV rc; +#ifndef NO_PKEY + CK_MECHANISM mech = { CKM_AES_ECB, NULL, 0 }; +#endif + +#ifdef NO_PKEY + UNUSED(session); +#endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -2989,54 +5371,76 @@ } key_len = attr->ulValueLen; +#ifndef NO_PKEY + /* CCA token protected key option */ + rc = ccatok_pkey_check(tokdata, session, key, &mech); + switch (rc) { + case CKR_OK: + rc = pkey_aes_ecb(key, in_data, in_data_len, + out_data, out_data_len, encrypt); + goto done; + case CKR_FUNCTION_NOT_SUPPORTED: + /* fallback */ + break; + default: + goto done; + } +#endif /* NO_PKEY */ + + /* Fallback: Perform the function via the CCA card ... */ rule_array_count = 4; memcpy(rule_array, "AES ECB KEYIDENTINITIAL ", rule_array_count * (size_t) CCA_KEYWORD_SIZE); - if (encrypt) { - dll_CSNBSAE(&return_code, - &reason_code, - &exit_data_len, - exit_data, - &rule_array_count, - rule_array, - &key_len, - attr->pValue, - &key_params_len, - NULL, - &block_size, - &IV_len, - NULL, - &chain_vector_len, - NULL, - (long int *)&in_data_len, - in_data, - (long int *)out_data_len, - local_out, - &opt_data_len, NULL); - } else { - dll_CSNBSAD(&return_code, - &reason_code, - &exit_data_len, - exit_data, - &rule_array_count, - rule_array, - &key_len, - attr->pValue, - &key_params_len, - NULL, - &block_size, - &IV_len, - NULL, - &chain_vector_len, - NULL, - (long int *)&in_data_len, - in_data, - (long int *)out_data_len, - local_out, - &opt_data_len, - NULL); - } + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + if (encrypt) { + dll_CSNBSAE(&return_code, + &reason_code, + &exit_data_len, + exit_data, + &rule_array_count, + rule_array, + &key_len, + attr->pValue, + &key_params_len, + NULL, + &block_size, + &IV_len, + NULL, + &chain_vector_len, + NULL, + (long int *)&in_data_len, + in_data, + (long int *)out_data_len, + local_out, + &opt_data_len, NULL); + } else { + dll_CSNBSAD(&return_code, + &reason_code, + &exit_data_len, + exit_data, + &rule_array_count, + rule_array, + &key_len, + attr->pValue, + &key_params_len, + NULL, + &block_size, + &IV_len, + NULL, + &chain_vector_len, + NULL, + (long int *)&in_data_len, + in_data, + (long int *)out_data_len, + local_out, + &opt_data_len, + NULL); + } + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) { @@ -3058,10 +5462,17 @@ } } - return CKR_OK; + rc = CKR_OK; + +#ifndef NO_PKEY +done: +#endif + + return rc; } CK_RV token_specific_aes_cbc(STDLL_TokData_t * tokdata, + SESSION *session, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, @@ -3079,6 +5490,13 @@ CK_ATTRIBUTE *attr = NULL; long int key_len; CK_RV rc; +#ifndef NO_PKEY + CK_MECHANISM mech = { CKM_AES_CBC, init_v, IV_len }; +#endif + +#ifdef NO_PKEY + UNUSED(session); +#endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -3092,7 +5510,24 @@ return rc; } key_len = attr->ulValueLen; - + +#ifndef NO_PKEY + /* CCA token protected key option */ + rc = ccatok_pkey_check(tokdata, session, key, &mech); + switch (rc) { + case CKR_OK: + rc = pkey_aes_cbc(key, init_v, in_data, in_data_len, + out_data, out_data_len, encrypt); + goto done; + case CKR_FUNCTION_NOT_SUPPORTED: + /* fallback */ + break; + default: + goto done; + } +#endif /* NO_PKEY */ + + /* Fallback: Perform the function via the CCA card ... */ if (in_data_len % 16 == 0) { rule_array_count = 3; memcpy(rule_array, "AES KEYIDENTINITIAL ", @@ -3112,51 +5547,56 @@ } length = in_data_len; - if (encrypt) { - dll_CSNBSAE(&return_code, - &reason_code, - &exit_data_len, - exit_data, - &rule_array_count, - rule_array, - &key_len, - attr->pValue, - &key_params_len, - exit_data, - &block_size, - &IV_len, - init_v, - &chain_vector_len, - chaining_vector, - &length, - in_data, - (long int *)out_data_len, - local_out, - &opt_data_len, - NULL); - } else { - dll_CSNBSAD(&return_code, - &reason_code, - &exit_data_len, - exit_data, - &rule_array_count, - rule_array, - &key_len, - attr->pValue, - &key_params_len, - NULL, - &block_size, - &IV_len, - init_v, - &chain_vector_len, - chaining_vector, - &length, - in_data, - (long int *)out_data_len, - local_out, - &opt_data_len, - NULL); - } + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + if (encrypt) { + dll_CSNBSAE(&return_code, + &reason_code, + &exit_data_len, + exit_data, + &rule_array_count, + rule_array, + &key_len, + attr->pValue, + &key_params_len, + exit_data, + &block_size, + &IV_len, + init_v, + &chain_vector_len, + chaining_vector, + &length, + in_data, + (long int *)out_data_len, + local_out, + &opt_data_len, + NULL); + } else { + dll_CSNBSAD(&return_code, + &reason_code, + &exit_data_len, + exit_data, + &rule_array_count, + rule_array, + &key_len, + attr->pValue, + &key_params_len, + NULL, + &block_size, + &IV_len, + init_v, + &chain_vector_len, + chaining_vector, + &length, + in_data, + (long int *)out_data_len, + local_out, + &opt_data_len, + NULL); + } + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { if (encrypt) { @@ -3197,7 +5637,13 @@ *out_data_len = length; - return CKR_OK; + rc = CKR_OK; + +#ifndef NO_PKEY +done: +#endif + + return rc; } /* See the top of this file for the declarations of mech_list and @@ -3242,7 +5688,8 @@ return FALSE; } -static CK_RV curve_supported(TEMPLATE *templ, uint8_t *curve_type, uint16_t *curve_bitlen) +static CK_RV curve_supported(TEMPLATE *templ, uint8_t *curve_type, + uint16_t *curve_bitlen, int *curve_nid) { CK_ATTRIBUTE *attr = NULL; unsigned int i; @@ -3264,6 +5711,7 @@ der_ec_supported[i].twisted == CK_FALSE) { *curve_type = der_ec_supported[i].curve_type; *curve_bitlen = der_ec_supported[i].len_bits; + *curve_nid = der_ec_supported[i].nid; return CKR_OK; } } @@ -3412,16 +5860,18 @@ unsigned char *param2 = NULL; uint8_t curve_type; uint16_t curve_bitlen; + int curve_nid; enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } - rv = curve_supported(publ_tmpl, &curve_type, &curve_bitlen); + rv = curve_supported(publ_tmpl, &curve_type, &curve_bitlen, &curve_nid); if (rv != CKR_OK) { TRACE_ERROR("Curve not supported\n"); return rv; @@ -3440,27 +5890,41 @@ rule_array_count = 1; memcpy(rule_array, "ECC-PAIR", (size_t) (CCA_KEYWORD_SIZE)); +#ifndef NO_PKEY + /* Add protected key related attributes to the rule array */ + rv = ccatok_pkey_add_attrs(tokdata, priv_tmpl, CKK_EC, curve_type, + curve_bitlen, rule_array, sizeof(rule_array), + (CK_ULONG *)&rule_array_count); + if (rv != CKR_OK) { + TRACE_ERROR("%s ccatok_pkey_add_attrs failed with rc=0x%lx\n", __func__, rv); + return rv; + } +#endif /* NO_PKEY */ + private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKB(&return_code, - &reason_code, - &exit_data_len, - exit_data, - &rule_array_count, - rule_array, - &key_value_structure_length, - key_value_structure, - &private_key_name_length, - private_key_name, - ¶m1, - param2, - ¶m1, - param2, - ¶m1, - param2, - ¶m1, param2, ¶m1, param2, &key_token_length, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, + &reason_code, + &exit_data_len, + exit_data, + &rule_array_count, + rule_array, + &key_value_structure_length, + key_value_structure, + &private_key_name_length, + private_key_name, + ¶m1, + param2, + ¶m1, + param2, + ¶m1, + param2, + ¶m1, param2, + ¶m1, param2, &key_token_length, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," @@ -3478,18 +5942,20 @@ regeneration_data_length = 0; - dll_CSNDPKG(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - ®eneration_data_length, - regeneration_data, - &key_token_length, - key_token, - transport_key_identifier, - &priv_key_token_length, priv_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKG(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + ®eneration_data_length, + regeneration_data, + &key_token_length, + key_token, + transport_key_identifier, + &priv_key_token_length, priv_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (EC KEY GENERATE) failed." @@ -3506,22 +5972,31 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, keytype, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rv = cca_reencipher_created_key(tokdata, priv_tmpl, priv_key_token, + priv_key_token_length, new_mk, keytype); + if (rv != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rv); + return rv; + } + TRACE_DEVEL("ECC secure private key token generated. size: %ld\n", priv_key_token_length); rule_array_count = 0; publ_key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKX(&return_code, &reason_code, - NULL, NULL, - &rule_array_count, rule_array, - &priv_key_token_length, priv_key_token, - &publ_key_token_length, publ_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKX(&return_code, &reason_code, + NULL, NULL, + &rule_array_count, rule_array, + &priv_key_token_length, priv_key_token, + &publ_key_token_length, publ_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKX (PUBLIC KEY TOKEN EXTRACT) failed. return:%ld," @@ -3560,8 +6035,13 @@ long signature_bit_length; CK_ATTRIBUTE *attr; CK_RV rc; +#ifndef NO_PKEY + CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; +#endif +#ifdef NO_PKEY UNUSED(sess); +#endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -3576,22 +6056,43 @@ return rc; } - /* CCA doc: page 113 */ +#ifndef NO_PKEY + /* CCA token protected key option: perform the function via CPACF */ + rc = ccatok_pkey_check(tokdata, sess, key_obj, &mech); + switch (rc) { + case CKR_OK: + rc = pkey_ec_sign(key_obj, in_data, in_data_len, + out_data, out_data_len, NULL); + goto done; + case CKR_FUNCTION_NOT_SUPPORTED: + /* fallback */ + break; + default: + goto done; + } +#endif /* NO_PKEY */ + + /* Fallback: Perform the function via the CCA card */ rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); *out_data_len = *out_data_len > 132 ? 132 : *out_data_len; - dll_CSNDDSG(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) &in_data_len, - in_data, - (long *) out_data_len, &signature_bit_length, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSG(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) &in_data_len, + in_data, + (long *) out_data_len, &signature_bit_length, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (EC SIGN) failed. return:%ld," @@ -3604,7 +6105,13 @@ " returned reason:%ld\n", reason_code); } - return CKR_OK; + rc = CKR_OK; + +#ifndef NO_PKEY +done: +#endif + + return rc; } CK_RV token_specific_ec_verify(STDLL_TokData_t * tokdata, @@ -3618,8 +6125,13 @@ unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; CK_RV rc; +#ifndef NO_PKEY + CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; +#endif +#ifdef NO_PKEY UNUSED(sess); +#endif if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -3634,20 +6146,41 @@ return rc; } - /* CCA doc: page 118 */ +#ifndef NO_PKEY + /* CCA token protected key option: perform the function via CPACF */ + rc = ccatok_pkey_check(tokdata, sess, key_obj, &mech); + switch (rc) { + case CKR_OK: + rc = pkey_ec_verify(key_obj, in_data, in_data_len, + out_data, out_data_len); + goto done; + case CKR_FUNCTION_NOT_SUPPORTED: + /* fallback */ + break; + default: + goto done; + } +#endif /* NO_PKEY */ + + /* Fallback: Perform the function via the CCA card */ rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); - dll_CSNDDSV(&return_code, - &reason_code, - NULL, - NULL, - &rule_array_count, - rule_array, - (long *) &(attr->ulValueLen), - attr->pValue, - (long *) &in_data_len, - in_data, (long *) &out_data_len, out_data); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDDSV(&return_code, + &reason_code, + NULL, + NULL, + &rule_array_count, + rule_array, + (long *) &(attr->ulValueLen), + attr->pValue, + (long *) &in_data_len, + in_data, (long *) &out_data_len, out_data); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; @@ -3664,7 +6197,13 @@ " returned reason:%ld\n", reason_code); } - return CKR_OK; + rc = CKR_OK; + +#ifndef NO_PKEY +done: +#endif + + return rc; } CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, @@ -3762,11 +6301,12 @@ return CKR_MECHANISM_INVALID; } - - dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, (long int *)&in_data_len, in_data, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, (long int *)&in_data_len, in_data, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH failed. return:%ld, reason:%ld\n", @@ -3918,10 +6458,12 @@ break; } - dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, use_buffer ? &buffer_len : (long *) &in_data_len, - use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, - cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, use_buffer ? &buffer_len : (long *) &in_data_len, + use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, + cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA UPDATE) failed. return:%ld," @@ -4015,10 +6557,12 @@ cca_ctx->tail_len, (void *)cca_ctx->tail, cca_ctx->chain_vector_len, cca_ctx->hash_len); - dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &cca_ctx->tail_len, cca_ctx->tail, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, &cca_ctx->tail_len, cca_ctx->tail, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA FINAL) failed. return:%ld," @@ -4172,12 +6716,17 @@ TRACE_INFO("The mac length is %ld\n", cca_ctx->hash_len); if (sign) { - dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, attr->pValue, - (long int *)&in_data_len, in_data, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, attr->pValue, + (long int *)&in_data_len, in_data, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, cca_ctx->hash); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC GENERATE) failed. " @@ -4194,12 +6743,17 @@ memcpy(signature, cca_ctx->hash, cca_ctx->hash_len); *sig_len = cca_ctx->hash_len; } else { // verify - dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, - attr->pValue, (long int *)&in_data_len, in_data, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, signature); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, + attr->pValue, (long int *)&in_data_len, in_data, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, signature); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); @@ -4400,13 +6954,18 @@ TRACE_INFO("CSNBHMG: key length is %lu\n", attr->ulValueLen); if (sign) { - dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, attr->pValue, - use_buffer ? &buffer_len : (long int *) &in_data_len, - use_buffer ? buffer : in_data, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &hsize, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, attr->pValue, + use_buffer ? &buffer_len : (long int *) &in_data_len, + use_buffer ? buffer : in_data, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &hsize, cca_ctx->hash); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN UPDATE) failed. " @@ -4414,13 +6973,19 @@ rc = CKR_FUNCTION_FAILED; } } else { // verify - dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, attr->pValue, - use_buffer ? &buffer_len : (long int *) &in_data_len, - use_buffer ? buffer : in_data, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &hsize, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, attr->pValue, + use_buffer ? &buffer_len : (long int *) &in_data_len, + use_buffer ? buffer : in_data, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &hsize, cca_ctx->hash); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC VERIFY UPDATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); @@ -4528,12 +7093,17 @@ TRACE_INFO("The mac length is %ld\n", cca_ctx->hash_len); if (sign) { - dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, attr->pValue, - &cca_ctx->tail_len, cca_ctx->tail, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, cca_ctx->hash); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, attr->pValue, + &cca_ctx->tail_len, cca_ctx->tail, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, cca_ctx->hash); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN FINAL) failed. " @@ -4550,12 +7120,17 @@ *sig_len = cca_ctx->hash_len; } else { // verify - dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&attr->ulValueLen, attr->pValue, - &cca_ctx->tail_len, cca_ctx->tail, - &cca_ctx->chain_vector_len, cca_ctx->chain_vector, - &cca_ctx->hash_len, signature); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&attr->ulValueLen, attr->pValue, + &cca_ctx->tail_len, cca_ctx->tail, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, signature); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + attr->pValue, attr->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); @@ -4612,6 +7187,7 @@ enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; rc = template_attribute_find(priv_tmpl, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { @@ -4635,11 +7211,20 @@ return CKR_TEMPLATE_INCONSISTENT; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, priv_tmpl, + opaque_attr->pValue, + opaque_attr->ulValueLen, + new_mk, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + t = opaque_attr->pValue; privkey_len = cca_rsa_inttok_privkey_get_len(&t[CCA_RSA_INTTOK_PRIVKEY_OFFSET]); pubkey_offset = CCA_RSA_INTTOK_HDR_LENGTH + privkey_len; @@ -4846,10 +7431,15 @@ key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &key_value_structure_length, key_value_structure, - &private_key_name_length, private_key_name, 0, NULL, 0, NULL, - 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_value_structure_length, key_value_structure, + &private_key_name_length, private_key_name, + 0, NULL, 0, NULL, + 0, NULL, 0, NULL, 0, NULL, + &key_token_length, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA CRT) failed." @@ -4866,10 +7456,13 @@ key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &key_token_length, key_token, - transport_key_identifier, &target_key_token_length, - target_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_token_length, key_token, + transport_key_identifier, &target_key_token_length, + target_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (RSA KEY TOKEN IMPORT) failed." @@ -4885,11 +7478,20 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, priv_tmpl, target_key_token, + target_key_token_length, new_mk, + token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + + /* Add the key object to the template */ if ((rc = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, target_key_token, @@ -4922,7 +7524,7 @@ return rc; } -static CK_RV import_rsa_pubkey(TEMPLATE * publ_tmpl) +static CK_RV import_rsa_pubkey(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; @@ -5071,10 +7673,14 @@ // Create a key token for the public key. // Public keys do not need to be wrapped, so just call PKB. - dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &key_value_structure_length, key_value_structure, - &private_key_name_length, private_key_name, 0, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_value_structure_length, key_value_structure, + &private_key_name_length, private_key_name, + 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, + &key_token_length, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA-PUBL) failed." @@ -5103,6 +7709,7 @@ enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; rc = template_attribute_find(object->template, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { @@ -5159,11 +7766,20 @@ return CKR_KEY_FUNCTION_NOT_PERMITTED; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, object->template, + opaque_attr->pValue, + opaque_attr->ulValueLen, + new_mk, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* create a dummy CKA_VALUE attribute with the key bit size but all zero */ if ((rc = build_update_attribute(object->template, CKA_VALUE, zorro, token_keybitsize / 8))) { @@ -5209,10 +7825,12 @@ rule_array_count = 1; - dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - (long int *)&value_attr->ulValueLen, value_attr->pValue, - target_key_id); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + (long int *)&value_attr->ulValueLen, value_attr->pValue, + target_key_id); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", @@ -5227,11 +7845,19 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, object->template, + target_key_id, CCA_KEY_ID_SIZE, new_mk, + token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* Add the key object to the template */ if ((rc = build_update_attribute(object->template, CKA_IBM_OPAQUE, target_key_id, CCA_KEY_ID_SIZE))) { @@ -5259,6 +7885,7 @@ enum cca_token_type token_type; unsigned int token_payloadbitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; rc = template_attribute_find(object->template, CKA_VALUE, &value_attr); if (rc == FALSE) { @@ -5298,11 +7925,20 @@ return CKR_TEMPLATE_INCONSISTENT; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, object->template, + opaque_attr->pValue, + opaque_attr->ulValueLen, + new_mk, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* calculate expected payload size from the given keybitlen */ plbitsize = (((keybitlen + 32) + 63) & (~63)) + 320; /* and check with the payload size within the cca hmac token */ @@ -5336,10 +7972,14 @@ 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; - dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &clr_key_len, NULL, &key_name_len, NULL, - &user_data_len, NULL, &token_data_len, NULL, &verb_data_len, - NULL, &key_token_len, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &clr_key_len, NULL, &key_name_len, NULL, + &user_data_len, NULL, &token_data_len, NULL, + &verb_data_len, NULL, &key_token_len, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); @@ -5351,9 +7991,13 @@ key_part_len = keylen * 8; key_token_len = sizeof(key_token); - dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &key_part_len, value_attr->pValue, - &key_token_len, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_part_len, value_attr->pValue, + &key_token_len, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); @@ -5365,8 +8009,12 @@ key_part_len = 0; key_token_len = sizeof(key_token); - dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &key_part_len, NULL, &key_token_len, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_part_len, NULL, &key_token_len, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); @@ -5381,11 +8029,18 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, object->template, key_token, + key_token_len, new_mk, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* Add the key object to the template */ if ((rc = build_update_attribute(object->template, CKA_IBM_OPAQUE, key_token, key_token_len))) { @@ -5457,10 +8112,16 @@ } static CK_RV build_public_EC_key_value_structure(CK_BYTE *pubkey, CK_ULONG publen, - uint8_t curve_type, uint16_t curve_bitlen, + uint8_t curve_type, uint16_t curve_bitlen, int curve_nid, unsigned char *key_value_structure, long *key_value_structure_length) { ECC_PUBL ecc_publ; + CK_RV rc = CKR_OK; + BN_CTX *ctx = NULL; + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + BIGNUM *bn_x = NULL, *bn_y = NULL; + int y_bit; ecc_publ.curve_type = curve_type; ecc_publ.reserved = 0x00; @@ -5486,13 +8147,97 @@ memset(key_value_structure + sizeof(ECC_PUBL), POINT_CONVERSION_UNCOMPRESSED, 1); memcpy(key_value_structure + sizeof(ECC_PUBL) + 1, pubkey, publen); *key_value_structure_length = sizeof(ECC_PUBL) + publen + 1; + } else if (publen == bitlen2bytelen(curve_bitlen) + 1) { + if (pubkey[0] != POINT_CONVERSION_COMPRESSED && + pubkey[0] != POINT_CONVERSION_COMPRESSED + 1) { + TRACE_ERROR("Unsupported public key format\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + /* Uncompress the EC point, CCA needs it uncompressed */ + + ctx = BN_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("BN_CTX_new failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + group = EC_GROUP_new_by_curve_name(curve_nid); + if (group == NULL) { + TRACE_ERROR("Curve %d is not supported by openssl. Cannot decompress " + "public key\n", curve_nid); + return CKR_CURVE_NOT_SUPPORTED; + } + + point = EC_POINT_new(group); + if (point == NULL) { + TRACE_ERROR("EC_POINT_new failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + bn_x = BN_bin2bn(pubkey + 1, bitlen2bytelen(curve_bitlen), NULL); + bn_y = BN_new(); + if (bn_x == NULL || bn_y == NULL) { + TRACE_ERROR("BN_bin2bn/BN_new failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + y_bit = (pubkey[0] == POINT_CONVERSION_COMPRESSED ? 0 : 1); + if (!EC_POINT_set_compressed_coordinates(group, point, bn_x, + y_bit, ctx)) { + TRACE_ERROR("EC_POINT_set_compressed_coordinates failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (!EC_POINT_is_on_curve(group, point, ctx)) { + TRACE_ERROR("EC_POINT_is_on_curve failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, ctx)) { + TRACE_ERROR("EC_POINT_is_on_curve failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (BN_bn2binpad(bn_x, key_value_structure + sizeof(ECC_PUBL) + 1, + bitlen2bytelen(curve_bitlen)) <= 0 || + BN_bn2binpad(bn_y, key_value_structure + sizeof(ECC_PUBL) + 1 + + bitlen2bytelen(curve_bitlen), + bitlen2bytelen(curve_bitlen)) <= 0) { + TRACE_ERROR("BN_bn2binpad failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + ecc_publ.q_length = publen + bitlen2bytelen(curve_bitlen); + memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); + memset(key_value_structure + sizeof(ECC_PUBL), + POINT_CONVERSION_UNCOMPRESSED, 1); + *key_value_structure_length = sizeof(ECC_PUBL) + ecc_publ.q_length; } else { TRACE_ERROR("Unsupported public key length %ld\n",publen); - TRACE_ERROR("Compressed public keys are not supported by this token.\n"); return CKR_TEMPLATE_INCONSISTENT; } - return CKR_OK; +done: + if (ctx) + BN_CTX_free(ctx); + if (group) + EC_GROUP_free(group); + if (point) + EC_POINT_free(point); + if (bn_x) + BN_free(bn_x); + if (bn_y) + BN_free(bn_y); + + return rc; } /* helper function, check cca ec type, keybits and add the CKA_EC_PARAMS attribute */ @@ -5628,6 +8373,7 @@ enum cca_token_type token_type; unsigned int token_keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; rc = template_attribute_find(priv_templ, CKA_IBM_OPAQUE, &opaque_attr); if (rc == TRUE) { @@ -5648,11 +8394,30 @@ return CKR_TEMPLATE_INCONSISTENT; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } +#ifndef NO_PKEY + /* Check protected key related attributes in the secure key token */ + rc = ccatok_pkey_check_attrs(tokdata, priv_templ, opaque_attr->pValue, + opaque_attr->ulValueLen, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("%s ccatok_pkey_check_attrs failed with rc=0x%lx\n", __func__, rc); + return rc; + } +#endif /* NO_PKEY */ + + rc = cca_reencipher_created_key(tokdata, priv_templ, + opaque_attr->pValue, + opaque_attr->ulValueLen, + new_mk, token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* check curve and add CKA_EC_PARAMS attribute */ t = opaque_attr->pValue; rc = check_cca_ec_type_and_add_params(t[8+9], token_keybitsize, priv_templ); @@ -5688,9 +8453,10 @@ CK_ULONG privlen = 0, publen = 0; uint8_t curve_type; uint16_t curve_bitlen; + int curve_nid; /* Check if curve supported and determine curve type and bitlen */ - rc = curve_supported(priv_templ, &curve_type, &curve_bitlen); + rc = curve_supported(priv_templ, &curve_type, &curve_bitlen, &curve_nid); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; @@ -5739,15 +8505,28 @@ key_token_length = CCA_KEY_TOKEN_SIZE; key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; - dll_CSNDPKB(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &key_value_structure_length, key_value_structure, - &private_key_name_length, private_key_name, - ¶m1, param2, ¶m1, param2, ¶m1, param2, - ¶m1, param2, ¶m1, param2, - &key_token_length, - key_token); +#ifndef NO_PKEY + /* Add protected key related attributes to the rule array */ + rc = ccatok_pkey_add_attrs(tokdata, priv_templ, CKK_EC, curve_type, + curve_bitlen, rule_array, sizeof(rule_array), + (CK_ULONG *)&rule_array_count); + if (rc != CKR_OK) { + TRACE_ERROR("%s ccatok_pkey_add_attrs failed with rc=0x%lx\n", __func__, rc); + return rc; + } +#endif /* NO_PKEY */ + + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, &reason_code, + &exit_data_len, exit_data, + &rule_array_count, rule_array, + &key_value_structure_length, key_value_structure, + &private_key_name_length, private_key_name, + ¶m1, param2, ¶m1, param2, ¶m1, param2, + ¶m1, param2, ¶m1, param2, + &key_token_length, + key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," @@ -5763,11 +8542,13 @@ key_token_length = CCA_KEY_TOKEN_SIZE; target_key_token_length = CCA_KEY_TOKEN_SIZE; - dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, - &rule_array_count, rule_array, - &key_token_length, key_token, - transport_key_identifier, - &target_key_token_length, target_key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, + &rule_array_count, rule_array, + &key_token_length, key_token, + transport_key_identifier, + &target_key_token_length, target_key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (EC KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", @@ -5785,11 +8566,19 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, token_type, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, token_type, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, priv_templ, target_key_token, + target_key_token_length, new_mk, + token_type); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* Add key token to template as CKA_IBM_OPAQUE */ if ((rc = build_update_attribute(priv_templ, CKA_IBM_OPAQUE, target_key_token, target_key_token_length))) { @@ -5807,7 +8596,7 @@ return CKR_OK; } -static CK_RV import_ec_pubkey(TEMPLATE *pub_templ) +static CK_RV import_ec_pubkey(STDLL_TokData_t *tokdata, TEMPLATE *pub_templ) { CK_RV rc; CK_ATTRIBUTE *opaque_attr = NULL; @@ -5879,13 +8668,14 @@ unsigned char *param2=NULL; uint8_t curve_type; uint16_t curve_bitlen; + int curve_nid; CK_BYTE *pubkey = NULL; CK_ULONG publen = 0; CK_ATTRIBUTE *attr = NULL; CK_ULONG field_len; /* Check if curve supported and determine curve type and bitlen */ - rc = curve_supported(pub_templ, &curve_type, &curve_bitlen); + rc = curve_supported(pub_templ, &curve_type, &curve_bitlen, &curve_nid); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; @@ -5910,6 +8700,7 @@ rc = build_public_EC_key_value_structure(pubkey, publen, curve_type, curve_bitlen, + curve_nid, (unsigned char *)&key_value_structure, &key_value_structure_length); if (rc != CKR_OK) @@ -5922,15 +8713,17 @@ key_token_length = CCA_KEY_TOKEN_SIZE; key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; - dll_CSNDPKB(&return_code, &reason_code, - &exit_data_len, exit_data, - &rule_array_count, rule_array, - &key_value_structure_length, key_value_structure, - &private_key_name_length, private_key_name, - ¶m1, param2, ¶m1, param2, ¶m1, param2, - ¶m1, param2, ¶m1, param2, - &key_token_length, - key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDPKB(&return_code, &reason_code, + &exit_data_len, exit_data, + &rule_array_count, rule_array, + &key_value_structure_length, key_value_structure, + &private_key_name_length, private_key_name, + ¶m1, param2, ¶m1, param2, ¶m1, param2, + ¶m1, param2, ¶m1, param2, + &key_token_length, + key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," @@ -5994,7 +8787,7 @@ switch(keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object - rc = import_rsa_pubkey(object->template); + rc = import_rsa_pubkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("RSA public key import failed, rc=0x%lx\n", rc); return rc; @@ -6042,7 +8835,7 @@ switch(keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object - rc = import_ec_pubkey(object->template); + rc = import_ec_pubkey(tokdata, object->template); if (rc != CKR_OK) { TRACE_DEVEL("ECpublic key import failed, rc=0x%lx\n", rc); return rc; @@ -6089,6 +8882,7 @@ enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; if (((struct cca_private_data *)tokdata->private_data)->inconsistent) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); @@ -6112,10 +8906,12 @@ memcpy(rule_array, "INTERNALHMAC MAC GENERATE", 4 * CCA_KEYWORD_SIZE); - dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, &clear_key_length, NULL, &key_name_length, - NULL, &user_data_length, NULL, &zero_length, NULL, - &zero_length, NULL, &key_token_length, key_token); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, &clear_key_length, NULL, &key_name_length, + NULL, &user_data_length, NULL, &zero_length, NULL, + &zero_length, NULL, &key_token_length, key_token); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." @@ -6144,12 +8940,16 @@ */ memcpy(key_type2, " ", CCA_KEYWORD_SIZE); - dll_CSNBKGN2(&return_code, &reason_code, &zero_length, NULL, - &rule_array_count, rule_array, &clear_key_length, key_type1, - key_type2, &key_name_length, NULL, &key_name_length, NULL, - &user_data_length, NULL, &user_data_length, NULL, &zero_length, - NULL, &zero_length, NULL, &key_token_length, key_token, - &zero_length, NULL); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKGN2(&return_code, &reason_code, &zero_length, NULL, + &rule_array_count, rule_array, + &clear_key_length, key_type1, + key_type2, &key_name_length, NULL, &key_name_length, NULL, + &user_data_length, NULL, &user_data_length, NULL, + &zero_length, NULL, &zero_length, NULL, + &key_token_length, key_token, + &zero_length, NULL); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN2 (HMAC KEY GENERATE) failed." @@ -6164,11 +8964,18 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, keytype, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, template, key_token, + key_token_length, new_mk, keytype); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + /* Add the key object to the template */ rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key); @@ -6190,7 +8997,8 @@ return CKR_OK; } -static CK_RV ccatok_wrap_key_rsa_pkcs(CK_MECHANISM *mech, CK_BBOOL length_only, +static CK_RV ccatok_wrap_key_rsa_pkcs(STDLL_TokData_t *tokdata, + CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) @@ -6322,10 +9130,16 @@ return rc; } - dll_CSNDSYX(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, (long *)&key_opaque->ulValueLen, - key_opaque->pValue, (long *)&wrap_key_opaque->ulValueLen, - wrap_key_opaque->pValue, &buffer_len, buffer); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDSYX(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, (long *)&key_opaque->ulValueLen, + key_opaque->pValue, (long *)&wrap_key_opaque->ulValueLen, + wrap_key_opaque->pValue, &buffer_len, buffer); + RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, + key_opaque->pValue, key_opaque->ulValueLen, + wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYX (SYMMETRIC KEY EXPORT) failed." @@ -6369,6 +9183,7 @@ enum cca_token_type keytype; unsigned int keybitsize; const CK_BYTE *mkvp; + CK_BBOOL new_mk; uint16_t val; CK_RV rc; @@ -6483,10 +9298,15 @@ return rc; } - dll_CSNDSYI(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, (long *)&wrapped_key_len, wrapped_key, - (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, - &buffer_len, buffer); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNDSYI(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, (long *)&wrapped_key_len, wrapped_key, + (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, + &buffer_len, buffer); + RETRY_NEW_MK_BLOB_END(tokdata, return_code, reason_code, + wrap_key_opaque->pValue, wrap_key_opaque->ulValueLen) + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYI (SYMMETRIC KEY IMPORT) failed." @@ -6506,11 +9326,18 @@ return CKR_FUNCTION_FAILED; } - if (check_expected_mkvp(tokdata, keytype, mkvp) != CKR_OK) { + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } + rc = cca_reencipher_created_key(tokdata, key->template, buffer, buffer_len, + new_mk, keytype); + if (rc != CKR_OK) { + TRACE_ERROR("cca_reencipher_created_key failed: 0x%lx\n", rc); + return rc; + } + switch (buffer[4]) { case 0x00: /* DES key token */ case 0x01: /* DES3 key token */ @@ -6645,7 +9472,8 @@ if (wrap_key_class != CKO_PUBLIC_KEY && wrap_key_type != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; - return ccatok_wrap_key_rsa_pkcs(mech, length_only, wrapping_key, key, + return ccatok_wrap_key_rsa_pkcs(tokdata, + mech, length_only, wrapping_key, key, wrapped_key, wrapped_key_len); default: return CKR_MECHANISM_INVALID; @@ -6948,13 +9776,19 @@ return CKR_BUFFER_TOO_SMALL; } - dll_CSNBCTT2(&return_code, &reason_code, NULL, NULL, &rule_array_count, - rule_array, (long *)&decr_key_opaque->ulValueLen, - decr_key_opaque->pValue, &in_iv_len, in_iv, - (long *)&in_data_len, in_data, &cv_len, cv, - (long *)&encr_key_opaque->ulValueLen, encr_key_opaque->pValue, - &out_iv_len, out_iv, (long *)out_data_len, out_data, - &zero, NULL, &zero, NULL); + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + RETRY_NEW_MK_BLOB_START() + dll_CSNBCTT2(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, (long *)&decr_key_opaque->ulValueLen, + decr_key_opaque->pValue, &in_iv_len, in_iv, + (long *)&in_data_len, in_data, &cv_len, cv, + (long *)&encr_key_opaque->ulValueLen, encr_key_opaque->pValue, + &out_iv_len, out_iv, (long *)out_data_len, out_data, + &zero, NULL, &zero, NULL); + RETRY_NEW_MK_BLOB2_END(tokdata, return_code, reason_code, + encr_key_opaque->pValue, encr_key_opaque->ulValueLen, + decr_key_opaque->pValue, decr_key_opaque->ulValueLen); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCTT2 (CIPHER TEXT TRANSLATE) failed." @@ -7014,6 +9848,9 @@ char buf[250]; CK_RV rc; unsigned long val; +#ifndef NO_PKEY + unsigned int min_card_version; +#endif UNUSED(event_type); @@ -7026,7 +9863,7 @@ if ((val & MASK_COPRO) == 0) return CKR_OK; - TRACE_DEVEL("%s Cross checking MKVPs due to event for APQN %02x.%04x\n", + TRACE_DEVEL("%s Cross checking MKVPs due to event for APQN %02X.%04X\n", __func__, apqn_data->card, apqn_data->domain); rc = cca_check_mks(tokdata); @@ -7034,13 +9871,1704 @@ __sync_or_and_fetch(&cca_private->inconsistent, TRUE); TRACE_ERROR("CCA master key setup is inconsistent, all crypto operations will fail from now on\n"); OCK_SYSLOG(LOG_ERR, "CCA master key setup is inconsistent, all crypto operations will fail from now on\n"); - } else { - __sync_and_and_fetch(&cca_private->inconsistent, FALSE); + return CKR_OK; + } + + __sync_and_and_fetch(&cca_private->inconsistent, FALSE); + + /* Re-check after APQN set change if protected key support is available */ + rc = cca_get_min_card_level(tokdata); + if (rc != CKR_OK) { + TRACE_WARNING("Could not re-determine min card level, protected key support not available.\n"); + return rc; + } + +#ifndef NO_PKEY + /* Read min card version from CCA private data. Needs a read lock.*/ + if (pthread_rwlock_rdlock(&cca_private->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RD-Lock failed.\n"); + return CKR_CANT_LOCK; + } + min_card_version = cca_private->min_card_version.ver; + if (pthread_rwlock_unlock(&cca_private->min_card_version_rwlock) != 0) { + TRACE_ERROR("CCA min_card_version RD-Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + /* Check minimum card version, XPRTCPAC requires min CEX7C */ + if (min_card_version < 7) { + TRACE_WARNING("Min card version now is %d, protected key support not available on this system.\n", + cca_private->min_card_version.ver); + /* Disable pkey */ + __sync_and_and_fetch(&cca_private->pkey_wrap_supported, 0); + } else if (cca_private->pkey_wrap_supported == 0 && + !ccatok_pkey_option_disabled(tokdata)) { + /* get firmware WKVP, this will enable PKEY on success */ + rc = ccatok_pkey_get_firmware_wkvp(tokdata); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_WARNING, + "%s: Warning: Could not get wkvp, protected key support not available.\n", + __func__); + TRACE_WARNING("Could not get wkvp, protected key support not available.\n"); + } + } +#endif /* NO_PKEY */ + + return CKR_OK; +} + +struct cca_affected_data { + struct hsm_mk_change_info *info; + CK_BBOOL affected; +}; + +static CK_RV cca_mk_change_is_affected_cb(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private) +{ + struct cca_affected_data *ad = private; + + UNUSED(tokdata); + + if (hsm_mk_change_apqns_find(ad->info->apqns, ad->info->num_apqns, + card, domain)) { + TRACE_DEVEL("%s APQN %02X.%04X (%s) is affected by MK change\n", + __func__, card, domain, adapter); + ad->affected = TRUE; + } + + return CKR_OK; +} + +static CK_RV cca_mk_change_is_affected(STDLL_TokData_t *tokdata, + struct hsm_mk_change_info *info) +{ + unsigned int i; + CK_BBOOL affected = FALSE; + struct cca_affected_data ad; + CK_RV rc; + + for (i = 0; i < info->num_mkvps; i++) { + TRACE_DEVEL("%s MK type: %d\n", __func__, info->mkvps[i].type); + switch (info->mkvps[i].type) { + case HSM_MK_TYPE_CCA_SYM: + case HSM_MK_TYPE_CCA_AES: + case HSM_MK_TYPE_CCA_APKA: + affected = TRUE; + break; + default: + break; + } + } + if (!affected) + goto out; + + ad.info = info; + ad.affected = FALSE; + rc = cca_iterate_adapters(tokdata, cca_mk_change_is_affected_cb, &ad); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); + return rc; + } + + affected = ad.affected; + +out: + TRACE_DEVEL("%s affected: %d\n", __func__, affected); + + return affected ? CKR_OK : CKR_FUNCTION_NOT_SUPPORTED; +} + +static unsigned char *cca_mk_change_find_mkvp_in_ops(STDLL_TokData_t *tokdata, + enum cca_mk_type mk_type, + unsigned int *idx) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned int i; + + for (i = 0; i < CCA_NUM_MK_TYPES; i++) { + if (cca_private->mk_change_ops[i].mk_change_active) { + switch (mk_type) { + case CCA_MK_SYM: + if (cca_private->mk_change_ops[i].new_sym_mkvp_set) { + if (idx != NULL) + *idx = i; + return cca_private->mk_change_ops[i].new_sym_mkvp; + } + break; + case CCA_MK_AES: + if (cca_private->mk_change_ops[i].new_aes_mkvp_set) { + if (idx != NULL) + *idx = i; + return cca_private->mk_change_ops[i].new_aes_mkvp; + } + break; + case CCA_MK_APKA: + if (cca_private->mk_change_ops[i].new_apka_mkvp_set) { + if (idx != NULL) + *idx = i; + return cca_private->mk_change_ops[i].new_apka_mkvp; + } + break; + default: + break; + } + } + } + + return NULL; +} + +static struct cca_mk_change_op *cca_mk_change_find_op(STDLL_TokData_t *tokdata, + const char *op, + unsigned int *idx) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned int i; + + for (i = 0; i < CCA_NUM_MK_TYPES; i++) { + if (cca_private->mk_change_ops[i].mk_change_active && + strcmp(cca_private->mk_change_ops[i].mk_change_op, op) == 0) { + if (idx != NULL) + *idx = i; + return &cca_private->mk_change_ops[i]; + } + } + + return NULL; +} + +static CK_RV cca_mk_change_activate_op(STDLL_TokData_t *tokdata, const char *id, + struct hsm_mk_change_info *info, + const unsigned char *new_sym_mk, + const unsigned char *new_aes_mk, + const unsigned char *new_apka_mk, + unsigned int *idx) +{ + struct cca_private_data *cca_private = tokdata->private_data; + unsigned int i; + int op_idx; + + /* Find a free operation slot */ + for (i = 0, op_idx = -1; i < CCA_NUM_MK_TYPES; i++) { + if (cca_private->mk_change_ops[i].mk_change_active == FALSE) { + op_idx = i; + break; + } + } + if (op_idx == -1) { + TRACE_ERROR("%s More than %d MK change ops are already active\n", + __func__, CCA_NUM_MK_TYPES); + return CKR_FUNCTION_FAILED; + } + + /* remember the infos of this MK change op */ + memset(&cca_private->mk_change_ops[op_idx], 0, + sizeof(cca_private->mk_change_ops[op_idx])); + strncpy(cca_private->mk_change_ops[op_idx].mk_change_op, id, + sizeof(cca_private->mk_change_ops[op_idx].mk_change_op) - 1); + cca_private->mk_change_ops[op_idx].mk_change_op + [sizeof(cca_private->mk_change_ops[op_idx].mk_change_op) - 1] = '\0'; + + if (new_sym_mk != NULL) { + memcpy(cca_private->mk_change_ops[op_idx].new_sym_mkvp, new_sym_mk, + CCA_MKVP_LENGTH); + cca_private->mk_change_ops[op_idx].new_sym_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("New SYM MK: ", (void *)new_sym_mk, + CCA_MKVP_LENGTH); + } + if (new_aes_mk != NULL) { + memcpy(cca_private->mk_change_ops[op_idx].new_aes_mkvp, new_aes_mk, + CCA_MKVP_LENGTH); + cca_private->mk_change_ops[op_idx].new_aes_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("New AES MK: ", (void *)new_aes_mk, + CCA_MKVP_LENGTH); + } + if (new_apka_mk != NULL) { + memcpy(cca_private->mk_change_ops[op_idx].new_apka_mkvp, new_apka_mk, + CCA_MKVP_LENGTH); + cca_private->mk_change_ops[op_idx].new_apka_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("New APKA MK: ", (void *)new_apka_mk, + CCA_MKVP_LENGTH); + } + + cca_private->mk_change_ops[op_idx].apqns = calloc(info->num_apqns, + sizeof(struct apqn)); + if (cca_private->mk_change_ops[op_idx].apqns == NULL) { + TRACE_ERROR("%s Failed to allocate list of MK change APQNs\n", + __func__); + return CKR_HOST_MEMORY; + } + + cca_private->mk_change_ops[op_idx].num_apqns = info->num_apqns; + memcpy(cca_private->mk_change_ops[op_idx].apqns, info->apqns, + info->num_apqns * sizeof(struct apqn)); + + cca_private->mk_change_ops[op_idx].mk_change_active = TRUE; + + TRACE_DEVEL("%s active MK change op (idx %u): %s\n", __func__, op_idx, + cca_private->mk_change_ops[op_idx].mk_change_op); + OCK_SYSLOG(LOG_INFO, "Slot %lu: A concurrent HSM master key change " + "operation (%s) is active for CCA %s%s%s%s%s\n", + tokdata->slot_id, + cca_private->mk_change_ops[op_idx].mk_change_op, + new_sym_mk != NULL ? "SYM" : "", + (new_sym_mk != NULL && new_aes_mk != NULL) ? ", " : "", + new_aes_mk != NULL ? "AES" : "", + ((new_aes_mk != NULL && new_apka_mk != NULL) || + (new_aes_mk == NULL && new_sym_mk != NULL && + new_apka_mk != NULL)) ? ", " : "", + new_apka_mk != NULL ? "APKA" : ""); + + *idx = op_idx; + + return CKR_OK; +} + +static CK_RV cca_mk_change_check_pending_ops_cb(struct hsm_mk_change_op *op, + void *private) +{ + STDLL_TokData_t *tokdata = private; + struct cca_private_data *cca_private; + struct hsm_mkvp *mkvps = NULL; + unsigned int num_mkvps = 0; + unsigned int i; + const unsigned char *new_sym_mk = NULL; + const unsigned char *new_aes_mk = NULL; + const unsigned char *new_apka_mk = NULL; + const unsigned char *mkvp; + CK_RV rc; + + cca_private = tokdata->private_data; + + rc = cca_mk_change_is_affected(tokdata, &op->info); + if (rc != CKR_OK) + return CKR_OK; + + new_sym_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, + HSM_MK_TYPE_CCA_SYM, + CCA_MKVP_LENGTH); + new_aes_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, + HSM_MK_TYPE_CCA_AES, + CCA_MKVP_LENGTH); + new_apka_mk = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, + HSM_MK_TYPE_CCA_APKA, + CCA_MKVP_LENGTH); + if (new_sym_mk == NULL && new_aes_mk == NULL && new_apka_mk == NULL) { + TRACE_ERROR("%s No CCA MK type found in MK change operation: %s\n", + __func__, op->id); + return CKR_FUNCTION_FAILED; + } + + switch (op->state) { + case HSM_MK_CH_STATE_REENCIPHERING: + case HSM_MK_CH_STATE_REENCIPHERED: + /* + * There can be up to 3 active MK change ops for the CCA token, + * one for each MK type, if the MKs are changed individually. + * However, these ops can not have intersecting MK types. + * No need to have the hsm_mk_change_rwlock, we're in token init + * function, and the API layer starts the event thread only after all + * token init's have been performed. + */ + if (new_sym_mk != NULL && + cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_SYM, &i) != NULL) { + TRACE_ERROR("%s Another MK change for CCA SYM is already " + "active: %s\n", __func__, + cca_private->mk_change_ops[i].mk_change_op); + return CKR_FUNCTION_FAILED; + } + if (new_aes_mk != NULL && + cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_AES, &i) != NULL) { + TRACE_ERROR("%s Another MK change for CCA AES is already " + "active: %s\n", __func__, + cca_private->mk_change_ops[i].mk_change_op); + return CKR_FUNCTION_FAILED; + } + if (new_apka_mk != NULL && + cca_mk_change_find_mkvp_in_ops(tokdata, CCA_MK_APKA, &i) != NULL) { + TRACE_ERROR("%s Another MK change for CCA APKA is already " + "active: %s\n", __func__, + cca_private->mk_change_ops[i].mk_change_op); + return CKR_FUNCTION_FAILED; + } + + rc = cca_mk_change_activate_op(tokdata, op->id, &op->info, + new_sym_mk, new_aes_mk, new_apka_mk, + &i); + if (rc != CKR_OK) + return rc; + + /* Load expected current MKVPs */ + rc = hsm_mk_change_token_mkvps_load(op->id, tokdata->slot_id, + &mkvps, &num_mkvps); + /* Ignore if this failed, no expected current MKVP is set then */ + if (rc == CKR_OK) { + mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, + HSM_MK_TYPE_CCA_SYM, + CCA_MKVP_LENGTH); + if (mkvp != NULL) { + memcpy(cca_private->expected_sym_mkvp, mkvp, CCA_MKVP_LENGTH); + cca_private->expected_sym_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("Current SYM MKVP: ", + cca_private->expected_sym_mkvp, + CCA_MKVP_LENGTH); + } + + mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, + HSM_MK_TYPE_CCA_AES, + CCA_MKVP_LENGTH); + if (mkvp != NULL) { + memcpy(cca_private->expected_aes_mkvp, mkvp, CCA_MKVP_LENGTH); + cca_private->expected_aes_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("Current AES MKVP: ", + cca_private->expected_aes_mkvp, + CCA_MKVP_LENGTH); + } + + mkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, + HSM_MK_TYPE_CCA_APKA, + CCA_MKVP_LENGTH); + if (mkvp != NULL) { + memcpy(cca_private->expected_apka_mkvp, mkvp, CCA_MKVP_LENGTH); + cca_private->expected_apka_mkvp_set = TRUE; + TRACE_DEBUG_DUMP("Current APKA MKVP: ", + cca_private->expected_apka_mkvp, + CCA_MKVP_LENGTH); + } + } + break; + + default: + break; + } + + if (mkvps != NULL) { + hsm_mk_change_mkvps_clean(mkvps, num_mkvps); + free(mkvps); } return CKR_OK; } +static CK_RV cca_mk_change_check_pending_ops(STDLL_TokData_t *tokdata) +{ + CK_RV rc; + + rc = hsm_mk_change_lock_create(); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_lock(FALSE); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_op_iterate(cca_mk_change_check_pending_ops_cb, + tokdata); + + hsm_mk_change_unlock(); + +out: + hsm_mk_change_lock_destroy(); + + return rc; +} + + +static const char *mk_type_to_string(enum cca_mk_type mk_type) +{ + switch (mk_type) { + case CCA_MK_SYM: + return "SYM"; + case CCA_MK_AES: + return "AES"; + case CCA_MK_APKA: + return "APKA"; + default: + return "UNKNOWN"; + } +} + +static CK_RV cca_check_token_config_expected_mkvp(STDLL_TokData_t *tokdata, + struct cca_mk_change_op *mk_change_op, + CK_BBOOL new_mk) +{ + struct cca_private_data *cca_private = tokdata->private_data; + FILE *file; + struct ConfigBaseNode *c, *config = NULL; + struct ConfigStructNode *struct_node; + unsigned char exp_sym_mkvp[CCA_MKVP_LENGTH]; + unsigned char exp_aes_mkvp[CCA_MKVP_LENGTH]; + unsigned char exp_apka_mkvp[CCA_MKVP_LENGTH]; + CK_BBOOL exp_sym_mkvp_set = FALSE; + CK_BBOOL exp_aes_mkvp_set = FALSE; + CK_BBOOL exp_apka_mkvp_set = FALSE; + CK_RV rc = CKR_OK; + int ret, i; + + if (cca_private->token_config_filename[0] == '\0') + return CKR_OK; + + file = fopen(cca_private->token_config_filename, "r"); + if (file == NULL) { + TRACE_ERROR("%s fopen('%s') failed with errno: %s\n", __func__, + cca_private->token_config_filename, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + ret = parse_configlib_file(file, &config, cca_config_parse_error, 0); + if (ret != 0) { + TRACE_ERROR("Error parsing config file '%s'\n", + cca_private->token_config_filename); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + confignode_foreach(c, config, i) { + TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", + c->key, c->type, c->line); + + if (confignode_hastype(c, CT_STRUCT)) { + struct_node = confignode_to_struct(c); + if (strcasecmp(struct_node->base.key, + CCA_CFG_EXPECTED_MKVPS) == 0) { + rc = cca_config_parse_exp_mkvps( + cca_private->token_config_filename, struct_node, + exp_sym_mkvp, &exp_sym_mkvp_set, + exp_aes_mkvp, &exp_aes_mkvp_set, + exp_apka_mkvp, &exp_apka_mkvp_set); + if (rc != CKR_OK) + break; + continue; + } + } + } + + if (mk_change_op->new_sym_mkvp_set && exp_sym_mkvp_set && + memcmp(exp_sym_mkvp, new_mk ? mk_change_op->new_sym_mkvp : + cca_private->expected_sym_mkvp, + CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("Expected SYM MKVP in config file '%s' does not specify " + "the %s MKVP\n", cca_private->token_config_filename, + new_mk ? "new" : "current"); + warnx("Expected SYM MKVP in config file '%s' does not specify the %s " + "MKVP.", cca_private->token_config_filename, + new_mk ? "new" : "current"); + rc = CKR_FUNCTION_FAILED; + } + + if (mk_change_op->new_aes_mkvp_set && exp_aes_mkvp_set && + memcmp(exp_aes_mkvp, new_mk ? mk_change_op->new_aes_mkvp : + cca_private->expected_aes_mkvp, + CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("Expected AES MKVP in config file '%s' does not specify " + "the %s MKVP\n", cca_private->token_config_filename, + new_mk ? "new" : "current"); + warnx("Expected AES MKVP in config file '%s' does not specify the %s " + "MKVP.", cca_private->token_config_filename, + new_mk ? "new" : "current"); + rc = CKR_FUNCTION_FAILED; + } + + if (mk_change_op->new_apka_mkvp_set && exp_apka_mkvp_set && + memcmp(exp_apka_mkvp, new_mk ? mk_change_op->new_apka_mkvp : + cca_private->expected_apka_mkvp, + CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("Expected APKA MKVP in config file '%s' does not specify " + "the %s MKVP\n", cca_private->token_config_filename, + new_mk ? "new" : "current"); + warnx("Expected APKA MKVP in config file '%s' does not specify the %s " + "MKVP.", cca_private->token_config_filename, + new_mk ? "new" : "current"); + rc = CKR_FUNCTION_FAILED; + } + +done: + confignode_deepfree(config); + fclose(file); + + return rc; +} + +static CK_RV cca_mk_change_apqn_check_mk_state(enum cca_mk_type mk_type, + const char *adapter, + unsigned short card, + unsigned short domain, + CK_SLOT_ID slot, + CK_BBOOL finalize, + CK_BBOOL cancel, + CK_BBOOL *error) +{ + const char *mk_type_str = mk_type_to_string(mk_type); + enum cca_cmk_state cur_mk_state; + enum cca_nmk_state new_mk_state; + CK_RV rc; + + rc = cca_get_mk_state(mk_type, &cur_mk_state, &new_mk_state); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mk_state (%s) failed for %s (%02X.%04X)\n", + mk_type_str, adapter, card, domain); + return rc; + } + + /* Ensure that a current master key is set in the card */ + if (cur_mk_state != CCA_CMK_STATUS_FULL) { + TRACE_ERROR("%s No CURRENT CCA %s master key is set on APQN %02X.%04X (%s)\n", + __func__, mk_type_str, card, domain, adapter); + warnx("Slot %lu: No CURRENT CCA %s master key is set on APQN %02X.%04X (%s)", + slot, mk_type_str, card, domain, adapter); + *error = TRUE; + } + + if (finalize) { + /* Ensure that the new master key register is empty */ + if (new_mk_state != CCA_NMK_STATUS_CLEAR) { + TRACE_ERROR("%s The NEW CCA %s master key register must be empty on APQN %02X.%04X (%s)\n", + __func__, mk_type_str, card, domain, adapter); + warnx("Slot %lu: The NEW CCA %s master key register must be empty on APQN %02X.%04X (%s)", + slot, mk_type_str, card, domain, adapter); + *error = TRUE; + } + } else if (!cancel) { + /* Ensure that the new master key is set in the card */ + if (new_mk_state != CCA_NMK_STATUS_FULL) { + TRACE_ERROR("%s No NEW CCA %s master key is set on APQN %02X.%04X (%s)\n", + __func__, mk_type_str, card, domain, adapter); + warnx("Slot %lu: No NEW CCA %s master key is set on APQN %02X.%04X (%s)", + slot, mk_type_str, card, domain, adapter); + *error = TRUE; + } + } + + return CKR_OK; +} + +static void cca_mk_change_apqn_check_mkvp(enum cca_mk_type mk_type, + const unsigned char *queried_mkvp, + const unsigned char *expected_mkvp, + const char *adapter, + unsigned short card, + unsigned short domain, + CK_SLOT_ID slot, + CK_BBOOL new_mk, + const char *msg, + CK_BBOOL *error) +{ + const char *mk_type_str = mk_type_to_string(mk_type); + + if (memcmp(queried_mkvp, expected_mkvp, CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("%s CCA %s master key on APQN %02X.%04X (%s) does not " + "match the %s master key\n", + new_mk ? "NEW" : "CURRENT", mk_type_str, card, domain, + adapter, msg); + warnx("Slot %lu: The %s CCA %s MK on APQN %02X.%04X (%s) does not " + "match the %s MKVP", slot, new_mk ? "NEW" : "CURRENT", + mk_type_str, card, domain, adapter, msg); + *error = TRUE; + } +} + +struct apqn_check_data { + CK_SLOT_ID slot; + event_mk_change_data_t *op; + struct hsm_mk_change_info *info; + const unsigned char *sym_new_mk; + const unsigned char *aes_new_mk; + const unsigned char *apka_new_mk; + CK_BBOOL finalize; + CK_BBOOL cancel; + CK_BBOOL error; +}; + +static CK_RV cca_mk_change_apqn_check_cb(STDLL_TokData_t *tokdata, + const char *adapter, + unsigned short card, + unsigned short domain, + void *private) +{ + struct cca_private_data *cca_private = tokdata->private_data; + struct apqn_check_data *ac = (struct apqn_check_data *)private; + unsigned char sym_cur_mkvp[CCA_MKVP_LENGTH]; + unsigned char sym_new_mkvp[CCA_MKVP_LENGTH]; + unsigned char aes_cur_mkvp[CCA_MKVP_LENGTH]; + unsigned char aes_new_mkvp[CCA_MKVP_LENGTH]; + unsigned char apka_cur_mkvp[CCA_MKVP_LENGTH]; + unsigned char apka_new_mkvp[CCA_MKVP_LENGTH]; + CK_RV rc; + + /* Check that this APQN is part of the MK change operation */ + if (hsm_mk_change_apqns_find(ac->info->apqns, ac->info->num_apqns, + card, domain) == FALSE) { + TRACE_ERROR("%s APQN %02X.%04X (%s) is not part of MK change '%s'\n", + __func__, card, domain, adapter, ac->op->id); + warnx("Slot %lu: APQN %02X.%04X must be included into this operation.", + ac->slot, card, domain); + + ac->error = TRUE; + return CKR_OK; + } + + if (ac->sym_new_mk != NULL) { + /* Check status of AES master key (DES, 3DES keys) */ + rc = cca_mk_change_apqn_check_mk_state(CCA_MK_SYM, adapter, card, + domain, ac->slot, + ac->finalize, ac->cancel, + &ac->error); + if (rc != CKR_OK) + return rc; + } + + if (ac->aes_new_mk != NULL) { + /* Check status of AES master key (AES, HMAC keys) */ + rc = cca_mk_change_apqn_check_mk_state(CCA_MK_AES, adapter, card, + domain, ac->slot, + ac->finalize, ac->cancel, + &ac->error); + if (rc != CKR_OK) + return rc; + } + + if (ac->apka_new_mk != NULL) { + /* Check status of APKA master key (RSA and ECC keys) */ + rc = cca_mk_change_apqn_check_mk_state(CCA_MK_APKA, adapter, card, + domain, ac->slot, + ac->finalize, ac->cancel, + &ac->error); + if (rc != CKR_OK) + return rc; + } + + /* Get master key verification patterns */ + rc = cca_get_mkvps(sym_cur_mkvp, sym_new_mkvp, aes_cur_mkvp, aes_new_mkvp, + apka_cur_mkvp, apka_new_mkvp); + if (rc != CKR_OK) { + TRACE_ERROR("cca_get_mkvps failed for %s (%02X.%04X)\n", + adapter, card, domain); + return rc; + } + + TRACE_DEBUG("Master key verification patterns for %s (%02X.%04X)\n", + adapter, card, domain); + TRACE_DEBUG_DUMP("SYM CUR MKVP: ", sym_cur_mkvp, CCA_MKVP_LENGTH); + TRACE_DEBUG_DUMP("SYM NEW MKVP: ", sym_new_mkvp, CCA_MKVP_LENGTH); + TRACE_DEBUG_DUMP("AES CUR MKVP: ", aes_cur_mkvp, CCA_MKVP_LENGTH); + TRACE_DEBUG_DUMP("AES NEW MKVP: ", aes_new_mkvp, CCA_MKVP_LENGTH); + TRACE_DEBUG_DUMP("APKA CUR MKVP: ", apka_cur_mkvp, CCA_MKVP_LENGTH); + TRACE_DEBUG_DUMP("APKA NEW MKVP: ", apka_new_mkvp, CCA_MKVP_LENGTH); + + /* Current MKs (only those included in the op) must be the expected MKs */ + if (ac->sym_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_SYM, sym_cur_mkvp, + ac->finalize ? + ac->sym_new_mk : + cca_private->expected_sym_mkvp, + adapter, card, domain, ac->slot, + FALSE, ac->finalize ? "operation's NEW" : + "expected", + &ac->error); + if (ac->aes_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_AES, aes_cur_mkvp, + ac->finalize ? + ac->aes_new_mk : + cca_private->expected_aes_mkvp, + adapter, card, domain, ac->slot, + FALSE, ac->finalize ? "operation's NEW" : + "expected", + &ac->error); + if (ac->apka_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_APKA, apka_cur_mkvp, + ac->finalize ? + ac->apka_new_mk : + cca_private->expected_apka_mkvp, + adapter, card, domain, ac->slot, + FALSE, ac->finalize ? "operation's NEW" : + "expected", + &ac->error); + + if (ac->finalize || ac->cancel) + return CKR_OK; /* Don't check New MKs for finalize or cancel */ + + /* New MKs must be the expected new MKs of the operation */ + if (ac->sym_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_SYM, sym_new_mkvp, ac->sym_new_mk, + adapter, card, domain, ac->slot, TRUE, + "specified", &ac->error); + if (ac->aes_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_AES, aes_new_mkvp, ac->aes_new_mk, + adapter, card, domain, ac->slot, TRUE, + "specified", &ac->error); + if (ac->apka_new_mk != NULL) + cca_mk_change_apqn_check_mkvp(CCA_MK_APKA, apka_new_mkvp, ac->apka_new_mk, + adapter, card, domain, ac->slot, TRUE, + "specified", &ac->error); + + return CKR_OK; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread safe and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_mk_change_init_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + struct cca_private_data *cca_private = tokdata->private_data; + struct apqn_check_data acd; + struct hsm_mkvp mkvps[3]; + unsigned int num_mkvps = 0; + CK_RV rc; + + TRACE_DEVEL("%s initial query for MK change op: %s\n", __func__, op->id); + + memset(&acd, 0, sizeof(acd)); + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + + acd.sym_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_SYM, + CCA_MKVP_LENGTH); + acd.aes_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_AES, + CCA_MKVP_LENGTH); + acd.apka_new_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_APKA, + CCA_MKVP_LENGTH); + + /* Check if selected APQNs have the expected MKs set/loaded */ + rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); + return rc; + } + + if (acd.error) + return CKR_FUNCTION_FAILED; + + /* Save current MKVPs of affected MK types of this token */ + if (acd.sym_new_mk != NULL) { + mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_SYM; + mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; + mkvps[num_mkvps].mkvp = cca_private->expected_sym_mkvp; + num_mkvps++; + } + if (acd.aes_new_mk != NULL) { + mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_AES; + mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; + mkvps[num_mkvps].mkvp = cca_private->expected_aes_mkvp; + num_mkvps++; + } + if (acd.apka_new_mk != NULL) { + mkvps[num_mkvps].type = HSM_MK_TYPE_CCA_APKA; + mkvps[num_mkvps].mkvp_len = CCA_MKVP_LENGTH; + mkvps[num_mkvps].mkvp = cca_private->expected_apka_mkvp; + num_mkvps++; + } + + rc = hsm_mk_change_lock_create(); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_lock(TRUE); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_token_mkvps_save(op->id, tokdata->slot_id, + mkvps, num_mkvps); + + hsm_mk_change_unlock(); + +out: + hsm_mk_change_lock_destroy(); + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_mk_change_finalize_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + struct cca_mk_change_op *mk_change_op; + struct apqn_check_data acd; + CK_RV rc; + + TRACE_DEVEL("%s finalize query for MK change op: %s\n", __func__, op->id); + + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + + mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); + if (mk_change_op == NULL) { + TRACE_ERROR("%s operation '%s' not active\n", __func__, op->id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + memset(&acd, 0, sizeof(acd)); + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + acd.finalize = TRUE; /* New MKs must be current ones */ + + if (mk_change_op->new_sym_mkvp_set) + acd.sym_new_mk = mk_change_op->new_sym_mkvp; + if (mk_change_op->new_aes_mkvp_set) + acd.aes_new_mk = mk_change_op->new_aes_mkvp; + if (mk_change_op->new_apka_mkvp_set) + acd.apka_new_mk = mk_change_op->new_apka_mkvp; + + /* Check if selected APQNs have the expected MKs set/loaded */ + rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); + goto out; + } + + if (acd.error) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = cca_check_token_config_expected_mkvp(tokdata, mk_change_op, TRUE); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_check_token_config_expected_mkvp failed: 0x%lx\n", + __func__, rc); + goto out; + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_mk_change_cancel_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + struct cca_mk_change_op *mk_change_op; + struct apqn_check_data acd; + CK_RV rc; + + TRACE_DEVEL("%s cancel query for MK change op: %s\n", __func__, op->id); + + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + + mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); + if (mk_change_op == NULL) { + TRACE_ERROR("%s operation '%s' not active\n", __func__, op->id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + memset(&acd, 0, sizeof(acd)); + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + acd.cancel = TRUE; /* No new MKs must be set */ + + if (mk_change_op->new_sym_mkvp_set) + acd.sym_new_mk = mk_change_op->new_sym_mkvp; + if (mk_change_op->new_aes_mkvp_set) + acd.aes_new_mk = mk_change_op->new_aes_mkvp; + if (mk_change_op->new_apka_mkvp_set) + acd.apka_new_mk = mk_change_op->new_apka_mkvp; + + /* Check if selected APQNs have the expected MKs set/loaded */ + rc = cca_iterate_adapters(tokdata, cca_mk_change_apqn_check_cb, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_iterate_adapters failed: 0x%lx\n", __func__, rc); + goto out; + } + + if (acd.error) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = cca_check_token_config_expected_mkvp(tokdata, mk_change_op, FALSE); + if (rc != CKR_OK) { + TRACE_ERROR("%s cca_check_token_config_expected_mkvp failed: 0x%lx\n", + __func__, rc); + goto out; + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return rc; +} + +static CK_RV cca_reencipher_sec_key(STDLL_TokData_t *tokdata, + struct cca_mk_change_op *mk_change_op, + CK_BYTE *sec_key, CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, CK_BBOOL from_old) +{ + enum cca_token_type keytype; + unsigned int keybitsize; + const CK_BYTE *mkvp = NULL; + const CK_BYTE *new_mkvp = NULL; + const char *mk_type; + const char *verb; + enum cca_ktc_type ktc_type; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long return_code, reason_code, rule_array_count, exit_data_len = 0; + long token_length = sec_key_len; + + if (analyse_cca_key_token(sec_key, sec_key_len, &keytype, &keybitsize, + &mkvp) == FALSE) { + TRACE_ERROR("%s Blob is not a valid secure key token\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(rule_array, 0, sizeof(rule_array)); + if (from_old) + memcpy(rule_array, "RTCMK ", CCA_KEYWORD_SIZE); + else + memcpy(rule_array, "RTNMK ", CCA_KEYWORD_SIZE); + rule_array_count = 2; + + switch (keytype) { + case sec_des_data_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "DES ", CCA_KEYWORD_SIZE); + mk_type = "SYM"; + new_mkvp = mk_change_op->new_sym_mkvp; + ktc_type = CCA_KTC_DATA; + break; + case sec_aes_data_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "AES ", CCA_KEYWORD_SIZE); + mk_type = "AES"; + new_mkvp = mk_change_op->new_aes_mkvp; + ktc_type = CCA_KTC_DATA; + break; + case sec_aes_cipher_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "AES ", CCA_KEYWORD_SIZE); + mk_type = "AES"; + new_mkvp = mk_change_op->new_aes_mkvp; + ktc_type = CCA_KTC_CIPHER; + break; + case sec_hmac_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "HMAC ", CCA_KEYWORD_SIZE); + mk_type = "AES"; + new_mkvp = mk_change_op->new_aes_mkvp; + ktc_type = CCA_KTC_CIPHER; + break; + case sec_rsa_priv_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "RSA ", CCA_KEYWORD_SIZE); + mk_type = "APKA"; + new_mkvp = mk_change_op->new_apka_mkvp; + ktc_type = CCA_KTC_PKA; + break; + case sec_ecc_priv_key: + memcpy(rule_array + CCA_KEYWORD_SIZE, "ECC ", CCA_KEYWORD_SIZE); + mk_type = "APKA"; + new_mkvp = mk_change_op->new_apka_mkvp; + ktc_type = CCA_KTC_PKA; + break; + default: + TRACE_ERROR("%s Blob is an invalid secure key type: %d\n", + __func__, keytype); + return CKR_FUNCTION_FAILED; + } + + if (new_mkvp == NULL) { + TRACE_ERROR("%s Master key type %s is not affected by operation %s\n", + __func__, mk_type, mk_change_op->mk_change_op); + return CKR_FUNCTION_FAILED; + } + + memcpy(reenc_sec_key, sec_key, sec_key_len); + + switch (ktc_type) { + case CCA_KTC_DATA: + verb = "CSNBKTC"; + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKTC(&return_code, &reason_code, + &exit_data_len, NULL, + &rule_array_count, rule_array, + reenc_sec_key); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + break; + case CCA_KTC_CIPHER: + verb = "CSNBKTC2"; + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNBKTC2(&return_code, &reason_code, + &exit_data_len, NULL, + &rule_array_count, rule_array, + &token_length, reenc_sec_key); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + break; + case CCA_KTC_PKA: + verb = "CSNDKTC"; + USE_CCA_ADAPTER_START(tokdata, return_code, reason_code) + dll_CSNDKTC(&return_code, &reason_code, + &exit_data_len, NULL, + &rule_array_count, rule_array, + &token_length, reenc_sec_key); + USE_CCA_ADAPTER_END(tokdata, return_code, reason_code) + break; + default: + return CKR_FUNCTION_FAILED; + } + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("%s (%s) failed. return:%ld, reason:%ld\n", verb, + rule_array, return_code, reason_code); + if (return_code == 8 && reason_code == 48) + return CKR_DEVICE_ERROR; /* MKVP of key not valid */ + return CKR_FUNCTION_FAILED; + } + + /* check for expected new MK */ + if (analyse_cca_key_token(reenc_sec_key, sec_key_len, &keytype, &keybitsize, + &mkvp) == FALSE) { + TRACE_ERROR("%s Blob is not a valid secure key token\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (memcmp(mkvp, new_mkvp, CCA_MKVP_LENGTH) != 0) { + TRACE_ERROR("%s Re-enciphered key blob is not enciphered by expected " + "new %s MK\n", __func__, mk_type); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Re-enciphered key blob is not enciphered" + " by expected new %s MK\n", tokdata->slot_id, mk_type); + return CKR_DEVICE_ERROR; + } + + return CKR_OK; +} + +struct reencipher_data { + STDLL_TokData_t *tokdata; + struct cca_mk_change_op *mk_change_op; +}; + +static CK_RV cca_reencipher_objects_reenc(CK_BYTE *sec_key, + CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, + void *private) +{ + struct reencipher_data *rd = private; + + return cca_reencipher_sec_key(rd->tokdata, rd->mk_change_op, + sec_key, reenc_sec_key, sec_key_len, FALSE); +} + +static CK_RV cca_reencipher_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + struct reencipher_data *rd = cb_data; + CK_RV rc; + + rc = obj_mgr_reencipher_secure_key(tokdata, obj, + cca_reencipher_objects_reenc, rd); + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_BBOOL cca_reencipher_filter_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *filter_data) +{ + struct cca_mk_change_op *mk_change_op = filter_data; + CK_ATTRIBUTE *attr; + enum cca_token_type keytype; + unsigned int keybitsize; + const CK_BYTE *mkvp = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(obj->template, CKA_IBM_OPAQUE, &attr) == FALSE) + return FALSE; + + if (analyse_cca_key_token(attr->pValue, attr->ulValueLen, + &keytype, &keybitsize, &mkvp) == FALSE) + return FALSE; + + switch (keytype) { + case sec_des_data_key: + return mk_change_op->new_sym_mkvp_set; + + case sec_aes_data_key: + case sec_aes_cipher_key: + case sec_hmac_key: + return mk_change_op->new_aes_mkvp_set; + + case sec_rsa_priv_key: + case sec_ecc_priv_key: + return mk_change_op->new_apka_mkvp_set; + + default: + return FALSE; + } +} + +static CK_BBOOL cca_reencipher_cancel_filter_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *filter_data) +{ + CK_ATTRIBUTE *attr; + + if (template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, + &attr) == FALSE) + return FALSE; + + return cca_reencipher_filter_cb(tokdata, obj, filter_data); +} + +static CK_RV cca_reencipher_cancel_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + CK_RV rc; + + UNUSED(cb_data); + + rc = obj_mgr_reencipher_secure_key_cancel(tokdata, obj); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_BBOOL cca_reencipher_finalize_is_new_mk_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BYTE *sec_key, + CK_ULONG sec_key_len, + void *cb_private) +{ + enum cca_token_type keytype; + unsigned int keybitsize; + const CK_BYTE *mkvp = NULL; + CK_BBOOL new_mk = FALSE; + + UNUSED(cb_private); + UNUSED(obj); + + if (analyse_cca_key_token(sec_key, sec_key_len, + &keytype, &keybitsize, &mkvp) == FALSE) + return FALSE; + + if (check_expected_mkvp(tokdata, keytype, mkvp, &new_mk) != CKR_OK) + return FALSE; + + return new_mk; +} + +static CK_RV cca_reencipher_finalize_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + CK_RV rc; + + UNUSED(cb_data); + + rc = obj_mgr_reencipher_secure_key_finalize(tokdata, obj, + cca_reencipher_finalize_is_new_mk_cb, NULL); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_RV cca_finalize_sessions_cb(STDLL_TokData_t *tokdata, + SESSION *session, CK_ULONG ctx_type, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key, + CK_BYTE *context, CK_ULONG context_len, + CK_BBOOL init_pending, + CK_BBOOL pkey_active, CK_BBOOL recover, + void *private) +{ + struct cca_mk_change_op *mk_change_op = private; + CK_ATTRIBUTE *opaque_attr = NULL; + OBJECT *key_obj = NULL; + CK_OBJECT_CLASS class; + enum cca_token_type keytype; + unsigned int keybitsize; + const CK_BYTE *mkvp; + CK_RV rc; + + UNUSED(session); + UNUSED(ctx_type); + UNUSED(mech); + UNUSED(context); + UNUSED(context_len); + UNUSED(init_pending); + UNUSED(pkey_active); + UNUSED(recover); + + if (key == CK_INVALID_HANDLE) + return CKR_OK; + + /* + * Update the key object from disk if it is a token object, the secure key + * is affected by the MK change operation, and it has been changed by + * another process, i.e. due to re-enciphering of the object by the + * pkcshsm_mk_change tool. + */ + rc = object_mgr_find_in_map_nocache(tokdata, key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get key object: 0x%lx\n", + tokdata->slot_id, rc); + goto done; + } + + if (!object_is_token_object(key_obj)) + goto done; + + rc = template_attribute_get_ulong(key_obj->template, CKA_CLASS, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to get object class: 0x%lx\n", __func__, rc); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get object class: 0x%lx\n", + tokdata->slot_id, rc); + goto done; + } + + switch (class) { + case CKO_PUBLIC_KEY: + case CKO_PRIVATE_KEY: + case CKO_SECRET_KEY: + break; + default: + /* Not a key object */ + goto done; + } + + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, + &opaque_attr)) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + TRACE_ERROR("%s Failed to get CKA_IBM_OPAQUE\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to gCKA_IBM_OPAQUE\n", + tokdata->slot_id); + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + + if (analyse_cca_key_token(opaque_attr->pValue, opaque_attr->ulValueLen, + &keytype, &keybitsize, &mkvp) == FALSE) { + TRACE_ERROR("%s Key token is not valid: handle: %lu\n", __func__, key); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Key token is not valid: handle: %lu\n", + tokdata->slot_id, key); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + switch (keytype) { + case sec_des_data_key: + if (mk_change_op->new_sym_mkvp_set == FALSE) + goto done; + break; + case sec_aes_data_key: + case sec_aes_cipher_key: + case sec_hmac_key: + if (mk_change_op->new_aes_mkvp_set == FALSE) + goto done; + break; + case sec_rsa_priv_key: + case sec_ecc_priv_key: + if (mk_change_op->new_apka_mkvp_set == FALSE) + goto done; + break; + default: + goto done; + } + + TRACE_INFO("%s Update token key object '%s' referenced by state of session " + "0x%lx\n", __func__, key_obj->name, session->handle); + OCK_SYSLOG(LOG_DEBUG, "Slot %lu: Update token key object '%s' referenced " + "by state of session 0x%lx\n", tokdata->slot_id, key_obj->name, + session->handle); + + rc = object_mgr_check_shm(tokdata, key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_check_shm failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to update token key object '%s' " + "from SHM: 0x%lx\n", tokdata->slot_id, key_obj->name, rc); + goto done; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_mk_change_reencipher(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + struct cca_private_data *cca_private = tokdata->private_data; + struct cca_mk_change_op *mk_change_op; + const unsigned char *new_sym_mk = NULL; + const unsigned char *new_aes_mk = NULL; + const unsigned char *new_apka_mk = NULL; + struct reencipher_data rd = { 0 }; + CK_RV rc = CKR_OK; + unsigned int op_idx; + CK_BBOOL token_objs = FALSE; + + if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0) { + token_objs = TRUE; + /* The tool should have logged in a R/W USER session */ + if (!session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s No user session exists\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", + tokdata->slot_id); + return CKR_FUNCTION_FAILED; + } + } + + if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); + if (token_objs == TRUE && mk_change_op == NULL) { + TRACE_DEVEL("HSM-MK-change op %s must already be active\n", op->id); + OCK_SYSLOG(LOG_ERR, + "Slot %lu: HSM-MK-change %s must already be active\n", + tokdata->slot_id, op->id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + /* Activate this MK change operation if not already active */ + if (mk_change_op == NULL) { + new_sym_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_SYM, + CCA_MKVP_LENGTH); + new_aes_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_AES, + CCA_MKVP_LENGTH); + new_apka_mk = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_CCA_APKA, + CCA_MKVP_LENGTH); + if (new_sym_mk == NULL && new_aes_mk == NULL && new_apka_mk == NULL) { + TRACE_ERROR("%s No CCA MK type found in MK change operation: %s\n", + __func__, op->id); + OCK_SYSLOG(LOG_ERR, "Slot %lu: No CCA MK type found in MK change " + "operation: %s\n", tokdata->slot_id, op->id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = cca_mk_change_activate_op(tokdata, op->id, info, + new_sym_mk, new_aes_mk, new_apka_mk, + &op_idx); + if (rc != CKR_OK) + goto out; + + mk_change_op = &cca_private->mk_change_ops[op_idx]; + } + + TRACE_DEVEL("%s MK change op: %s\n", __func__, + mk_change_op->mk_change_op); + if (mk_change_op->new_sym_mkvp_set) { + TRACE_DEBUG_DUMP("New SYM MK: ", (void *)mk_change_op->new_sym_mkvp, + CCA_MKVP_LENGTH); + } + if (mk_change_op->new_aes_mkvp_set) { + TRACE_DEBUG_DUMP("New AES MK: ", (void *)mk_change_op->new_aes_mkvp, + CCA_MKVP_LENGTH); + } + if (mk_change_op->new_apka_mkvp_set) { + TRACE_DEBUG_DUMP("New APKA MK: ", (void *)mk_change_op->new_apka_mkvp, + CCA_MKVP_LENGTH); + } + + /* Re-encipher key objects */ + rd.tokdata = tokdata; + rd.mk_change_op = mk_change_op; + + rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + cca_reencipher_filter_cb, mk_change_op, + cca_reencipher_objects_cb, &rd, + TRUE, "re-encipher"); + if (rc != CKR_OK) { + obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + cca_reencipher_cancel_filter_cb, mk_change_op, + cca_reencipher_cancel_objects_cb, NULL, + TRUE, "cancel"); + /* + * The pkcshsm_mk_change tool will send a CANCEL event, so leave the + * operation active for now. + */ + goto out; + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_mk_change_finalize_cancel(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info, + CK_BBOOL cancel) +{ + struct cca_private_data *cca_private = tokdata->private_data; + struct cca_mk_change_op *mk_change_op; + CK_RV rc = CKR_OK; + CK_BBOOL token_objs = FALSE; + + UNUSED(info); + + TRACE_DEVEL("%s %s MK change op: %s\n", __func__, + cancel ? "canceling" : "finalizing", op->id); + + if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0 || + (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { + token_objs = TRUE; + /* The tool should have logged in a R/W USER session */ + if (!session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s No user session exists\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", + tokdata->slot_id); + return CKR_FUNCTION_FAILED; + } + } + + if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + mk_change_op = cca_mk_change_find_op(tokdata, op->id, NULL); + if (mk_change_op == NULL) + goto out; + + /* + * Finalize/cancel token objects. + * If flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL is on, only process such + * token objects that do have the CKA_IBM_OPAQUE_REENC attribute. Those + * Objects have been newly created by another process after the first token + * finalization/cancellation (flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS) has + * been performed, and before all processes have deactivated the MK change + * operation. Thus, they were created with the re-enciphered secure key, + * and now need to be finalized/canceled. + */ + rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + token_objs && (op->flags & + EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) ? + cca_reencipher_cancel_filter_cb : + cca_reencipher_filter_cb, + mk_change_op, + cancel ? + cca_reencipher_cancel_objects_cb : + cca_reencipher_finalize_objects_cb, + NULL, TRUE, + cancel ? "cancel" : "finalize"); + if (rc != CKR_OK) + goto out; + + if (!token_objs && !cancel) { + /* update token keys referenced in active sessions */ + rc = session_mgr_iterate_session_ops(tokdata, NULL, + cca_finalize_sessions_cb, + mk_change_op); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to finalize sessions: 0x%lx\n", + tokdata->slot_id, rc); + goto out; + } + } + + /* + * Deactivate this MK change operation. + * For the pkcshsm_mk_change tool: Deactivate only after 2nd token object + * processing. + */ + if ((token_objs == FALSE && op->tool_pid != tokdata->real_pid) || + (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { + + if (!cancel) { + /* From now on the new MKs are the expected one */ + if (mk_change_op->new_sym_mkvp_set) + memcpy(cca_private->expected_sym_mkvp, + mk_change_op->new_sym_mkvp, CCA_MKVP_LENGTH); + if (mk_change_op->new_aes_mkvp_set) + memcpy(cca_private->expected_aes_mkvp, + mk_change_op->new_aes_mkvp, CCA_MKVP_LENGTH); + if (mk_change_op->new_apka_mkvp_set) + memcpy(cca_private->expected_apka_mkvp, + mk_change_op->new_apka_mkvp, CCA_MKVP_LENGTH); + } + + mk_change_op->mk_change_active = 0; + memset(mk_change_op->mk_change_op, 0, + sizeof(mk_change_op->mk_change_op)); + if (mk_change_op->apqns != NULL) + free(mk_change_op->apqns); + mk_change_op->apqns = NULL; + mk_change_op->num_apqns = 0; + + TRACE_DEVEL("%s %s MK change op: %s\n", __func__, + cancel ? "canceled" : "finalized", op->id); + OCK_SYSLOG(LOG_INFO, "Slot %lu: Concurrent HSM master key change " + "operation %s is %s\n", + tokdata->slot_id, op->id, cancel ? "canceled" : "finalized"); + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV cca_handle_mk_change_event(STDLL_TokData_t *tokdata, + unsigned int event_type, + unsigned int event_flags, + const char *payload, + unsigned int payload_len) +{ + CK_RV rc; + size_t bytes_read = 0; + struct hsm_mk_change_info info = { 0 }; + event_mk_change_data_t *hdr = (event_mk_change_data_t *)payload; + + UNUSED(event_flags); + + TRACE_DEVEL("%s event: 0x%x\n", __func__, event_type); + + if (payload_len <= sizeof (*hdr)) + return CKR_DATA_LEN_RANGE; + + TRACE_DEVEL("%s id: '%s' flags: 0x%x tool_pid: %d\n", __func__, hdr->id, + hdr->flags, hdr->tool_pid); + + rc = hsm_mk_change_info_unflatten((unsigned char *)payload + sizeof(*hdr), + payload_len - sizeof(*hdr), + &bytes_read, &info); + if (rc != CKR_OK) + return rc; + if (bytes_read < payload_len - sizeof(*hdr)) { + rc = CKR_DATA_LEN_RANGE; + goto out; + } + + rc = cca_mk_change_is_affected(tokdata, &info); + if (rc != CKR_OK) + goto out; + + if (event_type != EVENT_TYPE_MK_CHANGE_INITIATE_QUERY && + event_type != EVENT_TYPE_MK_CHANGE_REENCIPHER) { + /* Operation must be active */ + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); + rc = CKR_CANT_LOCK; + goto out; + } + + if (cca_mk_change_find_op(tokdata, hdr->id, NULL) == NULL) { + TRACE_ERROR("%s Must be a currently active operation: '%s'\n", + __func__, hdr->id); + rc = CKR_FUNCTION_FAILED; + pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock); + goto out; + } + + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + rc = CKR_CANT_LOCK; + goto out; + } + } + + switch (event_type) { + case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: + rc = cca_mk_change_init_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_REENCIPHER: + rc = cca_mk_change_reencipher(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: + rc = cca_mk_change_finalize_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: + rc = cca_mk_change_cancel_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_FINALIZE: + rc = cca_mk_change_finalize_cancel(tokdata, hdr, &info, FALSE); + break; + case EVENT_TYPE_MK_CHANGE_CANCEL: + rc = cca_mk_change_finalize_cancel(tokdata, hdr, &info, TRUE); + break; + default: + rc = CKR_FUNCTION_NOT_SUPPORTED; + break; + } + +out: + hsm_mk_change_info_clean(&info); + + TRACE_DEVEL("%s rc: 0x%lx\n", __func__, rc); + return rc; +} + /* * Called by the event thread, on receipt of an event. * @@ -7064,6 +11592,15 @@ return cca_handle_apqn_event(tokdata, event_type, (event_udev_apqn_data_t *)payload); + case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: + case EVENT_TYPE_MK_CHANGE_REENCIPHER: + case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: + case EVENT_TYPE_MK_CHANGE_FINALIZE: + case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: + case EVENT_TYPE_MK_CHANGE_CANCEL: + return cca_handle_mk_change_event(tokdata, event_type, event_flags, + payload, payload_len); + default: return CKR_FUNCTION_NOT_SUPPORTED; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_stdll.h opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_stdll.h --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_stdll.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_stdll.h 2023-05-15 14:42:55.000000000 +0200 @@ -45,6 +45,13 @@ #define CCA_PKB_EC_PUBL_KEY_LEN_OFFSET 6 #define CCATOK_EC_MAX_D_LEN 66 #define CCATOK_EC_MAX_Q_LEN 133 + +/* + * ECC private key section (X'20'), Key-usage and translation control flag. + */ +#define CCA_XPRTCPAC 0x01 +#define CCA_ECC_TOKEN_KEYUSAGE_OFFSET 16 + /* Key token generated by CSNDPKG */ /* CCA spec: page 460 & 470 & 471 */ #define CCA_PRIVKEY_ID 0x20 @@ -79,30 +86,51 @@ #define CCA_RSA_INTTOK_PUBKEY_E_LENGTH_OFFSET 6 /* Offset into an RSA public key area of the value of e, the public exponent */ #define CCA_RSA_INTTOK_PUBKEY_E_OFFSET 12 +/* Offset into the rule array returned by STATCCA and length of the returned + * CCA version field. */ +#define CCA_STATCCA_CCA_VERSION_OFFSET 24 +#define CCA_STATCCA_CCA_VERSION_LENGTH 8 /* Offset into the rule_array returned by the STATCCAE command for the - * Current Symmetric Master Key register status */ -#define CCA_STATCCAE_CMK_OFFSET 8 + * New and Current Symmetric Master Key register status */ +#define CCA_STATCCAE_SYM_NMK_OFFSET 0 +#define CCA_STATCCAE_SYM_CMK_OFFSET 8 /* Offset into the rule_array returned by the STATAES command for the - * Current AES Master Key register status */ -#define CCA_STATAES_CMK_OFFSET 8 + * New and Current AES Master Key register status */ +#define CCA_STATAES_AES_NMK_OFFSET 0 +#define CCA_STATAES_AES_CMK_OFFSET 8 /* Offset into the rule_array returned by the STATAPKA command for the - * Current APKA Master Key register status */ -#define CCA_STATAPKA_CMK_OFFSET 8 + * New and Current APKA Master Key register status */ +#define CCA_STATAPKA_APKA_NMK_OFFSET 0 +#define CCA_STATAPKA_APKA_CMK_OFFSET 8 /* Offsets into the verb_data returned by the STATICSB command for the * Master Key register verification pattern */ #define CCA_STATICSB_SYM_CMK_ID 0x0f07 -#define CCA_STATICSB_SYM_CMK_ID_OFFSET 134 /* ID = 0x0f01 */ +#define CCA_STATICSB_SYM_CMK_ID_OFFSET 134 /* ID = 0x0f07 */ #define CCA_STATICSB_SYM_CMK_MKVP_OFFSET 136 /* 8 bytes MKVP */ +#define CCA_STATICSB_SYM_NMK_ID 0x0f06 +#define CCA_STATICSB_SYM_NMK_ID_OFFSET 146 /* ID = 0x0f06 */ +#define CCA_STATICSB_SYM_NMK_MKVP_OFFSET 148 /* 8 bytes MKVP */ #define CCA_STATICSB_AES_CMK_ID 0x0f0b #define CCA_STATICSB_AES_CMK_ID_OFFSET 182 /* ID = 0x0f0b */ #define CCA_STATICSB_AES_CMK_MKVP_OFFSET 184 /* 8 bytes MKVP */ +#define CCA_STATICSB_AES_NMK_ID 0x0f0a +#define CCA_STATICSB_AES_NMK_ID_OFFSET 194 /* ID = 0x0f0a */ +#define CCA_STATICSB_AES_NMK_MKVP_OFFSET 196 /* 8 bytes MKVP */ #define CCA_STATICSB_APKA_CMK_ID 0x0f0e #define CCA_STATICSB_APKA_CMK_ID_OFFSET 218 /* ID = 0x0f0e */ #define CCA_STATICSB_APKA_CMK_MKVP_OFFSET 220 /* 8 bytes MKVP */ +#define CCA_STATICSB_APKA_NMK_ID 0x0f0d +#define CCA_STATICSB_APKA_NMK_ID_OFFSET 230 /* ID = 0x0f0d */ +#define CCA_STATICSB_APKA_NMK_MKVP_OFFSET 232 /* 8 bytes MKVP */ /* Offset to start of public RSA key section for an external public RSA key token */ #define CCA_RSA_EXTTOK_PUBKEY_OFFSET 8 /* Offset to length of n within an public RSA key section in an ext public RSA key token */ #define CCA_RSA_EXTTOK_PUBKEY_N_LENGTH_OFFSET 10 +/* Offset into the rule_array returned by the STATCRD2 command for the + * adapter serial number */ +#define CCA_STATCRD2_SERIAL_NUMBER_OFFSET 112 + +#define CCA_SERIALNO_LENGTH 8 /* CCA internal HMAC token payload bit length field offset */ #define CCA_HMAC_INTTOK_PAYLOAD_LENGTH_OFFSET 38 @@ -124,6 +152,31 @@ #define CCA_MKVP_LENGTH 8 +enum cca_mk_type { + CCA_MK_SYM, + CCA_MK_AES, + CCA_MK_APKA, +}; + +#define CCA_NUM_MK_TYPES 3 + +enum cca_nmk_state { + CCA_NMK_STATUS_CLEAR = 1, + CCA_NMK_STATUS_PARTIAL = 2, + CCA_NMK_STATUS_FULL = 3, +}; + +enum cca_cmk_state { + CCA_CMK_STATUS_CLEAR = 1, + CCA_CMK_STATUS_FULL = 2, +}; + +enum cca_ktc_type { + CCA_KTC_DATA, + CCA_KTC_CIPHER, + CCA_KTC_PKA, +}; + /* CCA STDLL debug logging definitions */ #ifdef DEBUG diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/cca_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/cca_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -11,7 +11,9 @@ -I${srcdir}/usr/lib/cca_stdll -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/include -DSTDLL_NAME=\"ccatok\" \ -I${top_builddir}/usr/lib/api -I${srcdir}/usr/lib/api \ - -I${top_builddir}/usr/lib/config -I${srcdir}/usr/lib/config + -I${top_builddir}/usr/lib/config -I${srcdir}/usr/lib/config \ + -I${srcdir}/usr/lib/hsm_mk_change \ + -I${top_builddir}/usr/lib/hsm_mk_change opencryptoki_stdll_libpkcs11_cca_la_LDFLAGS = -shared \ -Wl,-z,defs,-Bsymbolic -lcrypto -lpthread -nostartfiles \ @@ -41,13 +43,11 @@ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ - usr/lib/common/mech_openssl.c usr/lib/common/pqc_supported.c + usr/lib/common/mech_openssl.c usr/lib/common/pqc_supported.c \ + usr/lib/hsm_mk_change/hsm_mk_change.c \ + usr/lib/common/btree.c usr/lib/common/sess_mgr.c -if ENABLE_LOCKS -opencryptoki_stdll_libpkcs11_cca_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else +if !NO_PKEY opencryptoki_stdll_libpkcs11_cca_la_SOURCES += \ - usr/lib/common/btree.c usr/lib/common/sess_mgr.c -opencryptoki_stdll_libpkcs11_cca_la_LDFLAGS += -litm -endif + usr/lib/common/pkey_utils.c +endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/ccatok.conf opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/ccatok.conf --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/ccatok.conf 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/ccatok.conf 2023-05-15 14:42:55.000000000 +0200 @@ -19,3 +19,35 @@ # AES = "" # APKA = "" # } +# +# -------------------------------------------------------------------------- +# +# For s390x (Linux on IBM Z) systems: +# +# To optimize encrypt/decrypt and sign/verify performance, a corresponding +# protected key can be created for AES and EC secure keys and added to the +# secure key. This protected key is then used for certain mechanisms via +# CPACF, instead of performing the function via the CCA coprocessor. +# IBM specific boolean attribute CKA_IBM_PROTKEY_EXTRACTABLE must be true to +# make a key eligible for protected key support. +# +# PKEY_MODE = DISABLED | DEFAULT | ENABLED +# +# DISABLED : Protected key support disabled. All keys are used +# via their secure key attribute. This option allows +# to completely disable protected key support, e.g. +# for performance comparisons. +# +# DEFAULT : Use defaults for CKA_IBM_PROTKEY_EXTRACTABLE. If +# the application did not specify +# CKA_IBM_PROTKEY_EXTRACTABLE = true in its template, +# new keys of any type get default value +# CKA_IBM_PROTKEY_EXTRACTABLE = false. +# +# ENABLED : Enable protected key support for all keys. +# If the application did not specify +# CKA_IBM_PROTKEY_EXTRACTABLE = false in its template, +# new keys of any type get CKA_IBM_PROTKEY_EXTRACTABLE +# = true and a protected key is automatically created +# at first use of the key. +# diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/tok_struct.h opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/tok_struct.h --- opencryptoki-3.20.0+dfsg/usr/lib/cca_stdll/tok_struct.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/cca_stdll/tok_struct.h 2023-05-15 14:42:55.000000000 +0200 @@ -130,7 +130,11 @@ &token_specific_key_unwrap, &token_specific_reencrypt_single, NULL, // set_attribute_values - NULL, // set_attrs_for_new_object +#ifndef NO_PKEY + &token_specific_set_attrs_for_new_object, +#else + NULL, +#endif &token_specific_handle_event, }; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/btree.c opencryptoki-3.21.0+dfsg/usr/lib/common/btree.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/btree.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/btree.c 2023-05-15 14:42:55.000000000 +0200 @@ -19,6 +19,7 @@ #include #include +#include #include "pkcs11types.h" #include "local_types.h" @@ -42,7 +43,7 @@ if (node_num == 1) { temp = t->top; - return (temp->flags & BT_FLAG_FREE) ? NULL : temp; + return (temp->flags & BT_FLAG_FREE) ? NULL : temp; } i = node_num; @@ -68,9 +69,18 @@ */ struct btnode *bt_get_node(struct btree *t, unsigned long node_num) { - __transaction_atomic { /* start transaction */ - return __bt_get_node(t, node_num); - } /* end transaction */ + struct btnode *temp; + + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return NULL; + } + + temp = __bt_get_node(t, node_num); + + pthread_mutex_unlock(&t->mutex); + + return temp; } /* @@ -83,26 +93,34 @@ { struct btnode *n; void *v; + unsigned long ref; - __transaction_atomic { /* start transaction */ - /* - * Get the value within the transaction block, to ensure that the node - * is not deleted after it was obtained via bt_get_node, but before the - * value is obtained from the node. For a deleted node, the node->value - * points to another node in the free list. - */ - n = __bt_get_node(t, node_num); - v = ((n) ? n->value : NULL); +#ifndef DEBUG + UNUSED(ref); +#endif + + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return NULL; + } - if (v != NULL) - ((struct bt_ref_hdr *)v)->ref++; - } /* end transaction */ + /* + * Get the value within the locked block, to ensure that the node + * is not deleted after it was obtained via bt_get_node, but before the + * value is obtained from the node. For a deleted node, the node->value + * points to another node in the free list. + */ + n = __bt_get_node(t, node_num); + v = ((n) ? n->value : NULL); if (v != NULL) { + ref = __sync_add_and_fetch(&((struct bt_ref_hdr *)v)->ref, 1); + TRACE_DEBUG("bt_get_node_value: Btree: %p Value: %p Ref: %lu\n", - (void *)t, v, ((struct bt_ref_hdr *)v)->ref); + (void *)t, v, ref); } + pthread_mutex_unlock(&t->mutex); return v; } @@ -116,30 +134,23 @@ { int rc = 0; unsigned long ref; - int warn = 0; if (value == NULL) return 0; - __transaction_atomic { /* start transaction */ - if (((struct bt_ref_hdr *)value)->ref > 0) { - ref = --((struct bt_ref_hdr *)value)->ref; - } else { - warn = 1; - ref = 0; - } - } /* end transaction */ + if (((struct bt_ref_hdr *)value)->ref > 0) { + ref = __sync_sub_and_fetch(&((struct bt_ref_hdr *)value)->ref, 1); - if (warn) { + TRACE_DEBUG("bt_put_node_value: Btree: %p Value: %p Ref: %lu\n", + (void *)t, value, ((struct bt_ref_hdr *)value)->ref); + } else { TRACE_WARNING("bt_put_node_value: BTree: %p Value %p Ref already 0.\n", (void *)t, value); - } else { - TRACE_DEBUG("bt_put_node_value: Btree: %p Value: %p Ref: %lu\n", - (void *)t, value, ref); + ref = 0; } if (ref == 0 && t->delete_func) { - TRACE_DEBUG("delete_func: Btree: %p Value: %p\n", (void *)t, value); + TRACE_DEBUG("delete_func: Btree: %p Value: %p\n", (void *)t, value); t->delete_func(value); rc = 1; @@ -190,66 +201,79 @@ */ unsigned long bt_node_add(struct btree *t, void *value) { - TRACE_DEBUG("bt_node_add: Btree: %p Value: %p Ref: 1\n", (void *)t, value); + struct btnode *temp; + unsigned long new_node_index; - __transaction_atomic { /*start transaction */ - struct btnode *temp = t->top; - unsigned long new_node_index; - - ((struct bt_ref_hdr *)value)->ref = 1; - - if (!temp) { /* no root node yet exists, create it */ - t->size = 1; - if (!node_create(&t->top, NULL, value)) { - return 0; - } + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return 0; + } + + ((struct bt_ref_hdr *)value)->ref = 1; + + TRACE_DEBUG("bt_node_add: Btree: %p Value: %p Ref: %lu\n", (void *)t, value, + ((struct bt_ref_hdr *)value)->ref); + + temp = t->top; - return 1; - } else if (t->free_list) { - /* there's a node on the free list, - * use it instead of mallocing new - */ - temp = t->free_list; - t->free_list = temp->value; - temp->value = value; - temp->flags &= (~BT_FLAG_FREE); - t->free_nodes--; - new_node_index = GET_NODE_HANDLE(temp); - return new_node_index; + if (!temp) { /* no root node yet exists, create it */ + t->size = 1; + if (!node_create(&t->top, NULL, value)) { + pthread_mutex_unlock(&t->mutex); + return 0; } - new_node_index = t->size + 1; + pthread_mutex_unlock(&t->mutex); + return 1; + } else if (t->free_list) { + /* there's a node on the free list, + * use it instead of mallocing new + */ + temp = t->free_list; + t->free_list = temp->value; + temp->value = value; + temp->flags &= (~BT_FLAG_FREE); + t->free_nodes--; + new_node_index = GET_NODE_HANDLE(temp); + pthread_mutex_unlock(&t->mutex); + return new_node_index; + } + + new_node_index = t->size + 1; - while (new_node_index != 1) { - if (new_node_index & 1) { - if (!temp->right) { - if (!(node_create(&temp->right, temp, value))) { - return 0; - } - break; - } else { - /* If the bit is 1, traverse right */ - temp = temp->right; + while (new_node_index != 1) { + if (new_node_index & 1) { + if (!temp->right) { + if (!(node_create(&temp->right, temp, value))) { + pthread_mutex_unlock(&t->mutex); + return 0; } + break; } else { - if (!temp->left) { - if (!(node_create(&temp->left, temp, value))) { - return 0; - } - break; - } else { - /* If the bit is 0, traverse left */ - temp = temp->left; + /* If the bit is 1, traverse right */ + temp = temp->right; + } + } else { + if (!temp->left) { + if (!(node_create(&temp->left, temp, value))) { + pthread_mutex_unlock(&t->mutex); + return 0; } + break; + } else { + /* If the bit is 0, traverse left */ + temp = temp->left; } - - new_node_index >>= 1; } - t->size++; + new_node_index >>= 1; + } - return t->size; - } /* end transaction */ + t->size++; + new_node_index = t->size; + + pthread_mutex_unlock(&t->mutex); + return new_node_index; } void tree_dump(struct btnode *n, int depth) @@ -290,42 +314,38 @@ { struct btnode *node; void *value = NULL; -#ifdef DEBUG - unsigned long int ref; -#endif - __transaction_atomic { /* start transaction */ - node = __bt_get_node(t, node_num); + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return NULL; + } - if (node) { - /* - * Need to get the node value within the transaction block, - * otherwise the node might be deleted concurrently before the - * value was obtained from the node. - */ - value = node->value; - - node->flags |= BT_FLAG_FREE; - - /* add node to the free list, - * which is chained by using - * the value pointer - */ - node->value = t->free_list; - t->free_list = node; - t->free_nodes++; + node = __bt_get_node(t, node_num); -#ifdef DEBUG - ref = ((struct bt_ref_hdr *)value)->ref; -#endif - } - } /* end transaction */ + if (node) { + /* + * Need to get the node value within the locked block, + * otherwise the node might be deleted concurrently before the + * value was obtained from the node. + */ + value = node->value; + + node->flags |= BT_FLAG_FREE; + + /* add node to the free list, + * which is chained by using + * the value pointer + */ + node->value = t->free_list; + t->free_list = node; + t->free_nodes++; - if (value != NULL) { TRACE_DEBUG("bt_node_free: Btree: %p Value: %p Ref: %lu\n", (void *)t, - value, ref); + value, ((struct bt_ref_hdr *)value)->ref); } + pthread_mutex_unlock(&t->mutex); + if (value && put_value) bt_put_node_value(t, value); @@ -338,9 +358,16 @@ */ int bt_is_empty(struct btree *t) { - __transaction_atomic { /* start transaction */ - return (t->free_nodes == t->size); - } /* end transaction */ + CK_RV rc; + + if (pthread_mutex_lock(&t->mutex)) + return 0; + + rc = (t->free_nodes == t->size); + + pthread_mutex_unlock(&t->mutex); + + return rc; } /* bt_nodes_in_use @@ -349,9 +376,18 @@ */ unsigned long bt_nodes_in_use(struct btree *t) { - __transaction_atomic { /* start transaction */ - return (t->size - t->free_nodes); - } /* end transaction */ + CK_RV rc; + + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return -1; + } + + rc = (t->size - t->free_nodes); + + pthread_mutex_unlock(&t->mutex); + + return rc; } /* bt_for_each_node @@ -364,8 +400,8 @@ * p3 is passed through this function for the caller */ void bt_for_each_node(STDLL_TokData_t *tokdata, struct btree *t, void (*func) - (STDLL_TokData_t *tokdata, void *p1, unsigned long p2, - void *p3), void *p3) + (STDLL_TokData_t *tokdata, void *p1, unsigned long p2, + void *p3), void *p3) { unsigned int i; void *value; @@ -375,7 +411,7 @@ * Get the node value, not the node itself. This ensures that we either * get the value from a valid node, or NULL in case of a deleted node. * If we would get the node and then get the value from it without - * being in the transaction block, the node could have been deleted after + * being in the locked block, the node could have been deleted after * the node was obtained, but before the value was obtained. */ value = bt_get_node_value(t, i); @@ -400,33 +436,30 @@ unsigned long i; struct btnode *temp; + if (pthread_mutex_lock(&t->mutex)) { + TRACE_ERROR("BTree Lock failed.\n"); + return; + } + while (t->size) { - __transaction_atomic { /* start transaction */ - temp = t->top; - i = t->size; - while (i != 1) { - if (i & 1) { - /* If the bit is 1, traverse right */ - temp = temp->right; - } else { - /* If the bit is 0, traverse left */ - temp = temp->left; - } - i >>= 1; + temp = t->top; + i = t->size; + while (i != 1) { + if (i & 1) { + /* If the bit is 1, traverse right */ + temp = temp->right; + } else { + /* If the bit is 0, traverse left */ + temp = temp->left; } - } /* end transaction */ + i >>= 1; + } /* * The value pointed by value in a node marked as freed points * to the next node element in free_list and it shouldn't be * freed here because the loop will iterate through each node, * freed or not. - * ATTENTION: - * This might not be 100% thread save when using __transaction_atomic, - * since the node might get deleted concurrently while we are outside - * of the transaction block. It is assumed that bt_destroy is called - * during final cleanup, and thus is not used concurrently with - * bt_node_free() or bt_destroy() in other threads. */ if (t->delete_func && !(temp->flags & BT_FLAG_FREE)) { @@ -436,19 +469,18 @@ t->delete_func(temp->value); } - __transaction_atomic { /* start transaction */ - free(temp); - t->size--; - } /* end transaction */ + free(temp); + t->size--; } - __transaction_atomic { /* start transaction */ - /* the tree is gone now, clear all the other variables */ - t->top = NULL; - t->free_list = NULL; - t->free_nodes = 0; - t->delete_func = NULL; - } /* end transaction */ + /* the tree is gone now, clear all the other variables */ + t->top = NULL; + t->free_list = NULL; + t->free_nodes = 0; + t->delete_func = NULL; + + pthread_mutex_unlock(&t->mutex); + pthread_mutex_destroy(&t->mutex); } /* bt_init @@ -456,11 +488,32 @@ * Initialize a btree with a delete callback function that is used to delete * values during bt_node_free() and bt_destroy(). */ -void bt_init(struct btree *t, void (*delete_func)(void *)) +CK_RV bt_init(struct btree *t, void (*delete_func)(void *)) { + pthread_mutexattr_t attr; + t->free_list = NULL; t->top = NULL; t->size = 0; t->free_nodes = 0; t->delete_func = delete_func; + + /* + * Need a recursive mutex, because btree callback functions may call + * btree functions again + */ + if (pthread_mutexattr_init(&attr) != 0) { + TRACE_ERROR("pthread_mutexattr_init failed.\n"); + return CKR_CANT_LOCK; + } + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { + TRACE_ERROR("pthread_mutexattr_settype failed.\n"); + return CKR_CANT_LOCK; + } + if (pthread_mutex_init(&t->mutex, &attr) != 0) { + TRACE_ERROR("pthread_mutex_init failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/constant_time.h opencryptoki-3.21.0+dfsg/usr/lib/common/constant_time.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/constant_time.h 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/constant_time.h 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,424 @@ +/* + * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + * + * Copied from OpenSSL include/internal/constant_time.h + * The only changes are to add this notice. + */ + +#ifndef OSSL_INTERNAL_CONSTANT_TIME_H +# define OSSL_INTERNAL_CONSTANT_TIME_H +# pragma once + +# include +# include +# include /* For 'ossl_inline' */ + +/*- + * The boolean methods return a bitmask of all ones (0xff...f) for true + * and 0 for false. This is useful for choosing a value based on the result + * of a conditional in constant time. For example, + * if (a < b) { + * c = a; + * } else { + * c = b; + * } + * can be written as + * unsigned int lt = constant_time_lt(a, b); + * c = constant_time_select(lt, a, b); + */ + +/* Returns the given value with the MSB copied to all the other bits. */ +static ossl_inline unsigned int constant_time_msb(unsigned int a); +/* Convenience method for uint32_t. */ +static ossl_inline uint32_t constant_time_msb_32(uint32_t a); +/* Convenience method for uint64_t. */ +static ossl_inline uint64_t constant_time_msb_64(uint64_t a); + +/* Returns 0xff..f if a < b and 0 otherwise. */ +static ossl_inline unsigned int constant_time_lt(unsigned int a, + unsigned int b); +/* Convenience method for getting an 8-bit mask. */ +static ossl_inline unsigned char constant_time_lt_8(unsigned int a, + unsigned int b); +/* Convenience method for uint64_t. */ +static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b); + +/* Returns 0xff..f if a >= b and 0 otherwise. */ +static ossl_inline unsigned int constant_time_ge(unsigned int a, + unsigned int b); +/* Convenience method for getting an 8-bit mask. */ +static ossl_inline unsigned char constant_time_ge_8(unsigned int a, + unsigned int b); + +/* Returns 0xff..f if a == 0 and 0 otherwise. */ +static ossl_inline unsigned int constant_time_is_zero(unsigned int a); +/* Convenience method for getting an 8-bit mask. */ +static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a); +/* Convenience method for getting a 32-bit mask. */ +static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a); + +/* Returns 0xff..f if a == b and 0 otherwise. */ +static ossl_inline unsigned int constant_time_eq(unsigned int a, + unsigned int b); +/* Convenience method for getting an 8-bit mask. */ +static ossl_inline unsigned char constant_time_eq_8(unsigned int a, + unsigned int b); +/* Signed integers. */ +static ossl_inline unsigned int constant_time_eq_int(int a, int b); +/* Convenience method for getting an 8-bit mask. */ +static ossl_inline unsigned char constant_time_eq_int_8(int a, int b); + +/*- + * Returns (mask & a) | (~mask & b). + * + * When |mask| is all 1s or all 0s (as returned by the methods above), + * the select methods return either |a| (if |mask| is nonzero) or |b| + * (if |mask| is zero). + */ +static ossl_inline unsigned int constant_time_select(unsigned int mask, + unsigned int a, + unsigned int b); +/* Convenience method for unsigned chars. */ +static ossl_inline unsigned char constant_time_select_8(unsigned char mask, + unsigned char a, + unsigned char b); + +/* Convenience method for uint32_t. */ +static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, + uint32_t b); + +/* Convenience method for uint64_t. */ +static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, + uint64_t b); +/* Convenience method for signed integers. */ +static ossl_inline int constant_time_select_int(unsigned int mask, int a, + int b); + + +static ossl_inline unsigned int constant_time_msb(unsigned int a) +{ + return 0 - (a >> (sizeof(a) * 8 - 1)); +} + + +static ossl_inline uint32_t constant_time_msb_32(uint32_t a) +{ + return 0 - (a >> 31); +} + +static ossl_inline uint64_t constant_time_msb_64(uint64_t a) +{ + return 0 - (a >> 63); +} + +static ossl_inline size_t constant_time_msb_s(size_t a) +{ + return 0 - (a >> (sizeof(a) * 8 - 1)); +} + +static ossl_inline unsigned int constant_time_lt(unsigned int a, + unsigned int b) +{ + return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b))); +} + +static ossl_inline size_t constant_time_lt_s(size_t a, size_t b) +{ + return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b))); +} + +static ossl_inline unsigned char constant_time_lt_8(unsigned int a, + unsigned int b) +{ + return (unsigned char)constant_time_lt(a, b); +} + +static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b) +{ + return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b))); +} + +static ossl_inline unsigned int constant_time_ge(unsigned int a, + unsigned int b) +{ + return ~constant_time_lt(a, b); +} + +static ossl_inline size_t constant_time_ge_s(size_t a, size_t b) +{ + return ~constant_time_lt_s(a, b); +} + +static ossl_inline unsigned char constant_time_ge_8(unsigned int a, + unsigned int b) +{ + return (unsigned char)constant_time_ge(a, b); +} + +static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b) +{ + return (unsigned char)constant_time_ge_s(a, b); +} + +static ossl_inline unsigned int constant_time_is_zero(unsigned int a) +{ + return constant_time_msb(~a & (a - 1)); +} + +static ossl_inline size_t constant_time_is_zero_s(size_t a) +{ + return constant_time_msb_s(~a & (a - 1)); +} + +static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a) +{ + return (unsigned char)constant_time_is_zero(a); +} + +static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a) +{ + return constant_time_msb_32(~a & (a - 1)); +} + +static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a) +{ + return constant_time_msb_64(~a & (a - 1)); +} + +static ossl_inline unsigned int constant_time_eq(unsigned int a, + unsigned int b) +{ + return constant_time_is_zero(a ^ b); +} + +static ossl_inline size_t constant_time_eq_s(size_t a, size_t b) +{ + return constant_time_is_zero_s(a ^ b); +} + +static ossl_inline unsigned char constant_time_eq_8(unsigned int a, + unsigned int b) +{ + return (unsigned char)constant_time_eq(a, b); +} + +static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b) +{ + return (unsigned char)constant_time_eq_s(a, b); +} + +static ossl_inline unsigned int constant_time_eq_int(int a, int b) +{ + return constant_time_eq((unsigned)(a), (unsigned)(b)); +} + +static ossl_inline unsigned char constant_time_eq_int_8(int a, int b) +{ + return constant_time_eq_8((unsigned)(a), (unsigned)(b)); +} + +/* + * Returns the value unmodified, but avoids optimizations. + * The barriers prevent the compiler from narrowing down the + * possible value range of the mask and ~mask in the select + * statements, which avoids the recognition of the select + * and turning it into a conditional load or branch. + */ +static ossl_inline unsigned int value_barrier(unsigned int a) +{ +#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) + unsigned int r; + __asm__("" : "=r"(r) : "0"(a)); +#else + volatile unsigned int r = a; +#endif + return r; +} + +/* Convenience method for uint32_t. */ +static ossl_inline uint32_t value_barrier_32(uint32_t a) +{ +#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) + uint32_t r; + __asm__("" : "=r"(r) : "0"(a)); +#else + volatile uint32_t r = a; +#endif + return r; +} + +/* Convenience method for uint64_t. */ +static ossl_inline uint64_t value_barrier_64(uint64_t a) +{ +#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) + uint64_t r; + __asm__("" : "=r"(r) : "0"(a)); +#else + volatile uint64_t r = a; +#endif + return r; +} + +/* Convenience method for size_t. */ +static ossl_inline size_t value_barrier_s(size_t a) +{ +#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) + size_t r; + __asm__("" : "=r"(r) : "0"(a)); +#else + volatile size_t r = a; +#endif + return r; +} + +static ossl_inline unsigned int constant_time_select(unsigned int mask, + unsigned int a, + unsigned int b) +{ + return (value_barrier(mask) & a) | (value_barrier(~mask) & b); +} + +static ossl_inline size_t constant_time_select_s(size_t mask, + size_t a, + size_t b) +{ + return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b); +} + +static ossl_inline unsigned char constant_time_select_8(unsigned char mask, + unsigned char a, + unsigned char b) +{ + return (unsigned char)constant_time_select(mask, a, b); +} + +static ossl_inline int constant_time_select_int(unsigned int mask, int a, + int b) +{ + return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b)); +} + +static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b) +{ + return (int)constant_time_select((unsigned)mask, (unsigned)(a), + (unsigned)(b)); +} + +static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, + uint32_t b) +{ + return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b); +} + +static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, + uint64_t b) +{ + return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b); +} + +/* + * mask must be 0xFFFFFFFF or 0x00000000. + * + * if (mask) { + * uint32_t tmp = *a; + * + * *a = *b; + * *b = tmp; + * } + */ +static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a, + uint32_t *b) +{ + uint32_t xor = *a ^ *b; + + xor &= mask; + *a ^= xor; + *b ^= xor; +} + +/* + * mask must be 0xFFFFFFFF or 0x00000000. + * + * if (mask) { + * uint64_t tmp = *a; + * + * *a = *b; + * *b = tmp; + * } + */ +static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a, + uint64_t *b) +{ + uint64_t xor = *a ^ *b; + + xor &= mask; + *a ^= xor; + *b ^= xor; +} + +/* + * mask must be 0xFF or 0x00. + * "constant time" is per len. + * + * if (mask) { + * unsigned char tmp[len]; + * + * memcpy(tmp, a, len); + * memcpy(a, b); + * memcpy(b, tmp); + * } + */ +static ossl_inline void constant_time_cond_swap_buff(unsigned char mask, + unsigned char *a, + unsigned char *b, + size_t len) +{ + size_t i; + unsigned char tmp; + + for (i = 0; i < len; i++) { + tmp = a[i] ^ b[i]; + tmp &= mask; + a[i] ^= tmp; + b[i] ^= tmp; + } +} + +/* + * table is a two dimensional array of bytes. Each row has rowsize elements. + * Copies row number idx into out. rowsize and numrows are not considered + * private. + */ +static ossl_inline void constant_time_lookup(void *out, + const void *table, + size_t rowsize, + size_t numrows, + size_t idx) +{ + size_t i, j; + const unsigned char *tablec = (const unsigned char *)table; + unsigned char *outc = (unsigned char *)out; + unsigned char mask; + + memset(out, 0, rowsize); + + /* Note idx may underflow - but that is well defined */ + for (i = 0; i < numrows; i++, idx--) { + mask = (unsigned char)constant_time_is_zero_s(idx); + for (j = 0; j < rowsize; j++) + *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0); + } +} + +/* + * Expected usage pattern is to unconditionally set error and then + * wipe it if there was no actual error. |clear| is 1 or 0. + */ +void err_clear_last_constant_time(int clear); + +#endif /* OSSL_INTERNAL_CONSTANT_TIME_H */ diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/event_client.c opencryptoki-3.21.0+dfsg/usr/lib/common/event_client.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/event_client.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/event_client.c 2023-05-15 14:42:55.000000000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include #include "slotmgr.h" #include "event_client.h" @@ -27,16 +28,21 @@ struct sockaddr_un daemon_address; struct stat file_info; struct group *grp; + struct passwd *pwd; int rc; if (stat(file_path, &file_info)) return -errno; - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (!grp) return -errno; - if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid) + pwd = getpwnam(PKCSSLOTD_USER); + if (!pwd) + return -errno; + + if (file_info.st_uid != pwd->pw_uid || file_info.st_gid != grp->gr_gid) return -EPERM; if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/h_extern.h opencryptoki-3.21.0+dfsg/usr/lib/common/h_extern.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/h_extern.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/h_extern.h 2023-05-15 14:42:55.000000000 +0200 @@ -451,6 +451,8 @@ void copy_token_contents_sensibly(CK_TOKEN_INFO_PTR pInfo, TOKEN_DATA *nv_token_data); +CK_RV init_hsm_mk_change_lock(STDLL_TokData_t *tokdata); + CK_RV compute_PKCS5_PBKDF2_HMAC(STDLL_TokData_t *tokdata, CK_CHAR *pPin, CK_ULONG ulPinLen, CK_BYTE *salt, CK_ULONG salt_len, @@ -467,7 +469,7 @@ CK_RV get_hmac_digest(CK_ULONG mech, CK_ULONG *digest_mech, CK_BBOOL *general); -CK_RV mgf1(STDLL_TokData_t *tokdata, CK_BYTE *seed, CK_ULONG seedlen, +CK_RV mgf1(STDLL_TokData_t *tokdata, const CK_BYTE *seed, CK_ULONG seedlen, CK_BYTE *mask, CK_ULONG maskLen, CK_RSA_PKCS_MGF_TYPE mgf); CK_RV get_ecsiglen(OBJECT *key_obj, CK_ULONG *size); @@ -563,6 +565,8 @@ // RSA routines // +CK_BBOOL is_rsa_mechanism(CK_MECHANISM_TYPE mech); + CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, @@ -1445,20 +1449,20 @@ // CK_RV ckm_aes_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, CK_BBOOL xts); -CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *, CK_BYTE *in_data, +CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key); -CK_RV ckm_aes_ecb_decrypt(STDLL_TokData_t *, CK_BYTE *in_data, +CK_RV ckm_aes_ecb_decrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key); -CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *, CK_BYTE *in_data, +CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key); -CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *, CK_BYTE *in_data, +CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key); @@ -2131,6 +2135,26 @@ CK_BBOOL pin_locked(CK_SESSION_INFO *, CK_FLAGS); void set_login_flags(CK_USER_TYPE, CK_FLAGS_32 *); +#define CONTEXT_TYPE_DIGEST 1 +#define CONTEXT_TYPE_SIGN 2 +#define CONTEXT_TYPE_VERIFY 3 +#define CONTEXT_TYPE_ENCRYPT 4 +#define CONTEXT_TYPE_DECRYPT 5 + +CK_RV session_mgr_iterate_session_ops(STDLL_TokData_t *tokdata, + SESSION *session, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + SESSION *session, + CK_ULONG ctx_type, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE key, + CK_BYTE *context, + CK_ULONG context_len, + CK_BBOOL init_pending, + CK_BBOOL pkey_active, + CK_BBOOL recover, + void *private), + void *private); // object manager routines // @@ -2149,7 +2173,8 @@ CK_RV object_mgr_del_from_shm(OBJECT *obj, LW_SHM_TYPE *shm); CK_RV object_mgr_get_shm_entry_for_obj(STDLL_TokData_t *tokdata, OBJECT *obj, TOK_OBJ_ENTRY **entry); -CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj, + OBJ_LOCK_TYPE lock_type); CK_RV object_mgr_search_shm_for_obj(TOK_OBJ_ENTRY *list, CK_ULONG lo, CK_ULONG hi, @@ -2240,6 +2265,38 @@ CK_RV object_put(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL unlock); +CK_RV obj_mgr_reencipher_secure_key(STDLL_TokData_t *tokdata, OBJECT *obj, + CK_RV (*reenc)(CK_BYTE *sec_key, + CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, + void *private), + void *private); + +CK_RV obj_mgr_reencipher_secure_key_finalize(STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BBOOL is_blob_new_mk_cb( + STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BYTE *sec_key, + CK_ULONG sec_key_len, + void *cb_private), + void *cb_private); + +CK_RV obj_mgr_reencipher_secure_key_cancel(STDLL_TokData_t *tokdata, + OBJECT *obj); + +CK_RV obj_mgr_iterate_key_objects(STDLL_TokData_t *tokdata, + CK_BBOOL session_objects, + CK_BBOOL token_objects, + CK_BBOOL(*filter)(STDLL_TokData_t *tokdata, + OBJECT *obj, + void *filter_data), + void *filter_data, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data), + void *cb_data, CK_BBOOL syslog, + const char *msg); + /* structures used to hold arguments to callback functions triggered by either * bt_for_each_node or bt_node_free */ struct find_args { @@ -2324,6 +2381,11 @@ CK_RV object_lock(OBJECT *obj, OBJ_LOCK_TYPE type); CK_RV object_unlock(OBJECT *obj); +CK_RV object_init_ex_data_lock(OBJECT *obj); +CK_RV object_destroy_ex_data_lock(OBJECT *obj); +CK_RV object_ex_data_lock(OBJECT *obj, OBJ_LOCK_TYPE type); +CK_RV object_ex_data_unlock(OBJECT *obj); + // object attribute template routines // @@ -2378,6 +2440,8 @@ CK_RV template_merge(TEMPLATE *dest, TEMPLATE **src); +CK_RV template_remove_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type); + CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr); CK_RV template_unflatten(TEMPLATE **tmpl, CK_BYTE *data, CK_ULONG count); @@ -2498,6 +2562,7 @@ CK_RV rsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len); CK_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length); +CK_RV rsa_priv_check_and_swap_pq(TEMPLATE *tmpl); // dsa routines // @@ -2900,6 +2965,19 @@ CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj); +struct openssl_ex_data { + EVP_PKEY *pkey; +}; + +void openssl_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len); +CK_RV openssl_get_ex_data(OBJECT *obj, void **ex_data, size_t ex_data_len, + CK_BBOOL (*need_wr_lock)(OBJECT *obj, + void *ex_data, + size_t ex_data_len), + void (*ex_data_free)(struct _OBJECT *obj, + void *ex_data, + size_t ex_data_len)); + CK_RV openssl_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); CK_RV openssl_specific_rsa_encrypt(STDLL_TokData_t *, CK_BYTE *in_data, CK_ULONG in_data_len, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/host_defs.h opencryptoki-3.21.0+dfsg/usr/lib/common/host_defs.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/host_defs.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/host_defs.h 2023-05-15 14:42:55.000000000 +0200 @@ -212,6 +212,15 @@ // policy support (set via store_object_strength_f pointer) struct objstrength strength; + + /* Allow to attach external data to an object */ + void *ex_data; + size_t ex_data_len; + pthread_rwlock_t ex_data_rwlock; + void (*ex_data_free)(struct _OBJECT *obj, void *ex_data, + size_t ex_data_len); + CK_RV (*ex_data_reload)(struct _OBJECT *obj, void *ex_data, + size_t ex_data_len); } OBJECT; @@ -393,9 +402,7 @@ unsigned char user_wrap_key[32]; pthread_mutex_t login_mutex; struct btree sess_btree; -#ifdef ENABLE_LOCKS pthread_rwlock_t sess_list_rwlock; -#endif struct btree object_map_btree; struct btree sess_obj_btree; struct btree publ_token_obj_btree; @@ -406,6 +413,8 @@ const struct mechtable_funcs *mechtable_funcs; struct statistics *statistics; struct tokstore_strength store_strength; + CK_BBOOL hsm_mk_change_supported; + pthread_rwlock_t hsm_mk_change_rwlock; }; #endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/key.c opencryptoki-3.21.0+dfsg/usr/lib/common/key.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/key.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/key.c 2023-05-15 14:42:55.000000000 +0200 @@ -2662,6 +2662,135 @@ return rc; } +CK_RV rsa_priv_check_and_swap_pq(TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL; + CK_ATTRIBUTE *exponent1 = NULL, *exponent2 = NULL; + CK_ATTRIBUTE *coeff = NULL; + BIGNUM *bn_tmp = NULL; + BIGNUM *bn_p = NULL; + BIGNUM *bn_q = NULL; + BIGNUM *bn_invq = NULL; + BN_CTX *ctx = NULL; + CK_RV rc = CKR_OK; + CK_ULONG len; + CK_BYTE *buf = NULL; + + if (template_attribute_find(tmpl, CKA_PRIME_1, &prime1) == FALSE || + prime1->ulValueLen == 0 || prime1->pValue == NULL) { + TRACE_DEVEL("Could not find CKA_PRIME_1 for the key, not CRT format.\n"); + return CKR_OK; + } + + if (template_attribute_find(tmpl, CKA_PRIME_2, &prime2) == FALSE || + prime2->ulValueLen == 0 || prime2->pValue == NULL) { + TRACE_DEVEL("Could not find CKA_PRIME_2 for the key, not CRT format.\n"); + return CKR_OK; + } + + if (template_attribute_find(tmpl, CKA_EXPONENT_1, &exponent1) == FALSE || + exponent1->ulValueLen == 0 || exponent1->pValue == NULL) { + TRACE_DEVEL("Could not find CKA_EXPONENT_1 for the key, not CRT format.\n"); + return CKR_OK; + } + + if (template_attribute_find(tmpl, CKA_EXPONENT_2, &exponent2) == FALSE || + exponent2->ulValueLen == 0 || exponent2->pValue == NULL) { + TRACE_DEVEL("Could not find CKA_EXPONENT_2 for the key, not CRT format.\n"); + return CKR_OK; + } + + if (template_attribute_find(tmpl, CKA_COEFFICIENT, &coeff) == FALSE || + coeff->ulValueLen == 0 || coeff->pValue == NULL) { + TRACE_DEVEL("Could not find CKA_COEFFICIENT for the key, not CRT format.\n"); + return CKR_OK; + } + + ctx = BN_CTX_secure_new(); + if (ctx == NULL) { + TRACE_ERROR("BN_CTX_secure_new failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + bn_p = BN_CTX_get(ctx); + bn_q = BN_CTX_get(ctx); + bn_invq = BN_CTX_get(ctx); + + if (bn_p == NULL || bn_q == NULL || bn_invq== NULL) { + TRACE_ERROR("BN_CTX_get failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + if (BN_bin2bn(prime1->pValue, prime1->ulValueLen, bn_p) == NULL || + BN_bin2bn(prime2->pValue, prime2->ulValueLen, bn_q) == NULL){ + TRACE_ERROR("BN_bin2bn failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + /* check if p > q */ + if (BN_ucmp(bn_p, bn_q) != 1) { + /* Unprivileged key format, swap p and q, swap dp and dq, recalc qinv */ + bn_tmp = bn_p; + bn_p = bn_q; + bn_q = bn_tmp; + + /* qInv = (1/q) mod p */ + if (BN_mod_inverse(bn_invq, bn_q, bn_p, ctx) == NULL) { + TRACE_ERROR("BN_mod_inverse failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + len = BN_num_bytes(bn_invq); + buf = OPENSSL_secure_zalloc(len); + if (buf == NULL) { + TRACE_ERROR("OPENSSL_secure_zalloc failed.\n"); + rc = CKR_HOST_MEMORY; + goto out; + } + + if (BN_bn2binpad(bn_invq, buf, len) <= 0) { + TRACE_ERROR("BN_bn2binpad failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + prime1->type = CKA_PRIME_2; + prime2->type = CKA_PRIME_1; + + exponent1->type = CKA_EXPONENT_2; + exponent2->type = CKA_EXPONENT_1; + + rc = build_attribute(CKA_COEFFICIENT, buf, len, &coeff); + if (rc != CKR_OK) { + TRACE_ERROR("build_attribute for CKA_COEFFICIENT failed.\n"); + goto out; + } + + rc = template_update_attribute(tmpl, coeff); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute for CKA_COEFFICIENT failed.\n"); + free(coeff); + goto out; + } + } + +out: + if (bn_p != NULL) + BN_clear(bn_p); + if (bn_q != NULL) + BN_clear(bn_q); + if (ctx != NULL) + BN_CTX_free(ctx); + if (buf != NULL) + OPENSSL_clear_free(buf, len); + + return rc; +} + static CK_RV ibm_pqc_keyform_mode_attrs_by_mech(CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE *keyform_attr, CK_ATTRIBUTE_TYPE *mode_attr, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/loadsave.c opencryptoki-3.21.0+dfsg/usr/lib/common/loadsave.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/loadsave.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/loadsave.c 2023-05-15 14:42:55.000000000 +0200 @@ -132,7 +132,7 @@ // Set absolute permissions or rw-rw---- fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - grp = getgrnam("pkcs11"); // Obtain the group id + grp = getgrnam(PKCS_GROUP); // Obtain the group id if (grp) { // set ownership to pkcs11 group if (fchown(file, -1, grp->gr_gid) != 0) { @@ -1283,6 +1283,7 @@ CK_ULONG master_key_len; CK_BYTE *master_key = NULL; CK_BBOOL is_opaque = FALSE; + TEMPLATE *tmpl = NULL; /* Skip it if master key is not needed. */ if (!token_specific.data_store.use_master_key) @@ -1310,21 +1311,30 @@ /* For clear key tokens, let token generate masterkey * since token will also encrypt/decrypt the objects. */ + tmpl = (TEMPLATE *)calloc(1, sizeof(TEMPLATE)); + if (tmpl == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + switch (token_specific.data_store.encryption_algorithm) { case CKM_DES3_CBC: - rc = token_specific.t_des_key_gen(tokdata, &master_key, + rc = token_specific.t_des_key_gen(tokdata, tmpl, &master_key, &master_key_len, key_len, &is_opaque); break; case CKM_AES_CBC: - rc = token_specific.t_aes_key_gen(tokdata, &master_key, + rc = token_specific.t_aes_key_gen(tokdata, tmpl, &master_key, &master_key_len, key_len, &is_opaque); break; default: + template_free(tmpl); return CKR_MECHANISM_INVALID; } + template_free(tmpl); + if (rc != CKR_OK) return rc; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/lock_btree.c opencryptoki-3.21.0+dfsg/usr/lib/common/lock_btree.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/lock_btree.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/lock_btree.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,508 +0,0 @@ -/* - * COPYRIGHT (c) International Business Machines Corp. 2005-2017 - * - * 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 - */ - -/* - * btree.c - * Author: Kent Yoder - * - * v1 Binary tree functions 4/5/2011 - * - */ - - -#include -#include -#include - -#include "pkcs11types.h" -#include "local_types.h" -#include "trace.h" - -#define GET_NODE_HANDLE(n) get_node_handle(n, 1) -#define TREE_DUMP(t) tree_dump((t)->top, 0) - -/* - * __bt_get_node() - Low level function, needs proper locking before invocation. - */ -static struct btnode *__bt_get_node(struct btree *t, unsigned long node_num) -{ - struct btnode *temp; - unsigned long i; - - temp = t->top; - - if (!node_num || node_num > t->size) - return NULL; - - if (node_num == 1) { - temp = t->top; - return (temp->flags & BT_FLAG_FREE) ? NULL : temp; - } - - i = node_num; - while (i != 1) { - if (i & 1) { - /* If the bit is 1, traverse right */ - temp = temp->right; - } else { - /* If the bit is 0, traverse left */ - temp = temp->left; - } - i >>= 1; - } - - return (temp->flags & BT_FLAG_FREE) ? NULL : temp; -} - -/* - * bt_get_node - * - * Return a node of the tree @t with position @node_num. If the node has been - * freed or doesn't exist, return NULL - */ -struct btnode *bt_get_node(struct btree *t, unsigned long node_num) -{ - struct btnode *temp; - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return NULL; - } - - temp = __bt_get_node(t, node_num); - - pthread_mutex_unlock(&t->mutex); - - return temp; -} - -/* - * Get the value of the specified node. Returns NULL if the node has been - * deleted. Increases the value's reference counter to prevent it from being - * freed while in use. The caller needs to call bt_put_node_value() to - * decrease the reference counter when the value is no longer used. - */ -void *bt_get_node_value(struct btree *t, unsigned long node_num) -{ - struct btnode *n; - void *v; - unsigned long ref; - -#ifndef DEBUG - UNUSED(ref); -#endif - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return NULL; - } - - /* - * Get the value within the locked block, to ensure that the node - * is not deleted after it was obtained via bt_get_node, but before the - * value is obtained from the node. For a deleted node, the node->value - * points to another node in the free list. - */ - n = __bt_get_node(t, node_num); - v = ((n) ? n->value : NULL); - - if (v != NULL) { - ref = __sync_add_and_fetch(&((struct bt_ref_hdr *)v)->ref, 1); - - TRACE_DEBUG("bt_get_node_value: Btree: %p Value: %p Ref: %lu\n", - (void *)t, v, ref); - } - - pthread_mutex_unlock(&t->mutex); - return v; -} - -/* - * Decrease the node values reference counter. - * If the reference counter reaches zero, then the btree's delete callback - * function is called to delete the value. - * Returns 1 of the value has been deleted, 0 otherwise. - */ -int bt_put_node_value(struct btree *t, void *value) -{ - int rc = 0; - unsigned long ref; - - if (value == NULL) - return 0; - - if (((struct bt_ref_hdr *)value)->ref > 0) { - ref = __sync_sub_and_fetch(&((struct bt_ref_hdr *)value)->ref, 1); - - TRACE_DEBUG("bt_put_node_value: Btree: %p Value: %p Ref: %lu\n", - (void *)t, value, ((struct bt_ref_hdr *)value)->ref); - } else { - TRACE_WARNING("bt_put_node_value: BTree: %p Value %p Ref already 0.\n", - (void *)t, value); - ref = 0; - } - - if (ref == 0 && t->delete_func) { - TRACE_DEBUG("delete_func: Btree: %p Value: %p\n", (void *)t, value); - - t->delete_func(value); - rc = 1; - } - - return rc; -} - -/* create a new node and set @parent_ptr to its location */ -static struct btnode *node_create(struct btnode **child_ptr, - struct btnode *parent_ptr, void *value) -{ - struct btnode *node = malloc(sizeof(struct btnode)); - - if (!node) - return NULL; - - node->left = node->right = NULL; - node->flags = 0; - node->value = value; - *child_ptr = node; - node->parent = parent_ptr; - - return node; -} - -/* - * get_node_handle - * - * Recursively construct a node's handle by tracing its path back to the root - * node - */ -static unsigned long get_node_handle(struct btnode *node, - unsigned long handle_so_far) -{ - if (!node->parent) - return handle_so_far; - else if (node->parent->left == node) - return get_node_handle(node->parent, handle_so_far << 1); - else - return get_node_handle(node->parent, (handle_so_far << 1) + 1); -} - -/* - * Return node number (handle) of newly created node, or 0 for failure. - * Value must start with struct bt_ref_hdr to maintain the reference counter. - * The reference counter is initialized to 1. - */ -unsigned long bt_node_add(struct btree *t, void *value) -{ - struct btnode *temp; - unsigned long new_node_index; - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return 0; - } - - ((struct bt_ref_hdr *)value)->ref = 1; - - TRACE_DEBUG("bt_node_add: Btree: %p Value: %p Ref: %lu\n", (void *)t, value, - ((struct bt_ref_hdr *)value)->ref); - - temp = t->top; - - if (!temp) { /* no root node yet exists, create it */ - t->size = 1; - if (!node_create(&t->top, NULL, value)) { - pthread_mutex_unlock(&t->mutex); - return 0; - } - - pthread_mutex_unlock(&t->mutex); - return 1; - } else if (t->free_list) { - /* there's a node on the free list, - * use it instead of mallocing new - */ - temp = t->free_list; - t->free_list = temp->value; - temp->value = value; - temp->flags &= (~BT_FLAG_FREE); - t->free_nodes--; - new_node_index = GET_NODE_HANDLE(temp); - pthread_mutex_unlock(&t->mutex); - return new_node_index; - } - - new_node_index = t->size + 1; - - while (new_node_index != 1) { - if (new_node_index & 1) { - if (!temp->right) { - if (!(node_create(&temp->right, temp, value))) { - pthread_mutex_unlock(&t->mutex); - return 0; - } - break; - } else { - /* If the bit is 1, traverse right */ - temp = temp->right; - } - } else { - if (!temp->left) { - if (!(node_create(&temp->left, temp, value))) { - pthread_mutex_unlock(&t->mutex); - return 0; - } - break; - } else { - /* If the bit is 0, traverse left */ - temp = temp->left; - } - } - - new_node_index >>= 1; - } - - t->size++; - new_node_index = t->size; - - pthread_mutex_unlock(&t->mutex); - return new_node_index; -} - -void tree_dump(struct btnode *n, int depth) -{ - int i; - - if (!n) - return; - - for (i = 0; i < depth; i++) - printf(" "); - - if (n->flags & BT_FLAG_FREE) - printf("`- (deleted node)\n"); - else - printf("`- %p\n", n->value); - - tree_dump(n->left, depth + 1); - tree_dump(n->right, depth + 1); -} - -/* - * bt_node_free - * - * Move @node_num in tree @t to the free list, decrease the value's reference - * counter, and if the reference counter reaches zero, calls the dbtree's - * delete callback on its value. - * Return the deleted value. Note that if the callback routine frees - * the value, then the returned value might have already been freed. You still - * can use it as indication that it found the node_num in the tree and moved - * it to the free list. - * - * Note that bt_get_node will return NULL if the node is already on the free - * list, so no double freeing can occur - */ -void *bt_node_free(struct btree *t, unsigned long node_num, - int put_value) -{ - struct btnode *node; - void *value = NULL; - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return NULL; - } - - node = __bt_get_node(t, node_num); - - if (node) { - /* - * Need to get the node value within the locked block, - * otherwise the node might be deleted concurrently before the - * value was obtained from the node. - */ - value = node->value; - - node->flags |= BT_FLAG_FREE; - - /* add node to the free list, - * which is chained by using - * the value pointer - */ - node->value = t->free_list; - t->free_list = node; - t->free_nodes++; - - TRACE_DEBUG("bt_node_free: Btree: %p Value: %p Ref: %lu\n", (void *)t, - value, ((struct bt_ref_hdr *)value)->ref); - } - - pthread_mutex_unlock(&t->mutex); - - if (value && put_value) - bt_put_node_value(t, value); - - return value; -} - -/* bt_is_empty - * - * return 0 if binary tree has at least 1 node in use, !0 otherwise - */ -int bt_is_empty(struct btree *t) -{ - CK_RV rc; - - if (pthread_mutex_lock(&t->mutex)) - return 0; - - rc = (t->free_nodes == t->size); - - pthread_mutex_unlock(&t->mutex); - - return rc; -} - -/* bt_nodes_in_use - * - * return the number of nodes in the binary tree that are not free'd - */ -unsigned long bt_nodes_in_use(struct btree *t) -{ - CK_RV rc; - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return -1; - } - - rc = (t->size - t->free_nodes); - - pthread_mutex_unlock(&t->mutex); - - return rc; -} - -/* bt_for_each_node - * - * For each non-free'd node in the tree, run @func on it - * - * @func: - * p1 is the node's value - * p2 is the node's handle - * p3 is passed through this function for the caller - */ -void bt_for_each_node(STDLL_TokData_t *tokdata, struct btree *t, void (*func) - (STDLL_TokData_t *tokdata, void *p1, unsigned long p2, - void *p3), void *p3) -{ - unsigned int i; - void *value; - - for (i = 1; i < t->size + 1; i++) { - /* - * Get the node value, not the node itself. This ensures that we either - * get the value from a valid node, or NULL in case of a deleted node. - * If we would get the node and then get the value from it without - * being in the locked block, the node could have been deleted after - * the node was obtained, but before the value was obtained. - */ - value = bt_get_node_value(t, i); - - if (value) { - (*func) (tokdata, value, i, p3); - - bt_put_node_value(t, value); - value = NULL; - } - } -} - -/* bt_destroy - * - * Walk a binary tree backwards (largest index to smallest), deleting nodes - * along the way. - * Call the btree's delete callback on node->value before freeing the node. - */ -void bt_destroy(struct btree *t) -{ - unsigned long i; - struct btnode *temp; - - if (pthread_mutex_lock(&t->mutex)) { - TRACE_ERROR("BTree Lock failed.\n"); - return; - } - - while (t->size) { - temp = t->top; - i = t->size; - while (i != 1) { - if (i & 1) { - /* If the bit is 1, traverse right */ - temp = temp->right; - } else { - /* If the bit is 0, traverse left */ - temp = temp->left; - } - i >>= 1; - } - - /* - * The value pointed by value in a node marked as freed points - * to the next node element in free_list and it shouldn't be - * freed here because the loop will iterate through each node, - * freed or not. - */ - if (t->delete_func && !(temp->flags & BT_FLAG_FREE)) { - - TRACE_DEBUG("bt_destroy: Btree: %p Value: %p Ref: %lu\n", (void *)t, - temp->value, ((struct bt_ref_hdr *)temp->value)->ref); - - t->delete_func(temp->value); - } - - free(temp); - t->size--; - } - - /* the tree is gone now, clear all the other variables */ - t->top = NULL; - t->free_list = NULL; - t->free_nodes = 0; - t->delete_func = NULL; - - pthread_mutex_unlock(&t->mutex); - pthread_mutex_destroy(&t->mutex); -} - -/* bt_init - * - * Initialize a btree with a delete callback function that is used to delete - * values during bt_node_free() and bt_destroy(). - */ -void bt_init(struct btree *t, void (*delete_func)(void *)) -{ - pthread_mutexattr_t attr; - - t->free_list = NULL; - t->top = NULL; - t->size = 0; - t->free_nodes = 0; - t->delete_func = delete_func; - - /* - * Need a recursive mutex, because btree callback functions may call - * btree functions again - */ - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&t->mutex, &attr); -} diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/lock_sess_mgr.c opencryptoki-3.21.0+dfsg/usr/lib/common/lock_sess_mgr.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/lock_sess_mgr.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/lock_sess_mgr.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1349 +0,0 @@ -/* - * COPYRIGHT (c) International Business Machines Corp. 2001-2017 - * - * 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 - */ - -// File: session.c -// -// Session manager related functions -// -#include -#include // for memcmp() et al -#include - -#include "pkcs11types.h" -#include "local_types.h" -#include "defs.h" -#include "host_defs.h" -#include "h_extern.h" -#include "tok_spec_struct.h" -#include "trace.h" - -// session_mgr_find() -// -// search for the specified session. returning a pointer to the session -// might be dangerous, but performs well. -// -// The returned session must be put back (using bt_put_node_value()) by the -// caller to decrease the reference count! -// -// Returns: SESSION * or NULL -// -SESSION *session_mgr_find(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE handle) -{ - SESSION *result = NULL; - - if (!handle) { - return NULL; - } - - result = bt_get_node_value(&tokdata->sess_btree, handle); - - return result; -} - -// session_mgr_find_reset_error() -// -// search for the specified session and reset the ulDeviceError field -// in the session info. returning a pointer to the session might be -// dangerous, but performs well -// -// The returned session must be put back (using bt_put_node_value()) by the -// caller to decrease the reference count! -// -// Returns: SESSION * or NULL -// -SESSION *session_mgr_find_reset_error(STDLL_TokData_t *tokdata, - CK_SESSION_HANDLE handle) -{ - SESSION *res = session_mgr_find(tokdata, handle); - - if (res) - res->session_info.ulDeviceError = 0; - return res; -} - -void session_mgr_put(STDLL_TokData_t *tokdata, SESSION *session) -{ - bt_put_node_value(&tokdata->sess_btree, session); -} - -// session_mgr_new() -// -// creates a new session structure and adds it to the process's list -// of sessions -// -// Args: CK_ULONG flags : session flags (INPUT) -// SESSION ** sess : new session pointer (OUTPUT) -// -// Returns: CK_RV -// -CK_RV session_mgr_new(STDLL_TokData_t *tokdata, CK_ULONG flags, - CK_SLOT_ID slot_id, CK_SESSION_HANDLE_PTR phSession) -{ - SESSION *new_session = NULL; - CK_BBOOL user_session = FALSE; - CK_BBOOL so_session = FALSE; - CK_RV rc = CKR_OK; - - - new_session = (SESSION *) malloc(sizeof(SESSION)); - if (!new_session) { - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - rc = CKR_HOST_MEMORY; - goto done; - } - - memset(new_session, 0x0, sizeof(SESSION)); - - // find an unused session handle. session handles will wrap automatically... - // - new_session->session_info.slotID = slot_id; - new_session->session_info.flags = flags; - new_session->session_info.ulDeviceError = 0; - - - // determine the login/logout status of the new session. PKCS 11 requires - // that all sessions belonging to a process have the same login/logout - // status - // - so_session = session_mgr_so_session_exists(tokdata); - user_session = session_mgr_user_session_exists(tokdata); - - if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Write Lock failed.\n"); - rc = CKR_CANT_LOCK; - goto done; - } - - // we don't have to worry about having a user and SO session at the same - // time. that is prevented in the login routine - // - if (user_session) { - if (new_session->session_info.flags & CKF_RW_SESSION) { - new_session->session_info.state = CKS_RW_USER_FUNCTIONS; - } else { - new_session->session_info.state = CKS_RO_USER_FUNCTIONS; - tokdata->ro_session_count++; - } - } else if (so_session) { - new_session->session_info.state = CKS_RW_SO_FUNCTIONS; - } else { - if (new_session->session_info.flags & CKF_RW_SESSION) { - new_session->session_info.state = CKS_RW_PUBLIC_SESSION; - } else { - new_session->session_info.state = CKS_RO_PUBLIC_SESSION; - tokdata->ro_session_count++; - } - } - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - *phSession = bt_node_add(&tokdata->sess_btree, new_session); - if (*phSession == 0) { - rc = CKR_HOST_MEMORY; - /* new_session will be free'd below */ - } - -done: - if (rc != CKR_OK && new_session != NULL) { - TRACE_ERROR("Failed to add session to the btree.\n"); - free(new_session); - } - - return rc; -} - - -// session_mgr_so_session_exists() -// -// determines whether a RW_SO session exists for the specified process -// -// Returns: TRUE or FALSE -// -CK_BBOOL session_mgr_so_session_exists(STDLL_TokData_t *tokdata) -{ - CK_BBOOL result; - - /* we must acquire sess_list_rwlock in order to inspect - * global_login_state */ - if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Read Lock failed.\n"); - return FALSE; - } - result = (tokdata->global_login_state == CKS_RW_SO_FUNCTIONS); - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return result; -} - - -// session_mgr_user_session_exists() -// -// determines whether a USER session exists for the specified process -// -// Returns: TRUE or FALSE -// -CK_BBOOL session_mgr_user_session_exists(STDLL_TokData_t *tokdata) -{ - CK_BBOOL result; - - /* we must acquire sess_list_rwlock in order to inspect - * glogal_login_state */ - if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Read Lock failed.\n"); - return FALSE; - } - result = ((tokdata->global_login_state == CKS_RO_USER_FUNCTIONS) || - (tokdata->global_login_state == CKS_RW_USER_FUNCTIONS)); - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return result; -} - - -// session_mgr_public_session_exists() -// -// determines whether a PUBLIC session exists for the specified process -// -// Returns: TRUE or FALSE -// -CK_BBOOL session_mgr_public_session_exists(STDLL_TokData_t *tokdata) -{ - CK_BBOOL result; - - /* we must acquire sess_list_rwlock in order to inspect - * global_login_state */ - if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Read Lock failed.\n"); - return FALSE; - } - result = ((tokdata->global_login_state == CKS_RO_PUBLIC_SESSION) || - (tokdata->global_login_state == CKS_RW_PUBLIC_SESSION)); - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return result; -} - - -// session_mgr_readonly_exists() -// -// determines whether the specified process owns any read-only sessions. this is -// useful because the SO cannot log in if a read-only session exists. -// -CK_BBOOL session_mgr_readonly_session_exists(STDLL_TokData_t *tokdata) -{ - CK_BBOOL result; - - /* we must acquire sess_list_rwlock in order to inspect ro_session_count */ - if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Read Lock failed.\n"); - return FALSE; - } - - result = (tokdata->ro_session_count > 0); - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return result; -} - - -// session_mgr_close_session() -// -// removes the specified session from the process' session list -// -// Args: PROCESS * proc : parent process -// SESSION * session : session to remove -// -// Returns: TRUE on success else FALSE -// -CK_RV session_mgr_close_session(STDLL_TokData_t *tokdata, - CK_SESSION_HANDLE handle) -{ - SESSION *sess; - CK_RV rc = CKR_OK; - - sess = bt_get_node_value(&tokdata->sess_btree, handle); - if (!sess) { - TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); - return CKR_SESSION_HANDLE_INVALID; - } - - if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Write Lock failed.\n"); - bt_put_node_value(&tokdata->sess_btree, sess); - sess = NULL; - return CKR_CANT_LOCK; - } - - object_mgr_purge_session_objects(tokdata, sess, ALL); - - if ((sess->session_info.state == CKS_RO_PUBLIC_SESSION) || - (sess->session_info.state == CKS_RO_USER_FUNCTIONS)) { - tokdata->ro_session_count--; - } - - // Make sure this address is now invalid - sess->handle = CK_INVALID_HANDLE; - - if (sess->find_list) - free(sess->find_list); - - if (sess->encr_ctx.context) { - if (sess->encr_ctx.context_free_func != NULL) - sess->encr_ctx.context_free_func(tokdata, sess, - sess->encr_ctx.context, - sess->encr_ctx.context_len); - else - free(sess->encr_ctx.context); - } - - if (sess->encr_ctx.mech.pParameter) - free(sess->encr_ctx.mech.pParameter); - - if (sess->decr_ctx.context) { - if (sess->decr_ctx.context_free_func != NULL) - sess->decr_ctx.context_free_func(tokdata, sess, - sess->decr_ctx.context, - sess->decr_ctx.context_len); - else - free(sess->decr_ctx.context); - } - - if (sess->decr_ctx.mech.pParameter) - free(sess->decr_ctx.mech.pParameter); - - if (sess->digest_ctx.context) { - if (sess->digest_ctx.context_free_func != NULL) - sess->digest_ctx.context_free_func(tokdata, sess, - sess->digest_ctx.context, - sess->digest_ctx.context_len); - else - free(sess->digest_ctx.context); - } - - if (sess->digest_ctx.mech.pParameter) - free(sess->digest_ctx.mech.pParameter); - - if (sess->sign_ctx.context) { - if (sess->sign_ctx.context_free_func != NULL) - sess->sign_ctx.context_free_func(tokdata, sess, - sess->sign_ctx.context, - sess->sign_ctx.context_len); - else - free(sess->sign_ctx.context); - } - - if (sess->sign_ctx.mech.pParameter) - free(sess->sign_ctx.mech.pParameter); - - if (sess->verify_ctx.context) { - if (sess->verify_ctx.context_free_func != NULL) - sess->verify_ctx.context_free_func(tokdata, sess, - sess->verify_ctx.context, - sess->verify_ctx.context_len); - else - free(sess->verify_ctx.context); - } - - if (sess->verify_ctx.mech.pParameter) - free(sess->verify_ctx.mech.pParameter); - - bt_put_node_value(&tokdata->sess_btree, sess); - sess = NULL; - bt_node_free(&tokdata->sess_btree, handle, TRUE); - - // XXX XXX Not having this is a problem - // for IHS. The spec states that there is an implicit logout - // when the last session is closed. Cannonicaly this is what other - // implementaitons do. however on linux for some reason IHS can't seem - // to keep the session open, which means that they go through the login - // path EVERY time, which of course causes a reload of the private - // objects EVERY time. If we are logged out, we MUST purge the private - // objects from this process.. - // - if (bt_is_empty(&tokdata->sess_btree)) { - // SAB XXX if all sessions are closed. Is this effectivly logging out - if (token_specific.t_logout) { - rc = token_specific.t_logout(tokdata); - } - object_mgr_purge_private_token_objects(tokdata); - - tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; - // The objects really need to be purged .. but this impacts the - // performance under linux. So we need to make sure that the - // login state is valid. I don't really like this. - object_mgr_purge_map(tokdata, (SESSION *) 0xFFFF, PRIVATE); - } - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - return rc; -} - -/* session_free - * - * Callback used to free an individual SESSION object - */ -void session_free(STDLL_TokData_t *tokdata, void *node_value, - unsigned long node_idx, void *p3) -{ - SESSION *sess = (SESSION *) node_value; - - UNUSED(p3); - - object_mgr_purge_session_objects(tokdata, sess, ALL); - sess->handle = CK_INVALID_HANDLE; - - if (sess->find_list) - free(sess->find_list); - - if (sess->encr_ctx.context) { - if (sess->encr_ctx.context_free_func != NULL) - sess->encr_ctx.context_free_func(tokdata, sess, - sess->encr_ctx.context, - sess->encr_ctx.context_len); - else - free(sess->encr_ctx.context); - } - - if (sess->encr_ctx.mech.pParameter) - free(sess->encr_ctx.mech.pParameter); - - if (sess->decr_ctx.context) { - if (sess->decr_ctx.context_free_func != NULL) - sess->decr_ctx.context_free_func(tokdata, sess, - sess->decr_ctx.context, - sess->decr_ctx.context_len); - else - free(sess->decr_ctx.context); - } - - if (sess->decr_ctx.mech.pParameter) - free(sess->decr_ctx.mech.pParameter); - - if (sess->digest_ctx.context) { - if (sess->digest_ctx.context_free_func != NULL) - sess->digest_ctx.context_free_func(tokdata, sess, - sess->digest_ctx.context, - sess->digest_ctx.context_len); - else - free(sess->digest_ctx.context); - } - - if (sess->digest_ctx.mech.pParameter) - free(sess->digest_ctx.mech.pParameter); - - if (sess->sign_ctx.context) { - if (sess->sign_ctx.context_free_func != NULL) - sess->sign_ctx.context_free_func(tokdata, sess, - sess->sign_ctx.context, - sess->sign_ctx.context_len); - else - free(sess->sign_ctx.context); - } - - if (sess->sign_ctx.mech.pParameter) - free(sess->sign_ctx.mech.pParameter); - - if (sess->verify_ctx.context) { - if (sess->verify_ctx.context_free_func != NULL) - sess->verify_ctx.context_free_func(tokdata, sess, - sess->verify_ctx.context, - sess->verify_ctx.context_len); - else - free(sess->verify_ctx.context); - } - - if (sess->verify_ctx.mech.pParameter) - free(sess->verify_ctx.mech.pParameter); - - /* NB: any access to sess or @node_value after this returns will segfault */ - bt_node_free(&tokdata->sess_btree, node_idx, TRUE); -} - -// session_mgr_close_all_sessions() -// -// removes all sessions from the specified process. -// If tokdata is not NULL, then only sessions for that token instance are -// removed. -// -CK_RV session_mgr_close_all_sessions(STDLL_TokData_t *tokdata) -{ - bt_for_each_node(tokdata, &tokdata->sess_btree, session_free, NULL); - - if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Write Lock failed.\n"); - return CKR_CANT_LOCK; - } - - tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; - tokdata->ro_session_count = 0; - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return CKR_OK; -} - -/* session_login - * - * Callback used to update a SESSION object's login state to logged in based on - * user type - */ -void session_login(STDLL_TokData_t *tokdata, void *node_value, - unsigned long node_idx, void *p3) -{ - SESSION *s = (SESSION *) node_value; - CK_USER_TYPE user_type = *(CK_USER_TYPE *) p3; - - UNUSED(tokdata); - UNUSED(node_idx); - - if (s->session_info.flags & CKF_RW_SESSION) { - if (user_type == CKU_USER) - s->session_info.state = CKS_RW_USER_FUNCTIONS; - else - s->session_info.state = CKS_RW_SO_FUNCTIONS; - } else { - if (user_type == CKU_USER) - s->session_info.state = CKS_RO_USER_FUNCTIONS; - } - - tokdata->global_login_state = s->session_info.state; // SAB -} - -// session_mgr_login_all() -// -// changes the login status of all sessions in the token -// -// Arg: CK_USER_TYPE user_type : USER or SO -// -CK_RV session_mgr_login_all(STDLL_TokData_t *tokdata, CK_USER_TYPE user_type) -{ - if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Write Lock failed.\n"); - return CKR_CANT_LOCK; - } - - bt_for_each_node(tokdata, &tokdata->sess_btree, session_login, - (void *)&user_type); - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return CKR_OK; -} - -/* session_logout - * - * Callback used to update a SESSION object's login state to be logged out - */ -void session_logout(STDLL_TokData_t *tokdata, void *node_value, - unsigned long node_idx, void *p3) -{ - SESSION *s = (SESSION *) node_value; - - UNUSED(node_idx); - UNUSED(p3); - - // all sessions get logged out so destroy any private objects - // public objects are left alone - // - object_mgr_purge_session_objects(tokdata, s, PRIVATE); - - if (s->session_info.flags & CKF_RW_SESSION) - s->session_info.state = CKS_RW_PUBLIC_SESSION; - else - s->session_info.state = CKS_RO_PUBLIC_SESSION; - - tokdata->global_login_state = s->session_info.state; // SAB -} - -// session_mgr_logout_all() -// -// changes the login status of all sessions in the token -// -CK_RV session_mgr_logout_all(STDLL_TokData_t *tokdata) -{ - if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { - TRACE_ERROR("Write Lock failed.\n"); - return CKR_CANT_LOCK; - } - - bt_for_each_node(tokdata, &tokdata->sess_btree, session_logout, NULL); - - pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - - return CKR_OK; -} - - -// -// -CK_RV session_mgr_get_op_state(STDLL_TokData_t *tokdata, SESSION *sess, - CK_BBOOL length_only, - CK_BYTE *data, CK_ULONG *data_len) -{ - OP_STATE_DATA *op_data = NULL; - CK_ULONG max_data_len = *data_len; - CK_ULONG op_data_len; - CK_ULONG all_data_len = 0; - CK_ULONG offset, active_ops; - - if (!sess) { - TRACE_ERROR("Invalid function arguments.\n"); - return CKR_FUNCTION_FAILED; - } - - if (sess->find_active == TRUE) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - - // ensure that at least one operation is active - // - active_ops = 0; - - if (sess->encr_ctx.active == TRUE) { - if (sess->encr_ctx.state_unsaveable) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - active_ops++; - op_data_len = sizeof(OP_STATE_DATA) + - sizeof(ENCR_DECR_CONTEXT) + - sess->encr_ctx.context_len + sess->encr_ctx.mech.ulParameterLen; - all_data_len += op_data_len; - - if (length_only == FALSE) { - op_data = (OP_STATE_DATA *) data; - - if (max_data_len < op_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); - return CKR_BUFFER_TOO_SMALL; - } - - memset(op_data, 0, sizeof(*op_data)); -#ifdef PACKAGE_VERSION - strncpy((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)); -#endif - memcpy(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)); - memcpy(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)); - op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); - op_data->session_state = sess->session_info.state; - op_data->active_operation = STATE_ENCR; - - offset = sizeof(OP_STATE_DATA); - - memcpy((CK_BYTE *) op_data + offset, - &sess->encr_ctx, sizeof(ENCR_DECR_CONTEXT)); - - offset += sizeof(ENCR_DECR_CONTEXT); - - if (sess->encr_ctx.context_len != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->encr_ctx.context, sess->encr_ctx.context_len); - - offset += sess->encr_ctx.context_len; - } - - if (sess->encr_ctx.mech.ulParameterLen != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->encr_ctx.mech.pParameter, - sess->encr_ctx.mech.ulParameterLen); - } - - max_data_len -= op_data_len; - data += op_data_len; - } - } - - if (sess->decr_ctx.active == TRUE) { - if (sess->decr_ctx.state_unsaveable) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - active_ops++; - op_data_len = sizeof(OP_STATE_DATA) + - sizeof(ENCR_DECR_CONTEXT) + - sess->decr_ctx.context_len + sess->decr_ctx.mech.ulParameterLen; - all_data_len += op_data_len; - - if (length_only == FALSE) { - op_data = (OP_STATE_DATA *) data; - - if (max_data_len < op_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); - return CKR_BUFFER_TOO_SMALL; - } - - memset(op_data, 0, sizeof(*op_data)); -#ifdef PACKAGE_VERSION - strncpy((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)); -#endif - memcpy(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)); - memcpy(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)); - op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); - op_data->session_state = sess->session_info.state; - op_data->active_operation = STATE_DECR; - - offset = sizeof(OP_STATE_DATA); - - memcpy((CK_BYTE *) op_data + offset, - &sess->decr_ctx, sizeof(ENCR_DECR_CONTEXT)); - - offset += sizeof(ENCR_DECR_CONTEXT); - - if (sess->decr_ctx.context_len != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->decr_ctx.context, sess->decr_ctx.context_len); - - offset += sess->decr_ctx.context_len; - } - - if (sess->decr_ctx.mech.ulParameterLen != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->decr_ctx.mech.pParameter, - sess->decr_ctx.mech.ulParameterLen); - } - - max_data_len -= op_data_len; - data += op_data_len; - } - } - - if (sess->digest_ctx.active == TRUE) { - if (sess->digest_ctx.state_unsaveable) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - active_ops++; - op_data_len = sizeof(OP_STATE_DATA) + - sizeof(DIGEST_CONTEXT) + - sess->digest_ctx.context_len + sess->digest_ctx.mech.ulParameterLen; - all_data_len += op_data_len; - - if (length_only == FALSE) { - op_data = (OP_STATE_DATA *) data; - - if (max_data_len < op_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); - return CKR_BUFFER_TOO_SMALL; - } - - memset(op_data, 0, sizeof(*op_data)); -#ifdef PACKAGE_VERSION - strncpy((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)); -#endif - memcpy(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)); - memcpy(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)); - op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); - op_data->session_state = sess->session_info.state; - op_data->active_operation = STATE_DIGEST; - - offset = sizeof(OP_STATE_DATA); - - memcpy((CK_BYTE *) op_data + offset, - &sess->digest_ctx, sizeof(DIGEST_CONTEXT)); - - offset += sizeof(DIGEST_CONTEXT); - - if (sess->digest_ctx.context_len != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->digest_ctx.context, sess->digest_ctx.context_len); - - offset += sess->digest_ctx.context_len; - } - - if (sess->digest_ctx.mech.ulParameterLen != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->digest_ctx.mech.pParameter, - sess->digest_ctx.mech.ulParameterLen); - } - - max_data_len -= op_data_len; - data += op_data_len; - } - } - - if (sess->sign_ctx.active == TRUE) { - if (sess->sign_ctx.state_unsaveable) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - active_ops++; - op_data_len = sizeof(OP_STATE_DATA) + - sizeof(SIGN_VERIFY_CONTEXT) + - sess->sign_ctx.context_len + sess->sign_ctx.mech.ulParameterLen; - all_data_len += op_data_len; - - if (length_only == FALSE) { - op_data = (OP_STATE_DATA *) data; - - if (max_data_len < op_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); - return CKR_BUFFER_TOO_SMALL; - } - - memset(op_data, 0, sizeof(*op_data)); -#ifdef PACKAGE_VERSION - strncpy((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)); -#endif - memcpy(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)); - memcpy(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)); - op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); - op_data->session_state = sess->session_info.state; - op_data->active_operation = STATE_SIGN; - - offset = sizeof(OP_STATE_DATA); - - memcpy((CK_BYTE *) op_data + offset, - &sess->sign_ctx, sizeof(SIGN_VERIFY_CONTEXT)); - - offset += sizeof(SIGN_VERIFY_CONTEXT); - - if (sess->sign_ctx.context_len != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->sign_ctx.context, sess->sign_ctx.context_len); - - offset += sess->sign_ctx.context_len; - } - - if (sess->sign_ctx.mech.ulParameterLen != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->sign_ctx.mech.pParameter, - sess->sign_ctx.mech.ulParameterLen); - } - - max_data_len -= op_data_len; - data += op_data_len; - } - } - - if (sess->verify_ctx.active == TRUE) { - if (sess->verify_ctx.state_unsaveable) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_STATE_UNSAVEABLE; - } - active_ops++; - op_data_len = sizeof(OP_STATE_DATA) + - sizeof(SIGN_VERIFY_CONTEXT) + - sess->verify_ctx.context_len + sess->verify_ctx.mech.ulParameterLen; - all_data_len += op_data_len; - - if (length_only == FALSE) { - op_data = (OP_STATE_DATA *) data; - - if (max_data_len < op_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); - return CKR_BUFFER_TOO_SMALL; - } - - memset(op_data, 0, sizeof(*op_data)); -#ifdef PACKAGE_VERSION - strncpy((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)); -#endif - memcpy(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)); - memcpy(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)); - op_data->data_len = op_data_len - sizeof(OP_STATE_DATA); - op_data->session_state = sess->session_info.state; - op_data->active_operation = STATE_VERIFY; - - offset = sizeof(OP_STATE_DATA); - - memcpy((CK_BYTE *) op_data + offset, - &sess->verify_ctx, sizeof(SIGN_VERIFY_CONTEXT)); - - offset += sizeof(SIGN_VERIFY_CONTEXT); - - if (sess->verify_ctx.context_len != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->verify_ctx.context, sess->verify_ctx.context_len); - - offset += sess->verify_ctx.context_len; - } - - if (sess->verify_ctx.mech.ulParameterLen != 0) { - memcpy((CK_BYTE *) op_data + offset, - sess->verify_ctx.mech.pParameter, - sess->verify_ctx.mech.ulParameterLen); - } - - max_data_len -= op_data_len; - data += op_data_len; - } - } - - if (active_ops == 0) { - TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); - return CKR_OPERATION_NOT_INITIALIZED; - } - - *data_len = all_data_len; - return CKR_OK; -} - - -// -// -CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess, - CK_OBJECT_HANDLE encr_key, - CK_OBJECT_HANDLE auth_key, - CK_BYTE *data, CK_ULONG data_len) -{ - CK_BYTE *cur_data; - CK_ULONG cur_data_len; - OP_STATE_DATA *op_data = NULL; - CK_BYTE *mech_param = NULL; - CK_BYTE *context = NULL; - CK_BYTE *ptr1 = NULL; - CK_BYTE *ptr2 = NULL; - CK_BYTE *ptr3 = NULL; - CK_ULONG len; - CK_ULONG encr_key_needed = 0; - CK_ULONG auth_key_needed = 0; - - if (!sess || !data) { - TRACE_ERROR("%s received bad argument(s)\n", __func__); - return CKR_FUNCTION_FAILED; - } - - /* - * Validate the new state information. Don't touch the session - * until the new state is valid. - */ - cur_data = data; - cur_data_len = data_len; - while (cur_data_len >= sizeof(OP_STATE_DATA)) { - op_data = (OP_STATE_DATA *)cur_data; - - if (cur_data_len < op_data->data_len + sizeof(OP_STATE_DATA)) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - /* - * Make sure the session states are compatible: same OCK version, - * same token model, same session state. - */ -#ifdef PACKAGE_VERSION - if (strncmp((char *)op_data->library_version, PACKAGE_VERSION, - sizeof(op_data->library_version)) != 0) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } -#endif - if (memcmp(op_data->manufacturerID, - tokdata->nv_token_data->token_info.manufacturerID, - sizeof(op_data->manufacturerID)) != 0 || - memcmp(op_data->model, tokdata->nv_token_data->token_info.model, - sizeof(op_data->model)) != 0) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - if (sess->session_info.state != op_data->session_state) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - switch (op_data->active_operation) { - case STATE_ENCR: - case STATE_DECR: - { - ENCR_DECR_CONTEXT *ctx = - (ENCR_DECR_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(ENCR_DECR_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - encr_key_needed++; - } - break; - - case STATE_SIGN: - case STATE_VERIFY: - { - SIGN_VERIFY_CONTEXT *ctx = - (SIGN_VERIFY_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(SIGN_VERIFY_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - auth_key_needed++; - } - break; - - case STATE_DIGEST: - { - DIGEST_CONTEXT *ctx = - (DIGEST_CONTEXT *) (cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(DIGEST_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - } - break; - default: - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - /* move on to next operation */ - cur_data_len -= (op_data->data_len + sizeof(OP_STATE_DATA)); - cur_data += (op_data->data_len + sizeof(OP_STATE_DATA)); - } - /* nothing must be left over */ - if (cur_data_len > 0) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - if (encr_key_needed > 0 && encr_key == CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); - return CKR_KEY_NEEDED; - } - if (encr_key_needed == 0 && encr_key != CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); - return CKR_KEY_NOT_NEEDED; - } - if (auth_key_needed > 0 && auth_key == CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); - return CKR_KEY_NEEDED; - } - if (auth_key_needed == 0 && auth_key != CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); - return CKR_KEY_NOT_NEEDED; - } - - /* State information looks okay. Cleanup the current session state, first */ - if (sess->encr_ctx.active) - encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx); - if (sess->decr_ctx.active) - decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); - if (sess->digest_ctx.active) - digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx); - if (sess->sign_ctx.active) - sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); - if (sess->verify_ctx.active) - verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); - - /* Now process the saved operation states */ - cur_data = data; - cur_data_len = data_len; - while (cur_data_len >= sizeof(OP_STATE_DATA)) { - op_data = (OP_STATE_DATA *)cur_data; - - if (cur_data_len < op_data->data_len + sizeof(OP_STATE_DATA)) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - switch (op_data->active_operation) { - case STATE_ENCR: - case STATE_DECR: - { - ENCR_DECR_CONTEXT *ctx = - (ENCR_DECR_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(ENCR_DECR_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - if (encr_key == CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); - return CKR_KEY_NEEDED; - } - ptr1 = (CK_BYTE *) ctx; - ptr2 = ptr1 + sizeof(ENCR_DECR_CONTEXT); - ptr3 = ptr2 + ctx->context_len; - - if (ctx->context_len) { - context = (CK_BYTE *) malloc(ctx->context_len); - if (!context) { - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(context, ptr2, ctx->context_len); - } - - if (ctx->mech.ulParameterLen) { - mech_param = (CK_BYTE *) malloc(ctx->mech.ulParameterLen); - if (!mech_param) { - if (context) - free(context); - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(mech_param, ptr3, ctx->mech.ulParameterLen); - } - } - break; - - case STATE_SIGN: - case STATE_VERIFY: - { - SIGN_VERIFY_CONTEXT *ctx = - (SIGN_VERIFY_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(SIGN_VERIFY_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - if (auth_key == CK_INVALID_HANDLE) { - TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); - return CKR_KEY_NEEDED; - } - ptr1 = (CK_BYTE *) ctx; - ptr2 = ptr1 + sizeof(SIGN_VERIFY_CONTEXT); - ptr3 = ptr2 + ctx->context_len; - - if (ctx->context_len) { - context = (CK_BYTE *) malloc(ctx->context_len); - if (!context) { - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(context, ptr2, ctx->context_len); - } - - if (ctx->mech.ulParameterLen) { - mech_param = (CK_BYTE *) malloc(ctx->mech.ulParameterLen); - if (!mech_param) { - if (context) - free(context); - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(mech_param, ptr3, ctx->mech.ulParameterLen); - } - } - break; - - case STATE_DIGEST: - { - DIGEST_CONTEXT *ctx = - (DIGEST_CONTEXT *)(cur_data + sizeof(OP_STATE_DATA)); - - len = sizeof(DIGEST_CONTEXT) + ctx->context_len + - ctx->mech.ulParameterLen; - if (len != op_data->data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - ptr1 = (CK_BYTE *) ctx; - ptr2 = ptr1 + sizeof(DIGEST_CONTEXT); - ptr3 = ptr2 + ctx->context_len; - - if (ctx->context_len) { - context = (CK_BYTE *) malloc(ctx->context_len); - if (!context) { - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(context, ptr2, ctx->context_len); - } - - if (ctx->mech.ulParameterLen) { - mech_param = (CK_BYTE *) malloc(ctx->mech.ulParameterLen); - if (!mech_param) { - if (context) - free(context); - TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - return CKR_HOST_MEMORY; - } - memcpy(mech_param, ptr3, ctx->mech.ulParameterLen); - } - } - break; - default: - TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); - return CKR_SAVED_STATE_INVALID; - } - - /* copy the new state information */ - switch (op_data->active_operation) { - case STATE_ENCR: - memcpy(&sess->encr_ctx, ptr1, sizeof(ENCR_DECR_CONTEXT)); - - sess->encr_ctx.key = encr_key; - sess->encr_ctx.context = context; - sess->encr_ctx.mech.pParameter = mech_param; - break; - - case STATE_DECR: - memcpy(&sess->decr_ctx, ptr1, sizeof(ENCR_DECR_CONTEXT)); - - sess->decr_ctx.key = encr_key; - sess->decr_ctx.context = context; - sess->decr_ctx.mech.pParameter = mech_param; - break; - - case STATE_SIGN: - memcpy(&sess->sign_ctx, ptr1, sizeof(SIGN_VERIFY_CONTEXT)); - - sess->sign_ctx.key = auth_key; - sess->sign_ctx.context = context; - sess->sign_ctx.mech.pParameter = mech_param; - break; - - case STATE_VERIFY: - memcpy(&sess->verify_ctx, ptr1, sizeof(SIGN_VERIFY_CONTEXT)); - - sess->verify_ctx.key = auth_key; - sess->verify_ctx.context = context; - sess->verify_ctx.mech.pParameter = mech_param; - break; - - case STATE_DIGEST: - memcpy(&sess->digest_ctx, ptr1, sizeof(DIGEST_CONTEXT)); - - sess->digest_ctx.context = context; - sess->digest_ctx.mech.pParameter = mech_param; - break; - } - - context = NULL; - mech_param = NULL; - - /* move on to next operation */ - cur_data_len -= (op_data->data_len + sizeof(OP_STATE_DATA)); - cur_data += (op_data->data_len + sizeof(OP_STATE_DATA)); - } - - return CKR_OK; -} - -CK_RV session_mgr_cancel(STDLL_TokData_t *tokdata, SESSION *sess, - CK_FLAGS flags) -{ - if ((flags & CKF_ENCRYPT) && sess->encr_ctx.active) - encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx); - - if ((flags & CKF_DECRYPT) && sess->decr_ctx.active) - decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); - - if ((flags & CKF_DIGEST) && sess->digest_ctx.active) - digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx); - - if ((flags & CKF_SIGN) && sess->sign_ctx.active && - !sess->sign_ctx.recover) - sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); - - if ((flags & CKF_SIGN_RECOVER) && sess->sign_ctx.active && - sess->sign_ctx.recover) - sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx); - - if ((flags & CKF_VERIFY) && sess->verify_ctx.active && - !sess->verify_ctx.recover) - verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); - - if ((flags & CKF_VERIFY_RECOVER) && sess->verify_ctx.active && - sess->verify_ctx.recover) - verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx); - - if ((flags & CKF_FIND_OBJECTS) && sess->find_active) { - if (sess->find_list) - free(sess->find_list); - sess->find_list = NULL; - sess->find_len = 0; - sess->find_idx = 0; - sess->find_active = FALSE; - } - - return CKR_OK; -} - -// Return TRUE if the session we're in has its PIN expired. -CK_BBOOL pin_expired(CK_SESSION_INFO *si, CK_FLAGS flags) -{ - // If this is an SO session - if ((flags & CKF_SO_PIN_TO_BE_CHANGED) && - (si->state == CKS_RW_SO_FUNCTIONS)) - return TRUE; - - // Else we're a User session - return ((flags & CKF_USER_PIN_TO_BE_CHANGED) && - ((si->state == CKS_RO_USER_FUNCTIONS) || - (si->state == CKS_RW_USER_FUNCTIONS))); -} - -// Return TRUE if the session we're in has its PIN locked. -CK_BBOOL pin_locked(CK_SESSION_INFO *si, CK_FLAGS flags) -{ - // If this is an SO session - if ((flags & CKF_SO_PIN_LOCKED) && (si->state == CKS_RW_SO_FUNCTIONS)) - return TRUE; - - // Else we're a User session - return ((flags & CKF_USER_PIN_LOCKED) && - ((si->state == CKS_RO_USER_FUNCTIONS) || - (si->state == CKS_RW_USER_FUNCTIONS))); -} - -// Increment the login flags after an incorrect password -// has been passed to C_Login. New for v2.11. - KEY -void set_login_flags(CK_USER_TYPE userType, CK_FLAGS_32 *flags) -{ - if (userType == CKU_USER) { - if (*flags & CKF_USER_PIN_FINAL_TRY) { - *flags |= CKF_USER_PIN_LOCKED; - *flags &= ~(CKF_USER_PIN_FINAL_TRY); - } else if (*flags & CKF_USER_PIN_COUNT_LOW) { - *flags |= CKF_USER_PIN_FINAL_TRY; - *flags &= ~(CKF_USER_PIN_COUNT_LOW); - } else { - *flags |= CKF_USER_PIN_COUNT_LOW; - } - } else { - if (*flags & CKF_SO_PIN_FINAL_TRY) { - *flags |= CKF_SO_PIN_LOCKED; - *flags &= ~(CKF_SO_PIN_FINAL_TRY); - } else if (*flags & CKF_SO_PIN_COUNT_LOW) { - *flags |= CKF_SO_PIN_FINAL_TRY; - *flags &= ~(CKF_SO_PIN_COUNT_LOW); - } else { - *flags |= CKF_SO_PIN_COUNT_LOW; - } - } -} diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_aes.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_aes.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_aes.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_aes.c 2023-05-15 14:42:55.000000000 +0200 @@ -66,7 +66,7 @@ goto done; } - rc = ckm_aes_ecb_encrypt(tokdata, in_data, in_data_len, + rc = ckm_aes_ecb_encrypt(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key); done: @@ -121,7 +121,7 @@ goto done; } - rc = ckm_aes_ecb_decrypt(tokdata, in_data, in_data_len, + rc = ckm_aes_ecb_decrypt(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key); done: @@ -176,7 +176,7 @@ goto done; } - rc = ckm_aes_cbc_encrypt(tokdata, in_data, in_data_len, out_data, + rc = ckm_aes_cbc_encrypt(tokdata, sess, in_data, in_data_len, out_data, out_data_len, ctx->mech.pParameter, key); done: @@ -229,7 +229,7 @@ goto done; } - rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, out_data, + rc = ckm_aes_cbc_decrypt(tokdata, sess, in_data, in_data_len, out_data, out_data_len, ctx->mech.pParameter, key); done: @@ -296,7 +296,7 @@ add_pkcs_padding(clear + in_data_len, AES_BLOCK_SIZE, in_data_len, padded_len); - rc = ckm_aes_cbc_encrypt(tokdata, clear, padded_len, out_data, out_data_len, + rc = ckm_aes_cbc_encrypt(tokdata, sess, clear, padded_len, out_data, out_data_len, ctx->mech.pParameter, key); free(clear); @@ -363,7 +363,7 @@ rc = CKR_HOST_MEMORY; goto done; } - rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, clear, &padded_len, + rc = ckm_aes_cbc_decrypt(tokdata, sess, in_data, in_data_len, clear, &padded_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -627,7 +627,7 @@ memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); - rc = ckm_aes_ecb_encrypt(tokdata, clear, out_len, out_data, + rc = ckm_aes_ecb_encrypt(tokdata, sess, clear, out_len, out_data, out_data_len, key); if (rc == CKR_OK) { *out_data_len = out_len; @@ -712,7 +712,7 @@ memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); - rc = ckm_aes_ecb_decrypt(tokdata, cipher, out_len, out_data, + rc = ckm_aes_ecb_decrypt(tokdata, sess, cipher, out_len, out_data, out_data_len, key); if (rc == CKR_OK) { *out_data_len = out_len; @@ -797,7 +797,7 @@ memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); - rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, + rc = ckm_aes_cbc_encrypt(tokdata, sess, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -889,7 +889,7 @@ memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); - rc = ckm_aes_cbc_decrypt(tokdata, cipher, out_len, out_data, + rc = ckm_aes_cbc_decrypt(tokdata, sess, cipher, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -993,7 +993,7 @@ // // we don't do padding during the update // - rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, + rc = ckm_aes_cbc_encrypt(tokdata, sess, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -1093,7 +1093,7 @@ memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); - rc = ckm_aes_cbc_decrypt(tokdata, cipher, out_len, out_data, + rc = ckm_aes_cbc_decrypt(tokdata, sess, cipher, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -1598,7 +1598,7 @@ add_pkcs_padding(clear + context->len, AES_BLOCK_SIZE, context->len, out_len); - rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, + rc = ckm_aes_cbc_encrypt(tokdata, sess, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); } @@ -1652,7 +1652,7 @@ *out_data_len = out_len; rc = CKR_OK; } else { - rc = ckm_aes_cbc_decrypt(tokdata, context->data, AES_BLOCK_SIZE, clear, + rc = ckm_aes_cbc_decrypt(tokdata, sess, context->data, AES_BLOCK_SIZE, clear, &out_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { @@ -3799,10 +3799,10 @@ } if (xts) - rc = token_specific.t_aes_xts_key_gen(tokdata, &aes_key, &token_keysize, + rc = token_specific.t_aes_xts_key_gen(tokdata, tmpl, &aes_key, &token_keysize, key_size, &is_opaque); else - rc = token_specific.t_aes_key_gen(tokdata, &aes_key, &token_keysize, + rc = token_specific.t_aes_key_gen(tokdata, tmpl, &aes_key, &token_keysize, key_size, &is_opaque); if (rc != CKR_OK) goto err; @@ -3919,6 +3919,7 @@ // // CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, @@ -3940,7 +3941,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, + rc = token_specific.t_aes_ecb(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, 1); if (rc != CKR_OK) @@ -3952,6 +3953,7 @@ // // CK_RV ckm_aes_ecb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, @@ -3974,7 +3976,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, + rc = token_specific.t_aes_ecb(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, 0); if (rc != CKR_OK) @@ -3987,6 +3989,7 @@ // // CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, @@ -4010,7 +4013,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, + rc = token_specific.t_aes_cbc(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, init_v, 1); if (rc != CKR_OK) @@ -4023,6 +4026,7 @@ // // CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, @@ -4045,7 +4049,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, + rc = token_specific.t_aes_cbc(tokdata, sess, in_data, in_data_len, out_data, out_data_len, key, init_v, 0); if (rc != CKR_OK) diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_des3.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_des3.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_des3.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_des3.c 2023-05-15 14:42:55.000000000 +0200 @@ -2794,7 +2794,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_des_key_gen(tokdata, &des_key, &keysize, + rc = token_specific.t_des_key_gen(tokdata, tmpl, &des_key, &keysize, 3 * DES_KEY_SIZE, &is_opaque); if (rc != CKR_OK) goto err; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_des.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_des.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_des.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_des.c 2023-05-15 14:42:55.000000000 +0200 @@ -1235,7 +1235,7 @@ return CKR_MECHANISM_INVALID; } - rc = token_specific.t_des_key_gen(tokdata, &des_key, &keysize, + rc = token_specific.t_des_key_gen(tokdata, tmpl, &des_key, &keysize, DES_KEY_SIZE, &is_opaque); if (rc != CKR_OK) goto err; diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_ec.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_ec.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_ec.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_ec.c 2023-05-15 14:42:55.000000000 +0200 @@ -857,74 +857,6 @@ return rc; } -CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, - CK_MECHANISM_PTR mech, CK_ULONG *type, CK_ULONG *class) -{ - CK_RV rc; - - *type = 0; - *class = 0; - - rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_CLASS, class); - if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { - TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - - rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_KEY_TYPE, type); - if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { - TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - - if (rc == CKR_OK) - return CKR_OK; - - /* no CKA_KEY_TYPE found, derive from mech */ - switch (mech->mechanism) { - case CKM_DES_KEY_GEN: - *type = CKK_DES; - break; - case CKM_DES2_KEY_GEN: - *type = CKK_DES2; - break; - case CKM_DES3_KEY_GEN: - *type = CKK_DES3; - break; - case CKM_AES_KEY_GEN: - *type = CKK_AES; - break; - case CKM_AES_XTS_KEY_GEN: - *type = CKK_AES_XTS; - break; - case CKM_GENERIC_SECRET_KEY_GEN: - *type = CKK_GENERIC_SECRET; - break; - case CKM_RSA_PKCS_KEY_PAIR_GEN: - *type = CKK_RSA; - break; - case CKM_EC_KEY_PAIR_GEN: - *type = CKK_EC; - break; - case CKM_DSA_KEY_PAIR_GEN: - *type = CKK_DSA; - break; - case CKM_DH_PKCS_KEY_PAIR_GEN: - *type = CKK_DH; - break; - case CKM_IBM_DILITHIUM: - *type = CKK_IBM_PQC_DILITHIUM; - break; - case CKM_IBM_KYBER: - *type = CKK_IBM_PQC_KYBER; - break; - default: - return CKR_MECHANISM_INVALID; - } - - return CKR_OK; -} - /** * From PKCS#11 v2.40: PKCS #3 Diffie-Hellman key derivation * diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_openssl.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_openssl.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_openssl.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_openssl.c 2023-05-15 14:42:55.000000000 +0200 @@ -37,6 +37,101 @@ #include #endif +void openssl_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) +{ + struct openssl_ex_data *data = ex_data; + + if (ex_data == NULL || ex_data_len < sizeof(struct openssl_ex_data)) + return; + + if (data->pkey != NULL) { + EVP_PKEY_free(data->pkey); + data->pkey = NULL; + } + + free(data); + obj->ex_data = NULL; + obj->ex_data_len = 0; +} + +CK_RV openssl_reload_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) +{ + if (obj->ex_data_free != NULL) + obj->ex_data_free(obj, ex_data, ex_data_len); + return CKR_OK; +} + +/* + * Gets the attached OpenSSL ex_data from the key object. If no ex_data is + * attached yet, then a WRITE lock is obtained, the ex_data is allocated in the + * specified size, and the ex_data is returned. If the ex_data is already + * attached, the need_wr_lock routine is called to determine if a WRTE lock is + * needed. If the need_wr_lock routine returns TRUE, a WRITE lock is obtained, + * else, or if no need_wr_lock routine is specified, a READ lock is obtained + * and the ex_data is returned. The caller must release ex-data lock when + * finished working with it. + */ +CK_RV openssl_get_ex_data(OBJECT *obj, void **ex_data, size_t ex_data_len, + CK_BBOOL (*need_wr_lock)(OBJECT *obj, + void *ex_data, + size_t ex_data_len), + void (*ex_data_free)(struct _OBJECT *obj, + void *ex_data, + size_t ex_data_len)) +{ + CK_RV rc; + + rc = object_ex_data_lock(obj, READ_LOCK); + if (rc != CKR_OK) + return rc; + + if (obj->ex_data != NULL && + obj->ex_data_len >= ex_data_len && + (need_wr_lock == NULL || + need_wr_lock(obj, obj->ex_data, obj->ex_data_len) == FALSE)) { + *ex_data = obj->ex_data; + return CKR_OK; + } + + rc = object_ex_data_unlock(obj); + if (rc != CKR_OK) + return rc; + + rc = object_ex_data_lock(obj, WRITE_LOCK); + if (rc != CKR_OK) + return rc; + + if (obj->ex_data == NULL) { + obj->ex_data = calloc(1, ex_data_len); + if (obj->ex_data == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_ex_data_unlock(obj); + return CKR_HOST_MEMORY; + } + + obj->ex_data_len = ex_data_len; + obj->ex_data_free = ex_data_free != NULL ? ex_data_free : + openssl_free_ex_data; + obj->ex_data_reload = openssl_reload_ex_data; + } + + *ex_data = obj->ex_data; + return CKR_OK; +} + +static CK_BBOOL openssl_need_wr_lock(OBJECT *obj, void *ex_data, + size_t ex_data_len) +{ + struct openssl_ex_data *data = ex_data; + + UNUSED(obj); + + if (ex_data == NULL || ex_data_len < sizeof(struct openssl_ex_data)) + return FALSE; + + return data->pkey == NULL; +} + CK_RV openssl_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_ATTRIBUTE *publ_exp = NULL; @@ -876,6 +971,7 @@ CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { + struct openssl_ex_data *ex_data = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey = NULL; CK_RV rc; @@ -883,11 +979,26 @@ UNUSED(tokdata); - pkey = rsa_convert_public_key(key_obj); - if (pkey == NULL) { + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(struct openssl_ex_data), + openssl_need_wr_lock, NULL); + if (rc != CKR_OK) + return rc; + + if (ex_data->pkey == NULL) { + ex_data->pkey = rsa_convert_public_key(key_obj); + if (ex_data->pkey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + } + + pkey = ex_data->pkey; + if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; - return rc; + goto done; } ctx = EVP_PKEY_CTX_new(pkey, NULL); @@ -920,6 +1031,7 @@ EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); + object_ex_data_unlock(key_obj); return rc; } @@ -927,6 +1039,7 @@ CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { + struct openssl_ex_data *ex_data = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey = NULL; size_t outlen = in_data_len; @@ -934,11 +1047,26 @@ UNUSED(tokdata); - pkey = rsa_convert_private_key(key_obj); - if (pkey == NULL) { + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(struct openssl_ex_data), + openssl_need_wr_lock, NULL); + if (rc != CKR_OK) + return rc; + + if (ex_data->pkey == NULL) { + ex_data->pkey = rsa_convert_private_key(key_obj); + if (ex_data->pkey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + } + + pkey = ex_data->pkey; + if (EVP_PKEY_up_ref(pkey) != 1) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; - return rc; + goto done; } ctx = EVP_PKEY_CTX_new(pkey, NULL); @@ -971,6 +1099,7 @@ EVP_PKEY_free(pkey); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); + object_ex_data_unlock(key_obj); return rc; } @@ -1035,19 +1164,6 @@ } rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_2); - if (rc != CKR_OK) { - TRACE_DEVEL("rsa_parse_block failed\n"); - goto done; - } - - /* - * For PKCS #1 v1.5 padding, out_data_len must be less than - * modulus_bytes - 11. - */ - if (*out_data_len > (modulus_bytes - 11)) { - TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); - rc = CKR_ENCRYPTED_DATA_LEN_RANGE; - } done: OPENSSL_cleanse(out, sizeof(out)); @@ -2436,7 +2552,8 @@ CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { - EVP_PKEY *ec_key; + struct openssl_ex_data *ex_data = NULL; + EVP_PKEY *ec_key = NULL; ECDSA_SIG *sig = NULL; const BIGNUM *r, *s; CK_ULONG privlen, n; @@ -2452,10 +2569,26 @@ *out_data_len = 0; - rc = openssl_make_ec_key_from_template(key_obj->template, &ec_key); + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(struct openssl_ex_data), + openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; + if (ex_data->pkey == NULL) { + rc = openssl_make_ec_key_from_template(key_obj->template, + &ex_data->pkey); + if (rc != CKR_OK) + goto out; + } + + ec_key = ex_data->pkey; + if (EVP_PKEY_up_ref(ec_key) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + ctx = EVP_PKEY_CTX_new(ec_key, NULL); if (ctx == NULL) { TRACE_ERROR("EVP_PKEY_CTX_new failed\n"); @@ -2526,6 +2659,7 @@ free(sigbuf); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); + object_ex_data_unlock(key_obj); return rc; } @@ -2537,7 +2671,8 @@ CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj) { - EVP_PKEY *ec_key; + struct openssl_ex_data *ex_data = NULL; + EVP_PKEY *ec_key = NULL; CK_ULONG privlen; ECDSA_SIG *sig = NULL; BIGNUM *r = NULL, *s = NULL; @@ -2550,10 +2685,26 @@ UNUSED(tokdata); UNUSED(sess); - rc = openssl_make_ec_key_from_template(key_obj->template, &ec_key); + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(struct openssl_ex_data), + openssl_need_wr_lock, NULL); if (rc != CKR_OK) return rc; + if (ex_data->pkey == NULL) { + rc = openssl_make_ec_key_from_template(key_obj->template, + &ex_data->pkey); + if (rc != CKR_OK) + goto out; + } + + ec_key = ex_data->pkey; + if (EVP_PKEY_up_ref(ec_key) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + len = ec_prime_len_from_pkey(ec_key); if (len <= 0) { TRACE_ERROR("ec_prime_len_from_pkey failed\n"); @@ -2631,6 +2782,7 @@ OPENSSL_free(sigbuf); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); + object_ex_data_unlock(key_obj); return rc; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/mech_rsa.c opencryptoki-3.21.0+dfsg/usr/lib/common/mech_rsa.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/mech_rsa.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/mech_rsa.c 2023-05-15 14:42:55.000000000 +0200 @@ -26,9 +26,38 @@ #include "h_extern.h" #include "tok_spec_struct.h" #include "trace.h" +#include "constant_time.h" #include +CK_BBOOL is_rsa_mechanism(CK_MECHANISM_TYPE mech) +{ + switch (mech) { + case CKM_RSA_9796: + case CKM_RSA_PKCS: + case CKM_MD2_RSA_PKCS: + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA224_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_RSA_PKCS_PSS: + case CKM_SHA1_RSA_PKCS_PSS: + case CKM_SHA224_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS_PSS: + case CKM_SHA384_RSA_PKCS_PSS: + case CKM_SHA512_RSA_PKCS_PSS: + case CKM_RSA_PKCS_OAEP: + case CKM_RSA_X_509: + case CKM_RSA_X9_31: + case CKM_SHA1_RSA_X9_31: + return TRUE; + } + + return FALSE; +} + CK_RV rsa_get_key_info(OBJECT *key_obj, CK_ULONG *mod_bytes, CK_OBJECT_CLASS *keyclass) { @@ -170,10 +199,10 @@ * 1.5. */ -CK_RV rsa_parse_block(CK_BYTE *in_data, - CK_ULONG in_data_len, - CK_BYTE *out_data, - CK_ULONG *out_data_len, CK_ULONG type) +static CK_RV rsa_parse_block_type_1(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len) { CK_ULONG i; CK_RV rc = CKR_OK; @@ -200,93 +229,45 @@ /* * Check the block type. */ - if (in_data[1] != (CK_BYTE) type) { + if (in_data[1] != (CK_BYTE) PKCS_BT_1) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); return CKR_ENCRYPTED_DATA_INVALID; } /* * The block type shall be a single octet indicating the structure of the - * encryption block. It shall have value 00, 01, or 02. For a private-key - * operation, the block type shall be 00 or 01. For a public-key - * operation, it shall be 02. + * encryption block. It shall have value 01. For a private-key + * operation, the block type shall be 01. * - * For block type 00, the octets shall have value 00; for block type 01, - * they shall have value FF; and for block type 02, they shall be - * pseudorandomly generated and nonzero. + * For block type 01, they shall have value FF. * - * For block type 00, the data must begin with a nonzero octet or have - * known length so that the encryption block can be parsed unambiguously. - * For block types 01 and 02, the encryption block can be parsed + * For block type 01, the encryption block can be parsed * unambiguously since the padding string contains no octets with value 00 * and the padding string is separated from the data by an octet with * value 00. */ - switch (type) { - /* - * For block type 00, the octets shall have value 00. - * EB = 00 || 00 || 00 * i || D - * Where D must begin with a nonzero octet. - */ - case 0: - for (i = 2; i <= (in_data_len - 2); i++) { - if (in_data[i] != (CK_BYTE) 0) { - found = 1; - break; - } - } - if (!found) - i++; - break; - /* - * For block type 01, they shall have value FF. - * EB = 00 || 01 || FF * i || 00 || D - */ - case 1: - for (i = 2; i <= (in_data_len - 2); i++) { - if (in_data[i] != (CK_BYTE) 0xff) { - if (in_data[i] == (CK_BYTE) 0) { - i++; - found = 1; - break; - } - - TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); - return CKR_ENCRYPTED_DATA_INVALID; - } - } - if (!found) - i++; - break; - /* - * For block type 02, they shall be pseudorandomly generated and - * nonzero. - * EB = 00 || 02 || ?? * i || 00 || D - * Where ?? is nonzero. - */ - case 2: - for (i = 2; i <= (in_data_len - 2); i++) { + for (i = 2; i <= (in_data_len - 2); i++) { + if (in_data[i] != (CK_BYTE) 0xff) { if (in_data[i] == (CK_BYTE) 0) { i++; found = 1; break; } + + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; } - if (!found) - i++; - break; - default: - TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); - return CKR_ENCRYPTED_DATA_INVALID; } + if (!found) + i++; /* - * For block types 01 and 02, the padding string is at least eight octets + * For block type 01, the padding string is at least eight octets * long, which is a security condition for public-key operations that * prevents an attacker from recoving data by trying all possible * encryption blocks. */ - if ((type == 1 || type == 2) && ((i - 3) < 8)) { + if ((i - 3) < 8) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); return CKR_ENCRYPTED_DATA_INVALID; } @@ -307,6 +288,110 @@ return rc; } +static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + unsigned int ok = 0, found, zero; + size_t zero_index = 0, msg_index, mlen; + size_t i, j; + + /* + * The implementation of this function is copied from OpenSSL's function + * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c + * and is slightly modified to fit to the OpenCryptoki environment. + * + * The OpenSSL code is licensed under the Apache License 2.0. + * You can obtain a copy in the file LICENSE in the OpenSSL source + * distribution or at https://www.openssl.org/source/license.html + * + * Changes include: + * - Different variable, function and define names. + * - Usage of TRACE_ERROR to report errors and issue debug messages. + * - Different return codes. + */ + + /* + * The format is + * 00 || BT || PS || 00 || D + * BT - block type + * PS - padding string, at least 8 bytes of random non-zero data for BT = 2 + * D - data. + */ + + /* + * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", + * section 7.2.2. + */ + if (in_data_len < 11) { + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + ok = constant_time_is_zero(in_data[0]); + ok &= constant_time_eq(in_data[1], 2); + + /* scan over padding data */ + found = 0; + for (i = 2; i < in_data_len; i++) { + zero = constant_time_is_zero(in_data[i]); + + zero_index = constant_time_select_int(~found & zero, i, zero_index); + found |= zero; + } + + /* + * PS must be at least 8 bytes long, and it starts two bytes into |enc_msg|. + * If we never found a 0-byte, then |zero_index| is 0 and the check + * also fails. + */ + ok &= constant_time_ge(zero_index, 2 + 8); + + /* + * Skip the zero byte. This is incorrect if we never found a zero-byte + * but in this case we also do not copy the message out. + */ + msg_index = zero_index + 1; + mlen = in_data_len - msg_index; + + /* + * For good measure, do this check in constant time as well. + */ + ok &= constant_time_ge(*out_data_len, mlen); + + /* + * since at this point the |msg_index| does not provide the signal + * indicating if the padding check failed or not, we don't have to worry + * about leaking the length of returned message, we still need to ensure + * that we read contents of both buffers so that cache accesses don't leak + * the value of |good| + */ + for (i = msg_index, j = 0; i < in_data_len && j < *out_data_len; i++, j++) + out_data[j] = constant_time_select_8(ok, in_data[i], out_data[j]); + + *out_data_len = j; + + return constant_time_select_int(ok, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); +} + +CK_RV rsa_parse_block(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG type) +{ + switch (type) { + case PKCS_BT_1: + return rsa_parse_block_type_1(in_data, in_data_len, + out_data, out_data_len); + case PKCS_BT_2: + return rsa_parse_block_type_2(in_data, in_data_len, + out_data, out_data_len); + } + + return CKR_ARGUMENTS_BAD; +} + // // CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata, @@ -454,14 +539,8 @@ rc = token_specific.t_rsa_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key_obj); - if (rc != CKR_OK) { - if (rc == CKR_DATA_LEN_RANGE) { - TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); - rc = CKR_ENCRYPTED_DATA_LEN_RANGE; - goto done; - } - TRACE_DEVEL("Token Specific rsa decrypt failed.\n"); - } + rc = constant_time_select_int(constant_time_eq(rc, CKR_DATA_LEN_RANGE), + CKR_ENCRYPTED_DATA_INVALID, rc); done: object_put(tokdata, key_obj, TRUE); @@ -2377,7 +2456,7 @@ return rc; } -CK_RV mgf1(STDLL_TokData_t *tokdata, CK_BYTE *seed, CK_ULONG seedlen, +CK_RV mgf1(STDLL_TokData_t *tokdata, const CK_BYTE *seed, CK_ULONG seedlen, CK_BYTE *mask, CK_ULONG maskLen, CK_RSA_PKCS_MGF_TYPE mgf) { @@ -2535,96 +2614,136 @@ CK_ULONG *out_data_len, CK_RSA_PKCS_MGF_TYPE mgf, CK_BYTE *hash, CK_ULONG hlen) { - int error = 0;; - CK_RV rc = CKR_OK; - CK_ULONG dbMask_len, ps_len, i; - CK_BYTE *maskedSeed, *maskedDB, *dbMask, *seedMask; + size_t i, dblen = 0, mlen = -1, one_index = 0, msg_index; + unsigned int ok = 0, found_one_byte, mask; + const unsigned char *maskedseed, *maskeddb; + unsigned char *db = NULL; + unsigned char seed[EVP_MAX_MD_SIZE]; - UNUSED(emLen); + /* + * The implementation of this function is copied from OpenSSL's function + * RSA_padding_check_PKCS1_OAEP_mgf1() in crypto/rsa/rsa_oaep.c + * and is slightly modified to fit to the OpenCryptoki environment. + * + * The OpenSSL code is licensed under the Apache License 2.0. + * You can obtain a copy in the file LICENSE in the OpenSSL source + * distribution or at https://www.openssl.org/source/license.html + * + * Changes include: + * - Different variable and define names. + * - Usage of TRACE_ERROR to report errors and issue debug messages. + * - Different return codes. + * - No need for copying the input to an allocated 'em' buffer. The caller + * guarantees that the size of the input is already the size of the + * modulus. + */ - if (!emData || !out_data) { - TRACE_ERROR("%s received bad argument(s)\n", __func__); - return CKR_FUNCTION_FAILED; + /* + * |emLen| is guaranteed by the caller to be the modulus size. + * |emLen| >= 2 * |hlen| + 2 must hold for the modulus + * irrespective of the ciphertext, see PKCS #1 v2.2, section 7.1.2. + * This does not leak any side-channel information. + */ + if (emLen < 2 * hlen + 2) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; } - /* allocate memory now for later use */ - dbMask_len = *out_data_len - hlen - 1; - dbMask = malloc(sizeof(CK_BYTE) * dbMask_len); - seedMask = malloc(sizeof(CK_BYTE) * hlen); - if ((seedMask == NULL) || (dbMask == NULL)) { + dblen = emLen - hlen - 1; + db = calloc(1, dblen); + if (db == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); - rc = CKR_HOST_MEMORY; - goto done; + return CKR_HOST_MEMORY; } - /* pkcs1v2.2, section 7.1.2, Step 3b: - * Separate the encoded message EM and process the decrypted message. - * - * To mitigate fault and timing attacks, just flag errors and - * keep going. + /* + * The first byte must be zero, however we must not leak if this is + * true. See James H. Manger, "A Chosen Ciphertext Attack on RSA + * Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001). */ - maskedSeed = emData + 1; - maskedDB = emData + hlen + 1; + ok = constant_time_is_zero(emData[0]); - /* pkcs1v2.2, section 7.1.2, Step 3c: - * Compute seedMask using MGF1. - */ - if (mgf1(tokdata, maskedDB, dbMask_len, seedMask, hlen, mgf)) - error++; + maskedseed = emData + 1; + maskeddb = emData + 1 + hlen; + + if (mgf1(tokdata, maskeddb, dblen, seed, hlen, mgf) != CKR_OK) + goto done; - /* pkcs1v2.2, section 7.1.2, Step 3d: - * Compute seed using MGF1. - */ for (i = 0; i < hlen; i++) - seedMask[i] ^= maskedSeed[i]; + seed[i] ^= maskedseed[i]; - /* pkcs1v2.2, section 7.1.2, Step 3e: - * Compute dbMask using MGF1. - */ - if (mgf1(tokdata, seedMask, hlen, dbMask, dbMask_len, mgf)) - error++; + if (mgf1(tokdata, seed, hlen, db, dblen, mgf) != CKR_OK) + goto done; + + for (i = 0; i < dblen; i++) + db[i] ^= maskeddb[i]; + + ok &= constant_time_is_zero(CRYPTO_memcmp(db, hash, hlen)); - /* pkcs1v2.2, section 7.1.2, Step 3f: - * Compute db using MGF1. + found_one_byte = 0; + for (i = hlen; i < dblen; i++) { + /* + * Padding consists of a number of 0-bytes, followed by a 1. + */ + unsigned int equals1 = constant_time_eq(db[i], 1); + unsigned int equals0 = constant_time_is_zero(db[i]); + one_index = constant_time_select_int(~found_one_byte & equals1, + i, one_index); + found_one_byte |= equals1; + ok &= (found_one_byte | equals0); + } + + ok &= found_one_byte; + + /* + * At this point |good| is zero unless the plaintext was valid, + * so plaintext-awareness ensures timing side-channels are no longer a + * concern. */ - for (i = 0; i < dbMask_len; i++) - dbMask[i] ^= maskedDB[i]; + msg_index = one_index + 1; + mlen = dblen - msg_index; - /* pkcs1v2.2, section 7.1.2, Step 3g: - * DB = lHash’ || PS || 0x01 || M . - * - * If there is no octet with hexadecimal value 0x01 to separate - * PS from M, if lHash does not equal lHash’, output “decryption - * error” and stop. - */ - if (memcmp(dbMask, hash, hlen)) - error++; - - ps_len = hlen; - while ((ps_len < dbMask_len) && (dbMask[ps_len] == 0x00)) - ps_len++; - - if ((ps_len >= dbMask_len) || - (ps_len < dbMask_len && dbMask[ps_len] != 0x01) || - emData[0]) - error++; + /* + * For good measure, do this check in constant time as well. + */ + ok &= constant_time_ge(*out_data_len, mlen); - if (error) { - rc = CKR_FUNCTION_FAILED; - goto done; - } else { - ps_len++; - *out_data_len = dbMask_len - ps_len; - memcpy(out_data, dbMask + ps_len, dbMask_len - ps_len); + /* + * Move the result in-place by |dblen| - |hlen| - 1 - |mlen| bytes + * to the left. + * Then if |good| move |mlen| bytes from |db| + |hlen| + 1 to |out|. + * Otherwise leave |out| unchanged. + * Copy the memory back in a way that does not reveal the size of + * the data being copied via a timing side channel. This requires copying + * parts of the buffer multiple times based on the bits set in the real + * length. Clear bits do a non-copy with identical access pattern. + * The loop below has overall complexity of O(N*log(N)). + */ + *out_data_len = constant_time_select_int(constant_time_lt(dblen - hlen - 1, + *out_data_len), + dblen - hlen - 1, *out_data_len); + for (msg_index = 1; msg_index < dblen - hlen - 1; msg_index <<= 1) { + mask = ~constant_time_eq(msg_index & (dblen - hlen - 1 - mlen), + 0); + for (i = hlen + 1; i < dblen - msg_index; i++) + db[i] = constant_time_select_8(mask, db[i + msg_index], db[i]); + } + for (i = 0; i < *out_data_len; i++) { + mask = ok & constant_time_lt(i, mlen); + out_data[i] = constant_time_select_8(mask, db[i + hlen + 1], + out_data[i]); } done: - if (seedMask) - free(seedMask); - if (dbMask) - free(dbMask); + OPENSSL_cleanse(seed, sizeof(seed)); + if (db) { + OPENSSL_cleanse(db, dblen); + free(db); + } - return rc; + *out_data_len = constant_time_select_int(ok, mlen, 0); + + return constant_time_select_int(ok, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); } CK_RV emsa_pss_encode(STDLL_TokData_t *tokdata, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/new_host.c opencryptoki-3.21.0+dfsg/usr/lib/common/new_host.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/new_host.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/new_host.c 2023-05-15 14:42:55.000000000 +0200 @@ -88,11 +88,16 @@ /* set trace info */ set_trace(t); - bt_init(&sltp->TokData->sess_btree, free); - bt_init(&sltp->TokData->object_map_btree, free); - bt_init(&sltp->TokData->sess_obj_btree, call_object_free); - bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); - bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + rc = bt_init(&sltp->TokData->sess_btree, free); + rc |= bt_init(&sltp->TokData->object_map_btree, free); + rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + if (rc != CKR_OK) { + TRACE_ERROR("Btree init failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", @@ -203,6 +208,11 @@ } else { CloseXProcLock(sltp->TokData); final_data_store(sltp->TokData); + bt_destroy(&sltp->TokData->sess_btree); + bt_destroy(&sltp->TokData->object_map_btree); + bt_destroy(&sltp->TokData->sess_obj_btree); + bt_destroy(&sltp->TokData->priv_token_obj_btree); + bt_destroy(&sltp->TokData->publ_token_obj_btree); } } @@ -2367,7 +2377,7 @@ rc = decr_mgr_decrypt(tokdata, sess, length_only, &sess->decr_ctx, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("decr_mgr_decrypt() failed.\n"); done: @@ -2426,7 +2436,7 @@ rc = decr_mgr_decrypt_update(tokdata, sess, length_only, &sess->decr_ctx, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("decr_mgr_decrypt_update() failed.\n"); done: @@ -2483,7 +2493,7 @@ rc = decr_mgr_decrypt_final(tokdata, sess, length_only, &sess->decr_ctx, pLastPart, pulLastPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("decr_mgr_decrypt_final() failed.\n"); done: diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/object.c opencryptoki-3.21.0+dfsg/usr/lib/common/object.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/object.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/object.c 2023-05-15 14:42:55.000000000 +0200 @@ -181,6 +181,10 @@ if (rc != CKR_OK) goto error; + rc = object_init_ex_data_lock(o); + if (rc != CKR_OK) + goto error; + // copy the original object's attribute template // rc = template_copy(o->template, old_obj->template); @@ -330,6 +334,13 @@ { /* refactorization here to do actual free - fix from coverity scan */ if (obj) { + if (obj->ex_data != NULL) { + if (obj->ex_data_free != NULL) + obj->ex_data_free(obj, obj->ex_data, obj->ex_data_len); + else + free(obj->ex_data); + } + object_destroy_ex_data_lock(obj); if (obj->template) template_free(obj->template); object_destroy_lock(obj); @@ -786,6 +797,12 @@ if (rc != CKR_OK) goto error; + rc = object_init_ex_data_lock(obj); + if (rc != CKR_OK) { + object_destroy_lock(obj); + goto error; + } + *new_obj = obj; } else { /* Reload of existing object only changes the template */ @@ -893,6 +910,12 @@ if (rc != CKR_OK) goto done; + rc = object_init_ex_data_lock(o); + if (rc != CKR_OK) { + object_destroy_lock(o); + goto done; + } + *obj = o; return CKR_OK; @@ -962,5 +985,57 @@ return CKR_CANT_LOCK; } + return CKR_OK; +} + +CK_RV object_init_ex_data_lock(OBJECT *obj) +{ + if (pthread_rwlock_init(&obj->ex_data_rwlock, NULL) != 0) { + TRACE_DEVEL("Ex_data Lock init failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV object_destroy_ex_data_lock(OBJECT *obj) +{ + if (pthread_rwlock_destroy(&obj->ex_data_rwlock) != 0) { + TRACE_DEVEL("Ex_data Lock destroy failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV object_ex_data_lock(OBJECT *obj, OBJ_LOCK_TYPE type) +{ + switch (type) { + case NO_LOCK: + break; + case READ_LOCK: + if (pthread_rwlock_rdlock(&obj->ex_data_rwlock) != 0) { + TRACE_DEVEL("Ex_data Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + break; + case WRITE_LOCK: + if (pthread_rwlock_wrlock(&obj->ex_data_rwlock) != 0) { + TRACE_DEVEL("Ex_data Write-Lock failed.\n"); + return CKR_CANT_LOCK; + } + break; + } + + return CKR_OK; +} + +CK_RV object_ex_data_unlock(OBJECT *obj) +{ + if (pthread_rwlock_unlock(&obj->ex_data_rwlock) != 0) { + TRACE_DEVEL("Ex_data Unlock failed.\n"); + return CKR_CANT_LOCK; + } + return CKR_OK; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/obj_mgr.c opencryptoki-3.21.0+dfsg/usr/lib/common/obj_mgr.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/obj_mgr.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/obj_mgr.c 2023-05-15 14:42:55.000000000 +0200 @@ -28,6 +28,7 @@ #include "attributes.h" #include "tok_spec_struct.h" #include "trace.h" +#include "ock_syslog.h" #include "../api/apiproto.h" #include "../api/policy.h" @@ -930,34 +931,25 @@ * Accounting is done in shm, so check shm to see if object still exists. */ if (!session_obj) { - /* object_mgr_check_shm() needs the object to hold the READ lock */ - rc = object_lock(obj, READ_LOCK); + /* object_mgr_check_shm() needs the object to hold the object lock */ + rc = object_lock(obj, lock_type); if (rc != CKR_OK) goto done; locked = TRUE; - rc = object_mgr_check_shm(tokdata, obj); + rc = object_mgr_check_shm(tokdata, obj, lock_type); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); goto done; } + } - if (lock_type == READ_LOCK) { - /* already have the desired object lock */ - rc = CKR_OK; - goto done; - } - - rc = object_unlock(obj); - locked = FALSE; + if (!locked) { + rc = object_lock(obj, lock_type); if (rc != CKR_OK) goto done; } - rc = object_lock(obj, lock_type); - if (rc != CKR_OK) - goto done; - done: if (rc == CKR_OK) { TRACE_DEVEL("Object found: handle: %lu\n", handle); @@ -1038,7 +1030,7 @@ *handle = fa.map_handle; if (!object_is_session_object(obj)) { - rc = object_mgr_check_shm(tokdata, obj); + rc = object_mgr_check_shm(tokdata, obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_check_shm failed.\n"); return rc; @@ -1464,7 +1456,8 @@ rc = XProcLock(tokdata); if (rc != CKR_OK) { TRACE_ERROR("Failed to get Process Lock.\n"); - object_free(obj); + if (oldObj == NULL) + object_free(obj); return rc; } @@ -1559,13 +1552,6 @@ goto done; } - rc = save_token_object(tokdata, obj); - if (rc != CKR_OK) { - TRACE_ERROR("Failed to save token object, rc=0x%lx.\n",rc); - XProcUnLock(tokdata); - goto done; - } - if (object_is_private(obj)) { if (tokdata->global_shm->num_priv_tok_obj == 0) { TRACE_DEVEL("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); @@ -1607,6 +1593,13 @@ entry = &tokdata->global_shm->publ_tok_objs[index]; } + rc = save_token_object(tokdata, obj); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to save token object, rc=0x%lx.\n",rc); + XProcUnLock(tokdata); + goto done; + } + entry->count_lo = obj->count_lo; entry->count_hi = obj->count_hi; @@ -1866,14 +1859,27 @@ } -// The object must hold the READ lock when this function is called! +// The object must hold the READ or WRITE lock when this function is called! // -CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj) +CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj, + OBJ_LOCK_TYPE lock_type) { TOK_OBJ_ENTRY *entry = NULL; - CK_BBOOL rd_locked = TRUE, wr_locked = FALSE; + CK_BBOOL rd_locked = FALSE, wr_locked = FALSE; CK_RV rc; + switch (lock_type) { + case READ_LOCK: + rd_locked = TRUE; + break; + case WRITE_LOCK: + wr_locked = TRUE; + break; + case NO_LOCK: + TRACE_ERROR("Function must be called with READ or WRITE lock.\n"); + return CKR_FUNCTION_FAILED; + } + retry: rc = XProcLock(tokdata); if (rc != CKR_OK) { @@ -1940,12 +1946,30 @@ if (rc != CKR_OK) goto done; - rc = object_unlock(obj); + rc = object_ex_data_lock(obj, WRITE_LOCK); + if (rc != CKR_OK) + goto done; + + if (obj->ex_data != NULL && obj->ex_data_reload != NULL) { + rc = obj->ex_data_reload(obj, obj->ex_data, obj->ex_data_len); + if (rc != CKR_OK) { + TRACE_ERROR("ex_data_reload failed 0x%lx\n", rc); + object_ex_data_unlock(obj); + goto done; + } + } + + rc = object_ex_data_unlock(obj); if (rc != CKR_OK) goto done; - wr_locked = FALSE; - /* Re-acquire the READ lock only after we have released the XProcLock ! */ + if (lock_type == READ_LOCK) { + rc = object_unlock(obj); + if (rc != CKR_OK) + goto done; + wr_locked = FALSE; + /* Re-acquire the READ lock only after we have released the XProcLock! */ + } done: if (rc == CKR_OK) { @@ -1958,9 +1982,9 @@ } done_no_xproc_unlock: - if (wr_locked) + if (lock_type == READ_LOCK && wr_locked) object_unlock(obj); - if (!rd_locked) { + if (lock_type == READ_LOCK && !rd_locked) { if (rc == CKR_OK) rc = object_lock(obj, READ_LOCK); else @@ -2110,6 +2134,13 @@ continue; } + rc = object_init_ex_data_lock(new_obj); + if (rc != CKR_OK) { + object_destroy_lock(new_obj); + free(new_obj); + continue; + } + memcpy(new_obj->name, shm_te->name, 8); rc = reload_token_object(tokdata, new_obj); if (rc == CKR_OK) @@ -2167,6 +2198,13 @@ continue; } + rc = object_init_ex_data_lock(new_obj); + if (rc != CKR_OK) { + object_destroy_lock(new_obj); + free(new_obj); + continue; + } + memcpy(new_obj->name, shm_te->name, 8); rc = reload_token_object(tokdata, new_obj); if (rc == CKR_OK) @@ -2256,3 +2294,436 @@ } } #endif + +/* + * Re-enciphers a key that has a secure key in attribute CKA_IBM_OPAQUE by + * calling the reenc callback function. + * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. + * The object must hold the WRITE lock when this function is called! + */ +CK_RV obj_mgr_reencipher_secure_key(STDLL_TokData_t *tokdata, OBJECT *obj, + CK_RV (*reenc)(CK_BYTE *sec_key, + CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, + void *private), + void *private) +{ + CK_ATTRIBUTE *opaque_attr = NULL, *reenc_attr = NULL; + CK_KEY_TYPE key_type; + CK_RV rc; + + /* Update token object from SHM, if needed */ + if (object_is_token_object(obj)) { + rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_check_shm failed.\n"); + goto out; + } + } + + if (template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &key_type) + != CKR_OK) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto out; + } + + if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE, &opaque_attr)) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto out; + } + + rc = build_attribute(CKA_IBM_OPAQUE_REENC, opaque_attr->pValue, + opaque_attr->ulValueLen, &reenc_attr); + if (rc != CKR_OK) + goto out; + + if (key_type == CKK_AES_XTS) { + /* + * AES-XTS has 2 secure keys concatenated to each other. + * Re-encipher both keys separately. + */ + rc = reenc(opaque_attr->pValue, reenc_attr->pValue, + reenc_attr->ulValueLen / 2, private); + if (rc != CKR_OK) { + TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); + goto out; + } + + rc = reenc((CK_BYTE *)opaque_attr->pValue + reenc_attr->ulValueLen / 2, + reenc_attr->pValue, reenc_attr->ulValueLen / 2, + private); + if (rc != CKR_OK) { + TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); + goto out; + } + } else { + rc = reenc(opaque_attr->pValue, reenc_attr->pValue, reenc_attr->ulValueLen, + private); + if (rc != CKR_OK) { + TRACE_ERROR("Reencipher callback has failed, rc=0x%lx.\n",rc); + goto out; + } + } + + rc = template_update_attribute(obj->template, reenc_attr); + if (rc != CKR_OK) + goto out; + reenc_attr = NULL; + + if (!object_is_session_object(obj)) { + rc = object_mgr_save_token_object(tokdata, obj); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to save token object, rc=%lx.\n",rc); + goto out; + } + } + +out: + if (reenc_attr != NULL) + free(reenc_attr); + + return rc; +} + +/* + * Moves the re-enciphered secure key from attribute CKA_IBM_OPAQUE_REENC to + * CKA_IBM_OPAQUE, and the previous secure key from CKA_IBM_OPAQUE to + * CKA_IBM_OPAQUE_OLD. + * If the is_blob_new_mk_cb callback function is specified, then it is called to + * determine if the key blob in CKA_IBM_OPAQUE is already enciphered with the + * new master key. If it returns TRUE, then the key blob from CKA_IBM_OPAQUE + * is not moved to CKA_IBM_OPAQUE_OLD, and CKA_IBM_OPAQUE_REENC is removed. + * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. + * The object must hold the WRITE lock when this function is called! + */ +CK_RV obj_mgr_reencipher_secure_key_finalize(STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BBOOL is_blob_new_mk_cb( + STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BYTE *sec_key, + CK_ULONG sec_key_len, + void *cb_private), + void *cb_private) +{ + CK_ATTRIBUTE *opaque_attr = NULL, *old_attr = NULL, *reenc_attr = NULL; + CK_ATTRIBUTE *new_opaque_attr = NULL; + CK_KEY_TYPE key_type; + CK_RV rc; + + /* Update token object from SHM, if needed */ + if (object_is_token_object(obj)) { + rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_check_shm failed.\n"); + goto out; + } + } + + if (template_attribute_get_ulong(obj->template, CKA_KEY_TYPE, &key_type) + != CKR_OK) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto out; + } + + if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, + &reenc_attr)) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto out; + } + + if (!template_attribute_find(obj->template, CKA_IBM_OPAQUE, &opaque_attr)) { + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto out; + } + + if (is_blob_new_mk_cb != NULL && + is_blob_new_mk_cb(tokdata, obj, opaque_attr->pValue, + key_type == CKK_AES_XTS ? + opaque_attr->ulValueLen / 2 : + opaque_attr->ulValueLen, + cb_private) == TRUE) { + TRACE_DEVEL("is_blob_new_mk_cb returned TRUE, don't move blobs\n"); + + rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc != CKR_OK) + goto out; + + goto remove; + } + + rc = build_attribute(CKA_IBM_OPAQUE_OLD, opaque_attr->pValue, + opaque_attr->ulValueLen, &old_attr); + if (rc != CKR_OK) + goto out; + + rc = template_update_attribute(obj->template, old_attr); + if (rc != CKR_OK) + goto out; + old_attr = NULL; + + rc = build_attribute(CKA_IBM_OPAQUE, reenc_attr->pValue, + reenc_attr->ulValueLen, &new_opaque_attr); + if (rc != CKR_OK) + goto out; + + rc = template_update_attribute(obj->template, new_opaque_attr); + if (rc != CKR_OK) + goto out; + new_opaque_attr = NULL; + +remove: + rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc != CKR_OK) + goto out; + + if (!object_is_session_object(obj)) { + rc = object_mgr_save_token_object(tokdata, obj); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to save token object, rc=%lx.\n", rc); + goto out; + } + } + +out: + if (old_attr != NULL) + free(old_attr); + if (new_opaque_attr != NULL) + free(new_opaque_attr); + + return rc; +} + +/* + * Removes the re-enciphered secure key from attribute CKA_IBM_OPAQUE_REENC + * and also CKA_IBM_OPAQUE_OLD. + * Returns CKR_ATTRIBUTE_TYPE_INVALID if the key does not contain a secure key. + * The object must hold the WRITE lock when this function is called! + */ +CK_RV obj_mgr_reencipher_secure_key_cancel(STDLL_TokData_t *tokdata, + OBJECT *obj) +{ + CK_RV rc; + + /* Update token object from SHM, if needed */ + if (object_is_token_object(obj)) { + rc = object_mgr_check_shm(tokdata, obj, WRITE_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_check_shm failed.\n"); + goto out; + } + } + + rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_REENC); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc != CKR_OK) + goto out; + + rc = template_remove_attribute(obj->template, CKA_IBM_OPAQUE_OLD); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc != CKR_OK) + goto out; + + if (!object_is_session_object(obj)) { + rc = object_mgr_save_token_object(tokdata, obj); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to save token object, rc=%lx.\n",rc); + goto out; + } + } + +out: + return rc; +} + +struct iterate_obj_data { + CK_BBOOL (*filter)(STDLL_TokData_t *tokdata, OBJECT *obj, + void *filter_data); + void *filter_data; + CK_RV (*cb)(STDLL_TokData_t *tokdata, OBJECT *obj, void *cb_data); + void *cb_data; + const char *msg; + CK_BBOOL syslog; + CK_RV error; +}; + +static void obj_mgr_iterate_key_objects_cb(STDLL_TokData_t *tokdata, void *p1, + unsigned long p2, void *p3) +{ + struct iterate_obj_data *iod = p3; + OBJECT *obj = p1; + CK_OBJECT_CLASS class; + CK_RV rc; + + UNUSED(p2); + + if (iod->error != CKR_OK) /* Skip if previous reported an error */ + return; + + rc = object_lock(obj, WRITE_LOCK); + if (rc != CKR_OK) { + if (iod->syslog) + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get the object lock\n", + tokdata->slot_id); + return; + } + + rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to get object class: 0x%lx\n", __func__, rc); + if (iod->syslog) + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get object class: 0x%lx\n", + tokdata->slot_id, rc); + iod->error = rc; + goto out; + } + + switch (class) { + case CKO_PUBLIC_KEY: + case CKO_PRIVATE_KEY: + case CKO_SECRET_KEY: + break; + default: + /* Not a key object */ + goto out; + } + + if (iod->filter != NULL && + !iod->filter(tokdata, obj, iod->filter_data)) + goto out; + + if (obj->session != NULL) { + TRACE_INFO("%s %s session object 0x%lx of session 0x%lx\n", + __func__, iod->msg, p2, obj->session->handle); + if (iod->syslog) + OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s session object 0x%lx of " + "session 0x%lx\n", tokdata->slot_id, iod->msg, p2, + obj->session->handle); + } else { + TRACE_INFO("%s %s token object %s\n", __func__, iod->msg, obj->name); + if (iod->syslog) + OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s token object '%s'\n", + tokdata->slot_id, iod->msg, obj->name); + } + + rc = iod->cb(tokdata, obj, iod->cb_data); + if (rc != CKR_OK) { + if (obj->session != NULL) { + TRACE_ERROR("%s callback failed to process session object: 0x%lx\n", + __func__, rc); + if (iod->syslog) + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s session object " + "0x%lx of session 0x%lx: 0x%lx\n", tokdata->slot_id, + iod->msg, p2, obj->session->handle, rc); + } else { + TRACE_ERROR("%s callback failed to process token object %s: 0x%lx\n", + __func__, obj->name, rc); + if (iod->syslog) + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to %s token object '%s': 0x%lx\n", + tokdata->slot_id, iod->msg, obj->name, rc); + } + iod->error = rc; + goto out; + } + +out: + object_unlock(obj); +} + +CK_RV obj_mgr_iterate_key_objects(STDLL_TokData_t *tokdata, + CK_BBOOL session_objects, + CK_BBOOL token_objects, + CK_BBOOL(*filter)(STDLL_TokData_t *tokdata, + OBJECT *obj, + void *filter_data), + void *filter_data, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data), + void *cb_data, CK_BBOOL syslog, + const char *msg) +{ + struct iterate_obj_data iod; + CK_RV rc; + + iod.filter = filter; + iod.filter_data = filter_data; + iod.cb = cb; + iod.cb_data = cb_data; + iod.syslog = syslog; + iod.msg = msg; + iod.error = CKR_OK; + + if (session_objects) { + /* Session objects */ + bt_for_each_node(tokdata, &tokdata->sess_obj_btree, + obj_mgr_iterate_key_objects_cb, &iod); + if (iod.error != CKR_OK) { + TRACE_ERROR("%s failed to %s session objects: 0x%lx\n", + __func__, msg, iod.error); + if (syslog) + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to %s session objects: 0x%lx\n", + tokdata->slot_id, msg, iod.error); + return iod.error; + } + } + + if (token_objects) { + /* Update token objects */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + if (syslog) + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to get Process Lock\n", + tokdata->slot_id); + return rc; + } + + object_mgr_update_from_shm(tokdata); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + if (syslog) + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to release Process Lock\n", + tokdata->slot_id); + return rc; + } + + /* Public token objects */ + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, + obj_mgr_iterate_key_objects_cb, &iod); + if (iod.error != CKR_OK) { + TRACE_ERROR("%s failed to %s public token objects: 0x%lx\n", + __func__, msg, iod.error); + if (syslog) + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to %s public token " + "objects: 0x%lx\n", tokdata->slot_id, msg, + iod.error); + return iod.error; + } + + /* Private token objects */ + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, + obj_mgr_iterate_key_objects_cb, &iod); + if (iod.error != CKR_OK) { + TRACE_ERROR("%s failed to %s private token objects: 0x%lx\n", + __func__, msg, iod.error); + if (syslog) + OCK_SYSLOG(LOG_ERR,"Slot %lu: Failed to %s private token " + "objects: 0x%lx\n", tokdata->slot_id, msg, + iod.error); + return iod.error; + } + } + + return CKR_OK; +} diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/p11util.c opencryptoki-3.21.0+dfsg/usr/lib/common/p11util.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/p11util.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/p11util.c 2023-05-15 14:42:55.000000000 +0200 @@ -134,7 +134,7 @@ // const char *p11_get_cka(CK_ATTRIBUTE_TYPE atype) { - static char buf[40]; + static char buf[50]; switch (atype) { _sym2str(CKA_CLASS); @@ -211,6 +211,8 @@ _sym2str(CKA_ALLOWED_MECHANISMS); _sym2str(CKA_PROFILE_ID); _sym2str(CKA_IBM_OPAQUE); + _sym2str(CKA_IBM_OPAQUE_REENC); + _sym2str(CKA_IBM_OPAQUE_OLD); _sym2str(CKA_IBM_RESTRICTABLE); _sym2str(CKA_IBM_NEVER_MODIFIABLE); _sym2str(CKA_IBM_RETAINKEY); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/pkcs_utils.c opencryptoki-3.21.0+dfsg/usr/lib/common/pkcs_utils.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/pkcs_utils.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/pkcs_utils.c 2023-05-15 14:42:55.000000000 +0200 @@ -23,13 +23,16 @@ #include #include #include +#include #include #include #include "defs.h" #include "host_defs.h" +#ifndef OCK_TOOL #define OCK_TOOL +#endif #include "pkcs_utils.h" extern pkcs_trace_level_t trace_level; @@ -85,6 +88,40 @@ printf("%s", buf); } +#ifdef DEBUG + +/* a simple function for dumping out a memory area */ +void pkcs_hexdump(const char *prestr, void *buf, size_t buflen) +{ + /* 1 2 3 4 5 6 + 0123456789012345678901234567890123456789012345678901234567890123456789 + xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ................ + */ + + size_t i, j; + char line[68]; + for (i = 0; i < buflen; i += 16) { + for (j = 0; j < 16; j++) { + if (i + j < buflen) { + unsigned char b = ((unsigned char *) buf)[i + j]; + sprintf(line + j * 3, "%02hhx ", b); + line[51 + j] = (isalnum(b) ? b : '.'); + } else { + sprintf(line + j * 3, " "); + line[51 + j] = ' '; + } + } + line[47] = line[48] = line[49] = line[50] = ' '; + line[67] = '\0'; + if (prestr) + TRACE_DEBUG("%s%s\n", prestr, line); + else + TRACE_DEBUG("%s\n", line); + } +} + +#endif /* DEBUG */ + int compute_hash(int hash_type, int buf_size, const char *buf, char *digest) { EVP_MD_CTX *md_ctx = NULL; @@ -409,7 +446,7 @@ // Set absolute permissions or rw-rw---- fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - grp = getgrnam("pkcs11"); // Obtain the group id + grp = getgrnam(PKCS_GROUP); // Obtain the group id if (grp) { // set ownership to pkcs11 group if (fchown(file, -1, grp->gr_gid) != 0) { diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/pkcs_utils.h opencryptoki-3.21.0+dfsg/usr/lib/common/pkcs_utils.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/pkcs_utils.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/pkcs_utils.h 2023-05-15 14:42:55.000000000 +0200 @@ -61,6 +61,7 @@ void pkcs_trace(pkcs_trace_level_t level, const char * file, int line, const char *fmt, ...) __attribute__ ((format(printf, 4, 5))); +void pkcs_hexdump(const char *prestr, void *buf, size_t buflen); #define TRACE_NONE(...) \ pkcs_trace(TRACE_LEVEL_NONE, __FILE__, __LINE__, __VA_ARGS__) @@ -74,6 +75,12 @@ pkcs_trace(TRACE_LEVEL_DEVEL, __FILE__, __LINE__, __VA_ARGS__) #define TRACE_DEBUG(...) \ pkcs_trace(TRACE_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#ifdef DEBUG +void hexdump(const char *prestr, void *buf, size_t buflen); +#define TRACE_DEBUG_DUMP(_prestr, _buf, _buflen) pkcs_hexdump(_prestr, _buf, _buflen) +#else +#define TRACE_DEBUG_DUMP(...) +#endif #endif /* OCK_TOOL */ #endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/pkey_utils.c opencryptoki-3.21.0+dfsg/usr/lib/common/pkey_utils.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/pkey_utils.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/pkey_utils.c 2023-05-15 14:42:55.000000000 +0200 @@ -328,7 +328,7 @@ * because it tries to obtain a write lock on the key object. */ CK_RV pkey_update_and_save(STDLL_TokData_t *tokdata, OBJECT *key_obj, - CK_ATTRIBUTE *pkey_attr) + CK_ATTRIBUTE **pkey_attr) { CK_RV ret1, ret2; @@ -349,11 +349,12 @@ } /* Update attribute */ - ret1 = template_update_attribute(key_obj->template, pkey_attr); + ret1 = template_update_attribute(key_obj->template, *pkey_attr); if (ret1 != CKR_OK) { TRACE_ERROR("template_update_attribute failed with rc=0x%lx\n", ret1); goto done; } + *pkey_attr = NULL; /* Save to repository if it's a token object */ if (object_is_token_object(key_obj)) { diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/pkey_utils.h opencryptoki-3.21.0+dfsg/usr/lib/common/pkey_utils.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/pkey_utils.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/pkey_utils.h 2023-05-15 14:42:55.000000000 +0200 @@ -86,11 +86,13 @@ CK_BBOOL pkey_is_ec_public_key(TEMPLATE *tmpl); CK_RV pkey_update_and_save(STDLL_TokData_t *tokdata, OBJECT *key_obj, - CK_ATTRIBUTE *attr); + CK_ATTRIBUTE **attr); CK_BBOOL pkey_op_supported_by_cpacf(int msa_level, CK_MECHANISM_TYPE type, TEMPLATE *tmpl); +CK_BBOOL pkey_op_ec_curve_supported_by_cpacf(TEMPLATE *tmpl); + CK_RV pkey_aes_ecb(OBJECT *key, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG_PTR p_output_data_len, CK_BYTE encrypt); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/sess_mgr.c opencryptoki-3.21.0+dfsg/usr/lib/common/sess_mgr.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/sess_mgr.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/sess_mgr.c 2023-05-15 14:42:55.000000000 +0200 @@ -14,6 +14,7 @@ // #include #include // for memcmp() et al +#include #include "pkcs11types.h" #include "local_types.h" @@ -23,11 +24,10 @@ #include "tok_spec_struct.h" #include "trace.h" - // session_mgr_find() // // search for the specified session. returning a pointer to the session -// might be dangerous, but performs well +// might be dangerous, but performs well. // // The returned session must be put back (using bt_put_node_value()) by the // caller to decrease the reference count! @@ -115,29 +115,35 @@ so_session = session_mgr_so_session_exists(tokdata); user_session = session_mgr_user_session_exists(tokdata); + if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Write Lock failed.\n"); + rc = CKR_CANT_LOCK; + goto done; + } + // we don't have to worry about having a user and SO session at the same // time. that is prevented in the login routine // - __transaction_atomic { /* start transaction */ - if (user_session) { - if (new_session->session_info.flags & CKF_RW_SESSION) { - new_session->session_info.state = CKS_RW_USER_FUNCTIONS; - } else { - new_session->session_info.state = CKS_RO_USER_FUNCTIONS; - tokdata->ro_session_count++; - } - } else if (so_session) { - new_session->session_info.state = CKS_RW_SO_FUNCTIONS; + if (user_session) { + if (new_session->session_info.flags & CKF_RW_SESSION) { + new_session->session_info.state = CKS_RW_USER_FUNCTIONS; } else { - if (new_session->session_info.flags & CKF_RW_SESSION) { - new_session->session_info.state = CKS_RW_PUBLIC_SESSION; - } else { - new_session->session_info.state = CKS_RO_PUBLIC_SESSION; - tokdata->ro_session_count++; - } + new_session->session_info.state = CKS_RO_USER_FUNCTIONS; + tokdata->ro_session_count++; + } + } else if (so_session) { + new_session->session_info.state = CKS_RW_SO_FUNCTIONS; + } else { + if (new_session->session_info.flags & CKF_RW_SESSION) { + new_session->session_info.state = CKS_RW_PUBLIC_SESSION; + } else { + new_session->session_info.state = CKS_RO_PUBLIC_SESSION; + tokdata->ro_session_count++; } } + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); + *phSession = bt_node_add(&tokdata->sess_btree, new_session); if (*phSession == 0) { rc = CKR_HOST_MEMORY; @@ -162,13 +168,18 @@ // CK_BBOOL session_mgr_so_session_exists(STDLL_TokData_t *tokdata) { - __transaction_atomic { /* start transaction */ - CK_BBOOL result; + CK_BBOOL result; - result = (tokdata->global_login_state == CKS_RW_SO_FUNCTIONS); + /* we must acquire sess_list_rwlock in order to inspect + * global_login_state */ + if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Read Lock failed.\n"); + return FALSE; + } + result = (tokdata->global_login_state == CKS_RW_SO_FUNCTIONS); + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - return result; - } /* end transaction */ + return result; } @@ -180,14 +191,20 @@ // CK_BBOOL session_mgr_user_session_exists(STDLL_TokData_t *tokdata) { - __transaction_atomic { /* start transaction */ - CK_BBOOL result; + CK_BBOOL result; - result = ((tokdata->global_login_state == CKS_RO_USER_FUNCTIONS) || - (tokdata->global_login_state == CKS_RW_USER_FUNCTIONS)); + /* we must acquire sess_list_rwlock in order to inspect + * glogal_login_state */ + if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Read Lock failed.\n"); + return FALSE; + } + result = ((tokdata->global_login_state == CKS_RO_USER_FUNCTIONS) || + (tokdata->global_login_state == CKS_RW_USER_FUNCTIONS)); - return result; - } /* end transaction */ + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); + + return result; } @@ -199,14 +216,20 @@ // CK_BBOOL session_mgr_public_session_exists(STDLL_TokData_t *tokdata) { - __transaction_atomic { /* start transaction */ - CK_BBOOL result; + CK_BBOOL result; + + /* we must acquire sess_list_rwlock in order to inspect + * global_login_state */ + if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Read Lock failed.\n"); + return FALSE; + } + result = ((tokdata->global_login_state == CKS_RO_PUBLIC_SESSION) || + (tokdata->global_login_state == CKS_RW_PUBLIC_SESSION)); - result = ((tokdata->global_login_state == CKS_RO_PUBLIC_SESSION) || - (tokdata->global_login_state == CKS_RW_PUBLIC_SESSION)); + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - return result; - } /* end transaction */ + return result; } @@ -217,13 +240,19 @@ // CK_BBOOL session_mgr_readonly_session_exists(STDLL_TokData_t *tokdata) { - __transaction_atomic { /* start transaction */ - CK_BBOOL result; + CK_BBOOL result; + + /* we must acquire sess_list_rwlock in order to inspect ro_session_count */ + if (pthread_rwlock_rdlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Read Lock failed.\n"); + return FALSE; + } + + result = (tokdata->ro_session_count > 0); - result = (tokdata->ro_session_count > 0); + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); - return result; - } /* end transaction */ + return result; } @@ -245,18 +274,22 @@ sess = bt_get_node_value(&tokdata->sess_btree, handle); if (!sess) { TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); - rc = CKR_SESSION_HANDLE_INVALID; - goto done; + return CKR_SESSION_HANDLE_INVALID; + } + + if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Write Lock failed.\n"); + bt_put_node_value(&tokdata->sess_btree, sess); + sess = NULL; + return CKR_CANT_LOCK; } object_mgr_purge_session_objects(tokdata, sess, ALL); - __transaction_atomic { /* start transaction */ - if ((sess->session_info.state == CKS_RO_PUBLIC_SESSION) || - (sess->session_info.state == CKS_RO_USER_FUNCTIONS)) { - tokdata->ro_session_count--; - } - } /* end transaction */ + if ((sess->session_info.state == CKS_RO_PUBLIC_SESSION) || + (sess->session_info.state == CKS_RO_USER_FUNCTIONS)) { + tokdata->ro_session_count--; + } // Make sure this address is now invalid sess->handle = CK_INVALID_HANDLE; @@ -344,16 +377,14 @@ } object_mgr_purge_private_token_objects(tokdata); - __transaction_atomic { /* start transaction */ - tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; - } /* end transaction */ + tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; // The objects really need to be purged .. but this impacts the // performance under linux. So we need to make sure that the // login state is valid. I don't really like this. object_mgr_purge_map(tokdata, (SESSION *) 0xFFFF, PRIVATE); } -done: + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return rc; } @@ -440,16 +471,23 @@ // session_mgr_close_all_sessions() // -// removes all sessions from the specified process +// removes all sessions from the specified process. +// If tokdata is not NULL, then only sessions for that token instance are +// removed. // CK_RV session_mgr_close_all_sessions(STDLL_TokData_t *tokdata) { bt_for_each_node(tokdata, &tokdata->sess_btree, session_free, NULL); - __transaction_atomic { /* start transaction */ - tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; - tokdata->ro_session_count = 0; - } /* end transaction */ + if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Write Lock failed.\n"); + return CKR_CANT_LOCK; + } + + tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; + tokdata->ro_session_count = 0; + + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); return CKR_OK; } @@ -478,9 +516,7 @@ s->session_info.state = CKS_RO_USER_FUNCTIONS; } - __transaction_atomic { /* start transaction */ - tokdata->global_login_state = s->session_info.state; // SAB - } /* end transaction */ + tokdata->global_login_state = s->session_info.state; // SAB } // session_mgr_login_all() @@ -491,9 +527,16 @@ // CK_RV session_mgr_login_all(STDLL_TokData_t *tokdata, CK_USER_TYPE user_type) { + if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Write Lock failed.\n"); + return CKR_CANT_LOCK; + } + bt_for_each_node(tokdata, &tokdata->sess_btree, session_login, (void *)&user_type); + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); + return CKR_OK; } @@ -519,9 +562,7 @@ else s->session_info.state = CKS_RO_PUBLIC_SESSION; - __transaction_atomic { /* start transaction */ - tokdata->global_login_state = s->session_info.state; // SAB - } /* end transaction */ + tokdata->global_login_state = s->session_info.state; // SAB } // session_mgr_logout_all() @@ -530,8 +571,15 @@ // CK_RV session_mgr_logout_all(STDLL_TokData_t *tokdata) { + if (pthread_rwlock_wrlock(&tokdata->sess_list_rwlock)) { + TRACE_ERROR("Write Lock failed.\n"); + return CKR_CANT_LOCK; + } + bt_for_each_node(tokdata, &tokdata->sess_btree, session_logout, NULL); + pthread_rwlock_unlock(&tokdata->sess_list_rwlock); + return CKR_OK; } @@ -1299,3 +1347,146 @@ } } } + +struct session_iterate_data { + CK_RV (*cb)(STDLL_TokData_t *tokdata, SESSION *session, CK_ULONG ctx_type, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key, + CK_BYTE *context, CK_ULONG context_len, + CK_BBOOL init_pending, CK_BBOOL pkey_active, CK_BBOOL recover, + void *private); + void *private; + CK_RV error; +}; + +static void session_mgr_iterate_session_ops_cb(STDLL_TokData_t *tokdata, + void *p1, unsigned long p2, + void *p3) +{ + struct session_iterate_data *sid = p3; + SESSION *session = p1; + CK_RV rc = CKR_OK; + + UNUSED(p2); + + if (sid->error != CKR_OK) + return; + + if (session->digest_ctx.active && + session->digest_ctx.context != NULL && + session->digest_ctx.context_len > 0) { + rc = sid->cb(tokdata, session, CONTEXT_TYPE_DIGEST, + &session->digest_ctx.mech, CK_INVALID_HANDLE, + session->digest_ctx.context, + session->digest_ctx.context_len, + FALSE, FALSE, FALSE, sid->private); + if (rc != CKR_OK) { + TRACE_ERROR("%s callback function failed: 0x%lx\n", + __func__, rc); + goto out; + } + } + + if (session->sign_ctx.active && + session->sign_ctx.context != NULL && + session->sign_ctx.context_len > 0) { + rc = sid->cb(tokdata, session, CONTEXT_TYPE_SIGN, + &session->sign_ctx.mech, session->sign_ctx.key, + session->sign_ctx.context, + session->sign_ctx.context_len, + session->sign_ctx.init_pending, + session->sign_ctx.pkey_active, + session->sign_ctx.recover, + sid->private); + if (rc != CKR_OK) { + TRACE_ERROR("%s callback function failed: 0x%lx\n", + __func__, rc); + goto out; + } + } + + if (session->verify_ctx.active && + session->verify_ctx.context != NULL && + session->verify_ctx.context_len > 0) { + rc = sid->cb(tokdata, session, CONTEXT_TYPE_VERIFY, + &session->verify_ctx.mech, session->verify_ctx.key, + session->verify_ctx.context, + session->verify_ctx.context_len, + session->verify_ctx.init_pending, + session->verify_ctx.pkey_active, + session->verify_ctx.recover, + sid->private); + if (rc != CKR_OK) { + TRACE_ERROR("%s callback function failed: 0x%lx\n", + __func__, rc); + goto out; + } + } + + if (session->encr_ctx.active && + session->encr_ctx.context != NULL && + session->encr_ctx.context_len > 0) { + rc = sid->cb(tokdata, session, CONTEXT_TYPE_ENCRYPT, + &session->encr_ctx.mech, session->encr_ctx.key, + session->encr_ctx.context, + session->encr_ctx.context_len, + session->encr_ctx.init_pending, + session->encr_ctx.pkey_active, FALSE, + sid->private); + if (rc != CKR_OK) { + TRACE_ERROR("%s callback function failed: 0x%lx\n", + __func__, rc); + goto out; + } + } + + if (session->decr_ctx.active && + session->decr_ctx.context != NULL && + session->decr_ctx.context_len > 0) { + rc = sid->cb(tokdata, session, CONTEXT_TYPE_DECRYPT, + &session->decr_ctx.mech, session->decr_ctx.key, + session->decr_ctx.context, + session->decr_ctx.context_len, + session->decr_ctx.init_pending, + session->decr_ctx.pkey_active, FALSE, + sid->private); + if (rc != CKR_OK) { + TRACE_ERROR("%s callback function failed: 0x%lx\n", + __func__, rc); + goto out; + } + } + +out: + if (rc != CKR_OK) + sid->error = rc; +} + +CK_RV session_mgr_iterate_session_ops(STDLL_TokData_t *tokdata, + SESSION *session, + CK_RV (*cb)(STDLL_TokData_t *tokdata, + SESSION *session, + CK_ULONG ctx_type, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE key, + CK_BYTE *context, + CK_ULONG context_len, + CK_BBOOL init_pending, + CK_BBOOL pkey_active, + CK_BBOOL recover, + void *private), + void *private) +{ + struct session_iterate_data sid; + + sid.cb = cb; + sid.private = private; + sid.error = CKR_OK; + + if (session != NULL) + session_mgr_iterate_session_ops_cb(tokdata, session, 0, &sid); + else + bt_for_each_node(tokdata, &tokdata->sess_btree, + session_mgr_iterate_session_ops_cb, &sid); + + return sid.error; +} diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/shared_memory.c opencryptoki-3.21.0+dfsg/usr/lib/common/shared_memory.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/shared_memory.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/shared_memory.c 2023-05-15 14:42:55.000000000 +0200 @@ -172,11 +172,11 @@ goto done; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (!grp) { rc = -errno; - SYS_ERROR(errno, "getgrname(\"pkcs11\"): %s\n", - strerror(errno)); + SYS_ERROR(errno, "getgrname(\"%s\"): %s\n", PKCS_GROUP, + strerror(errno)); goto done; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/template.c opencryptoki-3.21.0+dfsg/usr/lib/common/template.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/template.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/template.c 2023-05-15 14:42:55.000000000 +0200 @@ -1567,32 +1567,29 @@ return rc; } - -/* template_update_attribute() +/* template_remove_attribute() * - * modifies an existing attribute or adds a new attribute to the template + * removes an attribute (if existing) from the template. * * Returns: CKR_OK on success, other CKR error on failure */ -CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *new_attr) +CK_RV template_remove_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type) { - DL_NODE *node = NULL, *list; + DL_NODE *node = NULL; CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found = FALSE; - if (!tmpl || !new_attr) { + if (!tmpl) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_ARGUMENTS_BAD; } node = tmpl->attribute_list; - /* if the attribute already exists in the list, remove it. - * this algorithm will limit an attribute to appearing at most - * once in the list - */ while (node != NULL) { attr = (CK_ATTRIBUTE *) node->data; - if (new_attr->type == attr->type) { + if (type == attr->type) { + found = TRUE; if (is_attribute_attr_array(attr->type)) { cleanse_and_free_attribute_array2( (CK_ATTRIBUTE_PTR)attr->pValue, @@ -1608,6 +1605,33 @@ node = node->next; } + return found ? CKR_OK : CKR_ATTRIBUTE_TYPE_INVALID; +} + +/* template_update_attribute() + * + * modifies an existing attribute or adds a new attribute to the template + * + * Returns: CKR_OK on success, other CKR error on failure + */ +CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *new_attr) +{ + DL_NODE *list; + CK_RV rc; + + if (!tmpl || !new_attr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_ARGUMENTS_BAD; + } + + /* if the attribute already exists in the list, remove it. + * this algorithm will limit an attribute to appearing at most + * once in the list + */ + rc = template_remove_attribute(tmpl, new_attr->type); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) + return rc; + /* add the new attribute */ list = dlist_add_as_first(tmpl->attribute_list, new_attr); if (list == NULL) { @@ -1619,7 +1643,6 @@ return CKR_OK; } - /* template_validate_attribute() * * essentially a group of if-then-else-switch clauses. separated from @@ -1811,6 +1834,8 @@ case CKA_LABEL: return CKR_OK; case CKA_IBM_OPAQUE: + case CKA_IBM_OPAQUE_REENC: + case CKA_IBM_OPAQUE_OLD: /* Allow this attribute to be modified in order to support * migratable keys on secure key tokens. */ diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/tok_specific.h opencryptoki-3.21.0+dfsg/usr/lib/common/tok_specific.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/tok_specific.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/tok_specific.h 2023-05-15 14:42:55.000000000 +0200 @@ -49,8 +49,8 @@ CK_RV token_specific_set_pin(STDLL_TokData_t *, SESSION *, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG); -CK_RV token_specific_des_key_gen(STDLL_TokData_t *, CK_BYTE **, CK_ULONG *, - CK_ULONG, CK_BBOOL *); +CK_RV token_specific_des_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, CK_BYTE **, + CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV token_specific_des_ecb(STDLL_TokData_t *, CK_BYTE *, @@ -232,18 +232,19 @@ CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *, TEMPLATE *template); -CK_RV token_specific_aes_key_gen(STDLL_TokData_t *, +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); -CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *, - CK_BYTE **, CK_ULONG *, CK_ULONG, CK_BBOOL *); +CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl, + CK_BYTE **, CK_ULONG *, CK_ULONG, + CK_BBOOL *); -CK_RV token_specific_aes_ecb(STDLL_TokData_t *, +CK_RV token_specific_aes_ecb(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); -CK_RV token_specific_aes_cbc(STDLL_TokData_t *, +CK_RV token_specific_aes_cbc(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/tok_spec_struct.h opencryptoki-3.21.0+dfsg/usr/lib/common/tok_spec_struct.h --- opencryptoki-3.20.0+dfsg/usr/lib/common/tok_spec_struct.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/tok_spec_struct.h 2023-05-15 14:42:55.000000000 +0200 @@ -82,8 +82,8 @@ CK_RV(*t_set_pin) (STDLL_TokData_t *, SESSION *, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG); - CK_RV(*t_des_key_gen) (STDLL_TokData_t *, CK_BYTE **, CK_ULONG *, CK_ULONG, - CK_BBOOL *); + CK_RV(*t_des_key_gen) (STDLL_TokData_t *, TEMPLATE *, CK_BYTE **, + CK_ULONG *, CK_ULONG, CK_BBOOL *); CK_RV(*t_des_ecb) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); CK_RV(*t_des_cbc) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, @@ -209,16 +209,16 @@ CK_RV(*t_generic_secret_key_gen) (STDLL_TokData_t *, TEMPLATE *); // Token Specific AES functions - CK_RV(*t_aes_key_gen) (STDLL_TokData_t *, CK_BYTE **, CK_ULONG *, CK_ULONG, - CK_BBOOL *); + CK_RV(*t_aes_key_gen) (STDLL_TokData_t *, TEMPLATE *, CK_BYTE **, + CK_ULONG *, CK_ULONG, CK_BBOOL *); - CK_RV(*t_aes_xts_key_gen) (STDLL_TokData_t *, CK_BYTE **, CK_ULONG *, CK_ULONG, - CK_BBOOL *); + CK_RV(*t_aes_xts_key_gen) (STDLL_TokData_t *, TEMPLATE *, CK_BYTE **, + CK_ULONG *, CK_ULONG, CK_BBOOL *); - CK_RV(*t_aes_ecb) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, + CK_RV(*t_aes_ecb) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); - CK_RV(*t_aes_cbc) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, + CK_RV(*t_aes_cbc) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); CK_RV(*t_aes_ctr) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/trace.c opencryptoki-3.21.0+dfsg/usr/lib/common/trace.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/trace.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/trace.c 2023-05-15 14:42:55.000000000 +0200 @@ -178,10 +178,10 @@ return (CKR_FUNCTION_FAILED); } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp == NULL) { - OCK_SYSLOG(LOG_ERR, "getgrnam(pkcs11) failed: %s." - "Tracing is disabled.\n", strerror(errno)); + OCK_SYSLOG(LOG_ERR, "getgrnam(%s) failed: %s." + "Tracing is disabled.\n", PKCS_GROUP, strerror(errno)); goto error; } @@ -201,8 +201,9 @@ /* set pkcs11 group permission on tracefile */ if (fchown(trace.fd, -1, grp->gr_gid) == -1) { - OCK_SYSLOG(LOG_ERR, "fchown(%s,-1,pkcs11) failed: %s." - "Tracing is disabled.\n", tracefile, strerror(errno)); + OCK_SYSLOG(LOG_ERR, "fchown(%s,-1,%s) failed: %s." + "Tracing is disabled.\n", tracefile, PKCS_GROUP, + strerror(errno)); goto error; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/common/utility.c opencryptoki-3.21.0+dfsg/usr/lib/common/utility.c --- opencryptoki-3.20.0+dfsg/usr/lib/common/utility.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/common/utility.c 2023-05-15 14:42:55.000000000 +0200 @@ -82,9 +82,10 @@ lockdir, strerror(errno)); goto err; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp == NULL) { - fprintf(stderr, "getgrname(pkcs11): %s", strerror(errno)); + fprintf(stderr, "getgrname(%s): %s", PKCS_GROUP, + strerror(errno)); goto err; } /* set ownership to euid, and pkcs11 group */ @@ -122,7 +123,7 @@ goto err; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp != NULL) { if (fchown(tokdata->spinxplfd, -1, grp->gr_gid) == -1) { OCK_SYSLOG(LOG_ERR, @@ -818,6 +819,81 @@ return rc; } +CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, + CK_MECHANISM_PTR mech, CK_ULONG *type, CK_ULONG *class) +{ + CK_RV rc; + + *type = 0; + *class = 0; + + rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_CLASS, class); + if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + rc = get_ulong_attribute_by_type(attrs, attrs_len, CKA_KEY_TYPE, type); + if (rc == CKR_ATTRIBUTE_VALUE_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (rc == CKR_OK) + return CKR_OK; + + /* no CKA_KEY_TYPE found, derive from mech */ + switch (mech->mechanism) { + case CKM_DES_KEY_GEN: + *type = CKK_DES; + break; + case CKM_DES2_KEY_GEN: + case CKM_PBE_SHA1_DES2_EDE_CBC: + *type = CKK_DES2; + break; + case CKM_DES3_KEY_GEN: + case CKM_PBE_SHA1_DES3_EDE_CBC: + *type = CKK_DES3; + break; + case CKM_AES_KEY_GEN: + *type = CKK_AES; + break; + case CKM_AES_XTS_KEY_GEN: + *type = CKK_AES_XTS; + break; + case CKM_GENERIC_SECRET_KEY_GEN: + case CKM_SHA1_KEY_DERIVATION: + case CKM_SHA224_KEY_DERIVATION: + case CKM_SHA256_KEY_DERIVATION: + case CKM_SHA384_KEY_DERIVATION: + case CKM_SHA512_KEY_DERIVATION: + *type = CKK_GENERIC_SECRET; + break; + case CKM_RSA_PKCS_KEY_PAIR_GEN: + *type = CKK_RSA; + break; + case CKM_EC_KEY_PAIR_GEN: + *type = CKK_EC; + break; + case CKM_DSA_KEY_PAIR_GEN: + *type = CKK_DSA; + break; + case CKM_DH_PKCS_KEY_PAIR_GEN: + *type = CKK_DH; + break; + case CKM_IBM_DILITHIUM: + *type = CKK_IBM_PQC_DILITHIUM; + break; + case CKM_IBM_KYBER: + *type = CKK_IBM_PQC_KYBER; + break; + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + void copy_token_contents_sensibly(CK_TOKEN_INFO_PTR pInfo, TOKEN_DATA *nv_token_data) { @@ -866,3 +942,44 @@ /* pInfo->ulRwSessionCount is set at the API level */ } +CK_RV init_hsm_mk_change_lock(STDLL_TokData_t *tokdata) +{ + pthread_rwlockattr_t attr; + + /* + * Request the API layer to lock against HSM-MK-change state changes. + * Set lock kind PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP to avoid + * writer starvation. Otherwise in a multi-threaded OCK application + * with a heavy crypto workload, the event thread would never get the + * HSM-MK-change lock as writer. + */ + if (pthread_rwlockattr_init(&attr) != 0) { + TRACE_ERROR("pthread_rwlockattr_init failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", + __func__); + return CKR_CANT_LOCK; + } + + if (pthread_rwlockattr_setkind_np(&attr, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) != 0) { + TRACE_ERROR("pthread_rwlockattr_setkind_np failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", + __func__); + pthread_rwlockattr_destroy(&attr); + return CKR_CANT_LOCK; + } + + if (pthread_rwlock_init(&tokdata->hsm_mk_change_rwlock, &attr) != 0) { + TRACE_ERROR("pthread_rwlock_init failed\n"); + OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the HSM-MK-change lock\n", + __func__); + pthread_rwlockattr_destroy(&attr); + return CKR_CANT_LOCK; + } + + pthread_rwlockattr_destroy(&attr); + + tokdata->hsm_mk_change_supported = TRUE; + + return CKR_OK; +} diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_specific.c opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -42,6 +42,8 @@ #include "events.h" #include "cfgparser.h" #include "configuration.h" +#include "hsm_mk_change.h" +#include "constant_time.h" #include #include @@ -52,6 +54,7 @@ #include #include #include +#include #ifdef DEBUG #include @@ -141,6 +144,7 @@ static m_add_module_t dll_m_add_module; static m_rm_module_t dll_m_rm_module; +static xcpa_cmdblock_t dll_xcpa_cmdblock; static xcpa_queryblock_t dll_xcpa_queryblock; static xcpa_internal_rv_t dll_xcpa_internal_rv; @@ -203,41 +207,778 @@ #define MAX_RETRY_COUNT 100 -#define RETRY_START(rc, tokdata) \ - do { \ - int retry_count; \ - CK_RV rc2; \ - if (((ep11_private_data_t *) \ - tokdata->private_data)-> \ - inconsistent) { \ +/* + * Macros to enclose EP11 library calls involving session bound blobs. + * If the EP11 token is in an inconsistent state, fail with CKR_DEVICE_ERROR. + * Obtain a target_info to be used with the EP11 library call. + * If in single-APQN mode, and that APQN went offline, select another APQN and + * retry the library call. + * In case of EP11 library function failed with CKR_SESSION_CLOSED, relogin + * all APQNs and retry the library call. + */ +#define RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) \ + do { \ + ep11_target_info_t* target_info; \ + int retry_count; \ + CK_RV rc2; \ + if (((ep11_private_data_t *) \ + (tokdata)->private_data)->inconsistent) { \ + (rc) = CKR_DEVICE_ERROR; \ + TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); \ + break; \ + } \ + target_info = get_target_info((tokdata)); \ + if (target_info == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + for (retry_count = 0; \ + target_info != NULL && \ + retry_count < MAX_RETRY_COUNT; \ + retry_count ++) { + +#define RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) \ + if (target_info->single_apqn && \ + ((rc) == CKR_IBM_TARGET_INVALID || \ + ((rc) == CKR_FUNCTION_FAILED && \ + !is_apqn_online(target_info->adapter, \ + target_info->domain)))) { \ + /* Single APQN went offline, select other */\ + TRACE_DEVEL("%s single APQN went offline\n",\ + __func__); \ + put_target_info((tokdata), target_info); \ + target_info = NULL; \ + (rc) = refresh_target_info((tokdata), \ + FALSE); \ + if ((rc) != CKR_OK) \ + break; \ + target_info = get_target_info((tokdata)); \ + if (target_info == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + if ((rc) != CKR_SESSION_CLOSED) \ + break; \ + rc2 = ep11tok_relogin_session((tokdata), \ + (session)); \ + if (rc2 != CKR_OK) { \ + (rc) = rc2; \ + break; \ + } \ + } \ + put_target_info((tokdata), target_info); \ + } while (0); + +/* + * Macros to enclose EP11 library calls not involving session bound blobs, and + * with given target_info. + * If the EP11 token is in an inconsistent state, fail with CKR_DEVICE_ERROR. + * If in single-APQN mode, and that APQN went offline, select another APQN and + * retry the library call. + */ +#define RETRY_SINGLE_APQN_START(tokdata, rc) \ + do { \ + int retry_count; \ + if (((ep11_private_data_t *) \ + (tokdata)->private_data)->inconsistent) { \ + (rc) = CKR_DEVICE_ERROR; \ + TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); \ + break; \ + } \ + for (retry_count = 0; \ + retry_count < MAX_RETRY_COUNT; \ + retry_count ++) { + +#define RETRY_SINGLE_APQN_END(rc, tokdata, target_info) \ + if ((target_info) == NULL) \ + break; \ + if ((target_info)->single_apqn && \ + ((rc) == CKR_IBM_TARGET_INVALID || \ + ((rc) == CKR_FUNCTION_FAILED && \ + !is_apqn_online((target_info)->adapter, \ + (target_info)->domain)))) { \ + /* Single APQN went offline, select other */\ + TRACE_DEVEL("%s single APQN went offline\n",\ + __func__); \ + put_target_info((tokdata), (target_info)); \ + target_info = NULL; \ + (rc) = refresh_target_info((tokdata), \ + FALSE); \ + if ((rc) != CKR_OK) \ + break; \ + (target_info) = get_target_info((tokdata)); \ + if ((target_info) == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + break; \ + } \ + } while (0); + +/* + * Macros to enclose EP11 library calls with 1, 2 or 3 key blobs as argument. + * If a master key change is active, and the single APQN has the new WK, + * obtain and use the re-enciphered blob(s) from CKA_IBM_OPAQUE_REENC from + * the key object(s). + * If a master key change is active, and the EP11 library call fails with + * CKR_IBM_WKID_MISMATCH and the used blob(s) are enciphered with the new WK, + * then select a new single APQN that has the new WK. If no available APQN has + * the new WK, wait until on at least one the new WK gets activated. + * In case the blob(s) are enciphered with the old WK, then obtain the + * re-enciphered blob(s) from CKA_IBM_OPAQUE_REENC from the key object(s) + * and retry the library call. + * If the retry was successful, indicate that the single APQN has the new WK. + */ +#define RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob, blobsize,\ + useblob, useblobsize, rc) \ + RETRY_REENC_BLOB3_START(tokdata, target_info, obj, blob, \ + blobsize, useblob, useblobsize, \ + NULL, blob, blobsize, blob, \ + blobsize, NULL, blob, blobsize, \ + blob, blobsize, rc) + +#define RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, \ + rc) \ + RETRY_REENC_BLOB3_END(tokdata, target_info, useblob, \ + useblobsize, NULL, 0, NULL, 0, rc) + +#define RETRY_REENC_BLOB2_START(tokdata, target_info, obj1, blob1, \ + blobsize1, useblob1, useblobsize1, \ + obj2, blob2, blobsize2, useblob2, \ + useblobsize2, rc) \ + RETRY_REENC_BLOB3_START(tokdata, target_info, obj1, \ + blob1, blobsize1, useblob1, \ + useblobsize1, obj2, blob2, \ + blobsize2, useblob2, \ + useblobsize2, NULL, blob1, \ + blobsize1, blob1, blobsize1, rc) + +#define RETRY_REENC_BLOB2_END(tokdata, target_info, useblob1, \ + useblobsize1, useblob2, useblobsize2, rc) \ + RETRY_REENC_BLOB3_END(tokdata, target_info, useblob1, \ + useblobsize1, useblob2, \ + useblobsize2, NULL, 0, rc) + +#define RETRY_REENC_BLOB3_START(tokdata, target_info, obj1, blob1, \ + blobsize1, useblob1, useblobsize1, \ + obj2, blob2, blobsize2, useblob2, \ + useblobsize2, obj3, blob3, blobsize3, \ + useblob3, useblobsize3, rc) \ + do { \ + int retry = 0; \ + do { \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + ((target_info)->single_apqn_has_new_wk || \ + retry == 1)) { \ + /* New WK is set on single APQN */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + (rc) = obj_opaque_2_reenc_blob((tokdata), \ + (obj1), &(useblob1), \ + &(useblobsize1)); \ + if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ + (useblob1) = (blob1); \ + (useblobsize1) = (blobsize1); \ + } else if ((rc) != CKR_OK) { \ + TRACE_ERROR("%s reenc blob1 invalid\n", \ + __func__); \ + break; \ + } \ + if (obj2 != NULL) { \ + (rc) = obj_opaque_2_reenc_blob((tokdata),\ + (obj2), &(useblob2),\ + &(useblobsize2)); \ + if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ + (useblob2) = (blob2); \ + (useblobsize2) = (blobsize2); \ + } else if ((rc) != CKR_OK) { \ + TRACE_ERROR( \ + "%s reenc blob2 invalid\n", \ + __func__); \ + break; \ + } \ + } \ + if (obj3 != NULL) { \ + (rc) = obj_opaque_2_reenc_blob((tokdata),\ + (obj3), &(useblob3),\ + &(useblobsize3)); \ + if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ + (useblob3) = (blob3); \ + (useblobsize3) = (blobsize3); \ + } else if ((rc) != CKR_OK) { \ + TRACE_ERROR( \ + "%s reenc blob3 invalid\n", \ + __func__); \ + break; \ + } \ + } \ + retry = 1; \ + } else { \ + (useblob1) = (blob1); \ + (useblobsize1) = (blobsize1); \ + if (obj2 != NULL) { \ + (useblob2) = (blob2); \ + (useblobsize2) = (blobsize2); \ + } \ + if (obj3 != NULL) { \ + (useblob3) = (blob3); \ + (useblobsize3) = (blobsize3); \ + } \ + } + +#define RETRY_REENC_BLOB3_END(tokdata, target_info, useblob1, \ + useblobsize1, useblob2, useblobsize2, \ + useblob3, useblobsize3, rc) \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (rc) == CKR_IBM_WKID_MISMATCH) { \ + if (ep11tok_is_blob_new_wkid((tokdata), \ + (useblob1), (useblobsize1)) || \ + (useblob2 != NULL && \ + ep11tok_is_blob_new_wkid((tokdata), \ + (useblob2), (useblobsize2))) || \ + (useblob3 != NULL && \ + ep11tok_is_blob_new_wkid((tokdata), \ + (useblob3), (useblobsize3)))) { \ + /* blob has new WK, but single APQN not. + Wait until other single APQN with + new WK set is available */ \ + TRACE_DEVEL("%s WKID mismatch, blob has "\ + "new WK, retry with new " \ + "single APQN with new WK, " \ + "wait if required\n", \ + __func__); \ + put_target_info((tokdata), \ + (target_info)); \ + (target_info) = NULL; \ + (rc) = refresh_target_info((tokdata), \ + TRUE); \ + if ((rc) != CKR_OK) \ + break; \ + (target_info) = \ + get_target_info((tokdata)); \ + if ((target_info) == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + /* Single APQN seems to now have new WK */ \ + TRACE_DEVEL("%s WKID mismatch, retry with " \ + "reenc-blob(s)\n", __func__); \ + retry = 1; \ + continue; \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 1 && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED) { \ + /* retry with re-enciphered blob worked */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + __sync_or_and_fetch( \ + &(target_info)->single_apqn_has_new_wk, \ + 1); \ + } \ + break; \ + } while (1); \ + } while (0); + +/* + * Macros to enclose EP11 library calls with the wrap-blob as argument. + * If a master key change is active, and the single APQN has the new WK, + * obtain and use the re-enciphered wrap-blob. + * If a master key change is active, and the EP11 library call fails with + * CKR_IBM_WKID_MISMATCH and the used wrap blob is enciphered with the new WK, + * then select a new single APQN that has the new WK. If no available APQN has + * the new WK, wait until on at least one the new WK gets activated. + * In case the used wrap blob is enciphered with the old WK, then obtain the + * re-enciphered wrap-blob and retry the library call. + * If the retry was successful, indicate that the single APQN has the new WK. + */ +#define RETRY_REENC_WRAPBLOB_START(tokdata, target_info, useblob) \ + do { \ + int retry = 0; \ + do { \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + (target_info)->single_apqn_has_new_wk && \ + retry == 0) { \ + /* New WK is already set on single APQN */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + (useblob) = ((ep11_private_data_t *) \ + (tokdata)->private_data)-> \ + raw2key_wrap_blob_reenc; \ + retry = 1; \ + } else { \ + (useblob) = ((ep11_private_data_t *) \ + (tokdata)->private_data)-> \ + raw2key_wrap_blob; \ + } + +#define RETRY_REENC_WRAPBLOB_END(tokdata, target_info, useblob, rc) \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (rc) == CKR_IBM_WKID_MISMATCH) { \ + if (ep11tok_is_blob_new_wkid((tokdata), \ + (useblob), \ + ((ep11_private_data_t *) \ + (tokdata)->private_data)-> \ + raw2key_wrap_blob_l)) { \ + /* blob has new WK, but single APQN not. + Wait until other single APQN with + new WK set is available */ \ + TRACE_DEVEL("%s WKID mismatch, blob has "\ + "new WK, retry with new " \ + "single APQN with new WK, " \ + "wait if required\n", \ + __func__); \ + put_target_info((tokdata), \ + (target_info)); \ + (target_info) = NULL; \ + (rc) = refresh_target_info((tokdata), \ + TRUE); \ + if ((rc) != CKR_OK) \ + break; \ + (target_info) = \ + get_target_info((tokdata)); \ + if ((target_info) == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + /* Single APQN seems to now have new WK */ \ + TRACE_DEVEL("%s WKID mismatch, retry with " \ + "reenc-wrap-blob\n", __func__); \ + (useblob) = ((ep11_private_data_t *) \ + (tokdata)->private_data)-> \ + raw2key_wrap_blob_reenc; \ + retry = 1; \ + continue; \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 1 && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED) { \ + /* retry with re-enciphered blob worked */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + __sync_or_and_fetch( \ + &(target_info)->single_apqn_has_new_wk, \ + 1); \ + } \ + break; \ + } while (1); \ + } while (0); + +/* + * Macros to enclose EP11 library calls with a blob as argument that gets + * updated by the EP11 library call. + * If a master key change is active, and the single APQN has the new WK, + * use the re-enciphered blob for the EP11 library call. + * If a master key change is active, and the EP11 library call fails with + * CKR_IBM_WKID_MISMATCH use the re-enciphered blob and retry the library call. + * Also indicate that the single APQN has the new WK. + * If a master key change is active, and the EP11 library call was successful + * when using the old blob, re-encipher the (potentially updated) blob. + * When re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the + * new WK was just activated on the single APQN, indicate that the single APQN + * has the new WK, and retry the EP11 library call with the (still unchanged) + * re-enciphered blob (which then will be potentially updated by the EP11 + * library call). + */ +#define RETRY_UPDATE_BLOB_START(tokdata, target_info, blob, blobsize, \ + reencblob, reencblobsize, \ + useblob, useblobsize) \ + do { \ + CK_RV rc2; \ + int retry = 0; \ + do { \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + ((target_info)->single_apqn_has_new_wk || \ + retry == 1)) { \ + /* New WK is set on single APQN */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + (useblob) = (reencblob); \ + (useblobsize) = (reencblobsize); \ + retry = 1; \ + } else { \ + (useblob) = (blob); \ + (useblobsize) = (blobsize); \ + } + +#define RETRY_UPDATE_BLOB_END(tokdata, target_info, blob, blobsize, \ + reencblob, reencblobsize, \ + useblob, useblobsize, rc) \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (rc) == CKR_IBM_WKID_MISMATCH) { \ + if (ep11tok_is_blob_new_wkid((tokdata), \ + (useblob), (useblobsize))) { \ + /* blob has new WK, but single APQN not. + Wait until other single APQN with + new WK set is available */ \ + TRACE_DEVEL("%s WKID mismatch, blob has "\ + "new WK, retry with new " \ + "single APQN with new WK, " \ + "wait if required\n", \ + __func__); \ + put_target_info((tokdata), \ + (target_info)); \ + (target_info) = NULL; \ + (rc) = refresh_target_info((tokdata), \ + TRUE); \ + if ((rc) != CKR_OK) \ + break; \ + (target_info) = \ + get_target_info((tokdata)); \ + if ((target_info) == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + /* Single APQN seems to now have new WK */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + retry = 1; \ + continue; \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED) { \ + /* Op worked, re-encipher updated blob */ \ + TRACE_DEVEL("%s reencipher updated blob\n", \ + __func__); \ + if ((blobsize) != (reencblobsize)) { \ + TRACE_ERROR("%s reencblobsize wrong \n", \ + __func__); \ + (rc) = CKR_ARGUMENTS_BAD; \ + break; \ + } \ + rc2 = ep11tok_reencipher_blob((tokdata), \ + &(target_info),\ + (blob), \ + (blobsize), \ + (reencblob)); \ + if (rc2 == CKR_IBM_WK_NOT_INITIALIZED) { \ + /* Single APQN now has new WK */ \ + TRACE_DEVEL("%s WKID mismatch on " \ + "reencipher, retry\n", __func__); \ + retry = 1; \ + continue; \ + } \ + if (rc2 != CKR_OK) { \ + (rc) = CKR_DEVICE_ERROR; \ + TRACE_ERROR("%s\n", \ + ock_err(ERR_DEVICE_ERROR)); \ + break; \ + } \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 1 && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED) { \ + /* retry with re-enciphered blob worked */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + __sync_or_and_fetch( \ + &(target_info)->single_apqn_has_new_wk, \ + 1); \ + /* old blob is no longer valid, replace with + * re-enciphered blob */ \ + if ((blobsize) != (useblobsize)) { \ + TRACE_ERROR("%s useblobsize wrong \n", \ + __func__); \ + (rc) = CKR_ARGUMENTS_BAD; \ + break; \ + } \ + memcpy((blob), (useblob), (blobsize)); \ + } \ + break; \ + } while (1); \ + } while (0); + +/* + * Macros to enclose EP11 library calls with a key blob and a state blob as + * arguments where the state blob gets updated by the EP11 library call. + * If a master key change is active, and the single APQN has the new WK, + * obtain and use the re-enciphered key blob CKA_IBM_OPAQUE_REENC from + * the key object, and also use the re-enciphered state blob(s) for the EP11 + * library call. + * If a master key change is active, and the EP11 library call fails with + * CKR_IBM_WKID_MISMATCH use the re-enciphered blobs and retry the library + * call. + * If the retry was successful, indicate that the single APQN has the new WK. + * If a master key change is active, and the EP11 library call was successful + * when using the old blobs, re-encipher the (potentially updated) state blob. + * When re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the + * new WK was just activated on the single APQN, indicate that the single APQN + * has the new WK, and retry the EP11 library call with the (still unchanged) + * re-enciphered state blob (which then will be potentially updated by the EP11 + * library call). + */ +#define RETRY_REENC_BLOB_STATE_START(tokdata, target_info, obj, blob, \ + blobsize, useblob, useblobsize, \ + stateblob, reencstate, \ + stateblobsize, usestate, \ + usestatesize, rc) \ + do { \ + int retry = 0; \ + do { \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + ((target_info)->single_apqn_has_new_wk || \ + retry == 1)) { \ + /* New WK is set on single APQN */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + (rc) = obj_opaque_2_reenc_blob((tokdata), \ + (obj), &(useblob), &(useblobsize));\ + if ((rc) == CKR_TEMPLATE_INCOMPLETE) { \ + (useblob) = (blob); \ + (useblobsize) = (blobsize); \ + } else if ((rc) != CKR_OK) { \ + TRACE_ERROR("%s reenc blob invalid\n", \ + __func__); \ + break; \ + } \ + (usestate) = (reencstate); \ + retry = 1; \ + } else { \ + (useblob) = (blob); \ + (useblobsize) = (blobsize); \ + (usestate) = (stateblob); \ + } \ + (usestatesize) = (stateblobsize); + +#define RETRY_REENC_BLOB_STATE_END(tokdata, target_info, blob, blobsize, \ + useblob, useblobsize, stateblob, \ + reencstate, stateblobsize, usestate, \ + usestatesize, newstate, rc) \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (rc) == CKR_IBM_WKID_MISMATCH) { \ + if (ep11tok_is_blob_new_wkid((tokdata), \ + (useblob), (useblobsize)) || \ + ep11tok_is_blob_new_wkid((tokdata), \ + (usestate), (usestatesize))) { \ + /* blob has new WK, but single APQN not. + Wait until other single APQN with + new WK set is available */ \ + TRACE_DEVEL("%s WKID mismatch, blob has "\ + "new WK, retry with new " \ + "single APQN with new WK, " \ + "wait if required\n", \ + __func__); \ + put_target_info((tokdata), \ + (target_info)); \ + (target_info) = NULL; \ + (rc) = refresh_target_info((tokdata), \ + TRUE); \ + if ((rc) != CKR_OK) \ + break; \ + (target_info) = \ + get_target_info((tokdata)); \ + if ((target_info) == NULL) { \ + (rc) = CKR_FUNCTION_FAILED; \ + break; \ + } \ + continue; \ + } \ + /* Single APQN seems to now have new WK */ \ + TRACE_DEVEL("%s WKID mismatch, retry with " \ + "reenc-blob\n", __func__); \ + retry = 1; \ + continue; \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 1 && \ + (((newstate) && (rc) == CKR_OK) || \ + (!(newstate) && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED))) { \ + /* retry with re-enciphered blob worked */ \ + TRACE_DEVEL("%s single APQN has new WK\n", \ + __func__); \ + __sync_or_and_fetch( \ + &(target_info)->single_apqn_has_new_wk, \ + 1); \ + /* old blobs are no longer valid, replace with + * re-enciphered blobs */ \ + if ((blobsize) != (useblobsize)) { \ + TRACE_ERROR("%s useblobsize wrong \n", \ + __func__); \ + (rc) = CKR_ARGUMENTS_BAD; \ + break; \ + } \ + memcpy((blob), (useblob), (blobsize)); \ + if ((stateblobsize) != (usestatesize)) { \ + TRACE_ERROR("%s usestatesize wrong \n", \ + __func__); \ + (rc) = CKR_ARGUMENTS_BAD; \ + break; \ + } \ + memcpy((stateblob), (usestate), \ + (stateblobsize)); \ + } \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + retry == 0 && \ + (((newstate) && (rc) == CKR_OK) || \ + (!(newstate) && \ + (rc) != CKR_IBM_WKID_MISMATCH && \ + (rc) != CKR_IBM_TARGET_INVALID && \ + (rc) != CKR_FUNCTION_FAILED))) { \ + /* worked, re-encipher updated state blob */ \ + TRACE_DEVEL("%s reencipher updated state " \ + "blob\n", __func__); \ + rc2 = ep11tok_reencipher_blob((tokdata), \ + &(target_info), \ + (stateblob), \ + (stateblobsize), \ + (reencstate)); \ + if (rc2 == CKR_IBM_WK_NOT_INITIALIZED) { \ + /* Single APQN now has new WK */ \ + TRACE_DEVEL("%s WKID mismatch on " \ + "reencipher, retry\n", \ + __func__); \ + __sync_or_and_fetch(&(target_info)-> \ + single_apqn_has_new_wk,\ + 1); \ + continue; \ + } \ + if (rc2 != CKR_OK) { \ + (rc) = CKR_DEVICE_ERROR; \ + TRACE_ERROR("%s\n", \ + ock_err(ERR_DEVICE_ERROR)); \ + break; \ + } \ + } \ + break; \ + } while (1); \ + } while (0); + +/* + * Macros to enclose EP11 library calls that create 1 or 2 key blobs as output. + * If a master key change is active, and the key blob(s) were created with the + * new WK, copy them to the re-enciphered blob(s) and indicate that the + * single APQN has the new WK. + * If a master key change is active, and the key blob(s) were created with the + * old WK, re-encipher the key blob(s). + * If re-enciphering fails with CKR_IBM_WK_NOT_INITIALIZED, because the new WK + * was just activated on the single APQN, indicate that the single APQN has + * the new WK, and retry the EP11 library call. This creates new key blob(s) + * that are then enciphered with the new WK. + */ +#define RETRY_REENC_CREATE_KEY_START() \ + RETRY_REENC_CREATE_KEY2_START() + +#define RETRY_REENC_CREATE_KEY_END(tokdata, target_info, blob, \ + reencblob, blobsize, rc) \ + RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, blob, \ + reencblob, blobsize, blob, \ + reencblob, 0, rc) + +#define RETRY_REENC_CREATE_KEY2_START() \ + do { \ + do { \ + +#define RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, blob1, \ + reencblob1, blobsize1, blob2, \ + reencblob2, blobsize2, rc) \ + if (((ep11_private_data_t *)(tokdata)-> \ + private_data)->mk_change_active && \ + (rc) == CKR_OK) { \ + /* Key creation successful */ \ + if (ep11tok_is_blob_new_wkid((tokdata), \ + (blob1), (blobsize1)) || \ + ((blobsize2) > 0 && \ + ep11tok_is_blob_new_wkid((tokdata), \ + (blob2), (blobsize2)))) { \ + /* Key created with new WK already: + supply it in reencblob as well */ \ + TRACE_DEVEL("%s new key has new WK\n", \ + __func__); \ + memcpy((reencblob1), (blob1), \ + (blobsize1)); \ + if ((blobsize2) > 0) \ + memcpy((reencblob2), (blob2), \ + (blobsize2)); \ + __sync_or_and_fetch(&(target_info)-> \ + single_apqn_has_new_wk, \ + 1); \ + } else { \ + /* created with old WK, re-encipher it */\ + TRACE_DEVEL("%s new key has old WK, " \ + "reencipher it\n", __func__);\ + (rc) = ep11tok_reencipher_blob((tokdata),\ + &(target_info), (blob1), \ + (blobsize1), (reencblob1)); \ + if ((rc) == CKR_IBM_WK_NOT_INITIALIZED) {\ + /* Single APQN now has new WK, + repeat key creation. */ \ + TRACE_DEVEL("%s WKID mismatch on " \ + "reencipher, retry\n", \ + __func__); \ + continue; \ + } \ + if ((rc) != CKR_OK) { \ + (rc) = CKR_DEVICE_ERROR; \ + TRACE_ERROR("%s\n", \ + ock_err(ERR_DEVICE_ERROR)); \ + break; \ + } \ + if ((blobsize2) > 0) { \ + (rc) = ep11tok_reencipher_blob( \ + (tokdata), &(target_info),\ + (blob2), (blobsize2), \ + (reencblob2)); \ + if ((rc) == \ + CKR_IBM_WK_NOT_INITIALIZED) {\ + /* Single APQN now has new WK, + repeat key creation. */ \ + TRACE_DEVEL("%s WKID mismatch " \ + "on reencipher, retry\n",\ + __func__); \ + continue; \ + } \ + if ((rc) != CKR_OK) { \ (rc) = CKR_DEVICE_ERROR; \ TRACE_ERROR("%s\n", \ ock_err(ERR_DEVICE_ERROR)); \ break; \ } \ - ep11_target_info_t* target_info = \ - get_target_info((tokdata)); \ - if (target_info == NULL) { \ - (rc) = CKR_FUNCTION_FAILED; \ - break; \ - } \ - for(retry_count = 0; \ - target_info != NULL && \ - retry_count < MAX_RETRY_COUNT; \ - retry_count ++) { - -#define RETRY_END(rc, tokdata, session) if ((rc) != CKR_SESSION_CLOSED) \ - break; \ - rc2 = ep11tok_relogin_session( \ - (tokdata), (session)); \ - if (rc2 != CKR_OK) { \ - (rc) = rc2; \ - break; \ - } \ - } \ - put_target_info((tokdata), \ - target_info); \ - } while (0); + } \ + } \ + } \ + break; \ + } while (1); \ + } while (0); #define CKF_EP11_HELPER_SESSION 0x80000000 @@ -306,6 +1047,8 @@ static CK_RV obj_opaque_2_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, CK_BYTE **blob, size_t *blobsize); +static CK_RV obj_opaque_2_reenc_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, + CK_BYTE **blob, size_t *blobsize); /* EP11 Firmware levels that contain the HMAC min/max keysize fix */ static const CK_VERSION cex4p_hmac_fix = { .major = 4, .minor = 20 }; @@ -561,11 +1304,17 @@ size_t max_control_point_index; CK_CHAR serialNumber[16]; CK_BYTE pqc_strength[PQC_BYTES]; + int single_apqn; + uint_32 adapter; /* set if single_apqn = 1 */ + uint_32 domain; /* set if single_apqn = 1 */ + volatile int single_apqn_has_new_wk; } ep11_target_info_t; typedef struct { + char token_config_filename[PATH_MAX]; ep11_target_t target_list; CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE]; + CK_BYTE raw2key_wrap_blob_reenc[MAX_BLOBSIZE]; size_t raw2key_wrap_blob_l; int cka_sensitive_default_true; char cp_filter_config_filename[PATH_MAX]; @@ -581,6 +1330,11 @@ char digest_libica_path[PATH_MAX]; unsigned char expected_wkvp[XCP_WKID_BYTES]; int expected_wkvp_set; + volatile int mk_change_active; + char mk_change_op[8]; /* set if mk_change_active = 1 */ + unsigned char new_wkvp[XCP_WKID_BYTES]; /* set if mk_change_active = 1 */ + struct apqn *mk_change_apqns; /* set if mk_change_active = 1 */ + unsigned int num_mk_change_apqns; /* set if mk_change_active = 1 */ int inconsistent; libica_t libica; void *lib_ep11; @@ -592,15 +1346,23 @@ static ep11_target_info_t *get_target_info(STDLL_TokData_t *tokdata); static void put_target_info(STDLL_TokData_t *tokdata, ep11_target_info_t *target_info); -static CK_RV refresh_target_info(STDLL_TokData_t *tokdata); +static CK_RV refresh_target_info(STDLL_TokData_t *tokdata, + CK_BBOOL wait_for_new_wk); static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, target_t *target, uint64_t flags); static void free_ep11_target_for_apqn(target_t target); static CK_RV update_ep11_attrs_from_blob(STDLL_TokData_t *tokdata, - SESSION *session, TEMPLATE *tmpl, + SESSION *session, OBJECT *key_obj, CK_BBOOL aes_xts); - +static CK_BBOOL is_apqn_online(uint_32 card, uint_32 domain); +static CK_RV ep11tok_mk_change_check_pending_ops(STDLL_TokData_t *tokdata); +static CK_RV ep11tok_reencipher_blob(STDLL_TokData_t *tokdata, + ep11_target_info_t **target_info, + CK_BYTE *blob, CK_ULONG blob_len, + CK_BYTE *new_blob); +static CK_BBOOL ep11tok_is_blob_new_wkid(STDLL_TokData_t *tokdata, + CK_BYTE *blob, CK_ULONG blob_len); /* defined in the makefile, ep11 library can run standalone (without HW card), crypto algorithms are implemented in software then (no secure key) */ @@ -648,10 +1410,13 @@ } static CK_RV check_expected_mkvp(STDLL_TokData_t *tokdata, CK_BYTE *blob, - size_t blobsize) + size_t blobsize, CK_BBOOL *new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; + if (new_wk != NULL) + *new_wk = FALSE; + if (blobsize < EP11_BLOB_WKID_OFFSET + XCP_WKID_BYTES) { TRACE_ERROR("EP11 key blob is too small\n"); return CKR_FUNCTION_FAILED; @@ -659,6 +1424,17 @@ if (memcmp(blob + EP11_BLOB_WKID_OFFSET, ep11_data->expected_wkvp, XCP_WKID_BYTES) != 0) { + /* If an MK change operation is active, also allow the new WK */ + if (ep11_data->mk_change_active && + memcmp(blob + EP11_BLOB_WKID_OFFSET, ep11_data->new_wkvp, + XCP_WKID_BYTES) == 0) { + + TRACE_DEBUG("The key is wrapped by the new WK\n"); + if (new_wk != NULL) + *new_wk = TRUE; + return CKR_OK; + } + TRACE_ERROR("The key's wrapping key verification pattern does not " "match the expected EP11 wrapping key\n"); TRACE_DEBUG_DUMP("WKVP of key: ", blob + EP11_BLOB_WKID_OFFSET, @@ -760,15 +1536,21 @@ */ typedef struct { + STDLL_TokData_t *tokdata; ep11_session_t *ep11_session; CK_BBOOL wrap_was_successful; + CK_RV wrap_error; CK_VOID_PTR secure_key; CK_ULONG secure_key_len; + CK_VOID_PTR secure_key_reenc; + CK_ULONG secure_key_reenc_len; CK_BYTE *pkey_buf; size_t *pkey_buflen_p; /* for AES XTS processing */ CK_VOID_PTR secure_key2; CK_ULONG secure_key_len2; + CK_VOID_PTR secure_key_reenc2; + CK_ULONG secure_key_reenc_len2; CK_BYTE *pkey_buf2; size_t *pkey_buflen_p2; CK_BBOOL aes_xts; @@ -810,20 +1592,28 @@ }; CK_MECHANISM mech = { CKM_IBM_CPACF_WRAP, &iv, sizeof(iv) }; pkey_wrap_handler_data_t *data = (pkey_wrap_handler_data_t *) handler_data; + ep11_private_data_t *ep11_data; target_t target = 0; - CK_RV ret; + CK_RV ret = CKR_OK; CK_BBOOL retry = FALSE; + CK_BYTE *blob; + CK_ULONG bloblen; + CK_BBOOL blobretry = FALSE; if (data->wrap_was_successful) goto done; + ep11_data = data->tokdata->private_data; + ret = get_ep11_target_for_apqn(adapter, domain, &target, XCP_MFL_PROBE); if (ret != CKR_OK) goto done; /* Create the protected key via CKM_IBM_CPACF_WRAP */ + blob = data->secure_key; + bloblen = data->secure_key_len; repeat: - ret = dll_m_WrapKey(data->secure_key, data->secure_key_len, + ret = dll_m_WrapKey(blob, bloblen, NULL, 0, NULL, 0, &mech, data->pkey_buf, data->pkey_buflen_p, target | XCP_TGTFL_SET_SCMD); @@ -837,11 +1627,22 @@ } } + if (ep11_data->mk_change_active && blobretry == FALSE && + ret == CKR_IBM_WKID_MISMATCH && data->secure_key_reenc != NULL) { + blob = data->secure_key_reenc; + bloblen = data->secure_key_reenc_len; + blobretry = TRUE; + goto repeat; + } + if (data->aes_xts && ret == CKR_OK) { /* Create the protected key via CKM_IBM_CPACF_WRAP */ retry = FALSE; + blobretry = FALSE; + blob = data->secure_key2; + bloblen = data->secure_key_len2; repeat2: - ret = dll_m_WrapKey(data->secure_key2, data->secure_key_len2, + ret = dll_m_WrapKey(blob, bloblen, NULL, 0, NULL, 0, &mech, data->pkey_buf2, data->pkey_buflen_p2, target | XCP_TGTFL_SET_SCMD); @@ -854,6 +1655,14 @@ goto repeat2; } } + + if (ep11_data->mk_change_active && blobretry == FALSE && + ret == CKR_IBM_WKID_MISMATCH && data->secure_key_reenc2 != NULL) { + blob = data->secure_key_reenc2; + bloblen = data->secure_key_reenc_len2; + blobretry = TRUE; + goto repeat2; + } } if (ret == CKR_OK) @@ -864,7 +1673,9 @@ done: /* Always return ok, calling function loops over this handler until - * data->wrap_was_successful = true, or no more APQN left */ + * data->wrap_was_successful = true, or no more APQN left. + * Pass back error in handler data anyway. */ + data->wrap_error = ret; return CKR_OK; } @@ -874,7 +1685,9 @@ */ static CK_RV ep11tok_pkey_skey2pkey(STDLL_TokData_t *tokdata, SESSION *session, CK_ATTRIBUTE *skey_attr, - CK_ATTRIBUTE **pkey_attr, CK_BBOOL aes_xts) + CK_ATTRIBUTE *skey_reenc_attr, + CK_ATTRIBUTE **pkey_attr, + CK_BBOOL aes_xts) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *tmp_attr = NULL; @@ -886,31 +1699,62 @@ wrapped_key_t *wk, *wk2; uint64_t token_size = 0; uint8_t wrapped_key[EP11_MAX_WRAPPED_KEY_SIZE * 2]; + ep11_target_info_t *target_info = NULL; CK_RV ret; + target_info = get_target_info(tokdata); + if (target_info == NULL) + return CKR_FUNCTION_FAILED; + /* Create the protected key via CKM_IBM_CPACF_WRAP */ memset(&pkey_wrap_handler_data, 0, sizeof(pkey_wrap_handler_data_t)); + pkey_wrap_handler_data.tokdata = tokdata; if (session != NULL) pkey_wrap_handler_data.ep11_session = (ep11_session_t *)session->private_data; pkey_wrap_handler_data.secure_key = skey_attr->pValue; pkey_wrap_handler_data.secure_key_len = skey_attr->ulValueLen; + if (skey_reenc_attr != NULL) { + pkey_wrap_handler_data.secure_key_reenc = skey_reenc_attr->pValue; + pkey_wrap_handler_data.secure_key_reenc_len = + skey_reenc_attr->ulValueLen; + } pkey_wrap_handler_data.pkey_buf = (CK_BYTE *)&ep11_buf; pkey_wrap_handler_data.pkey_buflen_p = &ep11_buflen; pkey_wrap_handler_data.aes_xts = FALSE; if (aes_xts) { pkey_wrap_handler_data.secure_key_len = skey_attr->ulValueLen / 2; - pkey_wrap_handler_data.secure_key2 = (CK_BYTE *)skey_attr->pValue + skey_attr->ulValueLen / 2; + pkey_wrap_handler_data.secure_key2 = + (CK_BYTE *)skey_attr->pValue + skey_attr->ulValueLen / 2; pkey_wrap_handler_data.secure_key_len2 = skey_attr->ulValueLen / 2; + if (skey_reenc_attr != NULL) { + pkey_wrap_handler_data.secure_key_reenc_len = + skey_reenc_attr->ulValueLen / 2; + pkey_wrap_handler_data.secure_key_reenc2 = + (CK_BYTE *)skey_reenc_attr->pValue + + skey_reenc_attr->ulValueLen / 2; + pkey_wrap_handler_data.secure_key_reenc_len2 = + skey_reenc_attr->ulValueLen / 2; + } pkey_wrap_handler_data.pkey_buf2 = (CK_BYTE *)&ep11_buf2; pkey_wrap_handler_data.pkey_buflen_p2 = &ep11_buflen2; pkey_wrap_handler_data.aes_xts = TRUE; } - ret = handle_all_ep11_cards(&ep11_data->target_list, - ep11tok_pkey_wrap_handler, &pkey_wrap_handler_data); - + if (target_info->single_apqn) { + /* If in single APQN mode, call handler for that single APQN only */ + RETRY_SINGLE_APQN_START(tokdata, ret) + pkey_wrap_handler_data.wrap_error = CKR_OK; + ep11tok_pkey_wrap_handler(target_info->adapter, target_info->domain, + &pkey_wrap_handler_data); + ret = pkey_wrap_handler_data.wrap_error; + RETRY_SINGLE_APQN_END(ret, tokdata, target_info) + } else { + ret = handle_all_ep11_cards(&ep11_data->target_list, + ep11tok_pkey_wrap_handler, + &pkey_wrap_handler_data); + } if (ret != CKR_OK || !pkey_wrap_handler_data.wrap_was_successful) { TRACE_ERROR("handle_all_ep11_cards failed or no APQN could do the wrap.\n"); ret = CKR_FUNCTION_FAILED; @@ -1001,6 +1845,8 @@ *pkey_attr = tmp_attr; + put_target_info(tokdata, target_info); + return ret; } @@ -1024,7 +1870,8 @@ size_t csum_l = sizeof(csum); CK_BYTE blob[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); - CK_ATTRIBUTE *pkey_attr = NULL, *blob_attr=NULL; + CK_BYTE blob_reenc[MAX_BLOBSIZE]; + CK_ATTRIBUTE *pkey_attr = NULL, *blob_attr = NULL, *blob_reenc_attr = NULL; ep11_target_info_t* target_info; CK_RV ret; @@ -1044,14 +1891,20 @@ trace_attributes(__func__, "Generate prot. test key:", tmpl, tmpl_len); /* Create an AES testkey with CKA_IBM_PROTKEY_EXTRACTABLE */ - ret = dll_m_GenerateKey(&mech, tmpl, tmpl_len, NULL, 0, - blob, &blobsize, csum, &csum_l, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, ret) + RETRY_REENC_CREATE_KEY_START() + ret = dll_m_GenerateKey(&mech, tmpl, tmpl_len, NULL, 0, + blob, &blobsize, csum, &csum_l, + target_info->target); + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blob_reenc, blobsize, ret) + RETRY_SINGLE_APQN_END(ret, tokdata, target_info) if (ret != CKR_OK) { TRACE_ERROR("dll_m_GenerateKey failed with rc=0x%lx\n",ret); goto done; } - if (check_expected_mkvp(tokdata, blob, blobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, blob, blobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); ret = CKR_DEVICE_ERROR; goto done; @@ -1064,10 +1917,20 @@ goto done; } + if (ep11_data->mk_change_active) { + ret = build_attribute(CKA_IBM_OPAQUE_REENC, blob_reenc, blobsize, + &blob_reenc_attr); + if (ret != CKR_OK) { + TRACE_ERROR("build_attribute CKA_IBM_OPAQUE_REENC failed with rc=0x%lx\n", ret); + goto done; + } + } + /* Create a protected key from this blob to obtain the LPAR MK vp. When * this function returns ok, we have a 64 byte pkey value: 32 bytes * encrypted key + 32 bytes vp. */ - ret = ep11tok_pkey_skey2pkey(tokdata, NULL, blob_attr, &pkey_attr, FALSE); + ret = ep11tok_pkey_skey2pkey(tokdata, NULL, blob_attr, blob_reenc_attr, + &pkey_attr, FALSE); if (ret != CKR_OK) { TRACE_ERROR("ep11tok_pkey_skey2pkey failed with rc=0x%lx\n", ret); goto done; @@ -1076,12 +1939,14 @@ memcpy(&ep11_data->pkey_mk_vp, (CK_BYTE *)pkey_attr->pValue + AES_KEY_SIZE_256, PKEY_MK_VP_LENGTH); - ep11_data->pkey_wrap_supported = 1; + __sync_or_and_fetch(&ep11_data->pkey_wrap_supported, 1); done: if (blob_attr) free(blob_attr); + if (blob_reenc_attr) + free(blob_reenc_attr); if (pkey_attr) free(pkey_attr); @@ -1138,6 +2003,7 @@ { ep11_private_data_t *ep11_data = tokdata->private_data; CK_ATTRIBUTE *skey_attr = NULL; + CK_ATTRIBUTE *skey_reenc_attr = NULL; CK_ATTRIBUTE *pkey_attr = NULL; CK_RV ret; int vp_offset; @@ -1150,8 +2016,16 @@ goto done; } + if (ep11_data->mk_change_active) { + /* Try to get CKA_IBM_OPAQUE_REENC, ignore if it fails */ + template_attribute_get_non_empty(key_obj->template, + CKA_IBM_OPAQUE_REENC, + &skey_reenc_attr); + } + /* Transform the secure key into a protected key */ - ret = ep11tok_pkey_skey2pkey(tokdata, session, skey_attr, &pkey_attr, aes_xts); + ret = ep11tok_pkey_skey2pkey(tokdata, session, skey_attr, skey_reenc_attr, + &pkey_attr, aes_xts); if (ret != CKR_OK) { TRACE_ERROR("protected key creation failed with rc=0x%lx\n",ret); goto done; @@ -1184,8 +2058,8 @@ } /* Now update the key obj. If it's a token obj, it will be also updated - * in the repository. */ - ret = pkey_update_and_save(tokdata, key_obj, pkey_attr); + * in the repository. pkey_attr is set to NULL if added to the object.*/ + ret = pkey_update_and_save(tokdata, key_obj, &pkey_attr); if (ret != CKR_OK) { TRACE_ERROR("pkey_update_and_save failed with rc=0x%lx\n", ret); goto done; @@ -1194,6 +2068,8 @@ ret = CKR_OK; done: + if (pkey_attr != NULL) + free(pkey_attr); return ret; } @@ -1768,12 +2644,17 @@ CK_ULONG i; CK_ATTRIBUTE *attr; CK_BBOOL cktrue = TRUE; + CK_BYTE *useblob; + size_t useblob_len; - RETRY_START(rc, tokdata) - rc = dll_m_GetAttributeValue(blob, blob_len, attrs, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, obj, blob, blob_len, + useblob, useblob_len, rc) + rc = dll_m_GetAttributeValue(useblob, useblob_len, attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE), target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { TRACE_ERROR("Retrieving attributes from AB unwrapped key failed, rc=0x%lx\n", @@ -2257,7 +3138,8 @@ static CK_RV rawkey_2_blob(STDLL_TokData_t * tokdata, SESSION * sess, unsigned char *key, CK_ULONG ksize, CK_KEY_TYPE ktype, - unsigned char *blob, size_t * blen, OBJECT * key_obj) + unsigned char *blob, unsigned char *blobreenc, + size_t *blen, OBJECT *key_obj) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE cipher[MAX_BLOBSIZE]; @@ -2275,6 +3157,7 @@ unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + CK_BYTE *wrap_blob; /* tell ep11 the attributes the user specified */ rc = build_ep11_attrs(tokdata, key_obj->template, &p_attrs, &attrs_len, @@ -2289,11 +3172,13 @@ * calls the ep11 lib (which in turns sends the request to the card), * all m_ function are ep11 functions */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, &mech, key, - ksize, cipher, &clen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, + &mech, key, ksize, cipher, &clen, + target_info->target); + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -2320,13 +3205,17 @@ /* the encrypted key is decrypted and a blob is build, * card accepts only blobs as keys */ - RETRY_START(rc, tokdata) - rc = dll_m_UnwrapKey(cipher, clen, ep11_data->raw2key_wrap_blob, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_UnwrapKey(cipher, clen, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob, blen, csum, &cslen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, blob, blobreenc, *blen, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -2370,12 +3259,16 @@ CK_ULONG bytes) { ep11_target_info_t* target_info; + CK_RV rc; target_info = get_target_info(tokdata); if (target_info == NULL) return CKR_FUNCTION_FAILED; - CK_RV rc = dll_m_GenerateRandom(output, bytes, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GenerateRandom(output, bytes, target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) + if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s output=%p bytes=%lu rc=0x%lx\n", @@ -2386,6 +3279,143 @@ return rc; } +static CK_BBOOL ep11tok_is_blob_new_wkid(STDLL_TokData_t *tokdata, + CK_BYTE *blob, CK_ULONG blob_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_ULONG data_len = 0, spki_len = 0, wkid_len = 0; + CK_BYTE *data; + CK_RV rc; + + /* + * Check if MACed SPKI or key/state blob. From the EP11 structure document: + * Session identifiers are guaranteed not to have 0x30 as their first + * byte. This allows a single-byte check to differentiate between blobs + * starting with session identifiers, and MACed SPKIs, which may be + * used as blobs under other conditions. + * Key and state blobs start with the session identifier (32 bytes). + * SPKIs start with a DER encoded SPKI, which itself stars with a SEQUENCE + * denoted by 0x30 followed by the DER encoded length of the SPKI. + */ + if (blob_len > 5 && blob[0] == 0x30 && + ber_decode_SEQUENCE(blob, &data, &data_len, &spki_len) == CKR_OK) { + /* Its a SPKI, WKID follows as OCTET STRING right after SPKI data */ + if (blob_len < spki_len + 2 + XCP_WKID_BYTES) { + TRACE_ERROR("MACed SPKI is too small\n"); + return CK_FALSE; + } + + rc = ber_decode_OCTET_STRING(blob + spki_len, &data, &data_len, + &wkid_len); + if (rc != CKR_OK || data_len != XCP_WKID_BYTES) { + TRACE_ERROR("Invalid MACed SPKI encoding\n"); + return CK_FALSE; + } + + if (memcmp(data, ep11_data->new_wkvp, XCP_WKID_BYTES) == 0) + return CK_TRUE; + + return CK_FALSE; + } + + /* Key or state blob */ + if (blob_len < EP11_BLOB_WKID_OFFSET + XCP_WKID_BYTES) { + TRACE_ERROR("EP11 blob is too small\n"); + return CK_FALSE; + } + + if (memcmp(blob + EP11_BLOB_WKID_OFFSET, ep11_data->new_wkvp, + XCP_WKID_BYTES) == 0) + return CK_TRUE; + + return CK_FALSE; +} + +static CK_RV ep11tok_reencipher_blob(STDLL_TokData_t *tokdata, + ep11_target_info_t **target_info, + CK_BYTE *blob, CK_ULONG blob_len, + CK_BYTE *new_blob) +{ + CK_BYTE req[MAX_BLOBSIZE]; + CK_BYTE resp[MAX_BLOBSIZE]; + CK_LONG req_len = 0; + size_t resp_len = 0; + struct XCPadmresp rb; + struct XCPadmresp lrb; + CK_RV rc; + + UNUSED(tokdata); + + TRACE_DEVEL("%s blob: %p blob_len: %lu\n", __func__, + (void *)blob, blob_len); + + if ((*target_info)->single_apqn == 0) { + TRACE_ERROR("%s must be used with single APQN target\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(&rb, 0, sizeof(rb)); + memset(&lrb, 0, sizeof(lrb)); + + RETRY_SINGLE_APQN_START(tokdata, rc) + rb.domain = (*target_info)->domain; + lrb.domain = (*target_info)->domain; + + resp_len = MAX_BLOBSIZE; + + req_len = dll_xcpa_cmdblock(req, MAX_BLOBSIZE, XCP_ADM_REENCRYPT, &rb, + NULL, blob, blob_len); + + if (req_len < 0) { + TRACE_ERROR("%s reencrypt cmd block construction failed\n", + __func__); + rc = CKR_FUNCTION_FAILED; + break; + } + + rc = dll_m_admin(resp, &resp_len, NULL, 0, req, req_len, NULL, 0, + (*target_info)->target); + RETRY_SINGLE_APQN_END(rc, tokdata, *target_info) + if (rc != CKR_OK || resp_len == 0) { + TRACE_ERROR("%s reencryption failed: 0x%lx %ld\n", __func__, rc, req_len); + return resp_len == 0 ? CKR_FUNCTION_FAILED : rc; + } + + if (dll_xcpa_internal_rv(resp, resp_len, &lrb, &rc) < 0) { + TRACE_ERROR("%s reencryption response malformed: 0x%lx\n", __func__, rc); + return CKR_FUNCTION_FAILED; + } + + if (rc != 0) { + TRACE_ERROR("%s reencryption failed: rc: 0x%lx reason: %u\n", __func__, + rc, lrb.reason); + switch (lrb.reason) { + case XCP_RSC_WK_MISSING: + case XCP_RSC_NEXT_WK_MISSING: + rc = CKR_IBM_WK_NOT_INITIALIZED; + } + return rc; + } + + if (blob_len != lrb.pllen) { + TRACE_ERROR("%s reencryption blob size changed: 0x%lx 0x%lx 0x%lx 0x%lx\n", + __func__, blob_len, lrb.pllen, resp_len, req_len); + return CKR_FUNCTION_FAILED; + } + + memcpy(new_blob, lrb.payload, blob_len); + + if (!ep11tok_is_blob_new_wkid(tokdata, new_blob, blob_len)) { + TRACE_ERROR("%s Re-enciphered key blob is not enciphered by expected " + "new WK\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Re-enciphered key blob is not enciphered" + " by expected new WK\n", tokdata->slot_id); + return CKR_DEVICE_ERROR; + } + + return CKR_OK; +} + /* * for importing keys we need to encrypt the keys and build the blob by * m_UnwrapKey, use one wrap key for this purpose, can be any key, @@ -2414,26 +3444,34 @@ return CKR_FUNCTION_FAILED; ep11_data->raw2key_wrap_blob_l = sizeof(ep11_data->raw2key_wrap_blob); - rc = dll_m_GenerateKey(&mech, tmpl_in, tmpl_len, NULL, 0, - ep11_data->raw2key_wrap_blob, - &ep11_data->raw2key_wrap_blob_l, csum, &csum_l, - target_info->target); - + RETRY_SINGLE_APQN_START(tokdata, rc) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_GenerateKey(&mech, tmpl_in, tmpl_len, NULL, 0, + ep11_data->raw2key_wrap_blob, + &ep11_data->raw2key_wrap_blob_l, csum, &csum_l, + target_info->target); + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_reenc, + ep11_data->raw2key_wrap_blob_l, rc) + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { TRACE_ERROR("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n", __func__, ep11_data->raw2key_wrap_blob_l, rc); + goto out; } else { TRACE_INFO("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n", __func__, ep11_data->raw2key_wrap_blob_l, rc); } if (check_expected_mkvp(tokdata, ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l) != CKR_OK) { + ep11_data->raw2key_wrap_blob_l, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; } +out: put_target_info(tokdata, target_info); return rc; } @@ -2575,6 +3613,7 @@ *(void **)(&dll_m_add_backend) = dlsym(hdl, "m_add_backend"); *(void **)(&dll_m_shutdown) = dlsym(hdl, "m_shutdown"); + *(void **)(&dll_xcpa_cmdblock) = dlsym(hdl, "xcpa_cmdblock"); *(void **)(&dll_xcpa_queryblock) = dlsym(hdl, "xcpa_queryblock"); *(void **)(&dll_xcpa_internal_rv) = dlsym(hdl, "xcpa_internal_rv"); @@ -2689,6 +3728,13 @@ TRACE_INFO("ep11 %s slot=%lu running\n", __func__, SlotNumber); + /* Request the API layer to lock against HSM-MK-change state changes. */ + rc = init_hsm_mk_change_lock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("init_hsm_mk_change_lock failed.\n"); + goto error; + } + ep11_data = calloc(1, sizeof(ep11_private_data_t)); if (ep11_data == NULL) return CKR_HOST_MEMORY; @@ -2750,7 +3796,16 @@ (ep11_data->ep11_lib_version.minor & 0xF0) >> 4, (ep11_data->ep11_lib_version.minor & 0x0F)); - rc = refresh_target_info(tokdata); + rc = ep11tok_mk_change_check_pending_ops(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to check for pending HSM MK change operations " + "rc=0x%lx\n", __func__, rc); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to check for pending HSM MK " + "change operations rc=0x%lx\n", tokdata->slot_id, rc); + goto error; + } + + rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s Failed to get the target info (refresh_target_info " "rc=0x%lx)\n", __func__, rc); @@ -2840,6 +3895,8 @@ dlclose(ep11_data->libica.library); if (ep11_data->lib_ep11 != NULL && !in_fork_initializer) dlclose(ep11_data->lib_ep11); + if (ep11_data->mk_change_apqns != NULL) + free(ep11_data->mk_change_apqns); free(ep11_data); tokdata->private_data = NULL; } @@ -2853,8 +3910,8 @@ static CK_RV make_maced_spki(STDLL_TokData_t *tokdata, SESSION * sess, OBJECT *pub_key_obj, CK_BYTE *spki, CK_ULONG spki_len, - CK_BYTE *maced_spki, CK_ULONG *maced_spki_len, - int curve_type) + CK_BYTE *maced_spki, CK_BYTE *maced_spki_reenc, + CK_ULONG *maced_spki_len, int curve_type) { unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; @@ -2953,12 +4010,15 @@ ep11_get_pin_blob(ep11_session, object_is_session_object(pub_key_obj), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(spki, spki_len, NULL, 0, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, &mech, p_attrs, attrs_len, maced_spki, maced_spki_len, csum, &cslen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, maced_spki, + maced_spki_reenc, *maced_spki_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3012,7 +4072,8 @@ */ static CK_RV import_aes_xts_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *aes_xts_key_obj, - CK_BYTE *blob, size_t *blob_size) + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size) { ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE cipher[MAX_BLOBSIZE]; @@ -3031,6 +4092,8 @@ unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t*) sess->private_data; + CK_BYTE *wrap_blob; + CK_BBOOL blob_new_mk = CK_FALSE, blob2_new_mk; rc = template_attribute_get_non_empty(aes_xts_key_obj->template, CKA_VALUE, &attr); @@ -3051,6 +4114,20 @@ goto import_aes_xts_key_end; } + rc = check_key_attributes(tokdata, CKK_AES, CKO_SECRET_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len, -1); + if (rc != CKR_OK) { + TRACE_ERROR("%s AES XTS check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto import_aes_xts_key_end; + } + + trace_attributes(__func__, "Import sym.:", new_p_attrs, new_attrs_len); + + ep11_get_pin_blob(ep11_session, object_is_session_object(aes_xts_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + +retry: memset(cipher, 0, sizeof(cipher)); memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); @@ -3058,12 +4135,14 @@ * calls the ep11 lib (which in turns sends the request to the card), * all m_ function are ep11 functions */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech, attr->pValue, attr->ulValueLen / 2, cipher, &clen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3075,28 +4154,20 @@ attr->ulValueLen / 2, clen, rc); } - rc = check_key_attributes(tokdata, CKK_AES, CKO_SECRET_KEY, p_attrs, - attrs_len, &new_p_attrs, &new_attrs_len, -1); - if (rc != CKR_OK) { - TRACE_ERROR("%s AES XTS check private key attributes failed with " - "rc=0x%lx\n", __func__, rc); - goto import_aes_xts_key_end; - } - - trace_attributes(__func__, "Import sym.:", new_p_attrs, new_attrs_len); - - ep11_get_pin_blob(ep11_session, object_is_session_object(aes_xts_key_obj), - &ep11_pin_blob, &ep11_pin_blob_len); - /* the encrypted key is decrypted and a blob is built, * card accepts only blobs as keys */ - RETRY_START(rc, tokdata) - rc = dll_m_UnwrapKey(cipher, clen, ep11_data->raw2key_wrap_blob, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_UnwrapKey(cipher, clen, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob, blob_size, csum, &cslen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, blob, blobreenc, + *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3106,19 +4177,24 @@ TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blob_size, rc); } + if (ep11_data->mk_change_active) + blob_new_mk = ep11tok_is_blob_new_wkid(tokdata, blob, *blob_size); + memset(cipher, 0, sizeof(cipher)); /* * calls the ep11 lib (which in turns sends the request to the card), * all m_ function are ep11 functions */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech, ((CK_BYTE *)attr->pValue) + attr->ulValueLen / 2, attr->ulValueLen / 2, cipher, &clen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3138,14 +4214,19 @@ /* the encrypted key is decrypted and a blob is built, * card accepts only blobs as keys */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, clen, - ep11_data->raw2key_wrap_blob, + wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech, new_p_attrs, new_attrs_len, blob + *blob_size, &blob_size2, csum, &cslen, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, blob + *blob_size, + blobreenc + *blob_size, blob_size2, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3155,6 +4236,36 @@ TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, blob_size2, rc); } + if (ep11_data->mk_change_active) { + blob2_new_mk = ep11tok_is_blob_new_wkid(tokdata, blob + *blob_size, + blob_size2); + if (blob_new_mk != blob2_new_mk) { + /* + * New MK has been set after importing key 1 but before + * importing key 2 + */ + if (blob2_new_mk == TRUE) { + /* + * Key 2 was created with new MK, key 1 with old MK. + * Key 2 already has blob and reenc_blob with new MK, + * Key 1 has blob with old MK, and blob_reenc with new MK. + * Supply blob_reenc with new MK in blob also. + */ + memcpy(blob, blobreenc, *blob_size); + } else { + /* + * Key 1 was created with new MK, but key 2 with old MK. + * This can happen when the single APQN with new MK went offline + * and a new single APQN with old MK is selected after creating + * key 1 but before creating key 2. Since there is no key1 blob + * with old MK, we need to re-create both keys (both with old + * MK now). + */ + goto retry; + } + } + } + /* update the concatenated blobsize */ *blob_size = *blob_size + blob_size2; @@ -3177,7 +4288,8 @@ */ static CK_RV import_RSA_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *rsa_key_obj, - CK_BYTE *blob, size_t *blob_size, + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -3196,6 +4308,7 @@ unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + CK_BYTE *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); @@ -3253,7 +4366,7 @@ * The card expects MACed-SPKIs as public keys. */ rc = make_maced_spki(tokdata, sess, rsa_key_obj, data, data_len, - blob, blob_size, -1); + blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); @@ -3266,6 +4379,12 @@ /* imported private RSA key goes here */ + rc = rsa_priv_check_and_swap_pq(rsa_key_obj->template); + if (rc != CKR_OK) { + TRACE_DEVEL("%s RSA check and swap failed\n", __func__); + goto import_RSA_key_end; + } + /* extract the secret data to be wrapped * since this is AES_CBC_PAD, padding is done in mechanism. */ @@ -3277,12 +4396,13 @@ } /* encrypt */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, &mech_w, - data, data_len, cipher, &cipher_l, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, cipher, &cipher_l, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); @@ -3310,13 +4430,18 @@ /* calls the card, it decrypts the private RSA key, * reads its BER format and builds a blob. */ - RETRY_START(rc, tokdata) - rc = dll_m_UnwrapKey(cipher, cipher_l, ep11_data->raw2key_wrap_blob, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_UnwrapKey(cipher, cipher_l, wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blobreenc, *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3354,7 +4479,8 @@ */ static CK_RV import_EC_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *ec_key_obj, - CK_BYTE *blob, size_t *blob_size, + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -3376,6 +4502,7 @@ CK_ULONG privkey_len, pubkey_len; CK_BYTE *pubkey = NULL; const struct _ec *curve = NULL; + CK_BYTE *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); @@ -3482,7 +4609,7 @@ * The card expects MACed-SPKIs as public keys. */ rc = make_maced_spki(tokdata, sess, ec_key_obj, data, data_len, - blob, blob_size, (int)curve->curve_type); + blob, blobreenc, blob_size, (int)curve->curve_type); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); @@ -3506,12 +4633,13 @@ } /* encrypt */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); @@ -3540,16 +4668,21 @@ /* calls the card, it decrypts the private EC key, * reads its BER format and builds a blob. */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, - ep11_data->raw2key_wrap_blob, + wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blobreenc, *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3584,7 +4717,8 @@ */ static CK_RV import_DSA_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *dsa_key_obj, - CK_BYTE *blob, size_t *blob_size, + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -3603,6 +4737,7 @@ unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + CK_BYTE *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); @@ -3676,7 +4811,7 @@ * The card expects MACed-SPKIs as public keys. */ rc = make_maced_spki(tokdata, sess, dsa_key_obj, data, data_len, - blob, blob_size, -1); + blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); @@ -3700,12 +4835,13 @@ } /* encrypt */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", @@ -3734,16 +4870,21 @@ /* calls the card, it decrypts the private EC key, * reads its BER format and builds a blob. */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, - ep11_data->raw2key_wrap_blob, + wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blobreenc, *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3776,7 +4917,8 @@ */ static CK_RV import_DH_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *dh_key_obj, - CK_BYTE *blob, size_t *blob_size, + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -3795,6 +4937,7 @@ unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + CK_BYTE *wrap_blob; memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); @@ -3860,7 +5003,7 @@ * The card expects MACed-SPKIs as public keys. */ rc = make_maced_spki(tokdata, sess, dh_key_obj, data, data_len, - blob, blob_size, -1); + blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); @@ -3896,12 +5039,13 @@ num_bits = value->ulValueLen * 8; /* encrypt */ - RETRY_START(rc, tokdata) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); @@ -3929,16 +5073,21 @@ /* calls the card, it decrypts the private EC key, * reads its BER format and builds a blob. */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, - ep11_data->raw2key_wrap_blob, + wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blobreenc, *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -3986,7 +5135,8 @@ */ static CK_RV import_IBM_pqc_key(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *pqc_key_obj, CK_KEY_TYPE keytype, - CK_BYTE *blob, size_t *blob_size, + CK_BYTE *blob, CK_BYTE *blobreenc, + size_t *blob_size, CK_BYTE *spki, size_t *spki_size) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -4010,6 +5160,7 @@ const struct pqc_oid *oid; const char *key_type_str; CK_MECHANISM_TYPE pqc_mech; + CK_BYTE *wrap_blob; switch (keytype) { case CKK_IBM_PQC_DILITHIUM: @@ -4117,7 +5268,7 @@ * The card expects MACed-SPKIs as public keys. */ rc = make_maced_spki(tokdata, sess, pqc_key_obj, data, data_len, - blob, blob_size, -1); + blob, blobreenc, blob_size, -1); if (rc != CKR_OK) { TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", __func__, rc); @@ -4177,17 +5328,18 @@ } /* encrypt */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) if (ep11_pqc_obj_strength_supported(target_info, pqc_mech, pqc_key_obj)) - rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, - ep11_data->raw2key_wrap_blob_l, + rc = dll_m_EncryptSingle(wrap_blob, ep11_data->raw2key_wrap_blob_l, &mech_w, data, data_len, cipher, &cipher_l, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, sess) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", __func__, rc, cipher_l); @@ -4216,16 +5368,21 @@ /* calls the card, it decrypts the private PQC key, * reads its BER format and builds a blob. */ - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_WRAPBLOB_START(tokdata, target_info, wrap_blob) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_UnwrapKey(cipher, cipher_l, - ep11_data->raw2key_wrap_blob, + wrap_blob, ep11_data->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, new_p_attrs, new_attrs_len, blob, blob_size, spki, spki_size, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, blobreenc, *blob_size, rc) + RETRY_REENC_WRAPBLOB_END(tokdata, target_info, wrap_blob, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -4268,9 +5425,11 @@ CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess, OBJECT * obj) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_KEY_TYPE keytype; CK_ATTRIBUTE *attr = NULL; CK_BYTE blob[MAX_BLOBSIZE]; + CK_BYTE blobreenc[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); CK_BYTE spki[MAX_BLOBSIZE]; size_t spkisize = sizeof(spki); @@ -4308,11 +5467,12 @@ return CKR_ATTRIBUTE_VALUE_INVALID; } memset(blob, 0, sizeof(blob)); + memset(blobreenc, 0, sizeof(blobreenc)); /* only these keys can be imported */ switch (keytype) { case CKK_RSA: - rc = import_RSA_key(tokdata, sess, obj, blob, &blobsize, + rc = import_RSA_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import RSA key rc=0x%lx blobsize=0x%zx\n", @@ -4323,7 +5483,7 @@ __func__, rc, blobsize); break; case CKK_EC: - rc = import_EC_key(tokdata, sess, obj, blob, &blobsize, + rc = import_EC_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import EC key rc=0x%lx blobsize=0x%zx\n", @@ -4334,7 +5494,7 @@ __func__, rc, blobsize); break; case CKK_DSA: - rc = import_DSA_key(tokdata, sess, obj, blob, &blobsize, + rc = import_DSA_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import DSA key rc=0x%lx blobsize=0x%zx\n", @@ -4345,7 +5505,7 @@ __func__, rc, blobsize); break; case CKK_DH: - rc = import_DH_key(tokdata, sess, obj, blob, &blobsize, + rc = import_DH_key(tokdata, sess, obj, blob, blobreenc, &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import DH key rc=0x%lx blobsize=0x%zx\n", @@ -4357,8 +5517,8 @@ break; case CKK_IBM_PQC_DILITHIUM: case CKK_IBM_PQC_KYBER: - rc = import_IBM_pqc_key(tokdata, sess, obj, keytype, blob, &blobsize, - spki, &spkisize); + rc = import_IBM_pqc_key(tokdata, sess, obj, keytype, blob, blobreenc, + &blobsize, spki, &spkisize); if (rc != CKR_OK) { TRACE_ERROR("%s import IBM PQC key kytype=0x%lx rc=0x%lx blobsize=0x%zx\n", __func__, keytype, rc, blobsize); @@ -4381,7 +5541,7 @@ * import that key (make a blob) */ rc = rawkey_2_blob(tokdata, sess, attr->pValue, attr->ulValueLen, - keytype, blob, &blobsize, obj); + keytype, blob, blobreenc, &blobsize, obj); if (rc != CKR_OK) { TRACE_ERROR("%s rawkey_2_blob rc=0x%lx " "blobsize=0x%zx\n", __func__, rc, blobsize); @@ -4395,7 +5555,7 @@ __func__, rc, blobsize); break; case CKK_AES_XTS: - rc = import_aes_xts_key(tokdata, sess, obj, blob, &blobsize); + rc = import_aes_xts_key(tokdata, sess, obj, blob, blobreenc, &blobsize); if (rc != CKR_OK) { TRACE_ERROR("%s import AES XTS key rc=0x%lx blobsize=0x%zx\n", __func__, rc, blobsize); @@ -4412,13 +5572,13 @@ case CKO_PRIVATE_KEY: case CKO_SECRET_KEY: if (check_expected_mkvp(tokdata, blob, keytype == CKK_AES_XTS ? - blobsize / 2 : blobsize) != CKR_OK) { + blobsize / 2 : blobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } if (keytype == CKK_AES_XTS) { if (check_expected_mkvp(tokdata, blob + blobsize / 2, - blobsize / 2) != CKR_OK) { + blobsize / 2, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); return CKR_DEVICE_ERROR; } @@ -4443,6 +5603,23 @@ return rc; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, blobreenc, blobsize, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + return rc; + } + + rc = template_update_attribute(obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + return rc; + } + } + if (spkisize > 0 && (class == CKO_PRIVATE_KEY || class == CKO_PUBLIC_KEY)) { /* spki may be a MACed SPKI, get length of SPKI part only */ rc = ber_decode_SEQUENCE(spki, &temp, &temp_len, &spkisize); @@ -4468,7 +5645,7 @@ } } - rc = update_ep11_attrs_from_blob(tokdata, sess, obj->template, + rc = update_ep11_attrs_from_blob(tokdata, sess, obj, (keytype == CKK_AES_XTS)); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", @@ -4483,7 +5660,9 @@ CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_BYTE blob[MAX_BLOBSIZE], blob2[MAX_BLOBSIZE]; + CK_BYTE reenc_blob[MAX_BLOBSIZE], reenc_blob2[MAX_BLOBSIZE]; size_t blobsize = sizeof(blob); size_t blobsize2 = sizeof(blob2); CK_BYTE csum[MAX_CSUMSIZE]; @@ -4501,8 +5680,10 @@ CK_ULONG ep11_pin_blob_len = 0; ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; CK_MECHANISM mech2 = {CKM_AES_KEY_GEN, NULL, 0}; + CK_BBOOL blob_new_mk = FALSE, blob2_new_mk = FALSE; memset(blob, 0, sizeof(blob)); + memset(reenc_blob, 0, sizeof(reenc_blob)); memset(csum, 0, sizeof(csum)); memset(blob2, 0, sizeof(blob2)); @@ -4552,11 +5733,15 @@ ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) - rc = dll_m_GenerateKey((xts ? &mech2 : mech), new_attrs2, new_attrs2_len, +retry: + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_GenerateKey(xts ? &mech2 : mech, new_attrs2, new_attrs2_len, ep11_pin_blob, ep11_pin_blob_len, blob, &blobsize, csum, &csum_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob, reenc_blob, blobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", @@ -4568,19 +5753,22 @@ TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); - if (check_expected_mkvp(tokdata, blob, blobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, blob, blobsize, &blob_new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } if (xts) { - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY_START() rc = dll_m_GenerateKey(&mech2, new_attrs2, new_attrs2_len, ep11_pin_blob, ep11_pin_blob_len, blob2, &blobsize2, csum, &csum_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + blob2, reenc_blob2, blobsize2, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", @@ -4592,12 +5780,39 @@ TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", __func__, rc, ep11_get_ckm(tokdata, mech->mechanism), attrs_len); - if (check_expected_mkvp(tokdata, blob2, blobsize2) != CKR_OK) { + if (check_expected_mkvp(tokdata, blob2, blobsize2, + &blob2_new_mk) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; } + if (ep11_data->mk_change_active && blob_new_mk != blob2_new_mk) { + /* + * New MK has been set after generating key 1 but before + * generating key 2 + */ + if (blob2_new_mk == TRUE) { + /* + * Key 2 was created with new MK, key 1 with old MK. + * Key 2 already has blob and reenc_blob with new MK, + * Key 1 has blob with old MK, and blob_reenc with new MK. + * Supply blob_reenc with new MK in blob also. + */ + memcpy(blob, reenc_blob, blobsize); + } else { + /* + * Key 1 was created with new MK, but key 2 with old MK. + * This can happen when the single APQN with new MK went offline + * and a new single APQN with old MK is selected after creating + * key 1 but before creating key 2. Since there is no key1 blob + * with old MK, we need to re-create both keys (both with old + * MK now). + */ + goto retry; + } + } + if (blobsize + blobsize2 > MAX_BLOBSIZE) { TRACE_ERROR("%s\n", ock_err(CKR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; @@ -4605,6 +5820,8 @@ } memcpy(blob + blobsize, blob2, blobsize2); + if (ep11_data->mk_change_active) + memcpy(reenc_blob + blobsize, reenc_blob2, blobsize2); blobsize = blobsize + blobsize2; } @@ -4622,7 +5839,24 @@ } attr = NULL; - rc = update_ep11_attrs_from_blob(tokdata, session, key_obj->template, xts); + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, reenc_blob, blobsize, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + + rc = template_update_attribute(key_obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + attr = NULL; + } + + rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, xts); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); @@ -5020,8 +6254,10 @@ { ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; - size_t state_len = MAX(MAX_DIGEST_STATE_BYTES, sizeof(libica_sha_context_t)); - CK_BYTE *state; + size_t state_len = MAX(MAX_DIGEST_STATE_BYTES * 2, + sizeof(libica_sha_context_t)); + size_t usestate_len = 0; + CK_BYTE *state, *usestate; libica_sha_context_t *libica_ctx; ep11_target_info_t* target_info; @@ -5043,7 +6279,34 @@ libica_ctx->first = CK_TRUE; rc = get_sha_block_size(mech->mechanism, &libica_ctx->block_size); } else { - rc = dll_m_DigestInit(state, &state_len, mech, target_info->target); + /* + * state is allocated large enough to hold 2 times the max state blob. + * Initially use the first half only. The second half is for the + * re-enciphered state blob (if mk change is active). + */ + state_len /= 2; + + RETRY_SINGLE_APQN_START(tokdata, rc) + RETRY_UPDATE_BLOB_START(tokdata, target_info, state, state_len, + state + state_len, state_len, + usestate, usestate_len) + rc = dll_m_DigestInit(usestate, &usestate_len, mech, + target_info->target); + if (rc == CKR_OK && retry == 1) { + /* + * Initially, the real state_len is unknown, and is set to + * allocated state size / 2. When the state was created on + * an APQN with new WK set already, move the state to the + * final place, which is state + usestate_len, where + * usestate_len now is the real state size. + */ + memmove(state + usestate_len, state + state_len, usestate_len); + } + state_len = usestate_len; + RETRY_UPDATE_BLOB_END(tokdata, target_info, state, state_len, + state + state_len, state_len, + usestate, usestate_len, rc) + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } put_target_info(tokdata, target_info); @@ -5061,7 +6324,7 @@ c->mech.mechanism = mech->mechanism; c->mech.pParameter = NULL; c->context = state; - c->context_len = state_len; + c->context_len = state_len * 2; /* current and re-enciphered state */ TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } @@ -5078,6 +6341,8 @@ ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; ep11_target_info_t* target_info; + CK_BYTE *state; + size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) @@ -5090,8 +6355,19 @@ out_data, out_data_len, SHA_MSG_PART_ONLY); } else { - rc = dll_m_Digest(c->context, c->context_len, in_data, in_data_len, - out_data, out_data_len, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len) + rc = dll_m_Digest(state, state_len, + in_data, in_data_len, + out_data, out_data_len, target_info->target); + RETRY_UPDATE_BLOB_END(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len, rc) + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } if (rc != CKR_OK) { @@ -5116,6 +6392,8 @@ CK_ULONG len; CK_RV rc = CKR_OK; ep11_target_info_t* target_info; + CK_BYTE *state; + size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) @@ -5169,8 +6447,18 @@ } } } else { - rc = dll_m_DigestUpdate(c->context, c->context_len, - in_data, in_data_len, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len) + rc = dll_m_DigestUpdate(state, state_len, + in_data, in_data_len, target_info->target); + RETRY_UPDATE_BLOB_END(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len, rc) + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } out: @@ -5193,6 +6481,8 @@ libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context; CK_RV rc; ep11_target_info_t* target_info; + CK_BYTE *state; + size_t state_len; target_info = get_target_info(tokdata); if (target_info == NULL) @@ -5207,8 +6497,18 @@ SHA_MSG_PART_ONLY : SHA_MSG_PART_FINAL); } else { - rc = dll_m_DigestFinal(c->context, c->context_len, - out_data, out_data_len, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len) + rc = dll_m_DigestFinal(state, state_len, + out_data, out_data_len, target_info->target); + RETRY_UPDATE_BLOB_END(tokdata, target_info, + c->context, c->context_len / 2, + c->context + (c->context_len / 2), + c->context_len / 2, state, state_len, rc) + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) } if (rc != CKR_OK) { @@ -5231,6 +6531,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblobsize; rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); if (rc != CKR_OK) { @@ -5242,10 +6544,14 @@ mech.pParameter = NULL; mech.ulParameterLen = 0; - RETRY_START(rc, tokdata) - rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, - out_data, out_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) + rc = dll_m_SignSingle(useblob, useblobsize, &mech, + in_data, in_data_len, + out_data, out_data_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5265,6 +6571,8 @@ CK_BYTE *spki; size_t spki_len = 0; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblob_len; rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len); if (rc != CKR_OK) { @@ -5276,10 +6584,14 @@ mech.pParameter = NULL; mech.ulParameterLen = 0; - RETRY_START(rc, tokdata) - rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, - signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, + useblob, useblob_len, rc) + rc = dll_m_VerifySingle(useblob, useblob_len, &mech, + in_data, in_data_len, + signature, sig_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5300,6 +6612,8 @@ CK_BYTE *keyblob; OBJECT *key_obj; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblobsize; rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -5312,10 +6626,13 @@ mech.ulParameterLen = ctx->mech.ulParameterLen; mech.pParameter = ctx->mech.pParameter; - RETRY_START(rc, tokdata) - rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, - sig, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) + rc = dll_m_SignSingle(useblob, useblobsize, &mech, in_data, in_data_len, + sig, sig_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5339,6 +6656,8 @@ size_t spki_len = 0; OBJECT *key_obj; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblob_len; rc = h_opaque_2_blob(tokdata, ctx->key, &spki, &spki_len, &key_obj, READ_LOCK); @@ -5351,10 +6670,14 @@ mech.ulParameterLen = ctx->mech.ulParameterLen; mech.pParameter = ctx->mech.pParameter; - RETRY_START(rc, tokdata) - rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, - signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, + useblob, useblob_len, rc) + rc = dll_m_VerifySingle(useblob, useblob_len, &mech, + in_data, in_data_len, + signature, sig_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5378,6 +6701,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblobsize; rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); if (rc != CKR_OK) { @@ -5401,10 +6726,13 @@ mech.pParameter = NULL; mech.ulParameterLen = 0; - RETRY_START(rc, tokdata) - rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, - out_data, out_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) + rc = dll_m_SignSingle(useblob, useblobsize, &mech, in_data, in_data_len, + out_data, out_data_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5427,6 +6755,8 @@ CK_BYTE *spki; size_t spki_len = 0; CK_MECHANISM mech; + CK_BYTE *useblob; + size_t useblob_len; rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len); if (rc != CKR_OK) { @@ -5450,10 +6780,14 @@ mech.pParameter = NULL; mech.ulParameterLen = 0; - RETRY_START(rc, tokdata) - rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, - out_data, out_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, + useblob, useblob_len, rc) + rc = dll_m_VerifySingle(useblob, useblob_len, &mech, + in_data, in_data_len, + out_data, out_data_len, target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5481,6 +6815,8 @@ CK_BYTE *decr_key, *encr_key; size_t decr_key_len = 0, encr_key_len = 0; int status; + CK_BYTE *decr_useblob, *encr_useblob; + size_t decr_useblob_len, encr_useblob_len; UNUSED(decr_ctx); UNUSED(encr_ctx); @@ -5505,11 +6841,20 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_ReencryptSingle(decr_key, decr_key_len, encr_key, encr_key_len, - decr_mech, encr_mech, in_data, in_data_len, - out_data, out_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB2_START(tokdata, target_info, + decr_key_obj, decr_key, decr_key_len, + decr_useblob, decr_useblob_len, + encr_key_obj, encr_key, encr_key_len, + encr_useblob, encr_useblob_len, rc) + rc = dll_m_ReencryptSingle(decr_useblob, decr_useblob_len, + encr_useblob, encr_useblob_len, + decr_mech, encr_mech, in_data, in_data_len, + out_data, out_data_len, target_info->target); + RETRY_REENC_BLOB2_END(tokdata, target_info, + decr_useblob, decr_useblob_len, + encr_useblob, encr_useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -5526,11 +6871,13 @@ * fallback here. */ CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj, CK_BYTE encrypt) { UNUSED(tokdata); + UNUSED(sess); return pkey_aes_ecb(key_obj, in_data, in_data_len, out_data, out_data_len, encrypt); @@ -5542,12 +6889,14 @@ * fallback here. */ CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj, CK_BYTE *init_v, CK_BYTE encrypt) { UNUSED(tokdata); + UNUSED(sess); return pkey_aes_cbc(key_obj, init_v, in_data, in_data_len, out_data, out_data_len, encrypt); @@ -5777,6 +7126,8 @@ CK_ATTRIBUTE *spki_attr = NULL; CK_BBOOL allocated = FALSE; CK_RV rc = CKR_OK; + CK_BYTE *useblob; + size_t useblob_len; if (mech->ulParameterLen != sizeof(CK_IBM_BTC_DERIVE_PARAMS) || mech->pParameter == NULL) { @@ -5816,10 +7167,13 @@ break; case CKO_PRIVATE_KEY: - RETRY_START(rc, tokdata) - rc = dll_m_GetAttributeValue(blob, bloblen, get_attr, 1, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, blob, bloblen, + useblob, useblob_len, rc) + rc = dll_m_GetAttributeValue(useblob, useblob_len, get_attr, 1, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) /* Only newer EP11 libs support this, ignore if error */ if (rc != CKR_OK) @@ -5857,15 +7211,220 @@ return rc; } +static CK_RV ep11tok_sha_key_derive_mech_pre_process(STDLL_TokData_t *tokdata, + OBJECT *base_key_obj, + OBJECT *derived_key_obj, + CK_MECHANISM *mech, + CK_ULONG keytype) +{ + CK_RV rc; + CK_ULONG hsize, value_len = 0; + CK_ATTRIBUTE *attr; + CK_BBOOL battr; + + UNUSED(tokdata); + + /* + * As per PKCS#11 standard: + * - If no length or key type is provided in the template, then the key + * produced by this mechanism will be a generic secret key. Its length + * will be the output size of the used digest. + * - If no key type is provided in the template, but a length is, then the + * key produced by this mechanism will be a generic secret key of the + * specified length. + * - If no length was provided in the template, but a key type is, then + * that key type must have a well-defined length. If it does, then the + * key produced by this mechanism will be of the type specified in the + * template. If it doesn’t, an error will be returned. + * - If both a key type and a length are provided in the template, the + * length must be compatible with that key type. The key produced by + * this mechanism will be of the specified type and length. + */ + switch (mech->mechanism) { + case CKM_SHA1_KEY_DERIVATION: + hsize = SHA1_HASH_SIZE; + break; + case CKM_SHA224_KEY_DERIVATION: + hsize = SHA224_HASH_SIZE; + break; + case CKM_SHA256_KEY_DERIVATION: + hsize = SHA256_HASH_SIZE; + break; + case CKM_SHA384_KEY_DERIVATION: + hsize = SHA384_HASH_SIZE; + break; + case CKM_SHA512_KEY_DERIVATION: + hsize = SHA512_HASH_SIZE; + break; + default: + TRACE_ERROR("%s invalid mechanism 0x%lx\n", __func__, + mech->mechanism); + return CKR_MECHANISM_INVALID; + } + + rc = template_attribute_get_ulong(derived_key_obj->template, CKA_VALUE_LEN, + &value_len); + if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { + TRACE_ERROR("%s error getting CKA_VALUE_LEN rc=0x%lx\n", __func__, rc); + return rc; + } + + if (value_len == 0) { + value_len = hsize; + } else if (value_len > hsize) { + TRACE_ERROR("%s CKA_VALUE_LEN is too large\n", __func__); + return CKR_TEMPLATE_INCONSISTENT; + } + + switch (keytype) { + case CKK_GENERIC_SECRET: + break; + case CKK_DES: + case CKK_DES2: + case CKK_DES3: + value_len = 0; + break; + case CKK_AES: + switch (value_len) { + case 16: + case 24: + case 32: + break; + default: + TRACE_ERROR("%s CKA_VALUE_LEN improper for AES\n", __func__); + return CKR_TEMPLATE_INCONSISTENT; + } + break; + case CKK_AES_XTS: + switch (value_len) { + case 32: + case 64: + break; + default: + TRACE_ERROR("%s CKA_VALUE_LEN improper for AES-XTS\n", __func__); + return CKR_TEMPLATE_INCONSISTENT; + } + break; + default: + TRACE_ERROR("%s invalid key type 0x%lx\n", __func__, keytype); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (value_len > 0) { + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&value_len, + sizeof(value_len), &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + + rc = template_update_attribute(derived_key_obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + return rc; + } + } + + /* + * As per PKCS#11 standard: + * - If the base key has its CKA_ALWAYS_SENSITIVE attribute set to CK_FALSE, + * then the derived key will as well. If the base key has its + * CKA_ALWAYS_SENSITIVE attribute set to CK_TRUE, then the derived key + * has its CKA_ALWAYS_SENSITIVE attribute set to the same value as its + * CKA_SENSITIVE attribute. + * - Similarly, if the base key has its CKA_NEVER_EXTRACTABLE attribute + * set to CK_FALSE, then the derived key will, too. If the base key has + * its CKA_NEVER_EXTRACTABLE attribute set to CK_TRUE, then the derived + * key has its CKA_NEVER_EXTRACTABLE attribute set to the opposite value + * from its CKA_EXTRACTABLE attribute. + */ + rc = template_attribute_get_bool(base_key_obj->template, + CKA_ALWAYS_SENSITIVE, &battr); + if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { + TRACE_ERROR("%s error getting CKA_ALWAYS_SENSITIVE rc=0x%lx\n", + __func__, rc); + return rc; + } + + if (battr == CK_TRUE) { + rc = template_attribute_get_bool(derived_key_obj->template, + CKA_SENSITIVE, &battr); + if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { + TRACE_ERROR("%s error getting CKA_SENSITIVE rc=0x%lx\n", + __func__, rc); + return rc; + } + } + + rc = build_attribute(CKA_ALWAYS_SENSITIVE, (CK_BYTE *)&battr, + sizeof(battr), &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + + rc = template_update_attribute(derived_key_obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + return rc; + } + + rc = template_attribute_get_bool(base_key_obj->template, + CKA_NEVER_EXTRACTABLE, &battr); + if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { + TRACE_ERROR("%s error getting CKA_NEVER_EXTRACTABLE rc=0x%lx\n", + __func__, rc); + return rc; + } + + if (battr == CK_TRUE) { + rc = template_attribute_get_bool(derived_key_obj->template, + CKA_EXTRACTABLE, &battr); + if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { + TRACE_ERROR("%s error getting CKA_EXTRACTABLE rc=0x%lx\n", + __func__, rc); + return rc; + } + + battr = !battr; + } + + rc = build_attribute(CKA_NEVER_EXTRACTABLE, (CK_BYTE *)&battr, + sizeof(battr), &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + + rc = template_update_attribute(derived_key_obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + return rc; + } + + return CKR_OK; +} + CK_RV ep11tok_derive_key(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE hBaseKey, CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE *keyblob; size_t keyblobsize; CK_BYTE newblob[MAX_BLOBSIZE]; + CK_BYTE newblobreenc[MAX_BLOBSIZE]; size_t newblobsize = sizeof(newblob); CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum); @@ -5895,8 +7454,11 @@ struct EP11_KYBER_MECH mech_ep11; OBJECT *kyber_secret_obj = NULL; CK_KEY_TYPE keytype; + CK_BYTE *useblob; + size_t useblobsize; memset(newblob, 0, sizeof(newblob)); + memset(newblobreenc, 0, sizeof(newblobreenc)); if (mech->mechanism == CKM_ECDH1_DERIVE || mech->mechanism == CKM_IBM_EC_X25519 || @@ -6140,6 +7702,21 @@ goto error; } + switch (mech->mechanism) { + case CKM_SHA1_KEY_DERIVATION: + case CKM_SHA224_KEY_DERIVATION: + case CKM_SHA256_KEY_DERIVATION: + case CKM_SHA384_KEY_DERIVATION: + case CKM_SHA512_KEY_DERIVATION: + rc = ep11tok_sha_key_derive_mech_pre_process(tokdata, base_key_obj, + key_obj, mech, ktype); + if (rc != CKR_OK) + goto error; + break; + default: + break; + } + curve_type = get_curve_type_from_template(key_obj->template); rc = build_ep11_attrs(tokdata, key_obj->template, &new_attrs2, &new_attrs2_len, @@ -6174,17 +7751,23 @@ ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, base_key_obj, keyblob, + keyblobsize, useblob, useblobsize, rc) + RETRY_REENC_CREATE_KEY_START() if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, base_key_obj)) rc = dll_m_DeriveKey(mech, new_attrs2, new_attrs2_len, - keyblob, keyblobsize, NULL, 0, + useblob, useblobsize, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, newblob, &newblobsize, csum, &cslen, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + newblob, newblobreenc, newblobsize, rc) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -6196,7 +7779,7 @@ __func__, hBaseKey, rc, *handle, newblobsize); if (class == CKO_SECRET_KEY || class == CKO_PRIVATE_KEY) { - if (check_expected_mkvp(tokdata, newblob, newblobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, newblob, newblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; @@ -6218,7 +7801,7 @@ opaque_attr = NULL; if (class == CKO_SECRET_KEY || class == CKO_PRIVATE_KEY) { - rc = update_ep11_attrs_from_blob(tokdata, session, key_obj->template, FALSE); + rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); @@ -6245,6 +7828,24 @@ break; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, newblobreenc, newblobsize, + &opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + + rc = template_update_attribute(key_obj->template, opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + opaque_attr = NULL; + } + if (class == CKO_SECRET_KEY && cslen >= EP11_CSUMSIZE) { /* First 3 bytes of csum is the check value */ rc = build_attribute(CKA_CHECK_VALUE, csum, EP11_CSUMSIZE, &chk_attr); @@ -6310,10 +7911,13 @@ CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE publblob[MAX_BLOBSIZE]; + CK_BYTE publblobreenc[MAX_BLOBSIZE]; size_t publblobsize = sizeof(publblob); CK_BYTE privblob[MAX_BLOBSIZE]; + CK_BYTE privblobreenc[MAX_BLOBSIZE]; size_t privblobsize = sizeof(privblob); CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *base_attr = NULL; @@ -6345,7 +7949,9 @@ memset(&dh_pgs, 0, sizeof(dh_pgs)); memset(publblob, 0, sizeof(publblob)); + memset(publblobreenc, 0, sizeof(publblobreenc)); memset(privblob, 0, sizeof(privblob)); + memset(privblobreenc, 0, sizeof(privblobreenc)); rc = build_ep11_attrs(tokdata, publ_tmpl, &dh_pPublicKeyTemplate, &dh_ulPublicKeyAttributeCount, @@ -6474,14 +8080,18 @@ new_priv_attrs_len)), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(pMechanism, new_publ_attrs, new_publ_attrs_len, new_priv_attrs, new_priv_attrs_len, ep11_pin_blob, ep11_pin_blob_len, privblob, &privblobsize, publblob, &publblobsize, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, + privblob, privblobreenc, privblobsize, + publblob, publblobreenc, publblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -6492,7 +8102,7 @@ TRACE_INFO("%s rc=0x%lx plen=%zd publblobsize=0x%zx privblobsize=0x%zx\n", __func__, rc, prime_attr->ulValueLen, publblobsize, privblobsize); - if (check_expected_mkvp(tokdata, privblob, privblobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, privblob, privblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dh_generate_keypair_end; @@ -6513,6 +8123,24 @@ goto dh_generate_keypair_end; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, publblobreenc, publblobsize, + &opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto dh_generate_keypair_end; + } + + rc = template_update_attribute(publ_tmpl, opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(opaque_attr); + goto dh_generate_keypair_end; + } + } + rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); @@ -6526,6 +8154,25 @@ free(opaque_attr); goto dh_generate_keypair_end; } + + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, privblobreenc, privblobsize, + &opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto dh_generate_keypair_end; + } + + rc = template_update_attribute(priv_tmpl, opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(opaque_attr); + goto dh_generate_keypair_end; + } + } + #ifdef DEBUG TRACE_DEBUG("%s DH SPKI\n", __func__); TRACE_DEBUG_DUMP(" ", publblob, publblobsize); @@ -6621,10 +8268,13 @@ CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_BYTE publblob[MAX_BLOBSIZE]; + CK_BYTE publblobreenc[MAX_BLOBSIZE]; size_t publblobsize = sizeof(publblob); CK_BYTE privblob[MAX_BLOBSIZE]; + CK_BYTE privblobreenc[MAX_BLOBSIZE]; size_t privblobsize = sizeof(privblob); CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *sub_prime_attr = NULL; @@ -6653,7 +8303,9 @@ memset(&dsa_pqgs, 0, sizeof(dsa_pqgs)); memset(publblob, 0, sizeof(publblob)); + memset(publblobreenc, 0, sizeof(publblobreenc)); memset(privblob, 0, sizeof(privblob)); + memset(privblobreenc, 0, sizeof(privblobreenc)); rc = build_ep11_attrs(tokdata, publ_tmpl, &dsa_pPublicKeyTemplate, &dsa_ulPublicKeyAttributeCount, @@ -6812,14 +8464,18 @@ new_priv_attrs_len)), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(pMechanism, new_publ_attrs, new_publ_attrs_len, new_priv_attrs, new_priv_attrs_len, ep11_pin_blob, ep11_pin_blob_len, privblob, &privblobsize, publblob, &publblobsize, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, + privblob, privblobreenc, privblobsize, + publblob, publblobreenc, publblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); @@ -6831,7 +8487,7 @@ TRACE_INFO("%s rc=0x%lx plen=%zd publblobsize=0x%zx privblobsize=0x%zx\n", __func__, rc, prime_attr->ulValueLen, publblobsize, privblobsize); - if (check_expected_mkvp(tokdata, privblob, privblobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, privblob, privblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto dsa_generate_keypair_end; @@ -6851,6 +8507,24 @@ goto dsa_generate_keypair_end; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, publblobreenc, publblobsize, + &opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto dsa_generate_keypair_end; + } + + rc = template_update_attribute(publ_tmpl, opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(opaque_attr); + goto dsa_generate_keypair_end; + } + } + rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); @@ -6865,6 +8539,24 @@ goto dsa_generate_keypair_end; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, privblobreenc, privblobsize, + &opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto dsa_generate_keypair_end; + } + + rc = template_update_attribute(priv_tmpl, opaque_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(opaque_attr); + goto dsa_generate_keypair_end; + } + } + /* set CKA_VALUE of the public key, first get key from SPKI */ rc = ber_decode_SPKI(publblob, &oid, &oid_len, &parm, &parm_len, &key, &bit_str_len); @@ -6920,12 +8612,15 @@ CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_ATTRIBUTE *n_attr = NULL; CK_BYTE privkey_blob[MAX_BLOBSIZE]; + CK_BYTE privkey_blobreenc[MAX_BLOBSIZE]; size_t privkey_blob_len = sizeof(privkey_blob); unsigned char spki[MAX_BLOBSIZE]; + unsigned char spkireenc[MAX_BLOBSIZE]; size_t spki_len = sizeof(spki); CK_ULONG bit_str_len; CK_BYTE *key; @@ -7010,14 +8705,18 @@ new_priv_attrs2_len)), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY2_START() rc = dll_m_GenerateKeyPair(pMechanism, new_publ_attrs2, new_publ_attrs2_len, new_priv_attrs2, new_priv_attrs2_len, ep11_pin_blob, ep11_pin_blob_len, privkey_blob, &privkey_blob_len, spki, &spki_len, target_info->target); - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, privkey_blob, + privkey_blobreenc, privkey_blob_len, + spki, spkireenc, spki_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " @@ -7031,7 +8730,8 @@ __func__, rc, spki_len, privkey_blob_len, ep11_get_ckm(tokdata, pMechanism->mechanism)); - if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len) != CKR_OK) { + if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len, + NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; @@ -7056,6 +8756,22 @@ goto error; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, spkireenc, spki_len, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + rc = template_update_attribute(publ_tmpl, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + goto error; + } + } + rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); @@ -7069,6 +8785,22 @@ goto error; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, privkey_blobreenc, + privkey_blob_len, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); + goto error; + } + rc = template_update_attribute(priv_tmpl, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + goto error; + } + } + if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) { /* scan the SPKI for CKA_EC_POINT */ @@ -7263,11 +8995,14 @@ CK_MECHANISM_PTR pMechanism, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_BYTE privkey_blob[MAX_BLOBSIZE]; + CK_BYTE privkey_blobreenc[MAX_BLOBSIZE]; size_t privkey_blob_len = sizeof(privkey_blob); unsigned char spki[MAX_BLOBSIZE]; + unsigned char spkireenc[MAX_BLOBSIZE]; size_t spki_len = sizeof(spki); CK_ULONG ktype; unsigned char *ep11_pin_blob = NULL; @@ -7387,7 +9122,8 @@ new_priv_attrs2_len)), &ep11_pin_blob, &ep11_pin_blob_len); - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_CREATE_KEY2_START() if (ep11_pqc_strength_supported(target_info, pMechanism->mechanism, pqc_oid)) rc = dll_m_GenerateKeyPair(pMechanism, @@ -7398,7 +9134,10 @@ &spki_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, sess) + RETRY_REENC_CREATE_KEY2_END(tokdata, target_info, privkey_blob, + privkey_blobreenc, privkey_blob_len, + spki, spkireenc, spki_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, sess) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, sess); TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " @@ -7412,7 +9151,8 @@ __func__, rc, spki_len, privkey_blob_len, ep11_get_ckm(tokdata, pMechanism->mechanism)); - if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len) != CKR_OK) { + if (check_expected_mkvp(tokdata, privkey_blob, privkey_blob_len, + NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; @@ -7437,6 +9177,22 @@ goto error; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, spkireenc, spki_len, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + rc = template_update_attribute(publ_tmpl, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + goto error; + } + } + rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr); if (rc != CKR_OK) { TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc); @@ -7450,6 +9206,24 @@ goto error; } + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, privkey_blobreenc, + privkey_blob_len, &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + rc = template_update_attribute(priv_tmpl, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + free(attr); + goto error; + } + } + + /* Decode SPKI */ rc = ibm_pqc_priv_unwrap_get_data(publ_tmpl, ktype, spki, spki_len, TRUE); if (rc != CKR_OK) { @@ -7581,7 +9355,7 @@ (void *)public_key_obj, (void *)private_key_obj); } - rc = update_ep11_attrs_from_blob(tokdata, sess, private_key_obj->template, FALSE); + rc = update_ep11_attrs_from_blob(tokdata, sess, private_key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); @@ -7768,6 +9542,32 @@ } } +/* Returns a re-enciphered blob for a key object. + * The passed key_obj must hold the READ lock! + */ +static CK_RV obj_opaque_2_reenc_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, + CK_BYTE **blob, size_t *blobsize) +{ + CK_ATTRIBUTE *attr = NULL; + CK_RV rc; + + UNUSED(tokdata); + + /* blob already exists */ + rc = template_attribute_get_non_empty(key_obj->template, + CKA_IBM_OPAQUE_REENC, + &attr); + if (rc == CKR_OK) { + *blob = attr->pValue; + *blobsize = (size_t) attr->ulValueLen; + TRACE_INFO("%s reenc blob found blobsize=0x%zx\n", __func__, *blobsize); + return CKR_OK; + } else { + TRACE_INFO("%s no reenc blob\n", __func__); + return rc; + } +} + /* Returns a blob for a key handle. * The blob is created if none was build yet. * The caller must put the returned kobj when no longer needed. @@ -8002,6 +9802,8 @@ goto error; } + INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); + error: object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8055,6 +9857,15 @@ switch (mech->mechanism) { case CKM_IBM_ECDSA_OTHER: case CKM_IBM_KYBER: + case CKM_RSA_PKCS: + case CKM_RSA_PKCS_OAEP: + case CKM_RSA_PKCS_PSS: + case CKM_RSA_X9_31: + case CKM_ECDSA: + case CKM_DSA: + case CKM_IBM_ED25519_SHA512: + case CKM_IBM_ED448_SHA3: + case CKM_IBM_DILITHIUM: return CK_TRUE; default: return CK_FALSE; @@ -8070,9 +9881,12 @@ CK_BYTE *keyblob; OBJECT *key_obj = NULL; SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; - size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES; - CK_BYTE *ep11_sign_state = malloc(ep11_sign_state_l); + size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES * 2; + CK_BYTE *ep11_sign_state = calloc(ep11_sign_state_l, 1); struct ECDSA_OTHER_MECH_PARAM mech_ep11; + CK_BYTE *useblob, *usestate; + size_t useblobsize, usestate_len; + CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; UNUSED(recover_mode); @@ -8108,6 +9922,7 @@ rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: + strength_index = key_obj->strength.strength; /* * Release obj lock, sign_mgr_init or ep11tok_sign_verify_init_ibm_ed * may re-acquire the lock @@ -8151,15 +9966,45 @@ mech = &mech_ep11.mech; } - RETRY_START(rc, tokdata) + /* + * state is allocated large enough to hold 2 times the max state blob. + * Initially use the first half only. The second half is for the + * re-enciphered state blob (if mk change is active). + */ + ep11_sign_state_l /= 2; + + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, keyblob, + keyblobsize, useblob, useblobsize, + ep11_sign_state, + ep11_sign_state + ep11_sign_state_l, + ep11_sign_state_l, + usestate, usestate_len, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_SignInit(ep11_sign_state, &ep11_sign_state_l, - mech, keyblob, keyblobsize, + rc = dll_m_SignInit(usestate, &usestate_len, + mech, useblob, useblobsize, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + if (rc == CKR_OK && retry == 1) { + /* + * Initially, the real state_len is unknown, and is set to + * allocated state size / 2. When the state was created on + * an APQN with new WK set already, move the state to the + * final place, which is state + usestate_len, where + * usestate_len now is the real state size. + */ + memmove(ep11_sign_state + usestate_len, + ep11_sign_state + ep11_sign_state_l, usestate_len); + } + ep11_sign_state_l = usestate_len; + RETRY_REENC_BLOB_STATE_END(tokdata, target_info, keyblob, keyblobsize, + useblob, useblobsize, ep11_sign_state, + ep11_sign_state + ep11_sign_state_l, + ep11_sign_state_l, usestate, usestate_len, + TRUE, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8173,7 +10018,7 @@ ctx->key = key; ctx->active = TRUE; ctx->context = ep11_sign_state; - ctx->context_len = ep11_sign_state_l; + ctx->context_len = ep11_sign_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; @@ -8197,7 +10042,7 @@ done: if (rc == CKR_OK) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); + INC_COUNTER(tokdata, session, mech, key_obj, strength_index); object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8216,6 +10061,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -8242,10 +10089,19 @@ goto done; /* no ep11 fallback possible */ } - RETRY_START(rc, tokdata) - rc = dll_m_Sign(ctx->context, ctx->context_len, in_data, in_data_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_Sign(state, state_len, + in_data, in_data_len, signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8271,6 +10127,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (!in_data || !in_data_len) return CKR_OK; @@ -8287,10 +10145,18 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_SignUpdate(ctx->context, ctx->context_len, in_data, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_SignUpdate(state, state_len, in_data, in_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8317,6 +10183,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = sign_mgr_sign_final(tokdata, session, length_only, ctx, signature, sig_len); @@ -8330,10 +10198,18 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_SignFinal(ctx->context, ctx->context_len, signature, sig_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_SignFinal(state, state_len, signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8361,6 +10237,10 @@ CK_BYTE *keyblob; OBJECT *key_obj = NULL; struct ECDSA_OTHER_MECH_PARAM mech_ep11; + CK_BYTE *useblob; + size_t useblobsize; + + UNUSED(length_only); rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -8390,14 +10270,18 @@ mech = &mech_ep11.mech; } - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_SignSingle(keyblob, keyblobsize, mech, in_data, in_data_len, + rc = dll_m_SignSingle(useblob, useblobsize, mech, + in_data, in_data_len, signature, sig_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -8406,9 +10290,6 @@ } done: - if (rc == CKR_OK && length_only == FALSE) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); - object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8425,9 +10306,12 @@ size_t spki_len = 0; OBJECT *key_obj = NULL; SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; - size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES; - CK_BYTE *ep11_sign_state = malloc(ep11_sign_state_l); + size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES * 2; + CK_BYTE *ep11_sign_state = calloc(ep11_sign_state_l, 1); struct ECDSA_OTHER_MECH_PARAM mech_ep11; + CK_BYTE *useblob, *usestate; + size_t useblob_len, usestate_len; + CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; if (!ep11_sign_state) { TRACE_ERROR("%s Memory allocation failed\n", __func__); @@ -8473,6 +10357,7 @@ rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: + strength_index = key_obj->strength.strength; /* * Release obj lock, verify_mgr_init or ep11tok_sign_verify_init_ibm_ed * may re-acquire the lock @@ -8516,14 +10401,44 @@ mech = &mech_ep11.mech; } - RETRY_START(rc, tokdata) + /* + * state is allocated large enough to hold 2 times the max state blob. + * Initially use the first half only. The second half is for the + * re-enciphered state blob (if mk change is active). + */ + ep11_sign_state_l /= 2; + + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, spki, spki_len, + useblob, useblob_len, + ep11_sign_state, + ep11_sign_state + ep11_sign_state_l, + ep11_sign_state_l, + usestate, usestate_len, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_VerifyInit(ep11_sign_state, &ep11_sign_state_l, mech, - spki, spki_len, target_info->target); + rc = dll_m_VerifyInit(usestate, &usestate_len, mech, + useblob, useblob_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + if (rc == CKR_OK && retry == 1) { + /* + * Initially, the real state_len is unknown, and is set to + * allocated state size / 2. When the state was created on + * an APQN with new WK set already, move the state to the + * final place, which is state + usestate_len, where + * usestate_len now is the real state size. + */ + memmove(ep11_sign_state + usestate_len, + ep11_sign_state + ep11_sign_state_l, usestate_len); + } + ep11_sign_state_l = usestate_len; + RETRY_REENC_BLOB_STATE_END(tokdata, target_info, spki, spki_len, + useblob, useblob_len, ep11_sign_state, + ep11_sign_state + ep11_sign_state_l, + ep11_sign_state_l, usestate, usestate_len, + TRUE, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8535,7 +10450,7 @@ ctx->key = key; ctx->active = TRUE; ctx->context = ep11_sign_state; - ctx->context_len = ep11_sign_state_l; + ctx->context_len = ep11_sign_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; @@ -8560,7 +10475,7 @@ done: if (rc == CKR_OK) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); + INC_COUNTER(tokdata, session, mech, key_obj, strength_index); object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8578,6 +10493,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -8605,10 +10522,19 @@ goto done; /* no ep11 fallback possible */ } - RETRY_START(rc, tokdata) - rc = dll_m_Verify(ctx->context, ctx->context_len, in_data, in_data_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_Verify(state, state_len, + in_data, in_data_len, signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8634,6 +10560,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (!in_data || !in_data_len) return CKR_OK; @@ -8650,10 +10578,18 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_VerifyUpdate(ctx->context, ctx->context_len, in_data, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_VerifyUpdate(state, state_len, in_data, in_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8679,6 +10615,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = verify_mgr_verify_final(tokdata, session, ctx, signature, sig_len); @@ -8692,10 +10630,18 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_VerifyFinal(ctx->context, ctx->context_len, signature, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_VerifyFinal(state, state_len, signature, sig_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -8722,6 +10668,8 @@ size_t spki_len = 0; OBJECT *key_obj = NULL; struct ECDSA_OTHER_MECH_PARAM mech_ep11; + CK_BYTE *useblob; + size_t useblob_len; rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK); if (rc != CKR_OK) { @@ -8760,14 +10708,18 @@ mech = &mech_ep11.mech; } - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, spki, spki_len, + useblob, useblob_len, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_VerifySingle(spki, spki_len, mech, in_data, in_data_len, + rc = dll_m_VerifySingle(useblob, useblob_len, mech, + in_data, in_data_len, signature, sig_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -8776,9 +10728,6 @@ } done: - if (rc == CKR_OK || rc == CKR_SIGNATURE_INVALID) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); - object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8795,6 +10744,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = decr_mgr_decrypt_final(tokdata, session, length_only, @@ -8809,14 +10760,24 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_DecryptFinal(ctx->context, ctx->context_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_DecryptFinal(state, state_len, output_part, p_output_part_len, target_info->target); - RETRY_END(rc, tokdata, session) - + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) + + rc = constant_time_select(constant_time_eq(rc, CKR_OK), + ep11_error_to_pkcs11_error(rc, session), + rc); if (rc != CKR_OK) { - rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); @@ -8841,6 +10802,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = decr_mgr_decrypt(tokdata, session, length_only, ctx, @@ -8856,14 +10819,24 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_Decrypt(ctx->context, ctx->context_len, input_data, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_Decrypt(state, state_len, input_data, input_data_len, output_data, p_output_data_len, target_info->target); - RETRY_END(rc, tokdata, session) - + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) + + rc = constant_time_select(constant_time_eq(rc, CKR_OK), + ep11_error_to_pkcs11_error(rc, session), + rc); if (rc != CKR_OK) { - rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); @@ -8889,6 +10862,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (!input_part || !input_part_len) { *p_output_part_len = 0; @@ -8909,14 +10884,24 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_DecryptUpdate(ctx->context, ctx->context_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_DecryptUpdate(state, state_len, input_part, input_part_len, output_part, p_output_part_len, target_info->target); - RETRY_END(rc, tokdata, session) - + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) + + rc = constant_time_select(constant_time_eq(rc, CKR_OK), + ep11_error_to_pkcs11_error(rc, session), + rc); if (rc != CKR_OK) { - rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); @@ -8940,6 +10925,10 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *useblob; + size_t useblobsize; + + UNUSED(length_only); rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -8962,27 +10951,30 @@ goto done; } - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_DecryptSingle(keyblob, keyblobsize, mech, input_data, + rc = dll_m_DecryptSingle(useblob, useblobsize, mech, input_data, input_data_len, output_data, p_output_data_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) + + rc = constant_time_select(constant_time_eq(rc, CKR_OK), + ep11_error_to_pkcs11_error(rc, session), + rc); if (rc != CKR_OK) { - rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); } else { TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } - if (rc == CKR_OK && length_only == FALSE) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); - - done: +done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -8999,6 +10991,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = encr_mgr_encrypt_final(tokdata, session, length_only, @@ -9013,11 +11007,19 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_EncryptFinal(ctx->context, ctx->context_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_EncryptFinal(state, state_len, output_part, p_output_part_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -9045,6 +11047,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (ctx->pkey_active) { rc = encr_mgr_encrypt(tokdata, session, length_only, ctx, @@ -9060,11 +11064,19 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_Encrypt(ctx->context, ctx->context_len, input_data, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_Encrypt(state, state_len, input_data, input_data_len, output_data, p_output_data_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -9093,6 +11105,8 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *state; + size_t state_len; if (!input_part || !input_part_len) { *p_output_part_len = 0; @@ -9113,11 +11127,19 @@ return rc; } - RETRY_START(rc, tokdata) - rc = dll_m_EncryptUpdate(ctx->context, ctx->context_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len) + rc = dll_m_EncryptUpdate(state, state_len, input_part, input_part_len, output_part, p_output_part_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ctx->context, ctx->context_len / 2, + ctx->context + (ctx->context_len / 2), + ctx->context_len / 2, state, state_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -9144,6 +11166,10 @@ size_t keyblobsize = 0; CK_BYTE *keyblob; OBJECT *key_obj = NULL; + CK_BYTE *useblob; + size_t useblobsize; + + UNUSED(length_only); rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, READ_LOCK); @@ -9177,16 +11203,19 @@ goto done; } - RETRY_START(rc, tokdata) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, keyblob, keyblobsize, + useblob, useblobsize, rc) if (ep11_pqc_obj_strength_supported(target_info, mech->mechanism, key_obj)) - rc = dll_m_EncryptSingle(keyblob, keyblobsize, mech, input_data, + rc = dll_m_EncryptSingle(useblob, useblobsize, mech, input_data, input_data_len, output_data, p_output_data_len, target_info->target); else rc = CKR_KEY_SIZE_RANGE; - RETRY_END(rc, tokdata, session) + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, useblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); @@ -9194,9 +11223,6 @@ TRACE_INFO("%s rc=0x%lx\n", __func__, rc); } - if (rc == CKR_OK && length_only == FALSE) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); - done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -9212,10 +11238,13 @@ CK_BYTE *blob; size_t blob_len = 0; OBJECT *key_obj = NULL; - size_t ep11_state_l = MAX_CRYPT_STATE_BYTES; + size_t ep11_state_l = MAX_CRYPT_STATE_BYTES * 2; CK_BYTE *ep11_state; + CK_BYTE *useblob, *usestate; + size_t useblob_len, usestate_len; + CK_ULONG strength_index = POLICY_STRENGTH_IDX_0; - ep11_state = malloc(ep11_state_l); /* freed by encr/decr_mgr.c */ + ep11_state = calloc(ep11_state_l, 1); /* freed by encr/decr_mgr.c */ if (!ep11_state) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; @@ -9245,6 +11274,7 @@ rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); switch (rc) { case CKR_OK: + strength_index = key_obj->strength.strength; /* Release obj lock, encr/decr_mgr_init may re-acquire the lock */ object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -9285,16 +11315,44 @@ goto done; } + /* + * ep11_state is allocated large enough to hold 2 times the max state blob. + * Initially use the first half only. The second half is for the + * re-enciphered state blob (if mk change is active). + */ + ep11_state_l /= 2; + if (op == DECRYPT) { ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; - RETRY_START(rc, tokdata) - rc = dll_m_DecryptInit(ep11_state, &ep11_state_l, mech, blob, - blob_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, blob, + blob_len, useblob, useblob_len, + ep11_state, ep11_state + ep11_state_l, + ep11_state_l, usestate, usestate_len, rc) + rc = dll_m_DecryptInit(usestate, &usestate_len, mech, useblob, + useblob_len, target_info->target); + if (rc == CKR_OK && retry == 1) { + /* + * Initially, the real state_len is unknown, and is set to + * allocated state size / 2. When the state was created on + * an APQN with new WK set already, move the state to the + * final place, which is state + usestate_len, where + * usestate_len now is the real state size. + */ + memmove(ep11_state + usestate_len, + ep11_state + ep11_state_l, usestate_len); + } + ep11_state_l = usestate_len; + RETRY_REENC_BLOB_STATE_END(tokdata, target_info, blob, blob_len, + useblob, useblob_len, + ep11_state, ep11_state + ep11_state_l, + ep11_state_l, usestate, usestate_len, + TRUE, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) ctx->key = key; ctx->active = TRUE; ctx->context = ep11_state; - ctx->context_len = ep11_state_l; + ctx->context_len = ep11_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; @@ -9335,14 +11393,35 @@ goto error; } - RETRY_START(rc, tokdata) - rc = dll_m_EncryptInit(ep11_state, &ep11_state_l, mech, blob, - blob_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_STATE_START(tokdata, target_info, key_obj, blob, + blob_len, useblob, useblob_len, + ep11_state, ep11_state + ep11_state_l, + ep11_state_l, usestate, usestate_len, rc) + rc = dll_m_EncryptInit(usestate, &usestate_len, mech, useblob, + useblob_len, target_info->target); + if (rc == CKR_OK && retry == 1) { + /* + * Initially, the real state_len is unknown, and is set to + * allocated state size / 2. When the state was created on + * an APQN with new WK set already, move the state to the + * final place, which is state + usestate_len, where + * usestate_len now is the real state size. + */ + memmove(ep11_state + usestate_len, + ep11_state + ep11_state_l, usestate_len); + } + ep11_state_l = usestate_len; + RETRY_REENC_BLOB_STATE_END(tokdata, target_info, blob, blob_len, + useblob, useblob_len, + ep11_state, ep11_state + ep11_state_l, + ep11_state_l, usestate, usestate_len, + TRUE, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) ctx->key = key; ctx->active = TRUE; ctx->context = ep11_state; - ctx->context_len = ep11_state_l; + ctx->context_len = ep11_state_l * 2; /* current and re-enciphered state */ ctx->pkey_active = FALSE; if (mech != &ctx->mech) { /* deferred init dup'ed mech already */ ctx->mech.mechanism = mech->mechanism; @@ -9373,7 +11452,7 @@ done: if (rc == CKR_OK) - INC_COUNTER(tokdata, session, mech, key_obj, POLICY_STRENGTH_IDX_0); + INC_COUNTER(tokdata, session, mech, key_obj, strength_index); object_put(tokdata, key_obj, TRUE); key_obj = NULL; @@ -9434,15 +11513,15 @@ CK_ULONG_PTR p_wrapped_key_len) { CK_RV rc; - CK_BYTE *wrapping_blob; - size_t wrapping_blob_len; + CK_BYTE *wrapping_blob, *use_wrapping_blob = NULL; + size_t wrapping_blob_len, use_wrapping_blob_len = 0; CK_OBJECT_CLASS class; - CK_BYTE *wrap_target_blob; - size_t wrap_target_blob_len; + CK_BYTE *wrap_target_blob, *use_wrap_target_blob; + size_t wrap_target_blob_len, use_wrap_target_blob_len; int size_query = 0; OBJECT *key_obj = NULL, *wrap_key_obj = NULL, *sobj = NULL; - CK_BYTE *sign_blob = NULL; - size_t sign_blob_len = ~0; + CK_BYTE *sign_blob = NULL, *use_sign_blob = NULL; + size_t sign_blob_len = ~0, use_sign_blob_len = 0; CK_KEY_TYPE ktype; /* ep11 weakness: @@ -9562,12 +11641,23 @@ * (wrapping blob). The wrapped key can be processed by any PKCS11 * implementation. */ - RETRY_START(rc, tokdata) - rc = - dll_m_WrapKey(wrap_target_blob, wrap_target_blob_len, wrapping_blob, - wrapping_blob_len, sign_blob, sign_blob_len, mech, - wrapped_key, p_wrapped_key_len, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB3_START(tokdata, target_info, + key_obj, wrap_target_blob, wrap_target_blob_len, + use_wrap_target_blob, use_wrap_target_blob_len, + wrap_key_obj, wrapping_blob, wrapping_blob_len, + use_wrapping_blob, use_wrapping_blob_len, + sobj, sign_blob, sign_blob_len, use_sign_blob, + use_sign_blob_len, rc) + rc = dll_m_WrapKey(use_wrap_target_blob, use_wrap_target_blob_len, + use_wrapping_blob, use_wrapping_blob_len, + use_sign_blob, use_sign_blob_len, mech, + wrapped_key, p_wrapped_key_len, target_info->target); + RETRY_REENC_BLOB3_END(tokdata, target_info, + use_wrap_target_blob, use_wrap_target_blob_len, + use_wrapping_blob, use_wrapping_blob_len, + use_sign_blob, use_sign_blob_len, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { TRACE_ERROR("%s m_WrapKey failed with rc=0x%lx\n", __func__, rc); @@ -9602,13 +11692,15 @@ CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE_PTR p_key) { + ep11_private_data_t *ep11_data = tokdata->private_data; CK_RV rc; - CK_BYTE *wrapping_blob, *temp; - size_t wrapping_blob_len; + CK_BYTE *wrapping_blob, *use_wrapping_blob, *temp; + size_t wrapping_blob_len, use_wrapping_blob_len; CK_BYTE csum[MAX_BLOBSIZE]; CK_ULONG cslen = sizeof(csum), temp_len; OBJECT *key_obj = NULL; CK_BYTE keyblob[MAX_BLOBSIZE]; + CK_BYTE keyblobreenc[MAX_BLOBSIZE]; size_t keyblobsize = sizeof(keyblob); CK_ATTRIBUTE *attr = NULL; CK_ULONG i; @@ -9624,8 +11716,8 @@ CK_ATTRIBUTE *new_attrs2 = NULL; CK_ULONG new_attrs2_len = 0; CK_BBOOL isab; - CK_BYTE *verifyblob = NULL; - size_t verifyblobsize = ~0; + CK_BYTE *verifyblob = NULL, *use_verifyblob = NULL; + size_t verifyblobsize = ~0, use_verifyblobsize = 0; OBJECT *vobj = NULL; CK_KEY_TYPE keytype; @@ -9672,6 +11764,7 @@ } memset(keyblob, 0, sizeof(keyblob)); + memset(keyblobreenc, 0, sizeof(keyblobreenc)); /*get key type of unwrapped key */ CK_ATTRIBUTE_PTR cla_attr = @@ -9793,14 +11886,26 @@ /* we need a blob for the new key created by unwrapping, * the wrapped key comes in BER */ - RETRY_START(rc, tokdata) - rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, wrapping_blob, - wrapping_blob_len, verifyblob, verifyblobsize, - ep11_pin_blob, - ep11_pin_blob_len, mech, new_attrs2, new_attrs2_len, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB2_START(tokdata, target_info, + kobj, wrapping_blob, wrapping_blob_len, + use_wrapping_blob, use_wrapping_blob_len, + vobj, verifyblob, verifyblobsize, + use_verifyblob, use_verifyblobsize, rc) + RETRY_REENC_CREATE_KEY_START() + rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, use_wrapping_blob, + use_wrapping_blob_len, use_verifyblob, + use_verifyblobsize, ep11_pin_blob, + ep11_pin_blob_len, mech, + new_attrs2, new_attrs2_len, keyblob, &keyblobsize, csum, &cslen, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_REENC_CREATE_KEY_END(tokdata, target_info, + keyblob, keyblobreenc, keyblobsize, rc) + RETRY_REENC_BLOB2_END(tokdata, target_info, use_wrapping_blob, + use_wrapping_blob_len, use_verifyblob, + use_verifyblobsize, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, session); @@ -9811,7 +11916,7 @@ TRACE_INFO("%s m_UnwrapKey rc=0x%lx blobsize=0x%zx mech=0x%lx\n", __func__, rc, keyblobsize, mech->mechanism); - if (check_expected_mkvp(tokdata, keyblob, keyblobsize) != CKR_OK) { + if (check_expected_mkvp(tokdata, keyblob, keyblobsize, NULL) != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_DEVICE_ERROR)); rc = CKR_DEVICE_ERROR; goto error; @@ -9831,6 +11936,24 @@ } attr = NULL; + if (ep11_data->mk_change_active) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, keyblobreenc, keyblobsize, + &attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + + rc = template_update_attribute(key_obj->template, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + attr = NULL; + } + if (isab) { rc = ab_unwrap_update_template(tokdata, session, keyblob, keyblobsize, key_obj, @@ -9841,7 +11964,7 @@ } } - rc = update_ep11_attrs_from_blob(tokdata, session, key_obj->template, FALSE); + rc = update_ep11_attrs_from_blob(tokdata, session, key_obj, FALSE); if (rc != CKR_OK) { TRACE_ERROR("%s update_ep11_attrs_from_blob failed with rc=0x%lx\n", __func__, rc); @@ -10118,8 +12241,10 @@ /* size query */ if (pMechanismList == NULL) { - rc = dll_m_GetMechanismList(0, pMechanismList, pulCount, - target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GetMechanismList(0, pMechanismList, pulCount, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #1\n", @@ -10150,7 +12275,10 @@ goto out; } mlist = tmp; - rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GetMechanismList(0, mlist, &counter, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #2\n", @@ -10190,7 +12318,10 @@ * that comes as parameter, this is a 'reduced size', * ep11 would complain about insufficient list size */ - rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GetMechanismList(0, mlist, &counter, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #3\n", @@ -10217,7 +12348,10 @@ } mlist = tmp; /* all the card has */ - rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GetMechanismList(0, mlist, &counter, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #4\n", @@ -10586,7 +12720,10 @@ pInfo->flags = (CK_FLAGS)(CKF_HW|CKF_GENERATE); break; default: - rc = dll_m_GetMechanismInfo(0, type, pInfo, target_info->target); + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_GetMechanismInfo(0, type, pInfo, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) break; } @@ -10676,6 +12813,27 @@ pInfo->ulMinKeySize = 16; break; + case CKM_SHA1_KEY_DERIVATION: + pInfo->ulMinKeySize = 8; + pInfo->ulMaxKeySize = SHA1_HASH_SIZE * 8; + break; + case CKM_SHA224_KEY_DERIVATION: + pInfo->ulMinKeySize = 8; + pInfo->ulMaxKeySize = SHA224_HASH_SIZE * 8; + break; + case CKM_SHA256_KEY_DERIVATION: + pInfo->ulMinKeySize = 8; + pInfo->ulMaxKeySize = SHA256_HASH_SIZE * 8; + break; + case CKM_SHA384_KEY_DERIVATION: + pInfo->ulMinKeySize = 8; + pInfo->ulMaxKeySize = SHA384_HASH_SIZE * 8; + break; + case CKM_SHA512_KEY_DERIVATION: + pInfo->ulMinKeySize = 8; + pInfo->ulMaxKeySize = SHA512_HASH_SIZE * 8; + break; + default: ; /* do not touch */ } @@ -10929,7 +13087,7 @@ memset(fname, 0, PATH_MAX); - /* via envrionment variable it is possible to overwrite the + /* via environment variable it is possible to overwrite the * directory where the ep11 token config file is searched. */ if (conf_dir) { @@ -10991,6 +13149,11 @@ return CKR_FUNCTION_FAILED; } + strncpy(ep11_data->token_config_filename, fname, + sizeof(ep11_data->token_config_filename)); + ep11_data->token_config_filename[ + sizeof(ep11_data->token_config_filename) - 1] = '\0'; + ep11_data->target_list.length = 0; ep11_data->pkey_mode = PKEY_MODE_DEFAULT; @@ -11590,6 +13753,27 @@ return rc; } +static CK_BBOOL is_apqn_online(uint_32 card, uint_32 domain) +{ + char fname[290]; + char buf[250]; + CK_RV rc; + +#ifdef EP11_HSMSIM + return CK_TRUE; +#endif + + sprintf(fname, "%s/card%02x/%02x.%04x/online", SYSFS_DEVICES_AP, + card, card, domain); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return CK_FALSE; + if (strcmp(buf, "1") != 0) + return CK_FALSE; + + return CK_TRUE; +} + static CK_RV is_card_ep11_and_online(const char *name) { char fname[290]; @@ -12008,17 +14192,20 @@ mech.ulParameterLen = 0; len = sizeof(ep11_session->session_id); - if (ep11tok_libica_digest_available(tokdata, ep11_data, mech.mechanism)) + if (ep11tok_libica_digest_available(tokdata, ep11_data, mech.mechanism)) { rc = ep11tok_libica_digest(tokdata, ep11_data, mech.mechanism, &ctx, (CK_BYTE_PTR)&session_id_data, sizeof(session_id_data), ep11_session->session_id, &len, SHA_MSG_PART_ONLY); - else - rc = dll_m_DigestSingle(&mech, (CK_BYTE_PTR)&session_id_data, - sizeof(session_id_data), - ep11_session->session_id, &len, - target_info->target); + } else { + RETRY_SINGLE_APQN_START(tokdata, rc) + rc = dll_m_DigestSingle(&mech, (CK_BYTE_PTR)&session_id_data, + sizeof(session_id_data), + ep11_session->session_id, &len, + target_info->target); + RETRY_SINGLE_APQN_END(rc, tokdata, target_info) + } put_target_info(tokdata, target_info); @@ -13017,6 +15204,26 @@ CK_RV rc; target_t target; + /* + * If an MK change operation is active, the current APQN must be part + * of the operation, even if it is offline (this only applies to an + * APQN_ALLOWLIST configuration, for a APQN_ANY configuration, we will only + * be called for currently online APQNs anyway). + */ + if (qw->ep11_data->mk_change_active && + !hsm_mk_change_apqns_find(qw->ep11_data->mk_change_apqns, + qw->ep11_data->num_mk_change_apqns, + adapter, domain)) { + TRACE_ERROR("APQN %02X.%04X is used by the EP11 token, but it is " + "not part of the active MK change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + OCK_SYSLOG(LOG_ERR, "APQN %02X.%04X is used by the EP11 token, but " + "it is not part of the active MK change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + qw->error = TRUE; + return CKR_OK; + } + rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); if (rc != CKR_OK) return rc; @@ -13042,7 +15249,70 @@ } TRACE_DEBUG("%s WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); - TRACE_DEBUG_DUMP("full WKVP: ", domain_info.wk, sizeof( domain_info.wk)); + TRACE_DEBUG_DUMP("full WKVP: ", domain_info.wk, sizeof(domain_info.wk)); + + if ((domain_info.flags & CK_IBM_DOM_COMMITTED_NWK) != 0) { + TRACE_DEBUG_DUMP("New WKVP: ", domain_info.nextwk, + sizeof(domain_info.nextwk)); + + /* New WK must be the expected new WK if a MK change op is ongoing */ + if (qw->ep11_data->mk_change_active && + memcmp(domain_info.nextwk, qw->ep11_data->new_wkvp, + XCP_WKID_BYTES) != 0) { + TRACE_ERROR("New EP11 wrapping key on APQN %02X.%04X does not " + "match the expected wrapping key of the active MK " + "change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + OCK_SYSLOG(LOG_ERR, "New EP11 wrapping key on APQN %02X.%04X does " + "not match the expected wrapping key of the active " + "HSM MK change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + qw->error = TRUE; + rc = CKR_OK; + goto out; + } + } else { + /* + * No new WK loaded: current WK must be the expected new WK if a MK + * change op is ongoing + */ + if (qw->ep11_data->mk_change_active && + memcmp(domain_info.wk, qw->ep11_data->new_wkvp, + XCP_WKID_BYTES) != 0) { + TRACE_ERROR("Current EP11 wrapping key on APQN %02X.%04X does not " + "match the expected new wrapping key of the active MK " + "change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + OCK_SYSLOG(LOG_ERR, "Current EP11 wrapping key on APQN %02X.%04X " + "does not match the expected new wrapping key of the " + "active HSM MK change operation '%s'\n", + adapter, domain, qw->ep11_data->mk_change_op); + /* + * Report error only if not within the pkcshsm_mk_change tool + * process. Otherwise the MK change operation could not be canceled + * when the new WK register has already been cleared by HSM admin. + */ + if (strcmp(program_invocation_short_name, + "pkcshsm_mk_change") != 0) { + qw->error = TRUE; + rc = CKR_OK; + goto out; + } + } + } + + /* + * If an MK change operation is pending, the current WK may already + * be the new WK of the operation. + */ + if (qw->ep11_data->mk_change_active && + memcmp(domain_info.wk, qw->ep11_data->new_wkvp, + XCP_WKID_BYTES) == 0) { + TRACE_DEBUG("%s APQN %02X.%04X already has the new WK\n", + __func__, adapter, domain); + rc = CKR_OK; + goto out; + } if (qw->ep11_data->expected_wkvp_set == FALSE && memcmp(qw->ep11_data->expected_wkvp, ep11_zero_mkvp, @@ -13096,6 +15366,18 @@ } if (ep11_data->expected_wkvp_set == FALSE) { + /* + * If a MK change operation is active, and all APQNs have the new WK + * already, use the new WK as the queried one. + */ + if (ep11_data->mk_change_active && + memcmp(ep11_data->expected_wkvp, ep11_zero_mkvp, + XCP_WKID_BYTES) == 0) { + TRACE_DEBUG("%s All APQNs already have the new WK\n",__func__); + memcpy(ep11_data->expected_wkvp, ep11_data->new_wkvp, + XCP_WKID_BYTES); + } + TRACE_DEBUG_DUMP("WKVP (queried): ", ep11_data->expected_wkvp, XCP_WKID_BYTES); } else { @@ -13402,6 +15684,131 @@ } } +struct single_target_data { + ep11_private_data_t *ep11_data; + int found; + int new_wk_found; + uint_32 adapter; + uint_32 domain; +}; + +static CK_RV setup_single_target_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + struct single_target_data *std = (struct single_target_data *)handler_data; + CK_IBM_DOMAIN_INFO domain_info; + CK_ULONG domain_info_len = sizeof(domain_info); + CK_RV rc; + target_t target; + int target_allocated = 0; + + if (!std->new_wk_found) { + /* Check if this APQN has the new WK loaded */ + rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); + if (rc != CKR_OK) + return rc; + + target_allocated = 1; + + rc = dll_m_get_xcp_info(&domain_info, &domain_info_len, + CK_IBM_XCPQ_DOMAIN, 0, target); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to query domain info from APQN %02X.%04X\n", + __func__, adapter, domain); + /* card may no longer be online, so ignore this error situation */ + goto out; + } + + if ((domain_info.flags & CK_IBM_DOM_CURR_WK) == 0) { + TRACE_ERROR("%s No EP11 wrapping key is set on APQN %02X.%04X\n", + __func__, adapter, domain); + goto out; + } + + if (memcmp(domain_info.wk, std->ep11_data->new_wkvp, + XCP_WKID_BYTES) == 0) { + std->adapter = adapter; + std->domain = domain; + std->new_wk_found = 1; + std->found = 1; + + TRACE_DEVEL("%s Select APQN %02X.%04X with new WK set\n", + __func__, adapter, domain); + } + } + + if (!std->found && !std->new_wk_found) { + std->adapter = adapter; + std->domain = domain; + std->found = 1; + + TRACE_DEVEL("%s Select APQN %02X.%04X\n", __func__, adapter, domain); + } + +out: + if (target_allocated) + free_ep11_target_for_apqn(target); + + return CKR_OK; +} + +static CK_RV ep11tok_setup_single_target(STDLL_TokData_t *tokdata, + ep11_target_info_t *target_info, + CK_BBOOL wait_for_new_wk) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct single_target_data std; + CK_RV rc; + int retries = 0; + +retry: + memset(&std, 0, sizeof(std)); + std.ep11_data = ep11_data; + + /* Search for an online APQN that preferably has the new WK set already */ + rc = handle_all_ep11_cards(&ep11_data->target_list, + setup_single_target_handler, &std); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: rc=0x%lx\n", + __func__, rc); + return rc; + } + + if (!std.found) { + TRACE_ERROR("%s no online APQN found\n",__func__); + return CKR_DEVICE_ERROR;; + } + + if (wait_for_new_wk && !std.new_wk_found) { + TRACE_DEVEL("%s no APQN with new MK set found, retry in 1 second\n", + __func__); + + retries++; + if (retries > 3600) /* Retry for max 1 hour */ + return CKR_DEVICE_ERROR; + + sleep(1); + goto retry; + } + + rc = get_ep11_target_for_apqn(std.adapter, std.domain, + &target_info->target, 0); + if (rc != CKR_OK) + return rc; + + target_info->single_apqn = 1; + target_info->adapter = std.adapter; + target_info->domain = std.domain; + target_info->single_apqn_has_new_wk = std.new_wk_found; + + OCK_SYSLOG(LOG_INFO, "Slot %lu: A concurrent HSM master key change " + "operation (%s) is active, EP11 token uses a single APQN: " + "%02X.%04X\n", tokdata->slot_id, ep11_data->mk_change_op, + std.adapter, std.domain); + + return CKR_OK; +} + CK_RV token_specific_set_attribute_values(STDLL_TokData_t *tokdata, SESSION *session, OBJECT *obj, @@ -13410,10 +15817,10 @@ ep11_private_data_t *ep11_data = tokdata->private_data; CK_OBJECT_CLASS class; CK_KEY_TYPE ktype; - size_t keyblobsize = 0; - CK_BYTE *keyblob; + size_t keyblobsize = 0, reencblobsize = 0; + CK_BYTE *keyblob, *reencblob = NULL; DL_NODE *node; - CK_ATTRIBUTE *ibm_opaque_attr = NULL; + CK_ATTRIBUTE *ibm_opaque_attr = NULL, *ibm_opaque_reenc_attr = NULL; CK_ATTRIBUTE_PTR attributes = NULL; CK_ULONG num_attributes = 0; CK_ATTRIBUTE *attr; @@ -13447,6 +15854,21 @@ return rc; } + if (ep11_data->mk_change_active) { + rc = obj_opaque_2_reenc_blob(tokdata, obj, &reencblob, &reencblobsize); + if (rc == CKR_TEMPLATE_INCOMPLETE) { + TRACE_DEVEL("%s no reenc key-blob, use old key-blob\n", __func__); + reencblob = keyblob; + reencblobsize = keyblobsize; + rc = CKR_OK; + } + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to get reenc key-blob rc=0x%lx\n", __func__, + rc); + return rc; + } + } + node = new_tmpl->attribute_list; while (node) { attr = (CK_ATTRIBUTE *)node->data; @@ -13509,53 +15931,108 @@ goto out; } - RETRY_START(rc, tokdata) - rc = dll_m_SetAttributeValue(ibm_opaque_attr->pValue, - (ktype != CKK_AES_XTS ? - ibm_opaque_attr->ulValueLen : - ibm_opaque_attr->ulValueLen / 2), + if (reencblob != NULL) { + rc = build_attribute(CKA_IBM_OPAQUE_REENC, reencblob, reencblobsize, + &ibm_opaque_reenc_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed rc=0x%lx\n", __func__, + rc); + goto out; + } + } + + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + ibm_opaque_attr->pValue, + ktype != CKK_AES_XTS ? + ibm_opaque_attr->ulValueLen : + ibm_opaque_attr->ulValueLen / 2, + ibm_opaque_reenc_attr->pValue, + ktype != CKK_AES_XTS ? + ibm_opaque_reenc_attr->ulValueLen : + ibm_opaque_reenc_attr->ulValueLen / 2, + keyblob, keyblobsize); + rc = dll_m_SetAttributeValue(keyblob, keyblobsize, attributes, num_attributes, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + ibm_opaque_attr->pValue, + ktype != CKK_AES_XTS ? + ibm_opaque_attr->ulValueLen : + ibm_opaque_attr->ulValueLen / 2, + ibm_opaque_reenc_attr->pValue, + ktype != CKK_AES_XTS ? + ibm_opaque_reenc_attr->ulValueLen : + ibm_opaque_reenc_attr->ulValueLen / 2, + keyblob, keyblobsize, rc); + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_SetAttributeValue failed rc=0x%lx\n", __func__, rc); - free(ibm_opaque_attr); goto out; } if (ktype == CKK_AES_XTS) { - RETRY_START(rc, tokdata) - rc = dll_m_SetAttributeValue((CK_BYTE *)ibm_opaque_attr->pValue + - (ibm_opaque_attr->ulValueLen / 2), - ibm_opaque_attr->ulValueLen / 2, + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_UPDATE_BLOB_START(tokdata, target_info, + (CK_BYTE *)ibm_opaque_attr->pValue + + (ibm_opaque_attr->ulValueLen / 2), + ibm_opaque_attr->ulValueLen / 2, + (CK_BYTE *)ibm_opaque_reenc_attr->pValue + + (ibm_opaque_reenc_attr->ulValueLen / 2), + ibm_opaque_reenc_attr->ulValueLen / 2, + keyblob, keyblobsize); + rc = dll_m_SetAttributeValue(keyblob, keyblobsize, attributes, num_attributes, target_info->target); - RETRY_END(rc, tokdata, session) + RETRY_UPDATE_BLOB_END(tokdata, target_info, + (CK_BYTE *)ibm_opaque_attr->pValue + + (ibm_opaque_attr->ulValueLen / 2), + ibm_opaque_attr->ulValueLen / 2, + (CK_BYTE *)ibm_opaque_reenc_attr->pValue + + (ibm_opaque_reenc_attr->ulValueLen / 2), + ibm_opaque_reenc_attr->ulValueLen / 2, + keyblob, keyblobsize, rc); + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); TRACE_ERROR("%s m_SetAttributeValue failed rc=0x%lx\n", __func__, rc); - free(ibm_opaque_attr); goto out; } } + rc = template_update_attribute(new_tmpl, ibm_opaque_attr); if (rc != CKR_OK) { TRACE_ERROR("%s template_update_attribute failed rc=0x%lx\n", __func__, rc); - free(ibm_opaque_attr); goto out; } + ibm_opaque_attr = NULL; + + if (ibm_opaque_reenc_attr != NULL) { + rc = template_update_attribute(new_tmpl, ibm_opaque_reenc_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed rc=0x%lx\n", + __func__, rc); + goto out; + } + ibm_opaque_reenc_attr = NULL; + } } out: if (attributes) free_attribute_array(attributes, num_attributes); + if (ibm_opaque_attr != NULL) + free(ibm_opaque_attr); + if (ibm_opaque_reenc_attr != NULL) + free(ibm_opaque_reenc_attr); + return rc; } @@ -13599,7 +16076,7 @@ TRACE_DEVEL("%s Refreshing target infos due to event for APQN %02x.%04x\n", __func__, apqn_data->card, apqn_data->domain); - rc = refresh_target_info(tokdata); + rc = refresh_target_info(tokdata, FALSE); if (rc != CKR_OK) { TRACE_DEVEL("%s Failed to get the target infos (refresh_target_info " "rc=0x%lx)\n", __func__, rc); @@ -13615,9 +16092,1279 @@ __sync_and_and_fetch(&ep11_data->inconsistent, 0); + /* Re-check after APQN set change if CPACF_WRAP mech is supported */ + if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_CPACF_WRAP) != CKR_OK) { + TRACE_INFO("CKM_IBM_CPACF_WRAP not supported on this system.\n"); + /* Disable pkey */ + __sync_and_and_fetch(&ep11_data->pkey_wrap_supported, 0); + } else if (ep11_data->pkey_wrap_supported == 0 && + !ep11tok_pkey_option_disabled(tokdata)) { + /* get firmware MKVP, this will enable PKEY on success */ + rc = ep11tok_pkey_get_firmware_mk_vp(tokdata); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_WARNING, + "%s: Warning: Could not get mk_vp, protected key support not available.\n", + __func__); + TRACE_WARNING("Could not get mk_vp, protected key support not available.\n"); + } + } + + return CKR_OK; +} + +static CK_RV ep11tok_mk_change_is_affected(STDLL_TokData_t *tokdata, + struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + unsigned int i; + CK_BBOOL affected = FALSE; + + if (hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_EP11, 0) == NULL) + goto out; + + /* APQN_ANY: token is affected independently of APQNs changed */ + if (ep11_data->target_list.length == 0) { + affected = TRUE; + goto out; + } + + /* APQN_ALLOWLIST */ + for (i = 0; i < (unsigned int)ep11_data->target_list.length; i++) { + if (hsm_mk_change_apqns_find(info->apqns, info->num_apqns, + ep11_data->target_list.apqns[2 * i], + ep11_data->target_list.apqns[2 * i + 1])) + affected = TRUE; + } + +out: + TRACE_DEVEL("%s affected: %d\n", __func__, affected); + + return affected ? CKR_OK : CKR_FUNCTION_NOT_SUPPORTED; +} + +static CK_RV ep11tok_activate_mk_change_op(STDLL_TokData_t *tokdata, + const char *id, + const struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + + ep11_data->mk_change_apqns = calloc(info->num_apqns, sizeof(struct apqn)); + if (ep11_data->mk_change_apqns == NULL) { + TRACE_ERROR("%s Failed to allocate list of MK change APQNs\n", + __func__); + return CKR_HOST_MEMORY; + } + + ep11_data->num_mk_change_apqns = info->num_apqns; + memcpy(ep11_data->mk_change_apqns, info->apqns, + info->num_apqns * sizeof(struct apqn)); + + strncpy(ep11_data->mk_change_op, id, sizeof(ep11_data->mk_change_op) - 1); + ep11_data->mk_change_op[sizeof(ep11_data->mk_change_op) - 1] = '\0'; + + ep11_data->mk_change_active = 1; + + return CKR_OK; +} + +static CK_RV ep11tok_mk_change_check_pending_ops_cb(struct hsm_mk_change_op *op, + void *private) +{ + STDLL_TokData_t *tokdata = private; + ep11_private_data_t *ep11_data; + struct hsm_mkvp *mkvps = NULL; + unsigned int num_mkvps = 0; + const unsigned char *wkvp; + int new_wkvp_set = 0; + CK_RV rc; + + ep11_data = tokdata->private_data; + + rc = ep11tok_mk_change_is_affected(tokdata, &op->info); + if (rc != CKR_OK) + return CKR_OK; + + switch (op->state) { + case HSM_MK_CH_STATE_REENCIPHERING: + case HSM_MK_CH_STATE_REENCIPHERED: + /* + * There can only be one active MK change op for the EP11 token. + * No need to have the hsm_mk_change_rwlock, we're in token init + * function, and the API layer starts the event thread only after all + * token init's have been performed. + */ + if (ep11_data->mk_change_active) { + TRACE_ERROR("%s Another MK change is already active: %s\n", + __func__, ep11_data->mk_change_op); + return CKR_FUNCTION_FAILED; + } + + /* Activate this MK change op for the token */ + rc = ep11tok_activate_mk_change_op(tokdata, op->id, &op->info); + if (rc != CKR_OK) + return rc; + + TRACE_DEVEL("%s active MK change op: %s\n", __func__, + ep11_data->mk_change_op); + + wkvp = hsm_mk_change_mkvps_find(op->info.mkvps, op->info.num_mkvps, + HSM_MK_TYPE_EP11, + sizeof(ep11_data->new_wkvp)); + if (wkvp != NULL) { + memcpy(ep11_data->new_wkvp, wkvp, sizeof(ep11_data->new_wkvp)); + new_wkvp_set = 1; + } + + if (new_wkvp_set == 0) { + TRACE_ERROR("%s No EP11 WKVP found in MK change operation: %s\n", + __func__, ep11_data->mk_change_op); + return CKR_FUNCTION_FAILED; + } + + TRACE_DEBUG_DUMP("New WKVP: ", ep11_data->new_wkvp, + sizeof(ep11_data->new_wkvp)); + + /* Load expected current WKVP */ + rc = hsm_mk_change_token_mkvps_load(op->id, tokdata->slot_id, + &mkvps, &num_mkvps); + /* Ignore if this failed, no expected current WKVP is set then */ + if (rc == CKR_OK) { + wkvp = hsm_mk_change_mkvps_find(mkvps, num_mkvps, HSM_MK_TYPE_EP11, + sizeof(ep11_data->expected_wkvp)); + if (wkvp != NULL) { + memcpy(ep11_data->expected_wkvp, wkvp, + sizeof(ep11_data->expected_wkvp)); + ep11_data->expected_wkvp_set = 1; + + TRACE_DEBUG_DUMP("Current WKVP: ", ep11_data->expected_wkvp, + sizeof(ep11_data->expected_wkvp)); + } + } + break; + + default: + break; + } + + if (mkvps != NULL) { + hsm_mk_change_mkvps_clean(mkvps, num_mkvps); + free(mkvps); + } + + return CKR_OK; +} + +static CK_RV ep11tok_mk_change_check_pending_ops(STDLL_TokData_t *tokdata) +{ + CK_RV rc; + + rc = hsm_mk_change_lock_create(); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_lock(false); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_op_iterate(ep11tok_mk_change_check_pending_ops_cb, + tokdata); + + hsm_mk_change_unlock(); + +out: + hsm_mk_change_lock_destroy(); + + return rc; +} + +struct apqn_check_data { + ep11_private_data_t *ep11_data; + CK_SLOT_ID slot; + event_mk_change_data_t *op; + struct hsm_mk_change_info *info; + CK_BBOOL finalize; + CK_BBOOL cancel; + CK_BBOOL error; +}; + +/* + * Note: This function is called EVENT_TYPE_MK_CHANGE_INITIATE_QUERY event + * handling within the pkcshsm_mk_change tool's process only. It is supposed + * to print error messages to stderr to inform the user about errors. + * + */ +static CK_RV mk_change_apqn_check_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + struct apqn_check_data *ac = (struct apqn_check_data *)handler_data; + + CK_IBM_DOMAIN_INFO domain_info; + CK_ULONG domain_info_len = sizeof(domain_info); + const unsigned char *wkvp; + CK_RV rc; + target_t target; + + /* + * Check that this APQN is part of the MK change operation, even if it is + * offline (this only applies to an APQN_ALLOWLIST configuration, for a + * APQN_ANY configuration, we will only be called for currently online + * APQNs anyway). + */ + if (hsm_mk_change_apqns_find(ac->info->apqns, ac->info->num_apqns, + adapter, domain) == FALSE) { + TRACE_ERROR("%s APQN %02X.%04X is not part of MK change '%s'\n", + __func__, adapter, domain, ac->op->id); + warnx("Slot %lu: APQN %02X.%04X must be included into this operation.", + ac->slot, adapter, domain); + + ac->error = TRUE; + return CKR_OK; + } + + /* Check that current and new WK is as expected */ + rc = get_ep11_target_for_apqn(adapter, domain, &target, 0); + if (rc != CKR_OK) { + warnx("Slot %lu: Failed to get target for APQN %02X.%04X", + ac->slot, adapter, domain); + ac->error = TRUE; + return rc; + } + + rc = dll_m_get_xcp_info(&domain_info, &domain_info_len, CK_IBM_XCPQ_DOMAIN, + 0, target); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to query domain info from APQN %02X.%04X: " + "0x%lx\n", __func__, adapter, domain, rc); + /* card may no longer be online, so ignore this error situation */ + rc = CKR_OK; + goto out; + } + + if ((domain_info.flags & CK_IBM_DOM_CURR_WK) == 0) { + TRACE_ERROR("%s No current EP11 wrapping key is set on APQN %02X.%04X\n", + __func__, adapter, domain); + warnx("Slot %lu: No current EP11 wrapping key is set on APQN %02X.%04X", + ac->slot, adapter, domain); + ac->error = TRUE; + goto out; + } + + TRACE_DEBUG("%s Current WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); + TRACE_DEBUG_DUMP("full WKVP: ", domain_info.wk, sizeof(domain_info.wk)); + + if (ac->finalize) { + /* Current WK must be the new WK. + * hsm_mk_change_rwlock is held by caller, if check_new_wk_set is TRUE. + */ + if (memcmp(domain_info.wk, ac->ep11_data->new_wkvp, + XCP_WKID_BYTES) != 0) { + TRACE_ERROR("EP11 wrapping key on APQN %02X.%04X does not " + "match the new wrapping key\n", adapter, domain); + warnx("Slot %lu: The current EP11 WK on APQN %02X.%04X does not match " + "the new WK", ac->slot, adapter, domain); + ac->error = TRUE; + } + goto out; + } + + /* Current WK must be the expected WK */ + if (memcmp(domain_info.wk, ac->ep11_data->expected_wkvp, + XCP_WKID_BYTES) != 0) { + TRACE_ERROR("EP11 wrapping key on APQN %02X.%04X does not " + "match the expected wrapping key\n", adapter, domain); + warnx("Slot %lu: The current EP11 WK on APQN %02X.%04X does not match " + "the expected one", ac->slot, adapter, domain); + ac->error = TRUE; + goto out; + } + + if (ac->cancel) /* Skip new WK check in case of cancel */ + goto out; + + if ((domain_info.flags & CK_IBM_DOM_COMMITTED_NWK) == 0) { + TRACE_ERROR("%s No new EP11 wrapping key is set/committed on APQN %02X.%04X\n", + __func__, adapter, domain); + warnx("Slot %lu: No new EP11 wrapping key is set/committed on APQN %02X.%04X", + ac->slot, adapter, domain); + ac->error = TRUE; + goto out; + } + + TRACE_DEBUG("%s New WKVP of APQN %02X.%04X:\n", __func__, adapter, domain); + TRACE_DEBUG_DUMP("full WKVP: ", domain_info.nextwk, + sizeof(domain_info.nextwk)); + + wkvp = hsm_mk_change_mkvps_find(ac->info->mkvps, ac->info->num_mkvps, + HSM_MK_TYPE_EP11, XCP_WKID_BYTES); + if (wkvp != NULL && + memcmp(domain_info.nextwk, wkvp, XCP_WKID_BYTES) != 0) { + TRACE_ERROR("New EP11 wrapping key on APQN %02X.%04X does not " + "match the specified wrapping key\n", adapter, domain); + warnx("Slot %lu: The new EP11 WK on APQN %02X.%04X does not match " + "the specified WKVP", ac->slot, adapter, domain); + ac->error = TRUE; + goto out; + } + +out: + free_ep11_target_for_apqn(target); + + return CKR_OK; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_mk_change_init_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct apqn_check_data acd; + struct hsm_mkvp mkvp; + CK_RV rc; + + TRACE_DEVEL("%s initial query for MK change op: %s\n", __func__, op->id); + + memset(&acd, 0, sizeof(acd)); + acd.ep11_data = ep11_data; + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + acd.error = FALSE; + + rc = handle_all_ep11_cards(&ep11_data->target_list, + mk_change_apqn_check_handler, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + return rc; + } + + if (acd.error) + return CKR_FUNCTION_FAILED; + + /* Save current WKVP of this token */ + mkvp.type = HSM_MK_TYPE_EP11; + mkvp.mkvp_len = XCP_WKID_BYTES; + mkvp.mkvp = ep11_data->expected_wkvp; + + rc = hsm_mk_change_lock_create(); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_lock(true); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_token_mkvps_save(op->id, tokdata->slot_id, &mkvp, 1); + + hsm_mk_change_unlock(); + +out: + hsm_mk_change_lock_destroy(); + + return rc; +} + +struct reencipher_data { + STDLL_TokData_t *tokdata; + ep11_target_info_t *target_info; +}; + +static CK_RV ep11tok_reencipher_objects_reenc(CK_BYTE *sec_key, + CK_BYTE *reenc_sec_key, + CK_ULONG sec_key_len, + void *private) +{ + struct reencipher_data *rd = private; + + return ep11tok_reencipher_blob(rd->tokdata, &rd->target_info, + sec_key, sec_key_len, reenc_sec_key); +} + +static CK_RV ep11tok_reencipher_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + struct reencipher_data *rd = cb_data; + CK_RV rc; + + rc = obj_mgr_reencipher_secure_key(tokdata, obj, + ep11tok_reencipher_objects_reenc, rd); + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_BBOOL ep11tok_reencipher_filter_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *filter_data) +{ + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + UNUSED(filter_data); + + return template_attribute_find(obj->template, CKA_IBM_OPAQUE_REENC, &attr); +} + +static CK_RV ep11tok_reencipher_cancel_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + CK_RV rc; + + UNUSED(cb_data); + + rc = obj_mgr_reencipher_secure_key_cancel(tokdata, obj); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_BBOOL ep11tok_reencipher_finalize_is_new_wk_cb( + STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_BYTE *sec_key, + CK_ULONG sec_key_len, + void *cb_private) +{ + UNUSED(cb_private); + UNUSED(obj); + + return ep11tok_is_blob_new_wkid(tokdata, sec_key, sec_key_len); +} + +static CK_RV ep11tok_reencipher_finalize_objects_cb(STDLL_TokData_t *tokdata, + OBJECT *obj, void *cb_data) +{ + CK_RV rc; + + UNUSED(cb_data); + + rc = obj_mgr_reencipher_secure_key_finalize(tokdata, obj, + ep11tok_reencipher_finalize_is_new_wk_cb, NULL); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) + rc = CKR_OK; + if (rc == CKR_OBJECT_HANDLE_INVALID) /* Obj was deleted by other proc */ + rc = CKR_OK; + + return rc; +} + +static CK_RV ep11tok_reencipher_session_op_ctx(STDLL_TokData_t *tokdata, + SESSION *session, + CK_BYTE *context, + CK_ULONG context_len, + ep11_target_info_t **target_info, + const char *ctx_type, + CK_BBOOL finalize) +{ + CK_RV rc; + + TRACE_INFO("%s %s %s state blob of session 0x%lx\n", __func__, + finalize ? "Finalize" : "Re-encipher", + ctx_type, session->handle); + OCK_SYSLOG(LOG_DEBUG, "Slot %lu: %s %s state blob of session 0x%lx\n", + tokdata->slot_id, finalize ? "Finalize" : "Re-encipher", + ctx_type, session->handle); + + /* The context is allocated at least twice as large as needed */ + if (finalize == FALSE) { + rc = ep11tok_reencipher_blob(tokdata, target_info, + context, context_len / 2, + context + (context_len / 2)); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to re-encipher %s state blob of session " + "0x%lx: 0x%lx\n", __func__, ctx_type, session->handle, + rc); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to re-encipher %s state blob" + "of session 0x%lx: 0x%lx\n", tokdata->slot_id, ctx_type, + session->handle, rc); + return rc; + } + } else { + memcpy(context, context + (context_len / 2), context_len / 2); + } + + return CKR_OK; +} + +struct reencipher_session_data { + ep11_target_info_t *target_info; + CK_BBOOL finalize; + CK_RV (*func)(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *context, CK_ULONG context_len, + ep11_target_info_t **target_info, const char *ctx_type, + CK_BBOOL finalize); +}; + +static CK_RV ep11tok_reencipher_sessions_cb(STDLL_TokData_t *tokdata, + SESSION *session, + CK_ULONG ctx_type, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE key, + CK_BYTE *context, + CK_ULONG context_len, + CK_BBOOL init_pending, + CK_BBOOL pkey_active, + CK_BBOOL recover, + void *private) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct reencipher_session_data *rsd = private; + const char *ctx_type_str = NULL; + + UNUSED(recover); + + /* Check preconditions */ + switch (ctx_type) { + case CONTEXT_TYPE_DIGEST: + if (ep11tok_libica_digest_available(tokdata, ep11_data, + mech->mechanism)) + return CKR_OK; + + ctx_type_str = "digest"; + break; + + case CONTEXT_TYPE_SIGN: + if (init_pending || pkey_active) + return CKR_OK; + if (ep11tok_libica_mech_available(tokdata, mech->mechanism, key)) + return CKR_OK; + + ctx_type_str = "sign"; + break; + + case CONTEXT_TYPE_VERIFY: + if (init_pending || pkey_active) + return CKR_OK; + if (ep11tok_libica_mech_available(tokdata, mech->mechanism, key)) + return CKR_OK; + + ctx_type_str = "verify"; + break; + + case CONTEXT_TYPE_ENCRYPT: + if (init_pending || pkey_active) + return CKR_OK; + + ctx_type_str = "encrypt"; + break; + + case CONTEXT_TYPE_DECRYPT: + if (init_pending || pkey_active) + return CKR_OK; + + ctx_type_str = "decrypt"; + break; + + default: + return CKR_OK; + } + + return rsd->func(tokdata, session, context, context_len, &rsd->target_info, + ctx_type_str, rsd->finalize); +} + +static CK_RV ep11tok_reencipher_sessions(STDLL_TokData_t *tokdata, + ep11_target_info_t **target_info, + CK_BBOOL finalize) +{ + struct reencipher_session_data rsd = { 0 }; + CK_RV rc; + + if (target_info != NULL) + rsd.target_info = *target_info; + rsd.finalize = finalize; + rsd.func = ep11tok_reencipher_session_op_ctx; + + rc = session_mgr_iterate_session_ops(tokdata, NULL, + ep11tok_reencipher_sessions_cb, &rsd); + + if (target_info != NULL) + *target_info = rsd.target_info; + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_mk_change_reencipher(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct reencipher_data rd = { 0 }; + CK_RV rc = CKR_OK; + const unsigned char *wkvp; + int new_wkvp_set = 0; + CK_BBOOL token_objs = FALSE; + + if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0) { + token_objs = TRUE; + /* The tool should have logged in a R/W USER session */ + if (!session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s No user session exists\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", + tokdata->slot_id); + return CKR_FUNCTION_FAILED; + } + } + + if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + if (token_objs == TRUE && ep11_data->mk_change_active == FALSE) { + TRACE_DEVEL("HSM-MK-change must already be active\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change must already be active\n", + tokdata->slot_id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + /* Activate this MK change operation */ + if (ep11_data->mk_change_active == FALSE) { + rc = ep11tok_activate_mk_change_op(tokdata, op->id, info); + if (rc != CKR_OK) + goto out; + } + + TRACE_DEVEL("%s active MK change op: %s\n", __func__, + ep11_data->mk_change_op); + + wkvp = hsm_mk_change_mkvps_find(info->mkvps, info->num_mkvps, + HSM_MK_TYPE_EP11, + sizeof(ep11_data->new_wkvp)); + if (wkvp != NULL) { + memcpy(ep11_data->new_wkvp, wkvp, sizeof(ep11_data->new_wkvp)); + new_wkvp_set = 1; + } + + if (new_wkvp_set == 0) { + TRACE_ERROR("%s No EP11 WKVP found in MK change operation: %s\n", + __func__, ep11_data->mk_change_op); + OCK_SYSLOG(LOG_ERR, + "Slot %lu: No EP11 WKVP found in MK change operation: %s\n", + tokdata->slot_id, ep11_data->mk_change_op); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + TRACE_DEBUG_DUMP("New WKVP: ", ep11_data->new_wkvp, + sizeof(ep11_data->new_wkvp)); + + /* Switch to single APQN mode (only for first event - token_objs = FALSE) */ + if (token_objs == FALSE) { + rc = refresh_target_info(tokdata, FALSE); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to select a single APQN: 0x%lx\n", + tokdata->slot_id, rc); + goto out; + } + } + + rd.tokdata = tokdata; + rd.target_info = get_target_info(tokdata); + if (rd.target_info == NULL) { + rc = CKR_FUNCTION_FAILED; + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to select a single APQN\n", + tokdata->slot_id); + goto out; + } + + if (rd.target_info->single_apqn == FALSE) { + TRACE_ERROR("%s Must operate in single-APQN mode\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to select a single APQN\n", + tokdata->slot_id); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + /* Re-encipher key objects */ + rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + NULL, NULL, + ep11tok_reencipher_objects_cb, &rd, + TRUE, "re-encipher"); + if (rc != CKR_OK) + goto out; + + if (!token_objs) { + /* Re-encipher session state blobs */ + rc = ep11tok_reencipher_sessions(tokdata, &rd.target_info, FALSE); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_ERR, "Slot %lu: Failed to re-encipher session " + "states: 0x%lx\n", tokdata->slot_id, rc); + goto out; + } + + /* Re-enciper the wrap blob */ + TRACE_INFO("Re-encipher the wrap blob\n"); + rc = ep11tok_reencipher_blob(tokdata, &rd.target_info, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + ep11_data->raw2key_wrap_blob_reenc); + if (rc != CKR_OK) { + TRACE_ERROR("Re-encipher of wrap blob failed.\n"); + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to re-encipher the wrap blob: 0x%lx\n", + tokdata->slot_id, rc); + goto out; + } + } + +out: + if (rc != CKR_OK && rd.target_info != NULL) { + obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + ep11tok_reencipher_filter_cb, NULL, + ep11tok_reencipher_cancel_objects_cb, NULL, + TRUE, "cancel"); + /* + * The pkcshsm_mk_change tool will send a CANCEL event, so leave the + * operation active for now. + */ + } + + put_target_info(tokdata, rd.target_info); + + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", + tokdata->slot_id); + if (rc == CKR_OK) + rc = CKR_CANT_LOCK; + } + + return rc; +} + +static CK_RV ep11tok_set_operation_state_cb(STDLL_TokData_t *tokdata, + SESSION *session, + CK_BYTE *context, + CK_ULONG context_len, + ep11_target_info_t **target_info, + const char *ctx_type, + CK_BBOOL finalize) +{ + TRACE_INFO("%s Re-encipher %s state blob of session 0x%lx\n", __func__, + ctx_type, session->handle); + + if (ep11tok_is_blob_new_wkid(tokdata, context, context_len / 2)) { + TRACE_DEVEL("%s state blob is already enciphered with new WK\n", + __func__); + return CKR_OK; + } + + if (ep11tok_is_blob_new_wkid(tokdata, context + (context_len / 2), + context_len / 2)) { + TRACE_DEVEL("%s state blob is already reenciphered\n", __func__); + return CKR_OK; + } + + if ((*target_info)->single_apqn_has_new_wk) { + TRACE_ERROR("%s New WK already activated, state blob can not be " + "reenciphered\n", __func__); + return CKR_SAVED_STATE_INVALID; + } + + return ep11tok_reencipher_session_op_ctx(tokdata, session, + context, context_len, target_info, + ctx_type, finalize); +} + +CK_RV ep11tok_set_operation_state(STDLL_TokData_t *tokdata, SESSION *session) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct reencipher_session_data rsd = { 0 }; + CK_RV rc; + + if (ep11_data->mk_change_active == FALSE) + return CKR_OK; + + /* Re-encipher the newly set session (if needed) */ + rsd.target_info = get_target_info(tokdata); + if (rsd.target_info == NULL) + return CKR_FUNCTION_FAILED; + + rsd.finalize = FALSE; + rsd.func = ep11tok_set_operation_state_cb; + + rc = session_mgr_iterate_session_ops(tokdata, session, + ep11tok_reencipher_sessions_cb, &rsd); + + put_target_info(tokdata, rsd.target_info); + + return rc; +} + +static CK_RV parse_expected_wkvp(ep11_private_data_t *ep11_data, + const char *fname, const char *strval, + unsigned char expected_wkvp[XCP_WKID_BYTES]) +{ + unsigned int i, val; + + if (strncasecmp(strval, "0x", 2) == 0) + strval += 2; + + if (strlen(strval) < XCP_WKID_BYTES * 2) { + TRACE_ERROR("%s expected WKVP is too short: '%s', expected %lu hex " + "characters in config file '%s'\n", __func__, strval, + sizeof(ep11_data->expected_wkvp) * 2, fname); + return CKR_FUNCTION_FAILED; + } + + if (strlen(strval) > XCP_WKID_BYTES * 2) { + TRACE_INFO("%s only the first %lu characters of the expected WKVP in " + "config file '%s' are used: %s\n", __func__, + sizeof(ep11_data->expected_wkvp) * 2, fname, strval); + } + + for (i = 0; i < XCP_WKID_BYTES; i++) { + if (sscanf(strval + (i * 2), "%02x", &val) != 1) { + TRACE_ERROR("%s failed to parse expected WKVP: '%s' at character " + "%u in config file '%s'\n", __func__, strval, (i * 2), + fname); + return CKR_FUNCTION_FAILED; + } + expected_wkvp[i] = val; + } + + TRACE_DEBUG_DUMP("Expected WKVP: ", expected_wkvp, XCP_WKID_BYTES); + return CKR_OK; } + +static CK_RV check_token_config_expected_wkvp(STDLL_TokData_t *tokdata, + CK_BBOOL new_wk) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct ConfigBaseNode *c, *config = NULL; + struct ConfigBareStringConstNode *barestr; + unsigned char wkvp[XCP_WKID_BYTES]; + char *strval = NULL; + FILE *fp; + CK_RV rc = CKR_OK; + int rc2, i; + + fp = fopen(ep11_data->token_config_filename, "r"); + if (fp == NULL) { + TRACE_ERROR("Failed to open config file '%s'\n", + ep11_data->token_config_filename); + return CKR_FUNCTION_FAILED; + } + + rc2 = parse_configlib_file(fp, &config, ep11_config_parse_error, 0); + fclose(fp); + if (rc2 != 0) { + TRACE_ERROR("Error parsing config file '%s'\n", + ep11_data->token_config_filename); + return CKR_FUNCTION_FAILED; + } + + confignode_foreach(c, config, i) { + TRACE_DEBUG("Config node: '%s' type: %u line: %u\n", + c->key, c->type, c->line); + + if (strcmp(c->key, "EXPECTED_WKVP") == 0) { + if (confignode_hastype(c, CT_STRINGVAL) || + confignode_hastype(c, CT_BAREVAL)) { + /* New style (key = value) tokens */ + strval = confignode_getstr(c); + break; + } else if (confignode_hastype(c, CT_BARECONST)) { + rc = ep11_config_next(&c, CT_BARESTRINGCONST, + ep11_data->token_config_filename, + "WKID as quoted hex string"); + if (rc != CKR_OK) + break; + + barestr = confignode_to_barestringconst(c); + strval = barestr->base.key; + break; + } + + ep11_config_error_token(ep11_data->token_config_filename, + c->key, c->line, NULL); + rc = CKR_FUNCTION_FAILED; + break; + } + } + + if (strval == NULL) { + TRACE_DEVEL("No 'EXPECTED_WKVP' in config file '%s'\n", + ep11_data->token_config_filename); + goto out; + } + + rc = parse_expected_wkvp(ep11_data, ep11_data->token_config_filename, + strval, wkvp); + if (rc != CKR_OK) + goto out; + + if (memcmp(wkvp, new_wk ? ep11_data->new_wkvp : ep11_data->expected_wkvp, + XCP_WKID_BYTES) != 0) { + TRACE_ERROR("Expected WKVP in config file '%s' does not specify the %s WKVP\n", + ep11_data->token_config_filename, + new_wk ? "new" : "current"); + warnx("Expected WKVP in config file '%s' does not specify the %s WKVP.", + ep11_data->token_config_filename, new_wk ? "new" : "current"); + rc = CKR_FUNCTION_FAILED; + } + +out: + confignode_deepfree(config); + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_mk_change_finalize_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct apqn_check_data acd; + CK_RV rc; + + TRACE_DEVEL("%s finalize query for MK change op: %s\n", __func__, op->id); + + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + + memset(&acd, 0, sizeof(acd)); + acd.ep11_data = ep11_data; + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + acd.finalize = TRUE; /* New WK must be set */ + acd.error = FALSE; + + rc = handle_all_ep11_cards(&ep11_data->target_list, + mk_change_apqn_check_handler, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + goto out; + } + + if (acd.error) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = check_token_config_expected_wkvp(tokdata, TRUE); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_token_config_expected_wkvp failed: 0x%lx\n", + __func__, rc); + goto out; + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_mk_change_finalize_cancel(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info, + CK_BBOOL cancel) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL token_objs = FALSE; + + UNUSED(info); + + TRACE_DEVEL("%s %s MK change op: %s\n", __func__, + cancel ? "canceling" : "finalizing", op->id); + + if ((op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS) != 0 || + (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { + token_objs = TRUE; + /* The tool should have logged in a R/W USER session */ + if (!session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s No user session exists\n", __func__); + OCK_SYSLOG(LOG_ERR, "Slot %lu: No user session exists\n", + tokdata->slot_id); + return CKR_FUNCTION_FAILED; + } + } + + if (pthread_rwlock_wrlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Write-Lock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change Write-Lock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + if (ep11_data->mk_change_active == FALSE) + goto out; + + /* + * Finalize/cancel token objects. + * If flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL is on, only process such + * token objects that do have the CKA_IBM_OPAQUE_REENC attribute. Those + * Objects have been newly created by another process after the first token + * finalization/cancellation (flag EVENT_MK_CHANGE_FLAGS_TOK_OBJS) has + * been performed, and before all processes have deactivated the MK change + * operation. Thus, they were created with the re-enciphered secure key, + * and now need to be finalized/canceled. + */ + rc = obj_mgr_iterate_key_objects(tokdata, !token_objs, token_objs, + token_objs && (op->flags & + EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) ? + ep11tok_reencipher_filter_cb : NULL, + NULL, + cancel ? + ep11tok_reencipher_cancel_objects_cb : + ep11tok_reencipher_finalize_objects_cb, + NULL, TRUE, + cancel ? "cancel" : "finalize"); + if (rc != CKR_OK) + goto out; + + if (!token_objs && !cancel) { + /* finalize session state blobs */ + rc = ep11tok_reencipher_sessions(tokdata, NULL, TRUE); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to finalize session states: 0x%lx\n", + tokdata->slot_id, rc); + goto out; + } + + /* Finalize the wrap blob */ + TRACE_INFO("Finalize the wrap blob\n"); + memcpy(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_reenc, + ep11_data->raw2key_wrap_blob_l); + } + + /* + * Deactivate this MK change operation. + * For the pkcshsm_mk_change tool: Deactivate only after 2nd token object + * processing. + */ + if ((token_objs == FALSE && op->tool_pid != tokdata->real_pid) || + (op->flags & EVENT_MK_CHANGE_FLAGS_TOK_OBJS_FINAL) != 0) { + + if (!cancel) { + /* From now on the new WK is the expected one */ + memcpy(ep11_data->expected_wkvp, ep11_data->new_wkvp, + XCP_WKID_BYTES); + } + + ep11_data->mk_change_active = 0; + memset(ep11_data->mk_change_op, 0, sizeof(ep11_data->mk_change_op)); + free(ep11_data->mk_change_apqns); + ep11_data->mk_change_apqns = NULL; + ep11_data->num_mk_change_apqns = 0; + + /* Switch to multiple APQN mode */ + rc = refresh_target_info(tokdata, FALSE); + if (rc != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Slot %lu: Failed to switch back to multi-APQN mode\n", + tokdata->slot_id); + goto out; + } + + TRACE_DEVEL("%s %s MK change op: %s\n", __func__, + cancel ? "canceled" : "finalized", op->id); + OCK_SYSLOG(LOG_INFO, "Slot %lu: Concurrent HSM master key change " + "operation %s is %s, EP11 token now use multi-APQN mode\n", + tokdata->slot_id, op->id, cancel ? "canceled" : "finalized"); + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + OCK_SYSLOG(LOG_ERR, "Slot %lu: HSM-MK-change unlock failed\n", + tokdata->slot_id); + rc = CKR_CANT_LOCK; + goto out; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_mk_change_cancel_query(STDLL_TokData_t *tokdata, + event_mk_change_data_t *op, + struct hsm_mk_change_info *info) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct apqn_check_data acd; + CK_RV rc; + + TRACE_DEVEL("%s cancel query for MK change op: %s\n", __func__, op->id); + + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + + memset(&acd, 0, sizeof(acd)); + acd.ep11_data = ep11_data; + acd.slot = tokdata->slot_id; + acd.op = op; + acd.info = info; + acd.cancel = TRUE; /* No new WK must be set */ + acd.error = FALSE; + + rc = handle_all_ep11_cards(&ep11_data->target_list, + mk_change_apqn_check_handler, &acd); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + goto out; + } + + if (acd.error) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = check_token_config_expected_wkvp(tokdata, FALSE); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_token_config_expected_wkvp failed: 0x%lx\n", + __func__, rc); + goto out; + } + +out: + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("MK-change Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return rc; +} + +/* + * ATTENTION: This function is called in a separate thread. All actions + * performed by this function must be thread save and use locks to lock + * against concurrent access by other threads. + */ +static CK_RV ep11tok_handle_mk_change_event(STDLL_TokData_t *tokdata, + unsigned int event_type, + unsigned int event_flags, + const char *payload, + unsigned int payload_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t bytes_read = 0; + struct hsm_mk_change_info info = { 0 }; + event_mk_change_data_t *hdr = (event_mk_change_data_t *)payload; + + UNUSED(event_flags); + + TRACE_DEVEL("%s event: 0x%x\n", __func__, event_type); + + if (payload_len <= sizeof (*hdr)) + return CKR_DATA_LEN_RANGE; + + TRACE_DEVEL("%s id: '%s' flags: 0x%x tool_pid: %d\n", __func__, hdr->id, + hdr->flags, hdr->tool_pid); + + rc = hsm_mk_change_info_unflatten((unsigned char *)payload + sizeof(*hdr), + payload_len - sizeof(*hdr), + &bytes_read, &info); + if (rc != CKR_OK) + return rc; + if (bytes_read < payload_len - sizeof(*hdr)) { + rc = CKR_DATA_LEN_RANGE; + goto out; + } + + rc = ep11tok_mk_change_is_affected(tokdata, &info); + if (rc != CKR_OK) + goto out; + + if (pthread_rwlock_rdlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Read-Lock failed.\n"); + rc = CKR_CANT_LOCK; + goto out; + } + + if (ep11_data->mk_change_active && + strcmp(ep11_data->mk_change_op, hdr->id) != 0) { + TRACE_ERROR("%s Must be currently active operation: '%s' vs '%s'\n", + __func__, ep11_data->mk_change_op, hdr->id); + rc = CKR_FUNCTION_FAILED; + pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock); + goto out; + } + + if (pthread_rwlock_unlock(&tokdata->hsm_mk_change_rwlock) != 0) { + TRACE_DEVEL("HSM-MK-change Unlock failed.\n"); + rc = CKR_CANT_LOCK; + goto out; + } + + switch (event_type) { + case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: + rc = ep11tok_mk_change_init_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_REENCIPHER: + rc = ep11tok_mk_change_reencipher(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: + rc = ep11tok_mk_change_finalize_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_FINALIZE: + rc = ep11tok_mk_change_finalize_cancel(tokdata, hdr, &info, FALSE); + break; + case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: + rc = ep11tok_mk_change_cancel_query(tokdata, hdr, &info); + break; + case EVENT_TYPE_MK_CHANGE_CANCEL: + rc = ep11tok_mk_change_finalize_cancel(tokdata, hdr, &info, TRUE); + break; + default: + rc = CKR_FUNCTION_NOT_SUPPORTED; + break; + } + +out: + hsm_mk_change_info_clean(&info); + + TRACE_DEVEL("%s rc: 0x%lx\n", __func__, rc); + return rc; +} + /* * Called by the event thread, on receipt of an event. * @@ -13641,6 +17388,15 @@ return ep11tok_handle_apqn_event(tokdata, event_type, (event_udev_apqn_data_t *)payload); + case EVENT_TYPE_MK_CHANGE_INITIATE_QUERY: + case EVENT_TYPE_MK_CHANGE_REENCIPHER: + case EVENT_TYPE_MK_CHANGE_FINALIZE_QUERY: + case EVENT_TYPE_MK_CHANGE_FINALIZE: + case EVENT_TYPE_MK_CHANGE_CANCEL_QUERY: + case EVENT_TYPE_MK_CHANGE_CANCEL: + return ep11tok_handle_mk_change_event(tokdata, event_type, event_flags, + payload, payload_len); + default: return CKR_FUNCTION_NOT_SUPPORTED; } @@ -13654,7 +17410,8 @@ * thread save way and gives back the previous one so that it is release when * no longer used (i.e. by a concurrently running thread). */ -static CK_RV refresh_target_info(STDLL_TokData_t *tokdata) +static CK_RV refresh_target_info(STDLL_TokData_t *tokdata, + CK_BBOOL wait_for_new_wk) { ep11_private_data_t *ep11_data = tokdata->private_data; volatile ep11_target_info_t *prev_info; @@ -13687,10 +17444,17 @@ if (rc != CKR_OK) goto error; - /* Setup the group target freshly with the current set of APQNs */ - rc = ep11tok_setup_target(tokdata, target_info); - if (rc != CKR_OK) - goto error; + if (ep11_data->mk_change_active) { + /* MK change active: Setup a single APQN target */ + rc = ep11tok_setup_single_target(tokdata, target_info, wait_for_new_wk); + if (rc != CKR_OK) + goto error; + } else { + /* Setup the group target freshly with the current set of APQNs */ + rc = ep11tok_setup_target(tokdata, target_info); + if (rc != CKR_OK) + goto error; + } /* Set the new one as the current one (locked against concurrent get's) */ if (pthread_rwlock_wrlock(&ep11_data->target_rwlock) != 0) { @@ -13809,7 +17573,7 @@ * object_mgr_create_final. */ static CK_RV update_ep11_attrs_from_blob(STDLL_TokData_t *tokdata, - SESSION *session, TEMPLATE *tmpl, + SESSION *session, OBJECT *key_obj, CK_BBOOL aes_xts) { ep11_private_data_t *ep11_data = tokdata->private_data; @@ -13820,6 +17584,8 @@ CK_ATTRIBUTE *attr, *blob_attr = NULL; CK_RV rc = CKR_OK; CK_ULONG i; + CK_BYTE *useblob, *blob; + size_t usebloblen; CK_ATTRIBUTE ibm_attrs[] = { { CKA_IBM_RESTRICTABLE, &restr, sizeof(restr) }, @@ -13838,18 +17604,23 @@ if (!ep11_data->pkey_wrap_supported) num_ibm_attrs -= 2; - if (template_attribute_get_non_empty(tmpl, CKA_IBM_OPAQUE, + if (template_attribute_get_non_empty(key_obj->template, CKA_IBM_OPAQUE, &blob_attr) != CKR_OK) { TRACE_ERROR("This key has no CKA_IBM_OPAQUE: should not occur!\n"); return CKR_FUNCTION_FAILED; } - RETRY_START(rc, tokdata) - rc = dll_m_GetAttributeValue(blob_attr->pValue, - (aes_xts ? blob_attr->ulValueLen / 2 : - blob_attr->ulValueLen), - ibm_attrs, num_ibm_attrs, target_info->target); - RETRY_END(rc, tokdata, session) + blob = blob_attr->pValue; + RETRY_SESSION_SINGLE_APQN_START(rc, tokdata) + RETRY_REENC_BLOB_START(tokdata, target_info, key_obj, + blob, blob_attr->ulValueLen, + useblob, usebloblen, rc) + rc = dll_m_GetAttributeValue(useblob, + aes_xts ? usebloblen / 2 : usebloblen, + ibm_attrs, num_ibm_attrs, + target_info->target); + RETRY_REENC_BLOB_END(tokdata, target_info, useblob, usebloblen, rc) + RETRY_SESSION_SINGLE_APQN_END(rc, tokdata, session) if (rc != CKR_OK) { rc = ep11_error_to_pkcs11_error(rc, NULL); @@ -13873,7 +17644,7 @@ return rc; } - rc = template_update_attribute(tmpl, attr); + rc = template_update_attribute(key_obj->template, attr); if (rc != CKR_OK) { free(attr); TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_specific.h opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_specific.h --- opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_specific.h 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_specific.h 2023-05-15 14:42:55.000000000 +0200 @@ -173,4 +173,6 @@ CK_BBOOL ep11tok_pkey_usage_ok(STDLL_TokData_t *tokdata, SESSION *session, CK_OBJECT_HANDLE hkey, CK_MECHANISM *mech); +CK_RV ep11tok_set_operation_state(STDLL_TokData_t *tokdata, SESSION *session); + #endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -13,7 +13,8 @@ -I${srcdir}/usr/lib/ep11_stdll -I${srcdir}/usr/lib/common \ -I${srcdir}/usr/include -I${top_builddir}/usr/lib/api \ -I${srcdir}/usr/lib/api -I${top_builddir}/usr/lib/config \ - -I${srcdir}/usr/lib/config + -I${srcdir}/usr/lib/config -I${srcdir}/usr/lib/hsm_mk_change \ + -I${top_builddir}/usr/lib/hsm_mk_change opencryptoki_stdll_libpkcs11_ep11_la_LDFLAGS = \ -shared -Wl,-z,defs,-Bsymbolic -lc -lpthread -lcrypto -lrt \ @@ -44,13 +45,6 @@ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ usr/lib/api/policyhelper.c usr/lib/config/configuration.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ - usr/lib/common/pqc_supported.c - -if ENABLE_LOCKS -opencryptoki_stdll_libpkcs11_ep11_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else -opencryptoki_stdll_libpkcs11_ep11_la_LDFLAGS += -litm -opencryptoki_stdll_libpkcs11_ep11_la_SOURCES += \ + usr/lib/common/pqc_supported.c \ + usr/lib/hsm_mk_change/hsm_mk_change.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c -endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11tok.conf opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11tok.conf --- opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/ep11tok.conf 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/ep11tok.conf 2023-05-15 14:42:55.000000000 +0200 @@ -72,7 +72,8 @@ # -------------------------------------------------------------------------- # # To optimize encrypt/decrypt and sign/verify performance, a corresponding -# protected key can be created for AES secure keys and added to the secure key. +# protected key can be created for AES and EC secure keys and added to the +# secure key. # This protected key is then used for certain mechanisms via CPACF, instead of # performing the function via the EP11 coprocessor. # IBM specific boolean attribute CKA_IBM_PROTKEY_EXTRACTABLE must be true to diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/new_host.c opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/new_host.c --- opencryptoki-3.20.0+dfsg/usr/lib/ep11_stdll/new_host.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ep11_stdll/new_host.c 2023-05-15 14:42:55.000000000 +0200 @@ -79,11 +79,16 @@ /* set trace info */ set_trace(t); - bt_init(&sltp->TokData->sess_btree, free); - bt_init(&sltp->TokData->object_map_btree, free); - bt_init(&sltp->TokData->sess_obj_btree, call_object_free); - bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); - bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + rc = bt_init(&sltp->TokData->sess_btree, free); + rc |= bt_init(&sltp->TokData->object_map_btree, free); + rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + if (rc != CKR_OK) { + TRACE_ERROR("Btree init failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", @@ -194,6 +199,11 @@ } else { CloseXProcLock(sltp->TokData); final_data_store(sltp->TokData); + bt_destroy(&sltp->TokData->sess_btree); + bt_destroy(&sltp->TokData->object_map_btree); + bt_destroy(&sltp->TokData->sess_obj_btree); + bt_destroy(&sltp->TokData->priv_token_obj_btree); + bt_destroy(&sltp->TokData->publ_token_obj_btree); } } @@ -1198,9 +1208,16 @@ rc = session_mgr_set_op_state(tokdata, sess, hEncryptionKey, hAuthenticationKey, pOperationState, ulOperationStateLen); - - if (rc != CKR_OK) + if (rc != CKR_OK) { TRACE_DEVEL("session_mgr_set_op_state() failed.\n"); + goto done; + } + + rc = ep11tok_set_operation_state(tokdata, sess); + if (rc != CKR_OK) { + TRACE_DEVEL("ep11tok_set_operation_state() failed.\n"); + goto done; + } done: TRACE_INFO("C_SetOperationState: rc = 0x%08lx, sess = %lu\n", @@ -2495,12 +2512,12 @@ length_only, sess->decr_ctx.key, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("ep11tok_decrypt_single() failed.\n"); } else { rc = ep11tok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("ep11tok_decrypt() failed.\n"); } @@ -2578,7 +2595,7 @@ rc = ep11tok_decrypt_update(tokdata, sess, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("ep11tok_decrypt_update() failed.\n"); done: @@ -2652,7 +2669,7 @@ } rc = ep11tok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("ep11tok_decrypt_final() failed.\n"); done: if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.c opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.c --- opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.c 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.c 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,968 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2022 + * + * 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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef OCK_TOOL +#include "pkcs_utils.h" +#else +#include "trace.h" +#endif +#include "hsm_mk_change.h" +#include "pkcs32.h" + +struct hsm_mk_change_op_hdr { + char id[6]; + uint32_t state; /* stored in big endian */ +}; + +struct hsm_mkvp_hdr { + uint32_t type; /* stored in big endian */ + uint32_t mkvp_len; /* stored in big endian */ + /* Followed by mkvp_len bytes MKVP. */ +}; + +static int hsm_mk_change_lock_fd = -1; + +CK_RV hsm_mk_change_lock_create(void) +{ + struct group *grp; + mode_t mode = (S_IRUSR | S_IRGRP); + + if (hsm_mk_change_lock_fd == -1) + hsm_mk_change_lock_fd = open(OCK_HSM_MK_CHANGE_LOCK_FILE, O_RDONLY); + + if (hsm_mk_change_lock_fd == -1) { + hsm_mk_change_lock_fd = open(OCK_HSM_MK_CHANGE_LOCK_FILE, + O_CREAT | O_RDONLY, mode); + + if (hsm_mk_change_lock_fd != -1) { + if (fchmod(hsm_mk_change_lock_fd, mode) == -1) { + TRACE_ERROR("%s fchmod(%s): %s\n", __func__, + OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); + goto error; + } + + grp = getgrnam(PKCS_GROUP); + if (grp != NULL) { + if (fchown(hsm_mk_change_lock_fd, -1, grp->gr_gid) == -1) { + TRACE_ERROR("%s fchown(%s): %s\n", __func__, + OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); + goto error; + } + } else { + TRACE_ERROR("%s getgrnam(): %s\n", __func__, strerror(errno)); + goto error; + } + } else { + TRACE_ERROR("%s open(%s): %s\n", __func__, + OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); + goto error; + } + } + + return CKR_OK; + +error: + if (hsm_mk_change_lock_fd != -1) + close(hsm_mk_change_lock_fd); + + return CKR_CANT_LOCK; +} + +void hsm_mk_change_lock_destroy(void) +{ + if (hsm_mk_change_lock_fd != -1) + close(hsm_mk_change_lock_fd); + hsm_mk_change_lock_fd = -1; +} + +CK_RV hsm_mk_change_lock(int exclusive) +{ + if (hsm_mk_change_lock_fd == -1) + return CKR_CANT_LOCK; + + if (flock(hsm_mk_change_lock_fd, exclusive ? LOCK_EX : LOCK_SH) != 0) { + TRACE_ERROR("%s flock(%s, %s): %s\n", __func__, + OCK_HSM_MK_CHANGE_LOCK_FILE, + exclusive ? "LOCK_EX" : "LOCK_SH", strerror(errno)); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV hsm_mk_change_unlock(void) +{ + if (hsm_mk_change_lock_fd == -1) + return CKR_CANT_LOCK; + + if (flock(hsm_mk_change_lock_fd, LOCK_UN) != 0) { + TRACE_ERROR("%s flock(%s, LOCK_UN): %s\n", __func__, + OCK_HSM_MK_CHANGE_LOCK_FILE, strerror(errno)); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV hsm_mk_change_apqns_flatten(const struct apqn *apqns, + unsigned int num_apqns, unsigned char *buff, + size_t *buff_len) +{ + size_t len = sizeof(uint32_t) + num_apqns * sizeof(struct apqn); + struct apqn *apqn; + unsigned int i; + + if (buff == NULL) { + *buff_len = len; + return CKR_OK; + } + + if (*buff_len < len) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *buff_len = len; + + TRACE_DEBUG("Num APQNs: %u\n", num_apqns); + + *((uint32_t *)buff) = htobe32(num_apqns); + buff += sizeof(uint32_t); + + for (i = 0; i < num_apqns; i++) { + TRACE_DEBUG("APQN %d: %02x.%04x\n", i, apqns[i].card, apqns[i].domain); + + apqn = (struct apqn *)buff; + apqn->card = htobe16(apqns[i].card); + apqn->domain = htobe16(apqns[i].domain); + buff += sizeof(struct apqn); + } + + return CKR_OK; +} + +CK_RV hsm_mk_change_apqns_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, struct apqn **apqns, + unsigned int *num_apqns) +{ + struct apqn *apqn; + unsigned int i; + CK_RV rc; + + if (buff_len < sizeof(uint32_t)) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *num_apqns = be32toh(*((uint32_t *)buff)); + buff += sizeof(uint32_t); + *bytes_read = sizeof(uint32_t); + + TRACE_DEBUG("Num APQNs: %u\n", *num_apqns); + + if (*num_apqns > 0) { + *apqns = calloc(*num_apqns, sizeof(struct apqn)); + if (*apqns == NULL) { + TRACE_ERROR("malloc failed\n"); + *num_apqns = 0; + return CKR_HOST_MEMORY; + } + } + + if (buff_len < sizeof(uint32_t) + *num_apqns * sizeof(struct apqn)) { + TRACE_ERROR("buffer too small\n"); + rc = CKR_BUFFER_TOO_SMALL; + goto error; + } + + for (i = 0; i < *num_apqns; i++) { + apqn = (struct apqn *)buff; + + (*apqns)[i].card = be16toh(apqn->card); + (*apqns)[i].domain = be16toh(apqn->domain); + buff += sizeof(struct apqn); + *bytes_read += sizeof(struct apqn); + + TRACE_DEBUG("APQN %d: %02x.%04x\n", i, (*apqns)[i].card, + (*apqns)[i].domain); + } + + return CKR_OK; + +error: + free(*apqns); + *apqns = NULL; + *num_apqns = 0; + + return rc; +} + +int hsm_mk_change_apqns_find(const struct apqn *apqns, unsigned int num_apqns, + unsigned short card, unsigned short domain) +{ + unsigned int i; + + for (i = 0; i < num_apqns; i++) { + if (apqns[i].card == card && apqns[i].domain == domain) + return 1; + } + + return 0; +} + +void hsm_mk_change_mkvps_clean(struct hsm_mkvp *mkvps, unsigned int num_mkvps) +{ + unsigned int i; + + for (i = 0; i < num_mkvps; i++) { + if (mkvps[i].mkvp != NULL) + free(mkvps[i].mkvp); + } + + memset(mkvps, 0, num_mkvps * sizeof(struct hsm_mkvp)); +} + +CK_RV hsm_mk_change_mkvps_flatten(const struct hsm_mkvp *mkvps, + unsigned int num_mkvps, unsigned char *buff, + size_t *buff_len) +{ + size_t len = sizeof(uint32_t); + struct hsm_mkvp_hdr *hdr; + unsigned int i; + + for (i = 0; i < num_mkvps; i++) + len += sizeof(struct hsm_mkvp_hdr) + mkvps[i].mkvp_len; + + if (buff == NULL) { + *buff_len = len; + return CKR_OK; + } + + if (*buff_len < len) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *buff_len = len; + + TRACE_DEBUG("Num MKVPs: %u\n", num_mkvps); + + *((uint32_t *)buff) = htobe32(num_mkvps); + buff += sizeof(uint32_t); + + for (i = 0; i < num_mkvps; i++) { + TRACE_DEBUG("MKVP %d: type: %d len %u\n", i, mkvps[i].type, + mkvps[i].mkvp_len); + TRACE_DEBUG_DUMP("MKVP: ", mkvps[i].mkvp, mkvps[i].mkvp_len); + + hdr = (struct hsm_mkvp_hdr *)buff; + hdr->type = htobe32(mkvps[i].type); + hdr->mkvp_len = htobe32(mkvps[i].mkvp_len); + buff += sizeof(struct hsm_mkvp_hdr); + + memcpy(buff, mkvps[i].mkvp, mkvps[i].mkvp_len); + buff += mkvps[i].mkvp_len; + } + + return CKR_OK; +} + +CK_RV hsm_mk_change_mkvps_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, struct hsm_mkvp **mkvps, + unsigned int *num_mkvps) +{ + struct hsm_mkvp_hdr *hdr; + unsigned int i; + CK_RV rc; + + if (buff_len < sizeof(uint32_t)) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *num_mkvps = be32toh(*((uint32_t *)buff)); + buff += sizeof(uint32_t); + buff_len -= sizeof(uint32_t); + *bytes_read = sizeof(uint32_t); + + TRACE_DEBUG("Num MKVPs: %u\n", *num_mkvps); + + if (*num_mkvps > 0) { + *mkvps = calloc(*num_mkvps, sizeof(struct hsm_mkvp)); + if (*mkvps == NULL) { + TRACE_ERROR("malloc failed\n"); + *num_mkvps = 0; + return CKR_HOST_MEMORY; + } + } + + for (i = 0; i < *num_mkvps; i++) { + if (buff_len < sizeof(struct hsm_mkvp_hdr)) { + TRACE_ERROR("buffer too small\n"); + rc = CKR_BUFFER_TOO_SMALL; + goto error; + } + + hdr = (struct hsm_mkvp_hdr *)buff; + (*mkvps)[i].type = be32toh(hdr->type); + (*mkvps)[i].mkvp_len = be32toh(hdr->mkvp_len); + buff += sizeof(struct hsm_mkvp_hdr); + buff_len -= sizeof(struct hsm_mkvp_hdr); + *bytes_read += sizeof(struct hsm_mkvp_hdr); + + if (buff_len < (*mkvps)[i].mkvp_len) { + TRACE_ERROR("buffer too small\n"); + rc = CKR_BUFFER_TOO_SMALL; + goto error; + } + + (*mkvps)[i].mkvp = calloc(1, (*mkvps)[i].mkvp_len); + if ((*mkvps)[i].mkvp == NULL) { + TRACE_ERROR("malloc failed\n"); + rc = CKR_HOST_MEMORY; + goto error; + } + + memcpy((*mkvps)[i].mkvp, buff, (*mkvps)[i].mkvp_len); + buff += (*mkvps)[i].mkvp_len; + buff_len -= (*mkvps)[i].mkvp_len; + *bytes_read += (*mkvps)[i].mkvp_len; + + TRACE_DEBUG("MKVP %d: type: %d len %u\n", i, (*mkvps)[i].type, + (*mkvps)[i].mkvp_len); + TRACE_DEBUG_DUMP("MKVP: ", (*mkvps)[i].mkvp, (*mkvps)[i].mkvp_len); + } + + return CKR_OK; + +error: + hsm_mk_change_mkvps_clean(*mkvps, *num_mkvps); + free(*mkvps); + *mkvps = NULL; + *num_mkvps = 0; + + return rc; +} + +const unsigned char *hsm_mk_change_mkvps_find(const struct hsm_mkvp *mkvps, + unsigned int num_mkvps, + enum hsm_mk_type type, + unsigned int mkvp_len) +{ + unsigned int i; + + for (i = 0; i < num_mkvps; i++) { + if (mkvps[i].type == type && + (mkvp_len == 0 || mkvps[i].mkvp_len == mkvp_len)) + return mkvps[i].mkvp; + } + + return NULL; +} + +void hsm_mk_change_info_clean(struct hsm_mk_change_info *info) +{ + unsigned int i; + + if (info->apqns != NULL) + free(info->apqns); + + if (info->mkvps != NULL) { + for (i = 0; i < info->num_mkvps; i++) { + if (info->mkvps[i].mkvp != NULL) + free(info->mkvps[i].mkvp); + } + free(info->mkvps); + } + + memset(info, 0, sizeof(*info)); +} + +CK_RV hsm_mk_change_info_flatten(const struct hsm_mk_change_info *info, + unsigned char *buff, size_t *buff_len) +{ + size_t apqns_len, mkvps_len; + CK_RV rc; + + rc = hsm_mk_change_apqns_flatten(info->apqns, info->num_apqns, + NULL, &apqns_len); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_mkvps_flatten(info->mkvps, info->num_mkvps, + NULL, &mkvps_len); + if (rc != CKR_OK) + return rc; + + if (buff == NULL) { + *buff_len = apqns_len + mkvps_len; + return CKR_OK; + } + + if (*buff_len < apqns_len + mkvps_len) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *buff_len = apqns_len + mkvps_len; + + rc = hsm_mk_change_apqns_flatten(info->apqns, info->num_apqns, + buff, &apqns_len); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_mkvps_flatten(info->mkvps, info->num_mkvps, + buff + apqns_len, &mkvps_len); + if (rc != CKR_OK) + return rc; + + return CKR_OK; +} + +CK_RV hsm_mk_change_info_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, + struct hsm_mk_change_info *info) +{ + size_t apqns_read = 0, mkvps_read = 0; + CK_RV rc; + + hsm_mk_change_info_clean(info); + + rc = hsm_mk_change_apqns_unflatten(buff, buff_len, &apqns_read, + &info->apqns, &info->num_apqns); + if (rc != CKR_OK) { + hsm_mk_change_info_clean(info); + return rc; + } + + rc = hsm_mk_change_mkvps_unflatten(buff + apqns_read, buff_len - apqns_read, + &mkvps_read, + &info->mkvps, &info->num_mkvps); + if (rc != CKR_OK) { + hsm_mk_change_info_clean(info); + return rc; + } + + *bytes_read = apqns_read + mkvps_read; + + return CKR_OK; +} + +CK_RV hsm_mk_change_slots_flatten(const CK_SLOT_ID *slots, + unsigned int num_slots, unsigned char *buff, + size_t *buff_len) +{ + size_t len = sizeof(uint32_t) + num_slots * sizeof(CK_SLOT_ID_32); + CK_SLOT_ID_32 *slot; + unsigned int i; + + if (buff == NULL) { + *buff_len = len; + return CKR_OK; + } + + if (*buff_len < len) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *buff_len = len; + + TRACE_DEBUG("Num Slots: %u\n", num_slots); + + *((uint32_t *)buff) = htobe32(num_slots); + buff += sizeof(uint32_t); + + for (i = 0; i < num_slots; i++) { + TRACE_DEBUG("Slot %d: %lu\n", i, slots[i]); + + slot = (CK_SLOT_ID_32 *)buff; + *slot = htobe32(slots[i]); + buff += sizeof(CK_SLOT_ID_32); + } + + return CKR_OK; +} + +CK_RV hsm_mk_change_slots_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, CK_SLOT_ID **slots, + unsigned int *num_slots) +{ + CK_SLOT_ID_32 *slot; + unsigned int i; + CK_RV rc; + + if (buff_len < sizeof(uint32_t)) { + TRACE_ERROR("buffer too small\n"); + return CKR_BUFFER_TOO_SMALL; + } + + *num_slots = be32toh(*((uint32_t *)buff)); + buff += sizeof(uint32_t); + *bytes_read = sizeof(uint32_t); + + TRACE_DEBUG("Num Slots: %u\n", *num_slots); + + if (*num_slots > 0) { + *slots = calloc(*num_slots, sizeof(CK_SLOT_ID)); + if (*slots == NULL) { + TRACE_ERROR("malloc failed\n"); + *num_slots = 0; + return CKR_HOST_MEMORY; + } + } + + if (buff_len < sizeof(uint32_t) + *num_slots * sizeof(CK_SLOT_ID_32)) { + TRACE_ERROR("buffer too small\n"); + rc = CKR_BUFFER_TOO_SMALL; + goto error; + } + + for (i = 0; i < *num_slots; i++) { + slot = (CK_SLOT_ID_32 *)buff; + (*slots)[i] = be32toh(*slot); + buff += sizeof(CK_SLOT_ID_32); + *bytes_read += sizeof(CK_SLOT_ID_32); + + TRACE_DEBUG("Slot %d: %lu\n", i, (*slots)[i]); + } + + return CKR_OK; + +error: + free(*slots); + *slots = NULL; + *num_slots = 0; + + return rc; +} + +void hsm_mk_change_op_clean(struct hsm_mk_change_op *op) +{ + hsm_mk_change_info_clean(&op->info); + if (op->slots != NULL) + free(op->slots); + memset(op, 0, sizeof(*op)); +} + +static void hsm_mk_change_op_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(PKCS_GROUP); // Obtain the group id + if (grp) { + // set ownership to pkcs11 group + if (fchown(file, -1, grp->gr_gid) != 0) { + goto error; + } + } else { + goto error; + } + + return; + +error: + TRACE_DEVEL("Unable to set permissions on file.\n"); +} + +static FILE* hsm_mk_change_op_open(const char *id, CK_SLOT_ID slot_id, + const char *mode) +{ + char hsm_mk_change_file[PATH_MAX]; + FILE *fp; + + if (slot_id != (CK_SLOT_ID)-1) { + if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s-%lu", + OCK_HSM_MK_CHANGE_PATH, id, slot_id) != 0) { + TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); + return NULL; + } + } else { + if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s", + OCK_HSM_MK_CHANGE_PATH, id) != 0) { + TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); + return NULL; + } + } + + TRACE_DEVEL("file to open: %s mode: %s\n", hsm_mk_change_file, mode); + + fp = fopen(hsm_mk_change_file, mode); + if (fp == NULL) { + TRACE_ERROR("%s fopen(%s, %s): %s\n", __func__, + hsm_mk_change_file, mode, strerror(errno)); + } + + return fp; +} + +CK_RV hsm_mk_change_op_save(const struct hsm_mk_change_op *op) +{ + struct hsm_mk_change_op_hdr *op_hdr; + size_t info_len = 0, slots_len, len; + unsigned char *buff = NULL; + FILE *fp = NULL; + CK_RV rc = CKR_OK; + + rc = hsm_mk_change_info_flatten(&op->info, NULL, &info_len); + if (rc != CKR_OK) + return rc; + + rc = hsm_mk_change_slots_flatten(op->slots, op->num_slots, NULL, + &slots_len); + if (rc != CKR_OK) + return rc; + + len = sizeof(struct hsm_mk_change_op_hdr) + info_len + slots_len; + + buff = calloc(1, len); + if (buff == NULL) { + TRACE_ERROR("malloc failed\n"); + return CKR_HOST_MEMORY; + } + + TRACE_DEBUG("Id: %s\n", op->id); + TRACE_DEBUG("State: %d\n", op->state); + op_hdr = (struct hsm_mk_change_op_hdr *)buff; + memcpy(op_hdr->id, op->id, sizeof(op_hdr->id)); + op_hdr->state = htobe32(op->state); + + rc = hsm_mk_change_info_flatten(&op->info, buff + sizeof(*op_hdr), + &info_len); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_slots_flatten(op->slots, op->num_slots, + buff + sizeof(*op_hdr) + info_len, + &slots_len); + if (rc != CKR_OK) + goto out; + + fp = hsm_mk_change_op_open(op->id, -1, "w"); + if (fp == NULL) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + hsm_mk_change_op_set_perm(fileno(fp)); + + if (fwrite(buff, len, 1, fp) != 1) { + TRACE_ERROR("fwrite(%s): %s\n", op->id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + +out: + free(buff); + if (fp != NULL) + fclose(fp); + return rc; +} + +CK_RV hsm_mk_change_op_load(const char *id, struct hsm_mk_change_op *op) +{ + struct hsm_mk_change_op_hdr *op_hdr; + struct stat sb; + size_t len, info_read = 0, slots_read; + FILE *fp; + unsigned char *buff = NULL; + CK_RV rc = CKR_OK; + + hsm_mk_change_op_clean(op); + + fp = hsm_mk_change_op_open(id, -1, "r"); + if (fp == NULL) + return CKR_FUNCTION_FAILED; + + if (fstat(fileno(fp), &sb)) { + TRACE_ERROR("fstat(%s): %s\n", op->id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + len = sb.st_size; + buff = calloc(1, len); + if (buff == NULL) { + TRACE_ERROR("malloc failed\n"); + rc = CKR_HOST_MEMORY; + goto out; + } + + if (fread(buff, len, 1, fp) != 1) { + TRACE_ERROR("fread(%s): %s\n", op->id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + op_hdr = (struct hsm_mk_change_op_hdr *)buff; + memcpy(op->id, op_hdr->id, sizeof(op_hdr->id)); + op->state = htobe32(op_hdr->state); + len -= sizeof(*op_hdr); + + TRACE_DEBUG("Id: %s\n", op->id); + TRACE_DEBUG("State: %d\n", op->state); + + rc = hsm_mk_change_info_unflatten(buff + sizeof(*op_hdr), len, &info_read, + &op->info); + if (rc != CKR_OK) + goto out; + + rc = hsm_mk_change_slots_unflatten(buff + sizeof(*op_hdr) + info_read, + len - info_read, &slots_read, + &op->slots, &op->num_slots); + if (rc != CKR_OK) + goto out; + + if (info_read + slots_read != len) { + TRACE_ERROR("Not all data read for file %s: len: %lu read: %lu\n", + op->id, len, info_read + slots_read); + rc = CKR_FUNCTION_FAILED; + goto out; + } + +out: + if (rc != CKR_OK) + hsm_mk_change_op_clean(op); + + if (buff != NULL) + free(buff); + fclose(fp); + return rc; +} + +CK_RV hsm_mk_change_op_create(struct hsm_mk_change_op *op) +{ + char hsm_mk_change_file[PATH_MAX]; + int fd; + CK_RV rc; + + if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/XXXXXX", + OCK_HSM_MK_CHANGE_PATH) != 0) { + TRACE_ERROR("HSM_MK_CHANGE directory path buffer overflow\n"); + return CKR_FUNCTION_FAILED; + } + + fd = mkstemp(hsm_mk_change_file); + if (fd < 0) { + TRACE_ERROR("mkstemp(%s) failed with: %s\n", hsm_mk_change_file, + strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + close(fd); /* written and permissions set by hsm_mk_change_op_save */ + + TRACE_DEVEL("created file: %s\n", hsm_mk_change_file); + + memcpy(op->id, &hsm_mk_change_file[strlen(hsm_mk_change_file) - 6], 6); + + rc = hsm_mk_change_op_save(op); + +out: + return rc; +} + +CK_RV hsm_mk_change_token_mkvps_save(const char *id, CK_SLOT_ID slot_id, + const struct hsm_mkvp *mkvps, + unsigned int num_mkvps) +{ + size_t len = 0; + unsigned char *buff = NULL; + FILE *fp = NULL; + CK_RV rc = CKR_OK; + + rc = hsm_mk_change_mkvps_flatten(mkvps, num_mkvps, NULL, &len); + if (rc != CKR_OK) + return rc; + + buff = calloc(1, len); + if (buff == NULL) { + TRACE_ERROR("malloc failed\n"); + return CKR_HOST_MEMORY; + } + + rc = hsm_mk_change_mkvps_flatten(mkvps, num_mkvps, buff, &len); + if (rc != CKR_OK) + goto out; + + fp = hsm_mk_change_op_open(id, slot_id, "w"); + if (fp == NULL) { + rc = CKR_FUNCTION_FAILED; + goto out; + } + + hsm_mk_change_op_set_perm(fileno(fp)); + + if (fwrite(buff, len, 1, fp) != 1) { + TRACE_ERROR("fwrite(%s-%lu): %s\n", id, slot_id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + +out: + free(buff); + if (fp != NULL) + fclose(fp); + return rc; +} + +CK_RV hsm_mk_change_token_mkvps_load(const char *id, CK_SLOT_ID slot_id, + struct hsm_mkvp **mkvps, + unsigned int *num_mkvps) +{ + struct stat sb; + size_t len, read = 0; + FILE *fp; + unsigned char *buff = NULL; + CK_RV rc = CKR_OK; + + fp = hsm_mk_change_op_open(id, slot_id, "r"); + if (fp == NULL) + return CKR_FUNCTION_FAILED; + + if (fstat(fileno(fp), &sb)) { + TRACE_ERROR("fstat(%s-%lu): %s\n", id, slot_id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + len = sb.st_size; + buff = calloc(1, len); + if (buff == NULL) { + TRACE_ERROR("malloc failed\n"); + rc = CKR_HOST_MEMORY; + goto out; + } + + if (fread(buff, len, 1, fp) != 1) { + TRACE_ERROR("fread(%s-%lu): %s\n", id, slot_id, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + rc = hsm_mk_change_mkvps_unflatten(buff, len, &read, mkvps, num_mkvps); + if (rc != CKR_OK) + goto out; + + if (read != len) { + TRACE_ERROR("Not all datta read for file %s-%lu: len: %lu read: %lu\n", + id, slot_id, len, read); + rc = CKR_FUNCTION_FAILED; + hsm_mk_change_mkvps_clean(*mkvps, *num_mkvps); + goto out; + } + +out: + if (buff != NULL) + free(buff); + fclose(fp); + return rc; +} + +CK_RV hsm_mk_change_op_remove(const char *id) +{ + char hsm_mk_change_file[PATH_MAX]; + struct dirent **namelist; + CK_RV rc = CKR_OK; + int n, i; + + n = scandir(OCK_HSM_MK_CHANGE_PATH, &namelist, NULL, alphasort); + if (n == -1) { + TRACE_ERROR("scandir(%s) failed with: %s\n", OCK_HSM_MK_CHANGE_PATH, + strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + for (i = 0; i < n ; i++) { + if (namelist[i]->d_name[0] == '.') + continue; + if (strncmp(namelist[i]->d_name, id, strlen(id)) != 0) + continue; + + if (ock_snprintf(hsm_mk_change_file, PATH_MAX, "%s/%s", + OCK_HSM_MK_CHANGE_PATH, namelist[i]->d_name) != 0) { + TRACE_ERROR("HSM_MK_CHANGE file path buffer overflow\n"); + rc = CKR_FUNCTION_FAILED; + break; + } + + TRACE_DEVEL("remove %s\n", hsm_mk_change_file); + + if (remove(hsm_mk_change_file) != 0) { + TRACE_ERROR("remove(%s) failed with: %s\n", hsm_mk_change_file, + strerror(errno)); + rc = CKR_FUNCTION_FAILED; + break; + } + } + + for (i = 0; i < n ; i++) + free(namelist[i]); + free(namelist); + + return rc; +} + +CK_RV hsm_mk_change_op_iterate(CK_RV (*cb)(struct hsm_mk_change_op *op, + void *private), void *private) +{ + struct hsm_mk_change_op op; + struct dirent **namelist; + CK_RV rc = CKR_OK; + int n, i; + + memset(&op, 0, sizeof(op)); + + n = scandir(OCK_HSM_MK_CHANGE_PATH, &namelist, NULL, alphasort); + if (n == -1) { + TRACE_ERROR("scandir(%s) failed with: %s\n", OCK_HSM_MK_CHANGE_PATH, + strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + for (i = 0; i < n ; i++) { + if (namelist[i]->d_name[0] == '.') + continue; + if (strlen(namelist[i]->d_name) > 6 && namelist[i]->d_name[6] == '-') + continue; + + rc = hsm_mk_change_op_load(namelist[i]->d_name, &op); + if (rc != CKR_OK) + break; + + rc = cb(&op, private); + hsm_mk_change_op_clean(&op); + if (rc != CKR_OK) + break; + } + + for (i = 0; i < n ; i++) + free(namelist[i]); + free(namelist); + + return rc; +} + diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.h opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.h --- opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.h 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.h 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,114 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2022 + * + * 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 HSM_MK_CHANGE_H +#define HSM_MK_CHANGE_H + +enum hsm_mk_change_state { + HSM_MK_CH_STATE_INITIAL = 0, + HSM_MK_CH_STATE_REENCIPHERING = 10, /* Tokens are reenciphering the keys */ + HSM_MK_CH_STATE_REENCIPHERED = 11, /* Keys are reenciphered */ + HSM_MK_CH_STATE_FINALIZING = 20, /* Tokens are finalizing the MK change */ + HSM_MK_CH_STATE_CANCELING = 30, /* Tokens are canceling the MK change */ + HSM_MK_CH_STATE_ERROR = 100, +}; + +struct apqn { + unsigned short card; + unsigned short domain; +}; + +enum hsm_mk_type { + HSM_MK_TYPE_EP11 = 1, + HSM_MK_TYPE_CCA_SYM = 2, + HSM_MK_TYPE_CCA_ASYM = 3, + HSM_MK_TYPE_CCA_AES = 4, + HSM_MK_TYPE_CCA_APKA = 5, +}; + +#define HSM_MK_TYPE_MAX HSM_MK_TYPE_CCA_APKA + +struct hsm_mkvp { + enum hsm_mk_type type; + unsigned int mkvp_len; + unsigned char *mkvp; +}; + +struct hsm_mk_change_info { + unsigned int num_apqns; + struct apqn *apqns; + unsigned int num_mkvps; + struct hsm_mkvp *mkvps; +}; + +struct hsm_mk_change_op { + char id[7]; + enum hsm_mk_change_state state; + struct hsm_mk_change_info info; + CK_SLOT_ID *slots; + unsigned int num_slots; +}; + +CK_RV hsm_mk_change_apqns_flatten(const struct apqn *apqns, + unsigned int num_apqns, unsigned char *buff, + size_t *buff_len); +CK_RV hsm_mk_change_apqns_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, struct apqn **apqns, + unsigned int *num_apqns); +int hsm_mk_change_apqns_find(const struct apqn *apqns, unsigned int num_apqns, + unsigned short card, unsigned short domain); + +void hsm_mk_change_mkvps_clean(struct hsm_mkvp *mkvps, unsigned int num_mkvps); +CK_RV hsm_mk_change_mkvps_flatten(const struct hsm_mkvp *mkvps, + unsigned int num_mkvps, unsigned char *buff, + size_t *buff_len); +CK_RV hsm_mk_change_mkvps_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, struct hsm_mkvp **mkvps, + unsigned int *num_mkvps); +const unsigned char *hsm_mk_change_mkvps_find(const struct hsm_mkvp *mkvps, + unsigned int num_mkvps, + enum hsm_mk_type type, + unsigned int mkvp_len); + +void hsm_mk_change_info_clean(struct hsm_mk_change_info *info); +CK_RV hsm_mk_change_info_flatten(const struct hsm_mk_change_info *info, + unsigned char *buff, size_t *buff_len); +CK_RV hsm_mk_change_info_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, + struct hsm_mk_change_info *info); + +CK_RV hsm_mk_change_slots_flatten(const CK_SLOT_ID *slots, + unsigned int num_slots, unsigned char *buff, + size_t *buff_len); +CK_RV hsm_mk_change_slots_unflatten(const unsigned char *buff, size_t buff_len, + size_t *bytes_read, CK_SLOT_ID **slots, + unsigned int *num_slots); + +void hsm_mk_change_op_clean(struct hsm_mk_change_op *op); +CK_RV hsm_mk_change_op_save(const struct hsm_mk_change_op *op); +CK_RV hsm_mk_change_op_load(const char *id, struct hsm_mk_change_op *op); +CK_RV hsm_mk_change_op_create(struct hsm_mk_change_op *op); +CK_RV hsm_mk_change_op_remove(const char *id); +CK_RV hsm_mk_change_op_iterate(CK_RV (*cb)(struct hsm_mk_change_op *op, + void *private), void *private); + +CK_RV hsm_mk_change_token_mkvps_save(const char *id, CK_SLOT_ID slot_id, + const struct hsm_mkvp *mkvps, + unsigned int num_mkvps); +CK_RV hsm_mk_change_token_mkvps_load(const char *id, CK_SLOT_ID slot_id, + struct hsm_mkvp **mkvps, + unsigned int *num_mkvps); + +CK_RV hsm_mk_change_lock_create(void); +void hsm_mk_change_lock_destroy(void); +CK_RV hsm_mk_change_lock(int exclusive); +CK_RV hsm_mk_change_unlock(void); + + +#endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.mk opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.mk --- opencryptoki-3.20.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.mk 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/hsm_mk_change/hsm_mk_change.mk 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1 @@ +noinst_HEADERS += usr/lib/hsm_mk_change/hsm_mk_change.h diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/ica_s390_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/ica_s390_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/ica_s390_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/ica_s390_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -38,13 +38,10 @@ usr/lib/ica_s390_stdll/ica_specific.c usr/lib/common/dlist.c \ usr/lib/common/mech_openssl.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ - usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c + usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ + usr/lib/common/btree.c usr/lib/common/sess_mgr.c -if ENABLE_LOCKS +if !HAVE_ALT_FIX_FOR_CVE_2022_4304 opencryptoki_stdll_libpkcs11_ica_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else -opencryptoki_stdll_libpkcs11_ica_la_LDFLAGS += -litm -opencryptoki_stdll_libpkcs11_ica_la_SOURCES += \ - usr/lib/common/btree.c usr/lib/common/sess_mgr.c + usr/lib/ica_s390_stdll/rsa_sup_mul.c endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/ica_specific.c opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/ica_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/ica_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/ica_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -46,6 +46,7 @@ #include #endif #include +#include #define ICA_MAX_MECH_LIST_ENTRIES 120 @@ -243,6 +244,14 @@ static ica_sha3_512_t p_ica_sha3_512; #endif +#ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 +int ossl_bn_rsa_do_unblind(const unsigned char *intermediate, + const BIGNUM *unblind, + const unsigned char *to_mod, + unsigned char *buf, int num, + BN_MONT_CTX *m_ctx, BN_ULONG n0); +#endif + struct phdr_cb_data { void *handle; }; @@ -420,6 +429,106 @@ return CKR_OK; } +typedef struct { + struct openssl_ex_data openssl_ex_data; /* This must be the first field ! */ + ica_rsa_key_mod_expo_t *modexpoKey; + ica_rsa_key_crt_t *crtKey; + ICA_EC_KEY *eckey; + unsigned int ec_privlen; + BN_BLINDING *blinding; + BN_MONT_CTX *blinding_mont_ctx; +#ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 + BN_ULONG blinding_mont_ctx_n0; +#endif +} ica_ex_data_t; + +void ica_free_ex_data(OBJECT *obj, void *ex_data, size_t ex_data_len) +{ + ica_ex_data_t *data = ex_data; + + if (ex_data == NULL || ex_data_len < sizeof(ica_ex_data_t)) + return; + + if (data->modexpoKey != NULL) { + free(data->modexpoKey->modulus); + free(data->modexpoKey->exponent); + free(data->modexpoKey); + data->modexpoKey = NULL; + } + + if (data->crtKey != NULL) { + free(data->crtKey->p); + free(data->crtKey->q); + free(data->crtKey->dp); + free(data->crtKey->dq); + free(data->crtKey->qInverse); + free(data->crtKey); + data->crtKey = NULL; + } + + if (data->eckey != NULL) { + p_ica_ec_key_free(data->eckey); + data->eckey = NULL; + data->ec_privlen = 0; + } + + if (data->blinding != NULL) { + BN_BLINDING_free(data->blinding); + data->blinding = NULL; + } + if (data->blinding_mont_ctx != NULL) { + BN_MONT_CTX_free(data->blinding_mont_ctx); + data->blinding_mont_ctx = NULL; + } +#ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 + data->blinding_mont_ctx_n0 = 0; +#endif + + openssl_free_ex_data(obj, ex_data, ex_data_len); +} + +static CK_BBOOL ica_need_wr_lock_rsa_pubkey(OBJECT *obj, void *ex_data, + size_t ex_data_len) +{ + ica_ex_data_t *data = ex_data; + + UNUSED(obj); + + if (ex_data == NULL || ex_data_len < sizeof(ica_private_data_t)) + return FALSE; + + return data->modexpoKey == NULL; +} + +static CK_BBOOL ica_need_wr_lock_rsa_privkey(OBJECT *obj, void *ex_data, + size_t ex_data_len) +{ + ica_ex_data_t *data = ex_data; + + UNUSED(obj); + + if (ex_data == NULL || ex_data_len < sizeof(ica_private_data_t)) + return FALSE; + + if (data->blinding == NULL || data->blinding_mont_ctx == NULL) + return TRUE; + + return data->modexpoKey == NULL && data->crtKey == NULL; +} + +static CK_BBOOL ica_need_wr_lock_ec_key(OBJECT *obj, void *ex_data, + size_t ex_data_len) +{ + ica_ex_data_t *data = ex_data; + + UNUSED(obj); + + if (ex_data == NULL || ex_data_len < sizeof(ica_private_data_t)) + return FALSE; + + return data->eckey == NULL; +} + // count_ones_in_byte: for use in adjust_des_key_parity_bits below static CK_BYTE count_ones_in_byte(CK_BYTE byte) { @@ -451,10 +560,12 @@ } } -CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **des_key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; @@ -1774,7 +1885,7 @@ crtkey->key_length = modulus->ulValueLen; /* buffers pointed by p, q, dp, dq and qInverse in struct - * ica_rsa_key_crt_t must be of size key_legth/2 or larger. + * ica_rsa_key_crt_t must be of size key_length/2 or larger. * p, dp and qInverse have an additional 8-byte padding. */ /* need to allocate the buffers. Also, all fields are @@ -1834,6 +1945,12 @@ crtkey->qInverse + (crtkey->key_length / 2) + 8 - coeff->ulValueLen; memcpy(ptr, coeff->pValue, coeff->ulValueLen); + /* If p < q, swap and recalculate now */ + if (ica_rsa_crt_key_check(crtkey) > 1) { + TRACE_ERROR("ica_rsa_crt_key_check failed\n"); + goto err_crtkey; + } + return crtkey; } @@ -1848,6 +1965,81 @@ return NULL; } +static CK_RV rsa_calc_private_exponent(ica_rsa_key_mod_expo_t *publKey, + ica_rsa_key_crt_t *privKey, + TEMPLATE *priv_tmpl) +{ + BIGNUM *d, *e = NULL, *p = NULL, *q = NULL; + CK_ATTRIBUTE *attr = NULL; + int len; + CK_BYTE *buff = NULL; + CK_RV rc = CKR_OK; + + /* + * Calculate ϕ(n) = (p − 1) * (q − 1) = n − p − q + 1. + * Then d = e ^−1 mod ϕ(n) + */ + d = BN_bin2bn(publKey->modulus, publKey->key_length, NULL); + e = BN_bin2bn(publKey->exponent, publKey->key_length, NULL); + p = BN_bin2bn(privKey->p + 8, privKey->key_length / 2, NULL); + q = BN_bin2bn(privKey->q, privKey->key_length / 2, NULL); + if (d == NULL || e == NULL || p == NULL || q == NULL) { + TRACE_DEVEL("BN_bin2bn failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (BN_sub(d, d, p) != 1 || + BN_sub(d, d, q) != 1 || + BN_add_word(d, 1) != 1 || + BN_mod_inverse(d, e, d, NULL) == NULL) { + TRACE_DEVEL("BN_sub/BN_add_word/BN_mod_inverse failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + len = BN_num_bytes(d); + buff = calloc(len, 1); + if (buff == NULL) { + TRACE_DEVEL("calloc failed\n"); + rc = CKR_HOST_MEMORY; + goto done; + } + + if (BN_bn2bin(d, buff) != len) { + TRACE_DEVEL("BN_bn2bin failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = build_attribute(CKA_PRIVATE_EXPONENT, buff, len, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + rc = template_update_attribute(priv_tmpl, attr); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + goto done; + } + attr = NULL; + +done: + if (d != NULL) + BN_free(d); + if (e != NULL) + BN_free(e); + if (p != NULL) + BN_free(p); + if (q != NULL) + BN_free(q); + if (buff != NULL) + free(buff); + if (attr != NULL) + free(attr); + + return rc; +} // static CK_RV ica_specific_rsa_keygen(STDLL_TokData_t *tokdata, @@ -2119,6 +2311,13 @@ } attr = NULL; + /* Calculate the private exponent and add it */ + rc = rsa_calc_private_exponent(publKey, privKey, priv_tmpl); + if (rc != CKR_OK) { + TRACE_ERROR("rsa_calc_private_exponent failed\n"); + goto privkey_cleanup; + } + // exponent 1: d mod(p-1) // tmpsize = privKey->key_length / 2; @@ -2240,6 +2439,364 @@ return rc; } +/* + * ICA token private data used by mod-expo callback function for generating the + * blinding factor by BN_BLINDING_create_param() or within BN_BLINDING_update() + * when a new blinding factor is generated after 32 requests. + * This variable must be thread local! + */ +static __thread ica_private_data_t *ica_blinding_private_data = NULL; + +static int ica_blinding_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx) +{ + ica_private_data_t *ica_data = ica_blinding_private_data; + ica_rsa_key_mod_expo_t ica_mode_expo; + unsigned char *buffer, *in, *out; + size_t size; + int rc = 0; + + if (ica_data == NULL) + return 0; + + size = BN_num_bytes(m); + buffer = calloc(1, 4 * size); + if (buffer == NULL) { + TRACE_ERROR("Failed to allocate a buffer for libica mod-expo\n"); + goto out; + } + + ica_mode_expo.key_length = size; + ica_mode_expo.modulus = buffer; + ica_mode_expo.exponent = buffer + size; + + in = buffer + 2 * size; + out = buffer + 3 * size; + + if (BN_bn2binpad(a, in, size) == -1 || + BN_bn2binpad(p, ica_mode_expo.exponent, size) == -1 || + BN_bn2binpad(m, ica_mode_expo.modulus, size) == -1) { + TRACE_ERROR("BN_bn2binpad failed\n"); + goto out; + } + + rc = ica_rsa_mod_expo(ica_data->adapter_handle, in, &ica_mode_expo, out); + if (rc != 0) { + TRACE_ERROR("ica_rsa_mod_expo failed with: %s\n", strerror(rc)); + rc = 0; + goto out; + } + + if (BN_bin2bn(out, size, r) == NULL) { + TRACE_ERROR("BN_bin2bn failed\n"); + goto out; + } + + rc = 1; + +out: + if (buffer != NULL) { + OPENSSL_cleanse(buffer, 4 * size); + free(buffer); + } + + /* Use software fallback if libica operation failed */ + return rc != 1 ? BN_mod_exp_mont(r, a, p, m, ctx, m_ctx) : 1; +} + +#ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 + +#ifdef SIXTY_FOUR_BIT_LONG + #define BN_MASK2 (0xffffffffffffffffL) +#endif +#ifdef SIXTY_FOUR_BIT + #define BN_MASK2 (0xffffffffffffffffLL) +#endif +#ifdef THIRTY_TWO_BIT + #error "Not supported" +#endif + +static CK_RV ica_calc_blinding_mont_ctx_n0(STDLL_TokData_t *tokdata, + ica_ex_data_t *ex_data, + BN_CTX *bn_ctx, + CK_ATTRIBUTE *modulus) +{ + BIGNUM *R = NULL, *Ri = NULL, *tmod = NULL; + BN_ULONG word; + + UNUSED(tokdata); + + /* Calculate blinding_mont_ctx_n0, BN_MONT_CTX is opaque */ + R = BN_CTX_get(bn_ctx); + Ri = BN_CTX_get(bn_ctx); + tmod = BN_CTX_get(bn_ctx); + if (R == NULL || Ri == NULL || tmod == NULL) { + TRACE_ERROR("BN_CTX_get failed\n"); + return CKR_FUNCTION_FAILED; + } + + BN_zero(R); + if (!BN_set_bit(R, BN_BITS2)) { + TRACE_ERROR("BN_set_bit failed\n"); + return CKR_FUNCTION_FAILED; + } + + memcpy(&word, ((CK_BYTE *)modulus->pValue) + modulus->ulValueLen - + sizeof(BN_ULONG), sizeof(word)); + if (!BN_set_word(tmod, word)) { + TRACE_ERROR("BN_set_word failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (BN_is_one(tmod)) + BN_zero(Ri); + else if ((BN_mod_inverse(Ri, R, tmod, bn_ctx)) == NULL) { + TRACE_ERROR("BN_mod_inverse failed\n"); + return CKR_FUNCTION_FAILED; + } + if (!BN_lshift(Ri, Ri, BN_BITS2)) { + TRACE_ERROR("BN_lshift failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (!BN_is_zero(Ri)) { + if (!BN_sub_word(Ri, 1)) { + TRACE_ERROR("BN_sub_word failed\n"); + return CKR_FUNCTION_FAILED; + } + } else { + if (!BN_set_word(Ri, BN_MASK2)) { + TRACE_ERROR("BN_set_word failed\n"); + return CKR_FUNCTION_FAILED; + } + } + + if (!BN_div(Ri, NULL, Ri, tmod, bn_ctx)) { + TRACE_ERROR("BN_div failed\n"); + return CKR_FUNCTION_FAILED; + } + + ex_data->blinding_mont_ctx_n0 = BN_get_word(Ri); + + return CKR_OK; +} +#endif + +static CK_RV ica_blinding_setup(STDLL_TokData_t *tokdata, OBJECT *key_obj, + ica_ex_data_t *ex_data, BN_CTX *bn_ctx) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_ATTRIBUTE *modulus = NULL, *pub_exp = NULL; + CK_RV rc = CKR_OK; + BIGNUM *n, *e; + + /* Get modulus a BIGNUM */ + rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, + &modulus); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get CKA_MODULUS\n"); + goto done; + } + + n = BN_CTX_get(bn_ctx); + if (n == NULL || + BN_bin2bn(modulus->pValue, modulus->ulValueLen, n) == NULL) { + TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for modulus\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Get public exponent a BIGNUM */ + rc = template_attribute_get_non_empty(key_obj->template, + CKA_PUBLIC_EXPONENT, &pub_exp); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get CKA_PUBLIC_EXPONENT\n"); + goto done; + } + + e = BN_CTX_get(bn_ctx); + if (e == NULL || + BN_bin2bn(pub_exp->pValue, pub_exp->ulValueLen, e) == NULL) { + TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for publ-exponent\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + BN_set_flags(n, BN_FLG_CONSTTIME); + + /* Create Montgomery context */ + ex_data->blinding_mont_ctx = BN_MONT_CTX_new(); + if (ex_data->blinding_mont_ctx == NULL) { + TRACE_ERROR("BN_MONT_CTX_new failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (BN_MONT_CTX_set(ex_data->blinding_mont_ctx, n, bn_ctx) != 1) { + TRACE_ERROR("BN_MONT_CTX_set failed\n"); + rc = CKR_FUNCTION_FAILED; + BN_MONT_CTX_free(ex_data->blinding_mont_ctx); + ex_data->blinding_mont_ctx = NULL; + goto done; + } + +#ifndef HAVE_ALT_FIX_FOR_CVE2022_4304 + rc = ica_calc_blinding_mont_ctx_n0(tokdata, ex_data, bn_ctx, modulus); + if (rc != CKR_OK) { + TRACE_ERROR("ica_calc_blinding_mont_ctx_n0 failed\n"); + goto done; + } +#endif + + /* + * BN_BLINDING_create_param() calls the ica_blinding_bn_mod_exp() + * callback which needs to know the ICA token private data. + */ + ica_blinding_private_data = ica_data; + + ex_data->blinding = BN_BLINDING_create_param(NULL, e, n, bn_ctx, + ica_blinding_bn_mod_exp, + ex_data->blinding_mont_ctx); + if (ex_data->blinding == NULL) { + TRACE_ERROR("BN_BLINDING_create_param failed\n"); + rc = CKR_FUNCTION_FAILED; + BN_MONT_CTX_free(ex_data->blinding_mont_ctx); + ex_data->blinding_mont_ctx = NULL; + goto done; + } + +done: + return rc; +} + +static CK_RV ica_blinding_convert(STDLL_TokData_t *tokdata, + ica_ex_data_t *ex_data, BN_CTX *bn_ctx, + CK_BYTE *in_data, CK_BYTE *out_data, + CK_ULONG data_len, BIGNUM **unblind) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + BIGNUM *bn_data = NULL; + int ret; + + bn_data = BN_CTX_get(bn_ctx); + if (bn_data == NULL || + BN_bin2bn(in_data, data_len, bn_data) == NULL) { + TRACE_ERROR("BN_CTX_get/BN_bin2bn failed\n"); + return CKR_FUNCTION_FAILED; + } + + *unblind = BN_CTX_get(bn_ctx); + if (*unblind == NULL) { + TRACE_ERROR("BN_CTX_get failed for unblind factor\n"); + return CKR_FUNCTION_FAILED; + } + BN_set_flags(*unblind, BN_FLG_CONSTTIME); + + if (!BN_BLINDING_lock(ex_data->blinding)) { + TRACE_ERROR("BN_BLINDING_lock failed\n"); + return CKR_FUNCTION_FAILED; + } + + /* BN_BLINDING_convert_ex() calls BN_BLINDING_update() which may call + * BN_BLINDING_create_param() to generate a new blinding factor. This + * calls the ica_blinding_bn_mod_exp() callback which needs to know + * the ICA token private data. + */ + ica_blinding_private_data = ica_data; + + ret = BN_BLINDING_convert_ex(bn_data, *unblind, ex_data->blinding, bn_ctx); + BN_BLINDING_unlock(ex_data->blinding); + if(ret != 1) { + TRACE_ERROR("BN_BLINDING_convert_ex failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (BN_bn2binpad(bn_data, out_data, data_len) != (int)data_len) { + TRACE_ERROR("BN_bn2binpad failed\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +static CK_RV ica_blinding_invert(STDLL_TokData_t *tokdata, OBJECT *key_obj, + ica_ex_data_t *ex_data, BN_CTX *bn_ctx, + CK_BYTE *in_data, CK_BYTE *out_data, + CK_ULONG data_len, BIGNUM *unblind) +{ +#ifdef HAVE_ALT_FIX_FOR_CVE2022_4304 + int rc; + BIGNUM *bn_data = NULL; + + UNUSED(tokdata); + UNUSED(key_obj); + + bn_data = BN_CTX_get(bn_ctx); + if (bn_data == NULL || + BN_bin2bn(in_data, data_len, bn_data) == NULL) { + TRACE_ERROR("BN_CTX_get/BN_bin2bn failed\n"); + return CKR_FUNCTION_FAILED; + } + BN_set_flags(bn_data, BN_FLG_CONSTTIME); + + /* + * BN_BLINDING_invert_ex is constant-time since OpenSSL commit + * https://github.com/openssl/openssl/commit/f06ef1657a3d4322153b26231a7afa3d55724e52 + * "Alternative fix for CVE-2022-4304". Care must be taken that bn_data + * has flag BN_FLG_CONSTTIME set. + * + * Commits for OpenSSL releases: + * - OpenSSL 1.1.1u: + * https://github.com/openssl/openssl/commit/3f499b24f3bcd66db022074f7e8b4f6ee266a3ae + * - OpenSSL 3.0.9: + * https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * - OpenSSl 3.1.1: + * https://github.com/openssl/openssl/commit/550a16247e899363ef973aa08623f9b19bb636fb + */ + rc = BN_BLINDING_invert_ex(bn_data, unblind, ex_data->blinding, bn_ctx); + if (rc != 1) { + TRACE_ERROR("BN_BLINDING_invert_ex failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (BN_bn2binpad(bn_data, out_data, data_len) != (int)data_len) { + TRACE_ERROR("BN_bn2binpad failed\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +#else + CK_ATTRIBUTE *modulus = NULL; + int rc; + + UNUSED(tokdata); + UNUSED(bn_ctx); + + /* Get modulus */ + rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, + &modulus); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get CKA_MODULUS\n"); + return rc; + } + + if (modulus->ulValueLen != data_len) { + TRACE_ERROR("Size of data is not size of modulus\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ossl_bn_rsa_do_unblind(in_data, unblind, modulus->pValue, + out_data, data_len, ex_data->blinding_mont_ctx, + ex_data->blinding_mont_ctx_n0); + if (rc <= 0) { + TRACE_ERROR("ossl_bn_rsa_do_unblind failed\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +#endif +} // // @@ -2249,25 +2806,37 @@ CK_BYTE *out_data, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + ica_ex_data_t *ex_data = NULL; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *pub_exp = NULL; CK_ATTRIBUTE *mod_bits = NULL; ica_rsa_key_mod_expo_t *publKey = NULL; CK_RV rc; - /* mech_sra.c:ckm_rsa_encrypt accepts only CKO_PUBLIC_KEY */ - template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); - template_attribute_get_non_empty(key_obj->template, CKA_MODULUS_BITS, - &mod_bits); - template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, - &pub_exp); + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(ica_ex_data_t), + ica_need_wr_lock_rsa_pubkey, ica_free_ex_data); + if (rc != CKR_OK) + return rc; - publKey = rsa_convert_mod_expo_key(modulus, mod_bits, pub_exp); - if (publKey == NULL) { - TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); - rc = CKR_FUNCTION_FAILED; - goto done; + if (ex_data->modexpoKey == NULL) { + /* mech_sra.c:ckm_rsa_encrypt accepts only CKO_PUBLIC_KEY */ + template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, + &modulus); + template_attribute_get_non_empty(key_obj->template, CKA_MODULUS_BITS, + &mod_bits); + template_attribute_get_non_empty(key_obj->template, CKA_PUBLIC_EXPONENT, + &pub_exp); + + ex_data->modexpoKey = rsa_convert_mod_expo_key(modulus, mod_bits, + pub_exp); + if (ex_data->modexpoKey == NULL) { + TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } } + publKey = ex_data->modexpoKey; /* in_data must be in big endian format. 'in_data' size in bits must not * exceed the bit length of the key, and size in bytes must @@ -2276,7 +2845,7 @@ if (publKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_DATA_LEN_RANGE; - goto cleanup_pubkey; + goto done; } rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, publKey, out_data); switch (rc) { @@ -2301,12 +2870,9 @@ break; } -cleanup_pubkey: - free(publKey->modulus); - free(publKey->exponent); - free(publKey); - done: + object_ex_data_unlock(key_obj); + return rc; } @@ -2318,6 +2884,7 @@ CK_BYTE *out_data, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + ica_ex_data_t *ex_data = NULL; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *prime1 = NULL; CK_ATTRIBUTE *prime2 = NULL; @@ -2327,134 +2894,167 @@ CK_ATTRIBUTE *priv_exp = NULL; ica_rsa_key_crt_t *crtKey = NULL; ica_rsa_key_mod_expo_t *modexpoKey = NULL; + BN_CTX *bn_ctx = NULL; + BIGNUM *unblind = NULL; + unsigned char *buff = NULL; CK_RV rc; - /* mech_rsa.c:ckm_rsa_decrypt accepts only CKO_PRIVATE_KEY, - * but Private Key can have 2 representations (see PKCS#1): - * - Modulus + private exponent - * - p, q, dp, dq and qInv (CRT format) - * The former should use ica_rsa_key_mod_expo_t and the latter - * ica_rsa_key_crt_t. Detect what representation this - * key_obj has and use the proper convert function */ - - template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, &modulus); - template_attribute_get_non_empty(key_obj->template, CKA_PRIVATE_EXPONENT, - &priv_exp); - template_attribute_get_non_empty(key_obj->template, CKA_PRIME_1, &prime1); - template_attribute_get_non_empty(key_obj->template, CKA_PRIME_2, &prime2); - template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_1, &exp1); - template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_2, &exp2); - template_attribute_get_non_empty(key_obj->template, CKA_COEFFICIENT, - &coeff); - - /* Need to check for CRT Key format *BEFORE* check for mod_expo key, - * that's because opencryptoki *HAS* a CKA_PRIVATE_EXPONENT attribute - * even in CRT keys (but with zero length) */ - - if (modulus && prime1 && prime2 && exp1 && exp2 && coeff ) { - /* ica_rsa_key_crt_t representation */ - crtKey = - rsa_convert_crt_key(modulus, prime1, prime2, exp1, exp2, coeff); - if (crtKey == NULL) { - TRACE_ERROR("rsa_convert_crt_key failed\n"); - rc = CKR_FUNCTION_FAILED; + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(ica_ex_data_t), + ica_need_wr_lock_rsa_privkey, ica_free_ex_data); + if (rc != CKR_OK) + return rc; + + if (ex_data->modexpoKey == NULL && ex_data->crtKey == NULL) { + /* mech_rsa.c:ckm_rsa_decrypt accepts only CKO_PRIVATE_KEY, + * but Private Key can have 2 representations (see PKCS#1): + * - Modulus + private exponent + * - p, q, dp, dq and qInv (CRT format) + * The former should use ica_rsa_key_mod_expo_t and the latter + * ica_rsa_key_crt_t. Detect what representation this + * key_obj has and use the proper convert function */ + + template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, + &modulus); + template_attribute_get_non_empty(key_obj->template, + CKA_PRIVATE_EXPONENT, &priv_exp); + template_attribute_get_non_empty(key_obj->template, CKA_PRIME_1, + &prime1); + template_attribute_get_non_empty(key_obj->template, CKA_PRIME_2, + &prime2); + template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_1, + &exp1); + template_attribute_get_non_empty(key_obj->template, CKA_EXPONENT_2, + &exp2); + template_attribute_get_non_empty(key_obj->template, CKA_COEFFICIENT, + &coeff); + + /* Need to check for CRT Key format *BEFORE* check for mod_expo key, + * that's because opencryptoki *HAS* a CKA_PRIVATE_EXPONENT attribute + * even in CRT keys (but with zero length) */ + + if (modulus && prime1 && prime2 && exp1 && exp2 && coeff) { + /* ica_rsa_key_crt_t representation */ + ex_data->crtKey = rsa_convert_crt_key(modulus, prime1, prime2, + exp1, exp2, coeff); + if (ex_data->crtKey == NULL) { + TRACE_ERROR("rsa_convert_crt_key failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + /* same check as above */ + if (ex_data->crtKey->key_length != in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + } else if (modulus && priv_exp) { + /* ica_rsa_key_mod_expo_t representation */ + ex_data->modexpoKey = rsa_convert_mod_expo_key(modulus, NULL, + priv_exp); + if (ex_data->modexpoKey == NULL) { + TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + /* in_data must be in big endian format. Size in bits must not + * exceed the bit length of the key, and size in bytes must + * be the same */ + if (ex_data->modexpoKey->key_length != in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + } else { + /* should never happen */ + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; goto done; } - /* same check as above */ - if (crtKey->key_length != in_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); - rc = CKR_ENCRYPTED_DATA_LEN_RANGE; - goto crt_cleanup; - } + } - rc = ica_rsa_crt(ica_data->adapter_handle, in_data, crtKey, out_data); - switch (rc) { - case 0: - rc = CKR_OK; - break; - case EINVAL: - TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); - rc = CKR_ARGUMENTS_BAD; - break; - case ENODEV: - TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); - rc = CKR_FUNCTION_NOT_SUPPORTED; - break; - case EPERM: - TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); - rc = CKR_KEY_SIZE_RANGE; - break; - default: - TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); - rc = CKR_FUNCTION_FAILED; - break; - } - goto crt_cleanup; - } else if (modulus && priv_exp) { - /* ica_rsa_key_mod_expo_t representation */ - modexpoKey = rsa_convert_mod_expo_key(modulus, NULL, priv_exp); - if (modexpoKey == NULL) { - TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); + crtKey = ex_data->crtKey; + modexpoKey = ex_data->modexpoKey; + + bn_ctx = BN_CTX_new(); + if (bn_ctx == NULL) { + TRACE_ERROR("BN_CTX_new failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (ex_data->blinding == NULL || ex_data->blinding_mont_ctx == NULL) { + rc = ica_blinding_setup(tokdata, key_obj, ex_data, bn_ctx); + if (rc != CKR_OK) { + TRACE_ERROR("ica_blinding_setup failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } - /* in_data must be in big endian format. Size in bits must not - * exceed the bit length of the key, and size in bytes must - * be the same */ - // FIXME: we're not cheking the size in bits of in_data - // - but how could we? - if (modexpoKey->key_length != in_data_len) { - TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); - rc = CKR_ENCRYPTED_DATA_LEN_RANGE; - goto modexpo_cleanup; - } + } - rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, modexpoKey, - out_data); - switch (rc) { - case 0: - rc = CKR_OK; - break; - case EINVAL: - TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); - rc = CKR_ARGUMENTS_BAD; - break; - case ENODEV: - TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); - rc = CKR_FUNCTION_NOT_SUPPORTED; - break; - case EPERM: - TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); - rc = CKR_KEY_SIZE_RANGE; - break; - default: - TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); - rc = CKR_FUNCTION_FAILED; - break; - } - goto modexpo_cleanup; - } else { - /* should never happen */ - TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); - rc = CKR_MECHANISM_PARAM_INVALID; + buff = malloc(in_data_len * 2); + if (buff == NULL) { + TRACE_ERROR("Failed to allocate blinding buffer\n"); + rc = CKR_HOST_MEMORY; goto done; } -crt_cleanup: - free(crtKey->p); - free(crtKey->q); - free(crtKey->dp); - free(crtKey->dq); - free(crtKey->qInverse); - free(crtKey); - goto done; - -modexpo_cleanup: - free(modexpoKey->modulus); - free(modexpoKey->exponent); - free(modexpoKey); + rc = ica_blinding_convert(tokdata, ex_data, bn_ctx, in_data, buff, + in_data_len, &unblind); + if (rc != CKR_OK) { + TRACE_ERROR("ica_blinding_convert\n"); + goto done; + } + + if (crtKey != NULL) { + rc = ica_rsa_crt(ica_data->adapter_handle, buff, crtKey, + buff + in_data_len); + } else { + rc = ica_rsa_mod_expo(ica_data->adapter_handle, buff, modexpoKey, + buff + in_data_len); + } + switch (rc) { + case 0: + rc = CKR_OK; + break; + case EINVAL: + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + break; + case ENODEV: + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rc = CKR_FUNCTION_NOT_SUPPORTED; + break; + case EPERM: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + rc = CKR_KEY_SIZE_RANGE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + break; + } + if (rc != CKR_OK) + goto done; + + rc = ica_blinding_invert(tokdata, key_obj, ex_data, bn_ctx, + buff + in_data_len, out_data, in_data_len, + unblind); + if (rc != CKR_OK) { + TRACE_ERROR("ica_blinding_invert\n"); + goto done; + } done: + object_ex_data_unlock(key_obj); + + if (bn_ctx != NULL) + BN_CTX_free(bn_ctx); + if (buff != NULL) { + OPENSSL_cleanse(buff, in_data_len * 2); + free(buff); + } + return rc; } @@ -2651,10 +3251,12 @@ os_specific_rsa_decrypt); } -CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, - CK_ULONG *len, CK_ULONG keysize, +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; @@ -2664,10 +3266,12 @@ return rng_generate(tokdata, *key, keysize); } -CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; @@ -2677,7 +3281,8 @@ return rng_generate(tokdata, *key, keysize); } -CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, +CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) @@ -2686,6 +3291,8 @@ int rc = CKR_OK; CK_ATTRIBUTE *attr = NULL; + UNUSED(sess); + if (!ica_data->ica_aes_available) return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); @@ -2721,6 +3328,7 @@ } CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, @@ -2731,6 +3339,8 @@ CK_RV rc; CK_ATTRIBUTE *attr = NULL; + UNUSED(sess); + if (!ica_data->ica_aes_available) return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, @@ -3575,50 +4185,50 @@ {DES3_OFB, CKM_DES_OFB64, {8, 8, CKF_ENCRYPT | CKF_DECRYPT}}, {DES3_CFB, CKM_DES_CFB64, {8, 8, CKF_ENCRYPT | CKF_DECRYPT}}, {SHA1, CKM_SHA_1, {0, 0, CKF_DIGEST}}, - {SHA1, CKM_SHA_1_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA1, CKM_SHA_1_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA1, CKM_SHA_1_HMAC, {80, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA1, CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA256, CKM_SHA224, {0, 0, CKF_DIGEST}}, - {SHA256, CKM_SHA224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA256, CKM_SHA224_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA256, CKM_SHA224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA256, CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA256, CKM_SHA256, {0, 0, CKF_DIGEST}}, - {SHA256, CKM_SHA256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA256, CKM_SHA256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA256, CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA256, CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA384, CKM_SHA384, {0, 0, CKF_DIGEST}}, - {SHA384, CKM_SHA384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA384, CKM_SHA384_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA384, CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA384, CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {SHA512, CKM_SHA512, {0, 0, CKF_DIGEST}}, - {SHA512, CKM_SHA512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA512, CKM_SHA512_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA512, CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA512, CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #ifdef SHA512_224 {SHA512_224, CKM_SHA512_224, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA512_224, CKM_SHA512_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA512_224, CKM_SHA512_224_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA512_224, CKM_SHA512_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA512_224, CKM_SHA512_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA512_256 {SHA512_256, CKM_SHA512_256, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA512_256, CKM_SHA512_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {SHA512_256, CKM_SHA512_256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA512_256, CKM_SHA512_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {SHA512_256, CKM_SHA512_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_224 {SHA3_224, CKM_IBM_SHA3_224, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA3_224, CKM_IBM_SHA3_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA3_224, CKM_IBM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_256 {SHA3_256, CKM_IBM_SHA3_256, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA3_256, CKM_IBM_SHA3_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA3_256, CKM_IBM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_384 {SHA3_384, CKM_IBM_SHA3_384, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA3_384, CKM_IBM_SHA3_384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA3_384, CKM_IBM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_512 {SHA3_512, CKM_IBM_SHA3_512, {0, 0, CKF_HW|CKF_DIGEST}}, - {SHA3_512, CKM_IBM_SHA3_512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {SHA3_512, CKM_IBM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {53, CKM_MD5, {0, 0, CKF_DIGEST}}, - {54, CKM_MD5_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {55, CKM_MD5_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {54, CKM_MD5_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, + {55, CKM_MD5_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif {P_RNG, CKM_AES_KEY_GEN, {16, 32, CKF_GENERATE}}, {P_RNG, CKM_AES_XTS_KEY_GEN, {32, 64, CKF_GENERATE}}, @@ -4832,6 +5442,7 @@ OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; ICA_EC_KEY *eckey; unsigned int privlen; @@ -4846,13 +5457,26 @@ return CKR_FUNCTION_NOT_SUPPORTED; } - /* Get the private key */ - ret = ica_build_ec_priv_key(key_obj, &eckey, &privlen); - if (ret != CKR_OK) { - TRACE_ERROR("ica_build_ec_priv_key() failed with rc = 0x%lx. \n", ret); - return ret; + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(ica_ex_data_t), + ica_need_wr_lock_ec_key, ica_free_ex_data); + if (rc != CKR_OK) + return rc; + + if (ex_data->eckey == NULL) { + /* Get the private key */ + ret = ica_build_ec_priv_key(key_obj, &ex_data->eckey, + &ex_data->ec_privlen); + if (ret != CKR_OK) { + TRACE_ERROR("ica_build_ec_priv_key() failed with rc = 0x%lx. \n", + ret); + goto end; + } } + eckey = ex_data->eckey; + privlen = ex_data->ec_privlen; + /* Create signature */ rc = p_ica_ecdsa_sign(ica_data->adapter_handle, eckey, (unsigned char *) in_data, @@ -4876,7 +5500,7 @@ ret = CKR_OK; end: - p_ica_ec_key_free(eckey); + object_ex_data_unlock(key_obj); return ret; } @@ -4911,6 +5535,7 @@ CK_ULONG signature_len, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + ica_ex_data_t *ex_data = NULL; CK_RV ret = CKR_OK; ICA_EC_KEY *eckey; unsigned int privlen; @@ -4923,13 +5548,26 @@ return CKR_FUNCTION_NOT_SUPPORTED; } - /* Get the public key */ - ret = ica_build_ec_pub_key(key_obj, &eckey, &privlen); - if (ret != CKR_OK) { - TRACE_ERROR("ica_build_ec_pub_key() failed with rc = 0x%lx. \n", ret); - return ret; + rc = openssl_get_ex_data(key_obj, (void **)&ex_data, + sizeof(ica_ex_data_t), + ica_need_wr_lock_ec_key, ica_free_ex_data); + if (rc != CKR_OK) + return rc; + + if (ex_data->eckey == NULL) { + /* Get the public key */ + ret = ica_build_ec_pub_key(key_obj, &ex_data->eckey, + &ex_data->ec_privlen); + if (ret != CKR_OK) { + TRACE_ERROR("ica_build_ec_pub_key() failed with rc = 0x%lx. \n", + ret); + goto end; + } } + eckey = ex_data->eckey; + privlen = ex_data->ec_privlen; + /* Signature length ok? */ if (signature_len != 2 * privlen) { TRACE_ERROR("Supplied signature length mismatch: " @@ -4966,7 +5604,7 @@ } end: - p_ica_ec_key_free(eckey); + object_ex_data_unlock(key_obj); return ret; } diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/rsa_sup_mul.c opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/rsa_sup_mul.c --- opencryptoki-3.20.0+dfsg/usr/lib/ica_s390_stdll/rsa_sup_mul.c 1970-01-01 01:00:00.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/ica_s390_stdll/rsa_sup_mul.c 2023-05-15 14:42:55.000000000 +0200 @@ -0,0 +1,664 @@ +/* + * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023 International Business Machines Corp. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + * + * Copied from OpenSSL crypto/bn/rsa_sup_mul.c and modified to fit to + * the OpenCrptoki environment. Note that in OpenSSL the file + * crypto/bn/rsa_sup_mul.c does no longer exist, it was removed with commit + * https://github.com/openssl/openssl/commit/4209ce68d8fe8b1506494efa03d378d05baf9ff8. + * + * Changes include: + * - The intermediate message and the modulus are supplied as byte arrays + * instead of BIGNUMs. The code has been adjusted to handle byte arrays as + * input. + * - Remove parameters 'BN_CTX ctx' and 'BN_BLINDING *blinding' since they are + * not used. + * - Includes have been adjusted to only include external OpenSSL headers. + * - Remove access to internal fields of BN_BLINDING. + * - Remove access to internal fields of BIGNUM. Function BN_to_limb() is + * replaced by BN_bn2binpad(). Note that the only BIGNUM is containing the + * unblinding factor. The message (and the modulus) are passed in in byte + * arrays, and thus do not need to be converted. + * - The ICA token only works on Linux on IBM Z, and it's big endian and 64 bit. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "constant_time.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + +#define DECLARE_IS_ENDIAN +#define IS_LITTLE_ENDIAN 0 +#define IS_BIG_ENDIAN 1 + +# ifndef INT128_MAX +# if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 +typedef __int128_t int128_t; +typedef __uint128_t uint128_t; +# define INT128_MIN __MININT__(int128_t) +# define INT128_MAX __MAXINT__(int128_t) +# define UINT128_MAX __MAXUINT__(uint128_t) +# endif +# endif + +# if BN_BYTES == 8 +typedef uint64_t limb_t; +# if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 +typedef uint128_t limb2_t; +# define HAVE_LIMB2_T +# endif +# define LIMB_BIT_SIZE 64 +# define LIMB_BYTE_SIZE 8 +# else +# error "Not supported" +# endif + +static inline void memcpy_r_allign(void *dest, int dest_bs, + const void *src, int src_bs, int size) +{ + memcpy((unsigned char *)dest + (dest_bs - size), + (unsigned char *)src + (src_bs - size), size); +} + +/* + * For multiplication we're using schoolbook multiplication, + * so if we have two numbers, each with 6 "digits" (words) + * the multiplication is calculated as follows: + * A B C D E F + * x I J K L M N + * -------------- + * N*F + * N*E + * N*D + * N*C + * N*B + * N*A + * M*F + * M*E + * M*D + * M*C + * M*B + * M*A + * L*F + * L*E + * L*D + * L*C + * L*B + * L*A + * K*F + * K*E + * K*D + * K*C + * K*B + * K*A + * J*F + * J*E + * J*D + * J*C + * J*B + * J*A + * I*F + * I*E + * I*D + * I*C + * I*B + * + I*A + * ========================== + * N*B N*D N*F + * + N*A N*C N*E + * + M*B M*D M*F + * + M*A M*C M*E + * + L*B L*D L*F + * + L*A L*C L*E + * + K*B K*D K*F + * + K*A K*C K*E + * + J*B J*D J*F + * + J*A J*C J*E + * + I*B I*D I*F + * + I*A I*C I*E + * + * 1+1 1+3 1+5 + * 1+0 1+2 1+4 + * 0+1 0+3 0+5 + * 0+0 0+2 0+4 + * + * 0 1 2 3 4 5 6 + * which requires n^2 multiplications and 2n full length additions + * as we can keep every other result of limb multiplication in two separate + * limbs + */ + +#if defined HAVE_LIMB2_T +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + limb2_t t; + /* + * this is idiomatic code to tell compiler to use the native mul + * those three lines will actually compile to single instruction + */ + + t = (limb2_t)a * b; + *hi = t >> LIMB_BIT_SIZE; + *lo = (limb_t)t; +} +#elif (BN_BYTES == 8) && (defined _MSC_VER) +# if defined(_M_X64) +/* + * on x86_64 (x64) we can use the _umul128 intrinsic to get one `mul` + * instruction to get both high and low 64 bits of the multiplication. + * https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-140 + */ +#include +#pragma intrinsic(_umul128) +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + *lo = _umul128(a, b, hi); +} +# elif defined(_M_ARM64) || defined (_M_IA64) +/* + * We can't use the __umulh() on x86_64 as then msvc generates two `mul` + * instructions; so use this more portable intrinsic on platforms that + * don't support _umul128 (like aarch64 (ARM64) or ia64) + * https://learn.microsoft.com/en-us/cpp/intrinsics/umulh?view=msvc-140 + */ +#include +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + *lo = a * b; + *hi = __umulh(a, b); +} +# else +# error Only x64, ARM64 and IA64 supported. +# endif /* defined(_M_X64) */ +#else +/* + * if the compiler doesn't have either a 128bit data type nor a "return + * high 64 bits of multiplication" + */ +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + limb_t a_low = (limb_t)(uint32_t)a; + limb_t a_hi = a >> 32; + limb_t b_low = (limb_t)(uint32_t)b; + limb_t b_hi = b >> 32; + + limb_t p0 = a_low * b_low; + limb_t p1 = a_low * b_hi; + limb_t p2 = a_hi * b_low; + limb_t p3 = a_hi * b_hi; + + uint32_t cy = (uint32_t)(((p0 >> 32) + (uint32_t)p1 + (uint32_t)p2) >> 32); + + *lo = p0 + (p1 << 32) + (p2 << 32); + *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; +} +#endif + +/* add two limbs with carry in, return carry out */ +static ossl_inline limb_t _add_limb(limb_t *ret, limb_t a, limb_t b, limb_t carry) +{ + limb_t carry1, carry2, t; + /* + * `c = a + b; if (c < a)` is idiomatic code that makes compilers + * use add with carry on assembly level + */ + + *ret = a + carry; + if (*ret < a) + carry1 = 1; + else + carry1 = 0; + + t = *ret; + *ret = t + b; + if (*ret < t) + carry2 = 1; + else + carry2 = 0; + + return carry1 + carry2; +} + +/* + * add two numbers of the same size, return overflow + * + * add a to b, place result in ret; all arrays need to be n limbs long + * return overflow from addition (0 or 1) + */ +static ossl_inline limb_t add(limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + limb_t c = 0; + ossl_ssize_t i; + + for(i = n - 1; i > -1; i--) + c = _add_limb(&ret[i], a[i], b[i], c); + + return c; +} + +/* + * return number of limbs necessary for temporary values + * when multiplying numbers n limbs large + */ +static ossl_inline size_t mul_limb_numb(size_t n) +{ + return 2 * n * 2; +} + +/* + * multiply two numbers of the same size + * + * multiply a by b, place result in ret; a and b need to be n limbs long + * ret needs to be 2*n limbs long, tmp needs to be mul_limb_numb(n) limbs + * long + */ +static void limb_mul(limb_t *ret, limb_t *a, limb_t *b, size_t n, limb_t *tmp) +{ + limb_t *r_odd, *r_even; + size_t i, j, k; + + r_odd = tmp; + r_even = &tmp[2 * n]; + + memset(ret, 0, 2 * n * sizeof(limb_t)); + + for (i = 0; i < n; i++) { + for (k = 0; k < i + n + 1; k++) { + r_even[k] = 0; + r_odd[k] = 0; + } + for (j = 0; j < n; j++) { + /* + * place results from even and odd limbs in separate arrays so that + * we don't have to calculate overflow every time we get individual + * limb multiplication result + */ + if (j % 2 == 0) + _mul_limb(&r_even[i + j], &r_even[i + j + 1], a[i], b[j]); + else + _mul_limb(&r_odd[i + j], &r_odd[i + j + 1], a[i], b[j]); + } + /* + * skip the least significant limbs when adding multiples of + * more significant limbs (they're zero anyway) + */ + add(ret, ret, r_even, n + i + 1); + add(ret, ret, r_odd, n + i + 1); + } +} + +/* modifies the value in place by performing a right shift by one bit */ +static ossl_inline void rshift1(limb_t *val, size_t n) +{ + limb_t shift_in = 0, shift_out = 0; + size_t i; + + for (i = 0; i < n; i++) { + shift_out = val[i] & 1; + val[i] = shift_in << (LIMB_BIT_SIZE - 1) | (val[i] >> 1); + shift_in = shift_out; + } +} + +/* extend the LSB of flag to all bits of limb */ +static ossl_inline limb_t mk_mask(limb_t flag) +{ + flag |= flag << 1; + flag |= flag << 2; + flag |= flag << 4; + flag |= flag << 8; + flag |= flag << 16; +#if (LIMB_BYTE_SIZE == 8) + flag |= flag << 32; +#endif + return flag; +} + +/* + * copy from either a or b to ret based on flag + * when flag == 0, then copies from b + * when flag == 1, then copies from a + */ +static ossl_inline void cselect(limb_t flag, limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + /* + * would be more efficient with non volatile mask, but then gcc + * generates code with jumps + */ + volatile limb_t mask; + size_t i; + + mask = mk_mask(flag); + for (i = 0; i < n; i++) { +#if (LIMB_BYTE_SIZE == 8) + ret[i] = constant_time_select_64(mask, a[i], b[i]); +#else + ret[i] = constant_time_select_32(mask, a[i], b[i]); +#endif + } +} + +static limb_t _sub_limb(limb_t *ret, limb_t a, limb_t b, limb_t borrow) +{ + limb_t borrow1, borrow2, t; + /* + * while it doesn't look constant-time, this is idiomatic code + * to tell compilers to use the carry bit from subtraction + */ + + *ret = a - borrow; + if (*ret > a) + borrow1 = 1; + else + borrow1 = 0; + + t = *ret; + *ret = t - b; + if (*ret > t) + borrow2 = 1; + else + borrow2 = 0; + + return borrow1 + borrow2; +} + +/* + * place the result of a - b into ret, return the borrow bit. + * All arrays need to be n limbs long + */ +static limb_t sub(limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + limb_t borrow = 0; + ossl_ssize_t i; + + for (i = n - 1; i > -1; i--) + borrow = _sub_limb(&ret[i], a[i], b[i], borrow); + + return borrow; +} + +/* return the number of limbs necessary to allocate for the mod() tmp operand */ +static ossl_inline size_t mod_limb_numb(size_t anum, size_t modnum) +{ + return (anum + modnum) * 3; +} + +/* + * calculate a % mod, place the result in ret + * size of a is defined by anum, size of ret and mod is modnum, + * size of tmp is returned by mod_limb_numb() + */ +static void mod(limb_t *ret, limb_t *a, size_t anum, limb_t *mod, + size_t modnum, limb_t *tmp) +{ + limb_t *atmp, *modtmp, *rettmp; + limb_t res; + size_t i; + + memset(tmp, 0, mod_limb_numb(anum, modnum) * LIMB_BYTE_SIZE); + + atmp = tmp; + modtmp = &tmp[anum + modnum]; + rettmp = &tmp[(anum + modnum) * 2]; + + for (i = modnum; i 0; i--, rp--) { + v = _mul_add_limb(rp, mod, modnum, rp[modnum-1] * ni0, tmp2); + v = v + carry + rp[-1]; + carry |= (v != rp[-1]); + carry &= (v <= rp[-1]); + rp[-1] = v; + } + + /* perform the final reduction by mod... */ + carry -= sub(ret, rp, mod, modnum); + + /* ...conditionally */ + cselect(carry, ret, rp, ret, modnum); +} + +#if LIMB_BYTE_SIZE == 8 +static ossl_inline uint64_t be64(uint64_t host) +{ + uint64_t big = 0; + DECLARE_IS_ENDIAN; + + if (!IS_LITTLE_ENDIAN) + return host; + + big |= (host & 0xff00000000000000) >> 56; + big |= (host & 0x00ff000000000000) >> 40; + big |= (host & 0x0000ff0000000000) >> 24; + big |= (host & 0x000000ff00000000) >> 8; + big |= (host & 0x00000000ff000000) << 8; + big |= (host & 0x0000000000ff0000) << 24; + big |= (host & 0x000000000000ff00) << 40; + big |= (host & 0x00000000000000ff) << 56; + return big; +} + +#else +/* Not all platforms have htobe32(). */ +static ossl_inline uint32_t be32(uint32_t host) +{ + uint32_t big = 0; + DECLARE_IS_ENDIAN; + + if (!IS_LITTLE_ENDIAN) + return host; + + big |= (host & 0xff000000) >> 24; + big |= (host & 0x00ff0000) >> 8; + big |= (host & 0x0000ff00) << 8; + big |= (host & 0x000000ff) << 24; + return big; +} +#endif + +/* + * We assume that intermediate and unblind are used similar to + * BN_BLINDING_invert_ex() arguments. + * to_mod is RSA modulus. + * buf and num is the serialization buffer and its length. + * num is always the RSA modulus size. + * + * Here we use classic/Montgomery multiplication and modulo. After the calculation finished + * we serialize the new structure instead of BIGNUMs taking endianness into account. + */ +int ossl_bn_rsa_do_unblind(const unsigned char *intermediate, + const BIGNUM *unblind, + const unsigned char *to_mod, + unsigned char *buf, int num, + BN_MONT_CTX *m_ctx, BN_ULONG n0) +{ + limb_t *l_im = NULL, *l_mul = NULL, *l_mod = NULL; + limb_t *l_ret = NULL, *l_tmp = NULL, l_buf; + size_t l_im_count = 0, l_mul_count = 0, l_size = 0, l_mod_count = 0; + size_t l_tmp_count = 0; + int ret = 0; + size_t i; + unsigned char *tmp; + + l_im_count = (num + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + l_mul_count = (BN_num_bytes(unblind) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + l_mod_count = (num + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + + l_size = l_im_count > l_mul_count ? l_im_count : l_mul_count; + if (l_size * LIMB_BYTE_SIZE == (size_t)num) + l_im = (limb_t *)intermediate; + else + l_im = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); + l_mul = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); + if (l_mod_count * LIMB_BYTE_SIZE == (size_t)num) + l_mod = (limb_t *)to_mod; + else + l_mod = OPENSSL_zalloc(l_mod_count * LIMB_BYTE_SIZE); + + if ((l_im == NULL) || (l_mul == NULL) || (l_mod == NULL)) + goto err; + + if (l_im != (limb_t *)intermediate) + memcpy_r_allign(l_im, l_size * LIMB_BYTE_SIZE, intermediate, num, num); + BN_bn2binpad(unblind, (unsigned char *)l_mul, l_size * LIMB_BYTE_SIZE); + if (l_mod != (limb_t *)to_mod) + memcpy_r_allign(l_mod, l_mod_count * LIMB_BYTE_SIZE, to_mod, num, num); + + l_ret = OPENSSL_malloc(2 * l_size * LIMB_BYTE_SIZE); + + if (m_ctx != NULL) { + l_tmp_count = mul_limb_numb(l_size) > mod_montgomery_limb_numb(l_mod_count) ? + mul_limb_numb(l_size) : mod_montgomery_limb_numb(l_mod_count); + l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); + } else { + l_tmp_count = mul_limb_numb(l_size) > mod_limb_numb(2 * l_size, l_mod_count) ? + mul_limb_numb(l_size) : mod_limb_numb(2 * l_size, l_mod_count); + l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); + } + + if ((l_ret == NULL) || (l_tmp == NULL)) + goto err; + + if (m_ctx != NULL) { + limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); + mod_montgomery(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, + n0, l_tmp); + } else { + limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); + mod(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, l_tmp); + } + + memset(buf, 0, num); + tmp = buf; + for (i = 0; i < l_mod_count; i++) { +#if LIMB_BYTE_SIZE == 8 + l_buf = be64(l_ret[i]); +#else + l_buf = be32(l_ret[i]); +#endif + if (i == 0) { + int delta = LIMB_BYTE_SIZE - ((l_mod_count * LIMB_BYTE_SIZE) - num); + + memcpy(tmp, ((char *)&l_buf) + LIMB_BYTE_SIZE - delta, delta); + tmp += delta; + } else { + memcpy(tmp, &l_buf, LIMB_BYTE_SIZE); + tmp += LIMB_BYTE_SIZE; + } + } + ret = num; + + err: + if (l_im != (limb_t *)intermediate) + OPENSSL_free(l_im); + OPENSSL_free(l_mul); + if (l_mod != (limb_t *)to_mod) + OPENSSL_free(l_mod); + OPENSSL_free(l_tmp); + OPENSSL_free(l_ret); + + return ret; +} + +#pragma GCC diagnostic pop diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/icsf_specific.c opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/icsf_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/icsf_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/icsf_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -375,8 +375,17 @@ if (icsf_data == NULL) return CKR_HOST_MEMORY; list_init(&icsf_data->sessions); - pthread_mutex_init(&icsf_data->sess_list_mutex, NULL); - bt_init(&icsf_data->objects, free); + if (pthread_mutex_init(&icsf_data->sess_list_mutex, NULL) != 0) { + TRACE_ERROR("Initializing session list lock failed.\n"); + free(icsf_data); + return CKR_CANT_LOCK; + } + if (bt_init(&icsf_data->objects, free) != CKR_OK) { + TRACE_ERROR("BTree init failed.\n"); + pthread_mutex_destroy(&icsf_data->sess_list_mutex); + free(icsf_data); + return CKR_FUNCTION_FAILED; + } tokdata->private_data = icsf_data; rc = XProcLock(tokdata); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/icsf_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/icsf_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/icsf_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/icsf_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -45,15 +45,7 @@ usr/lib/common/ec_supported.c usr/lib/api/policyhelper.c \ usr/lib/config/configuration.c usr/lib/common/pqc_supported.c \ usr/lib/config/cfgparse.y usr/lib/config/cfglex.l \ - usr/lib/common/mech_openssl.c - -if ENABLE_LOCKS -opencryptoki_stdll_libpkcs11_icsf_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else -opencryptoki_stdll_libpkcs11_icsf_la_LDFLAGS += -litm -opencryptoki_stdll_libpkcs11_icsf_la_SOURCES += \ + usr/lib/common/mech_openssl.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c -endif usr/lib/icsf_stdll/icsf_specific.$(OBJEXT): usr/lib/config/cfgparse.h diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/new_host.c opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/new_host.c --- opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/new_host.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/new_host.c 2023-05-15 14:42:55.000000000 +0200 @@ -77,11 +77,16 @@ /* set trace info */ set_trace(t); - bt_init(&sltp->TokData->sess_btree, free); - bt_init(&sltp->TokData->object_map_btree, free); - bt_init(&sltp->TokData->sess_obj_btree, call_object_free); - bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); - bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + rc = bt_init(&sltp->TokData->sess_btree, free); + rc |= bt_init(&sltp->TokData->object_map_btree, free); + rc |= bt_init(&sltp->TokData->sess_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->priv_token_obj_btree, call_object_free); + rc |= bt_init(&sltp->TokData->publ_token_obj_btree, call_object_free); + if (rc != CKR_OK) { + TRACE_ERROR("Btree init failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } if (strlen(sinfp->tokname)) { if (ock_snprintf(abs_tokdir_name, PATH_MAX, "%s/%s", @@ -192,6 +197,11 @@ } else { CloseXProcLock(sltp->TokData); final_data_store(sltp->TokData); + bt_destroy(&sltp->TokData->sess_btree); + bt_destroy(&sltp->TokData->object_map_btree); + bt_destroy(&sltp->TokData->sess_obj_btree); + bt_destroy(&sltp->TokData->priv_token_obj_btree); + bt_destroy(&sltp->TokData->publ_token_obj_btree); } } @@ -1791,7 +1801,7 @@ rc = icsftok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("icsftok_decrypt() failed.\n"); done: @@ -1847,7 +1857,7 @@ rc = icsftok_decrypt_update(tokdata, sess, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("icsftok_decrypt_update() failed.\n"); done: @@ -1905,7 +1915,7 @@ length_only = TRUE; rc = icsftok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); - if (rc != CKR_OK) + if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) TRACE_DEVEL("icsftok_decrypt_final() failed.\n"); done: if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/pbkdf.c opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/pbkdf.c --- opencryptoki-3.20.0+dfsg/usr/lib/icsf_stdll/pbkdf.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/icsf_stdll/pbkdf.c 2023-05-15 14:42:55.000000000 +0200 @@ -62,7 +62,7 @@ return CKR_FUNCTION_FAILED; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp) { if (fchown(file, -1, grp->gr_gid) != 0) { TRACE_ERROR("fchown failed: %s\n", strerror(errno)); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/lib.mk opencryptoki-3.21.0+dfsg/usr/lib/lib.mk --- opencryptoki-3.20.0+dfsg/usr/lib/lib.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/lib.mk 2023-05-15 14:42:55.000000000 +0200 @@ -22,3 +22,4 @@ include usr/lib/common/common.mk include usr/lib/config/config.mk +include usr/lib/hsm_mk_change/hsm_mk_change.mk diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/soft_stdll/soft_specific.c opencryptoki-3.21.0+dfsg/usr/lib/soft_stdll/soft_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/soft_stdll/soft_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/soft_stdll/soft_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -118,56 +118,56 @@ {CKM_DES3_CMAC_GENERAL, {16, 24, CKF_SIGN | CKF_VERIFY}}, #if !(NOSHA1) {CKM_SHA_1, {0, 0, CKF_DIGEST}}, - {CKM_SHA_1_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA_1_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA_1_HMAC, {80, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, #endif {CKM_SHA224, {0, 0, CKF_DIGEST}}, - {CKM_SHA224_HMAC, {0, 0, CKF_SIGN|CKF_VERIFY}}, - {CKM_SHA224_HMAC_GENERAL, {0, 0, CKF_SIGN|CKF_VERIFY}}, + {CKM_SHA224_HMAC, {112, 2048, CKF_SIGN|CKF_VERIFY}}, + {CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN|CKF_VERIFY}}, {CKM_SHA256, {0, 0, CKF_DIGEST}}, - {CKM_SHA256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384, {0, 0, CKF_DIGEST}}, - {CKM_SHA384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA384_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512, {0, 0, CKF_DIGEST}}, - {CKM_SHA512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA512_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #ifdef NID_sha512_224WithRSAEncryption {CKM_SHA512_224, {0, 0, CKF_DIGEST}}, - {CKM_SHA512_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA512_224_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha512_256WithRSAEncryption {CKM_SHA512_256, {0, 0, CKF_DIGEST}}, - {CKM_SHA512_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_SHA512_256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_224 {CKM_IBM_SHA3_224, {0, 0, CKF_DIGEST}}, - {CKM_IBM_SHA3_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_IBM_SHA3_224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_256 {CKM_IBM_SHA3_256, {0, 0, CKF_DIGEST}}, - {CKM_IBM_SHA3_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_IBM_SHA3_256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_384 {CKM_IBM_SHA3_384, {0, 0, CKF_DIGEST}}, - {CKM_IBM_SHA3_384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_IBM_SHA3_384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #ifdef NID_sha3_512 {CKM_IBM_SHA3_512, {0, 0, CKF_DIGEST}}, - {CKM_IBM_SHA3_512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_IBM_SHA3_512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD2) {CKM_MD2, {0, 0, CKF_DIGEST}}, - {CKM_MD2_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_MD2_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_MD2_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_MD2_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {CKM_MD5, {0, 0, CKF_DIGEST}}, - {CKM_MD5_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, - {CKM_MD5_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_MD5_HMAC, {8, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_MD5_HMAC_GENERAL, {8, 2048, CKF_SIGN | CKF_VERIFY}}, #endif {CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_GENERATE}}, {CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}}, @@ -252,10 +252,12 @@ return CKR_OK; } -CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **des_key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; @@ -519,10 +521,12 @@ openssl_specific_rsa_decrypt); } -CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, - CK_ULONG *len, CK_ULONG keysize, +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; @@ -532,10 +536,12 @@ return rng_generate(tokdata, *key, keysize); } -CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_aes_xts_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; @@ -545,24 +551,28 @@ return rng_generate(tokdata, *key, keysize); } -CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, +CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { + UNUSED(sess); + return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } -CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, +CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { + UNUSED(sess); + return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/soft_stdll/soft_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/soft_stdll/soft_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/soft_stdll/soft_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/soft_stdll/soft_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -36,13 +36,5 @@ usr/lib/soft_stdll/soft_specific.c usr/lib/common/attributes.c \ usr/lib/common/dlist.c usr/lib/common/mech_openssl.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ - usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c - -if ENABLE_LOCKS -opencryptoki_stdll_libpkcs11_sw_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else -opencryptoki_stdll_libpkcs11_sw_la_LDFLAGS += -litm -opencryptoki_stdll_libpkcs11_sw_la_SOURCES += \ + usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ usr/lib/common/btree.c usr/lib/common/sess_mgr.c -endif diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/tpm_stdll/tpm_specific.c opencryptoki-3.21.0+dfsg/usr/lib/tpm_stdll/tpm_specific.c --- opencryptoki-3.20.0+dfsg/usr/lib/tpm_stdll/tpm_specific.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/tpm_stdll/tpm_specific.c 2023-05-15 14:42:55.000000000 +0200 @@ -2377,10 +2377,12 @@ return CKR_OK; } -CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, - CK_ULONG *len, CK_ULONG keysize, - CK_BBOOL *is_opaque) +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **des_key, CK_ULONG *len, + CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; @@ -3162,10 +3164,12 @@ return rc; } -CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, - CK_ULONG *len, CK_ULONG keysize, +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { + UNUSED(tmpl); + *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; @@ -3175,24 +3179,28 @@ return rng_generate(tokdata, *key, keysize); } -CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, +CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { + UNUSED(session); + return openssl_specific_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, encrypt); } -CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, +CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, SESSION *session, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { + UNUSED(session); + return openssl_specific_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); @@ -3251,9 +3259,9 @@ "Directory(%s) missing: %s\n", lockdir, strerror(errno)); goto err; } - grp = getgrnam("pkcs11"); + grp = getgrnam(PKCS_GROUP); if (grp == NULL) { - fprintf(stderr, "getgrname(pkcs11): %s", strerror(errno)); + fprintf(stderr, "getgrname(%s): %s", PKCS_GROUP, strerror(errno)); goto err; } /* set ownership to euid, and pkcs11 group */ diff -Nru opencryptoki-3.20.0+dfsg/usr/lib/tpm_stdll/tpm_stdll.mk opencryptoki-3.21.0+dfsg/usr/lib/tpm_stdll/tpm_stdll.mk --- opencryptoki-3.20.0+dfsg/usr/lib/tpm_stdll/tpm_stdll.mk 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/lib/tpm_stdll/tpm_stdll.mk 2023-05-15 14:42:55.000000000 +0200 @@ -38,14 +38,5 @@ usr/lib/tpm_stdll/tpm_openssl.c usr/lib/tpm_stdll/tpm_util.c \ usr/lib/common/dlist.c usr/lib/common/mech_openssl.c \ usr/lib/common/utility_common.c usr/lib/common/ec_supported.c \ - usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c - -if ENABLE_LOCKS -opencryptoki_stdll_libpkcs11_tpm_la_SOURCES += \ - usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c -else -opencryptoki_stdll_libpkcs11_tpm_la_LDFLAGS += -litm -opencryptoki_stdll_libpkcs11_tpm_la_SOURCES += \ - usr/lib/common/btree.c \ - usr/lib/common/sess_mgr.c -endif + usr/lib/api/policyhelper.c usr/lib/common/pqc_supported.c \ + usr/lib/common/btree.c usr/lib/common/sess_mgr.c diff -Nru opencryptoki-3.20.0+dfsg/usr/sbin/p11sak/p11sak.c opencryptoki-3.21.0+dfsg/usr/sbin/p11sak/p11sak.c --- opencryptoki-3.20.0+dfsg/usr/sbin/p11sak/p11sak.c 2023-02-13 09:22:42.000000000 +0100 +++ opencryptoki-3.21.0+dfsg/usr/sbin/p11sak/p11sak.c 2023-05-15 14:42:55.000000000 +0200 @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) International Business Machines Corp. 2001-2020 + * COPYRIGHT (c) International Business Machines Corp. 2001-2022 * * 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 @@ -14,872 +14,2861 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include #include -#include "cfgparser.h" -#include "configuration.h" +#include #include -#include - -#include +#include #include -#include +#include -#include -#include "uri.h" -#include "p11util.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define P11SAK_DECLARE_CURVES #include "p11sak.h" +#include "p11util.h" +#include "pin_prompt.h" +#include "cfgparser.h" +#include "configuration.h" #include "mechtable.h" +#include "defs.h" +#include "uri.h" -static const char *default_pkcs11lib = "libopencryptoki.so"; +#if OPENSSL_VERSION_PREREQ(3, 0) +#include +#include +#include +#endif + +static CK_RV p11sak_generate_key(void); +static CK_RV p11sak_list_key(void); +static CK_RV p11sak_remove_key(void); +static CK_RV p11sak_set_key_attr(void); +static CK_RV p11sak_copy_key(void); +static CK_RV p11sak_import_key(void); +static CK_RV p11sak_export_key(void); +static void print_generate_import_key_attr_help(void); +static void print_list_key_attr_help(void); +static void print_set_copy_key_attr_help(void); + +static void *pkcs11_lib = NULL; +static bool pkcs11_initialized = false; +static CK_FUNCTION_LIST *pkcs11_funcs = NULL; +static CK_SESSION_HANDLE pkcs11_session = CK_INVALID_HANDLE; +static CK_INFO pkcs11_info; +static CK_TOKEN_INFO pkcs11_tokeninfo; +static CK_SLOT_INFO pkcs11_slotinfo; + +static struct ConfigBaseNode *p11sak_cfg = NULL; + +static bool opt_help = false; +static bool opt_version = false; +static CK_SLOT_ID opt_slot = (CK_SLOT_ID)-1; +static char *opt_pin = NULL; +static bool opt_force_pin_prompt = false; +static struct p11sak_enum_value *opt_keytype = NULL; +static CK_ULONG opt_keybits_num = 0; +static struct p11sak_enum_value *opt_keybits = NULL; +static struct p11sak_enum_value *opt_group = NULL; +static char *opt_pem_file = NULL; +static struct p11sak_enum_value *opt_curve = NULL; +static struct p11sak_enum_value *opt_pqc_version = NULL; +static char *opt_label = NULL; +static bool opt_force = false; +static CK_ULONG opt_exponent = 0; +static char *opt_attr = NULL; +static char *opt_id = NULL; +static bool opt_long = false; +static bool opt_detailed_uri = false; +static char *opt_sort = NULL; +static char *opt_new_attr = NULL; +static char *opt_new_label = NULL; +static char *opt_new_id = NULL; +static char *opt_file = NULL; +static char *opt_pem_password = NULL; +static bool opt_force_pem_pwd_prompt = false; +static bool opt_opaque = false; +static struct p11sak_enum_value *opt_asym_kind = NULL; +static bool opt_spki = false; + +static bool opt_slot_is_set(const struct p11sak_arg *arg); +static CK_RV generic_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV generic_add_secret_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_ULONG generic_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV aes_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV aes_add_secret_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_ULONG aes_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_ULONG aes_xts_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_ULONG rsa_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_ULONG dh_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_ULONG dsa_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV rsa_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV rsa_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_RV ec_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV ec_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_RV dh_prepare(const struct p11sak_keytype *keytype, void **private); +static void dh_cleanup(const struct p11sak_keytype *keytype, void *private); +static CK_RV dh_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV dh_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_RV dh_add_private_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_RV dsa_prepare(const struct p11sak_keytype *keytype, void **private); +static void dsa_cleanup(const struct p11sak_keytype *keytype, void *private); +static CK_RV dsa_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize); +static CK_RV dsa_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private); +static CK_RV ibm_dilithium_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs, + void *private); +static CK_RV ibm_kyber_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs, + void *private); + +static CK_RV p11sak_import_check_des_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV p11sak_import_check_3des_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV p11sak_import_check_generic_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV p11sak_import_check_aes_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV p11sak_import_check_aes_xts_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize); +static CK_RV p11sak_import_sym_clear_des_3des_aes_generic( + const struct p11sak_keytype *keytype, + CK_BYTE *data, CK_ULONG data_len, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); +static CK_RV p11sak_import_rsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); +static CK_RV p11sak_import_dh_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); +static CK_RV p11sak_import_dsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); +static CK_RV p11sak_import_ec_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs); +static CK_RV p11sak_import_dilithium_kyber_pem_data( + const struct p11sak_keytype *keytype, + unsigned char *data, size_t data_len, + bool private, + CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs); +static CK_RV p11sak_export_sym_clear_des_3des_aes_generic( + const struct p11sak_keytype *keytype, + CK_BYTE **data, CK_ULONG* data_len, + CK_OBJECT_HANDLE key, const char *label); +static CK_RV p11sak_export_rsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY **pkey, bool private, + CK_OBJECT_HANDLE key, const char *label); +static CK_RV p11sak_export_dh_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY **pkey, bool private, + CK_OBJECT_HANDLE key, const char *label); +static CK_RV p11sak_export_dsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY **pkey, bool private, + CK_OBJECT_HANDLE key, const char *label); +static CK_RV p11sak_export_ec_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY **pkey, bool private, + CK_OBJECT_HANDLE key, const char *label); +static CK_RV p11sak_export_dilithium_kyber_pem_data( + const struct p11sak_keytype *keytype, + unsigned char **data, size_t *data_len, + bool private, CK_OBJECT_HANDLE key, + const char *label); + +static void print_bool_attr_short(const CK_ATTRIBUTE *val, bool applicable); +static void print_bool_attr_long(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_utf8_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_byte_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_ulong_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_date_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_mech_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_mech_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_attr_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_class_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_key_type_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_oid_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_ibm_dilithium_keyform_attr(const char *attr, + const CK_ATTRIBUTE *val, + int indent, bool sensitive); +static void print_ibm_kyber_keyform_attr(const char *attr, + const CK_ATTRIBUTE *val, + int indent, bool sensitive); + +#define DECLARE_KEY_ATTRS \ + { .name = "CKA_LABEL", .type = CKA_LABEL, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_utf8_attr, }, \ + { .name = "CKA_CLASS", .type = CKA_CLASS, \ + .secret = true, .public = true, .private = true, .settable = false, \ + .print_long = print_class_attr, }, \ + { .name = "CKA_KEY_TYPE", .type = CKA_KEY_TYPE, \ + .secret = true, .public = true, .private = true, .settable = false, \ + .print_long = print_key_type_attr, }, \ + { .name = "CKA_ID", .type = CKA_ID, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_START_DATE", .type = CKA_START_DATE, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_date_attr, }, \ + { .name = "CKA_END_DATE", .type = CKA_END_DATE, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_date_attr, }, \ + { .name = "CKA_KEY_GEN_MECHANISM", .type = CKA_KEY_GEN_MECHANISM, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_mech_attr, }, \ + { .name = "CKA_ALLOWED_MECHANISMS", .type = CKA_ALLOWED_MECHANISMS, \ + .secret = true, .public = true, .private = true, .settable = true, \ + .print_long = print_mech_array_attr, } + +#define DECLARE_SECRET_KEY_ATTRS \ + { .name = "CKA_CHECK_VALUE", .type = CKA_CHECK_VALUE, \ + .secret = true, .public = false, .private = false, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_WRAP_TEMPLATE", .type = CKA_WRAP_TEMPLATE, \ + .secret = true, .public = true, .private = false, .settable = true, \ + .print_long = print_attr_array_attr, }, \ + { .name = "CKA_UNWRAP_TEMPLATE", .type = CKA_UNWRAP_TEMPLATE, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_attr_array_attr, }, \ + { .name = "CKA_DERIVE_TEMPLATE", .type = CKA_DERIVE_TEMPLATE, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_attr_array_attr, } + +#define DECLARE_PUBLIC_KEY_ATTRS \ + { .name = "CKA_SUBJECT", .type = CKA_SUBJECT, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_WRAP_TEMPLATE", .type = CKA_WRAP_TEMPLATE, \ + .secret = true, .public = true, .private = false, .settable = true, \ + .print_long = print_attr_array_attr, }, \ + { .name = "CKA_PUBLIC_KEY_INFO", .type = CKA_PUBLIC_KEY_INFO, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +#define DECLARE_PRIVATE_KEY_ATTRS \ + { .name = "CKA_SUBJECT", .type = CKA_SUBJECT, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_UNWRAP_TEMPLATE", .type = CKA_UNWRAP_TEMPLATE, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_attr_array_attr, }, \ + { .name = "CKA_PUBLIC_KEY_INFO", .type = CKA_PUBLIC_KEY_INFO, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_DERIVE_TEMPLATE", .type = CKA_DERIVE_TEMPLATE, \ + .secret = true, .public = false, .private = true, .settable = true, \ + .print_long = print_attr_array_attr, } + +static const struct p11sak_attr p11sak_des_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_SECRET_KEY_ATTRS, + { .name = "CKA_VALUE", .type = CKA_VALUE, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_3des_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_SECRET_KEY_ATTRS, + { .name = "CKA_VALUE", .type = CKA_VALUE, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_generic_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_SECRET_KEY_ATTRS, + { .name = "CKA_VALUE", .type = CKA_VALUE, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_VALUE_LEN", .type = CKA_VALUE_LEN, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_ulong_attr, }, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_aes_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_SECRET_KEY_ATTRS, + { .name = "CKA_VALUE", .type = CKA_VALUE, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_VALUE_LEN", .type = CKA_VALUE_LEN, + .secret = true, .public = false, .private = false, .settable = true, + .print_long = print_ulong_attr, }, + { .name = NULL }, +}; + +#define DECLARE_PUBLIC_RSA_ATTRS \ + { .name = "CKA_MODULUS", .type = CKA_MODULUS, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_MODULUS_BITS", .type = CKA_MODULUS_BITS, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_ulong_attr, }, \ + { .name = "CKA_PUBLIC_EXPONENT", .type = CKA_PUBLIC_EXPONENT, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +static const struct p11sak_attr p11sak_public_rsa_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_PUBLIC_RSA_ATTRS, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_rsa_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_PUBLIC_RSA_ATTRS, + { .name = "CKA_PRIVATE_EXPONENT", .type = CKA_PRIVATE_EXPONENT, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_PRIME_1", .type = CKA_PRIME_1, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_PRIME_2", .type = CKA_PRIME_2, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_EXPONENT_1", .type = CKA_EXPONENT_1, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_EXPONENT_2", .type = CKA_EXPONENT_2, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_COEFFICIENT", .type = CKA_COEFFICIENT, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +#define DECLARE_DH_ATTRS \ + { .name = "CKA_PRIME", .type = CKA_PRIME, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_BASE", .type = CKA_BASE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_VALUE", .type = CKA_VALUE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +static const struct p11sak_attr p11sak_public_dh_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_DH_ATTRS, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_dh_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_DH_ATTRS, + { .name = "CKA_VALUE_BITS", .type = CKA_VALUE_BITS, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_ulong_attr, }, + { .name = NULL }, +}; + +#define DECLARE_DSA_ATTRS \ + { .name = "CKA_PRIME", .type = CKA_PRIME, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_SUBPRIME", .type = CKA_SUBPRIME, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_BASE", .type = CKA_BASE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_VALUE", .type = CKA_VALUE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +static const struct p11sak_attr p11sak_public_dsa_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_DSA_ATTRS, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_dsa_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_DSA_ATTRS, + { .name = NULL }, +}; + +#define DECLARE_EC_ATTRS \ + { .name = "CKA_EC_PARAMS", .type = CKA_EC_PARAMS, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_oid_attr, } + +static const struct p11sak_attr p11sak_public_ec_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_EC_ATTRS, + { .name = "CKA_EC_POINT", .type = CKA_EC_POINT, + .secret = false, .public = true, .private = false, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_ec_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_EC_ATTRS, + { .name = "CKA_VALUE", .type = CKA_VALUE, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +#define DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS \ + { .name = "CKA_IBM_DILITHIUM_KEYFORM", .type = CKA_IBM_DILITHIUM_KEYFORM, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_ibm_dilithium_keyform_attr, }, \ + { .name = "CKA_IBM_DILITHIUM_MODE", .type = CKA_IBM_DILITHIUM_MODE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_oid_attr, }, \ + { .name = "CKA_IBM_DILITHIUM_RHO", .type = CKA_IBM_DILITHIUM_RHO, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, }, \ + { .name = "CKA_IBM_DILITHIUM_T1", .type = CKA_IBM_DILITHIUM_T1, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +static const struct p11sak_attr p11sak_public_ibm_dilithium_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_ibm_dilithium_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_PUBLIC_IBM_DILITHIUM_ATTRS, + { .name = "CKA_IBM_DILITHIUM_SEED", .type = CKA_IBM_DILITHIUM_SEED, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_IBM_DILITHIUM_TR", .type = CKA_IBM_DILITHIUM_TR, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_IBM_DILITHIUM_S1", .type = CKA_IBM_DILITHIUM_S1, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_IBM_DILITHIUM_S2", .type = CKA_IBM_DILITHIUM_S2, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = "CKA_IBM_DILITHIUM_T0", .type = CKA_IBM_DILITHIUM_T0, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +#define DECLARE_PUBLIC_IBM_KYBER_ATTRS \ + { .name = "CKA_IBM_KYBER_KEYFORM", .type = CKA_IBM_KYBER_KEYFORM, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_ibm_kyber_keyform_attr, }, \ + { .name = "CKA_IBM_KYBER_MODE", .type = CKA_IBM_KYBER_MODE, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_oid_attr, }, \ + { .name = "CKA_IBM_KYBER_PK", .type = CKA_IBM_KYBER_PK, \ + .secret = false, .public = true, .private = true, .settable = true, \ + .print_long = print_byte_array_attr, } + +static const struct p11sak_attr p11sak_public_ibm_kyber_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PUBLIC_KEY_ATTRS, + DECLARE_PUBLIC_IBM_KYBER_ATTRS, + { .name = NULL }, +}; + +static const struct p11sak_attr p11sak_private_ibm_kyber_attrs[] = { + DECLARE_KEY_ATTRS, + DECLARE_PRIVATE_KEY_ATTRS, + DECLARE_PUBLIC_IBM_KYBER_ATTRS, + { .name = "CKA_IBM_KYBER_SK", .type = CKA_IBM_KYBER_SK, + .secret = false, .public = false, .private = true, .settable = true, + .print_long = print_byte_array_attr, }, + { .name = NULL }, +}; + +static const struct p11sak_keytype p11sak_des_keytype = { + .name = "DES", .type = CKK_DES, .ckk_name = "CKK_DES", + .keygen_mech = { .mechanism = CKM_DES_KEY_GEN, }, + .is_asymmetric = false, + .sign_verify = true, .encrypt_decrypt = true, + .wrap_unwrap = true, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DES, + .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, + .secret_attrs = p11sak_des_attrs, + .import_check_sym_keysize = p11sak_import_check_des_keysize, + .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, + .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, +}; + +static const struct p11sak_keytype p11sak_3des_keytype = { + .name = "3DES", .type = CKK_DES3, .ckk_name = "CKK_DES3", + .keygen_mech = { .mechanism = CKM_DES3_KEY_GEN, }, + .is_asymmetric = false, + .sign_verify = true, .encrypt_decrypt = true, + .wrap_unwrap = true, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DES3, + .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, + .secret_attrs = p11sak_3des_attrs, + .import_check_sym_keysize = p11sak_import_check_3des_keysize, + .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, + .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, +}; + +static const struct p11sak_keytype p11sak_generic_keytype = { + .name = "GENERIC", .type = CKK_GENERIC_SECRET, + .ckk_name = "CKK_GENERIC_SECRET", + .keygen_mech = { .mechanism = CKM_GENERIC_SECRET_KEY_GEN, }, + .is_asymmetric = false, + .keygen_get_key_size = generic_get_key_size, + .keygen_add_secret_attrs = generic_add_secret_attrs, + .sign_verify = true, .encrypt_decrypt = false, + .wrap_unwrap = false, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_GENERIC_SECRET, + .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = generic_keysize_adjust, + .secret_attrs = p11sak_generic_attrs, + .import_check_sym_keysize = p11sak_import_check_generic_keysize, + .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, + .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, +}; + +static const struct p11sak_keytype p11sak_aes_keytype = { + .name = "AES", .type = CKK_AES, .ckk_name = "CKK_AES", + .keygen_mech = { .mechanism = CKM_AES_KEY_GEN, }, + .is_asymmetric = false, + .keygen_get_key_size = aes_get_key_size, + .keygen_add_secret_attrs = aes_add_secret_attrs, + .sign_verify = true, .encrypt_decrypt = true, + .wrap_unwrap = true, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_AES, + .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = aes_keysize_adjust, + .secret_attrs = p11sak_aes_attrs, + .import_check_sym_keysize = p11sak_import_check_aes_keysize, + .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, + .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, +}; + +static const struct p11sak_keytype p11sak_aes_xts_keytype = { + .name = "AES-XTS", .type = CKK_AES_XTS, .ckk_name = "CKK_AES_XTS", + .keygen_mech = { .mechanism = CKM_AES_XTS_KEY_GEN, }, + .is_asymmetric = false, + .keygen_get_key_size = aes_get_key_size, + .keygen_add_secret_attrs = aes_add_secret_attrs, + .sign_verify = true, .encrypt_decrypt = true, + .wrap_unwrap = true, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_AES_XTS, + .keysize_attr = CKA_VALUE_LEN, .key_keysize_adjust = aes_xts_keysize_adjust, + .secret_attrs = p11sak_aes_attrs, + .import_check_sym_keysize = p11sak_import_check_aes_xts_keysize, + .import_sym_clear = p11sak_import_sym_clear_des_3des_aes_generic, + .export_sym_clear = p11sak_export_sym_clear_des_3des_aes_generic, +}; + +static const struct p11sak_keytype p11sak_rsa_keytype = { + .name = "RSA", .type = CKK_RSA, .ckk_name = "CKK_RSA", + .keygen_mech = { .mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN, }, + .is_asymmetric = true, + .keygen_get_key_size = rsa_get_key_size, + .keygen_add_public_attrs = rsa_add_public_attrs, + .sign_verify = true, .encrypt_decrypt = true, + .wrap_unwrap = true, .derive = false, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_RSA, + .keysize_attr = CKA_MODULUS, .keysize_attr_value_len = true, + .key_keysize_adjust = rsa_keysize_adjust, + .public_attrs = p11sak_public_rsa_attrs, + .private_attrs = p11sak_private_rsa_attrs, + .import_asym_pkey = p11sak_import_rsa_pkey, + .export_asym_pkey = p11sak_export_rsa_pkey, +}; + +static const struct p11sak_keytype p11sak_dh_keytype = { + .name = "DH", .type = CKK_DH, .ckk_name = "CKK_DH", + .keygen_mech = { .mechanism = CKM_DH_PKCS_KEY_PAIR_GEN, }, + .is_asymmetric = true, + .keygen_prepare = dh_prepare, + .keygen_cleanup = dh_cleanup, + .keygen_get_key_size = dh_get_key_size, + .keygen_add_public_attrs = dh_add_public_attrs, + .keygen_add_private_attrs = dh_add_private_attrs, + .sign_verify = false, .encrypt_decrypt = false, + .wrap_unwrap = false, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DH, + .keysize_attr = CKA_PRIME, .keysize_attr_value_len = true, + .key_keysize_adjust = dh_keysize_adjust, + .public_attrs = p11sak_public_dh_attrs, + .private_attrs = p11sak_private_dh_attrs, + .import_asym_pkey = p11sak_import_dh_pkey, + .export_asym_pkey = p11sak_export_dh_pkey, +}; + +static const struct p11sak_keytype p11sak_dsa_keytype = { + .name = "DSA", .type = CKK_DSA, .ckk_name = "CKK_DSA", + .keygen_mech = { .mechanism = CKM_DSA_KEY_PAIR_GEN, }, + .is_asymmetric = true, + .keygen_prepare = dsa_prepare, + .keygen_cleanup = dsa_cleanup, + .keygen_get_key_size = dsa_get_key_size, + .keygen_add_public_attrs = dsa_add_public_attrs, + .sign_verify = true, .encrypt_decrypt = false, + .wrap_unwrap = false, .derive = false, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_DSA, + .keysize_attr = CKA_PRIME, .keysize_attr_value_len = true, + .key_keysize_adjust = dsa_keysize_adjust, + .public_attrs = p11sak_public_dsa_attrs, + .private_attrs = p11sak_private_dsa_attrs, + .import_asym_pkey = p11sak_import_dsa_pkey, + .export_asym_pkey = p11sak_export_dsa_pkey, +}; + +static const struct p11sak_keytype p11sak_ec_keytype = { + .name = "EC", .type = CKK_EC, .ckk_name = "CKK_EC", + .keygen_mech = { .mechanism = CKM_EC_KEY_PAIR_GEN, }, + .is_asymmetric = true, + .keygen_get_key_size = ec_get_key_size, + .keygen_add_public_attrs = ec_add_public_attrs, + .sign_verify = true, .encrypt_decrypt = false, + .wrap_unwrap = false, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_EC, + .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, + .public_attrs = p11sak_public_ec_attrs, + .private_attrs = p11sak_private_ec_attrs, + .import_asym_pkey = p11sak_import_ec_pkey, + .export_asym_pkey = p11sak_export_ec_pkey, +}; + +static const struct p11sak_keytype p11sak_ibm_dilithium_keytype = { + .name = "IBM-Dilithium", .type = CKK_IBM_PQC_DILITHIUM, + .ckk_name = "CKK_IBM_PQC_DILITHIUM", + .keygen_mech = { .mechanism = CKM_IBM_DILITHIUM, }, + .is_asymmetric = true, + .keygen_add_public_attrs = ibm_dilithium_add_public_attrs, + .sign_verify = true, .encrypt_decrypt = false, + .wrap_unwrap = false, .derive = false, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_PQC_DILITHIUM, + .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, + .public_attrs = p11sak_public_ibm_dilithium_attrs, + .private_attrs = p11sak_private_ibm_dilithium_attrs, + .import_asym_pem_data = p11sak_import_dilithium_kyber_pem_data, + .export_asym_pem_data = p11sak_export_dilithium_kyber_pem_data, + .pem_name_private = "IBM-DILITHIUM PRIVATE KEY", + .pem_name_public = "IBM-DILITHIUM PUBLIC KEY", +}; + +static const struct p11sak_keytype p11sak_ibm_kyber_keytype = { + .name = "IBM-Kyber", .type = CKK_IBM_PQC_KYBER, + .ckk_name = "CKK_IBM_PQC_KYBER", + .keygen_mech = { .mechanism = CKM_IBM_KYBER, }, + .is_asymmetric = true, + .keygen_add_public_attrs = ibm_kyber_add_public_attrs, + .sign_verify = false, .encrypt_decrypt = true, + .wrap_unwrap = false, .derive = true, + .filter_attr = CKA_KEY_TYPE, .filter_value = CKK_IBM_PQC_KYBER, + .keysize_attr = (CK_ATTRIBUTE_TYPE)-1, + .public_attrs = p11sak_public_ibm_kyber_attrs, + .private_attrs = p11sak_private_ibm_kyber_attrs, + .import_asym_pem_data = p11sak_import_dilithium_kyber_pem_data, + .export_asym_pem_data = p11sak_export_dilithium_kyber_pem_data, + .pem_name_private = "IBM-KYBER PRIVATE KEY", + .pem_name_public = "IBM-KYBER PUBLIC KEY", +}; + +static const struct p11sak_keytype p11sak_secret_keytype = { + .name = "Secret", + .is_asymmetric = false, + .filter_attr = CKA_CLASS, .filter_value = CKO_SECRET_KEY, +}; + +static const struct p11sak_keytype p11sak_public_keytype = { + .name = "Public", + .is_asymmetric = true, + .filter_attr = CKA_CLASS, .filter_value = CKO_PUBLIC_KEY, +}; + +static const struct p11sak_keytype p11sak_private_keytype = { + .name = "Private", + .is_asymmetric = true, + .filter_attr = CKA_CLASS, .filter_value = CKO_PRIVATE_KEY, +}; + +static const struct p11sak_keytype p11sak_all_keytype = { + .name = "All", + .filter_attr = (CK_ATTRIBUTE_TYPE)-1, +}; + +static const struct p11sak_keytype *p11sak_keytypes[] = { + &p11sak_des_keytype, + &p11sak_3des_keytype, + &p11sak_generic_keytype, + &p11sak_aes_keytype, + &p11sak_aes_xts_keytype, + &p11sak_rsa_keytype, + &p11sak_dh_keytype, + &p11sak_dsa_keytype, + &p11sak_ec_keytype, + &p11sak_ibm_dilithium_keytype, + &p11sak_ibm_kyber_keytype, + NULL, +}; + +static const struct p11sak_class p11sak_classes[] = { + { .name = "CKO_DATA", .class = CKO_DATA, }, + { .name = "CKO_CERTIFICATE", .class = CKO_CERTIFICATE, }, + { .name = "CKO_PUBLIC_KEY", .class = CKO_PUBLIC_KEY, }, + { .name = "CKO_PRIVATE_KEY", .class = CKO_PRIVATE_KEY, }, + { .name = "CKO_SECRET_KEY", .class = CKO_SECRET_KEY, }, + { .name = "CKO_HW_FEATURE", .class = CKO_HW_FEATURE, }, + { .name = "CKO_DOMAIN_PARAMETERS", .class = CKO_DOMAIN_PARAMETERS, }, + { .name = "CKO_PROFILE", .class = CKO_PROFILE, }, + { .name = NULL, .class = 0, } +}; + +static const struct p11sak_opt p11sak_generic_opts[] = { + { .short_opt = 'h', .long_opt = "help", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_help, }, + .description = "Print this help, then exit." }, + { .short_opt = 'v', .long_opt = "version", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_version, }, + .description = "Print version information, then exit."}, + { .short_opt = 0, .long_opt = NULL, }, +}; + +#define PKCS11_OPTS \ + { .short_opt = 's', .long_opt = "slot", .required = true, \ + .arg = { .type = ARG_TYPE_NUMBER, .required = true, \ + .value.number = &opt_slot, .is_set = opt_slot_is_set, \ + .name = "SLOT", }, \ + .description = "The PKCS#11 slot ID.", }, \ + { .short_opt = 'p', .long_opt = "pin", .required = false, \ + .arg = { .type = ARG_TYPE_STRING, .required = true, \ + .value.string = &opt_pin, .name = "USER-PIN" }, \ + .description = "The PKCS#11 user pin. If this option is not specified, " \ + "and environment variable PKCS11_USER_PIN is not set, " \ + "then you will be prompted for the PIN.", }, \ + { .short_opt = 0, .long_opt = "force-pin-prompt", .required = false, \ + .long_opt_val = OPT_FORCE_PIN_PROMPT, \ + .arg = { .type = ARG_TYPE_PLAIN, .required = false, \ + .value.plain = &opt_force_pin_prompt, }, \ + .description = "Enforce user PIN prompt, even if environment variable " \ + "PKCS11_USER_PIN is set, or the '-p'/'--pin' option is " \ + "specified.", } + +#define FILTER_OPTS \ + { .short_opt = 'L', .long_opt = "label", .required = false, \ + .arg = { .type = ARG_TYPE_STRING, .required = true, \ + .value.string = &opt_label, .name = "LABEL", }, \ + .description = "Filter the keys by label (optional). You can use " \ + "wildcards ('*' and '?') in the label specification. To " \ + "specify a wildcard character that should not be treated "\ + "as a wildcard, it must be escaped using a backslash " \ + "('\\*' or '\\?'). Also, a backslash character that " \ + "should not be treated a an escape character must be " \ + "escaped ('\\\\').", }, \ + { .short_opt = 'i', .long_opt = "id", .required = false, \ + .arg = { .type = ARG_TYPE_STRING, .required = true, \ + .value.string = &opt_id, .name = "ID", }, \ + .description = "Filter the keys by ID (optional). Specify a hex string " \ + "(not prefixed with 0x) of any number of bytes.", }, \ + { .short_opt = 'a', .long_opt = "attr", .required = false, \ + .arg = { .type = ARG_TYPE_STRING, .required = true, \ + .value.string = &opt_attr, .name = "ATTRS", }, \ + .description = "Filter the key by its boolean attribute values:\n" \ + "P L M B Y R E D G C V O W U S A X N T I (optional). " \ + "Specify a set of these letters without any blanks in " \ + "between. See below for the meaning of the attribute " \ + "letters. Attributes that are not specified are not " \ + "used to filter the keys.", } + +#define KEYGEN_KEYTYPES(args_prefix) \ + { .value = "des", .args = NULL, \ + .private = { .ptr = &p11sak_des_keytype, }, }, \ + { .value = "3des", .args = NULL, \ + .private = { .ptr = &p11sak_3des_keytype }, }, \ + { .value = "generic", .args = args_prefix##_generic_args, \ + .private = { .ptr = &p11sak_generic_keytype }, }, \ + { .value = "aes", .args = args_prefix##_aes_args, \ + .private = { .ptr = &p11sak_aes_keytype }, }, \ + { .value = "aes-xts", .args = args_prefix##_aes_xts_args, \ + .private = { .ptr = &p11sak_aes_xts_keytype }, }, \ + { .value = "rsa", .args = args_prefix##_rsa_args, \ + .private = { .ptr = &p11sak_rsa_keytype }, }, \ + { .value = "dh", .args = args_prefix##_dh_args, \ + .private = { .ptr = &p11sak_dh_keytype }, }, \ + { .value = "dsa", .args = args_prefix##_dsa_args, \ + .private = { .ptr = &p11sak_dsa_keytype }, }, \ + { .value = "ec", .args = args_prefix##_ec_args, \ + .private = { .ptr = &p11sak_ec_keytype }, }, \ + { .value = "ibm-dilithium", .args = args_prefix##_ibm_dilithium_args, \ + .private = { .ptr = &p11sak_ibm_dilithium_keytype }, }, \ + { .value = "ibm-kyber", .args = args_prefix##_ibm_kyber_args, \ + .private = { .ptr = &p11sak_ibm_kyber_keytype }, } + +#define GROUP_KEYTYPES \ + { .value = "public", .args = NULL, \ + .private = { .ptr = &p11sak_public_keytype }, }, \ + { .value = "private", .args = NULL, \ + .private = { .ptr = &p11sak_private_keytype }, }, \ + { .value = "secret", .args = NULL, \ + .private = { .ptr = &p11sak_secret_keytype }, }, \ + { .value = "all", .args = NULL, \ + .private = { .ptr = &p11sak_all_keytype }, } + +static const struct p11sak_opt p11sak_generate_key_opts[] = { + PKCS11_OPTS, + { .short_opt = 'L', .long_opt = "label", .required = true, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_label, .name = "LABEL", }, + .description = "The label of the key to be generated. For asymmetric " + "keys set individual labels for public and private key, " + "separated by a colon (':'): 'PUB_LABEL:PRIV_LABEL'. If " + "only one label is specified for an asymmetric key, the " + "label is automatically extended by ':pub' and ':prv' for " + "the public and private keys respectively. To use the " + "same label for public and private keys specify the equal " + "sign ('=') for the private key label part: " + "'LABEL:='.", }, + { .short_opt = 'a', .long_opt = "attr", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_attr, .name = "ATTRS", }, + .description = "The boolean attributes to set for the key:\n" + "P L M B Y R E D G C V O W U S A X N T I (optional). " + "Specify a set of these letters without any blanks in " + "between. See below for the meaning of the attribute " + "letters. For asymmetric keys set individual key " + "attributes for public and private key separated by a " + "colon (':'): 'PUB-ATTRS:PRIV-ATTRS'.", }, + { .short_opt = 'i', .long_opt = "id", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_id, .name = "ID", }, + .description = "The ID of the key to be generated. Specify a hex string " + "(not prefixed with 0x) of any number of bytes. For " + "asymmetric keys the same ID is set for both, the public " + "and the private key.", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_generic_args[] = { + { .name = "KEYBITS", .type = ARG_TYPE_NUMBER, .required = true, + .value.number = &opt_keybits_num, + .description = "Size of the generic key in bits.", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_aes_keybits[] = { + { .value = "128", .args = NULL, .private = { .num = 128 }, }, + { .value = "192", .args = NULL, .private = { .num = 192 }, }, + { .value = "256", .args = NULL, .private = { .num = 256 }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_aes_args[] = { + { .name = "KEYBITS", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_aes_keybits, + .value.enum_value = &opt_keybits, + .description = "Size of the AES key in bits:", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_aes_xts_keybits[] = { + { .value = "128", .args = NULL, .private = { .num = 128 * 2 }, }, + { .value = "256", .args = NULL, .private = { .num = 256 * 2 }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_aes_xts_args[] = { + { .name = "KEYBITS", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_aes_xts_keybits, + .value.enum_value = &opt_keybits, + .description = "Size of the AES-XTS key in bits:", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_rsa_keybits[] = { + { .value = "512", .args = NULL, .private = { .num = 512 }, }, + { .value = "1024", .args = NULL, .private = { .num = 1024 }, }, + { .value = "2048", .args = NULL, .private = { .num = 2048 }, }, + { .value = "4096", .args = NULL, .private = { .num = 4096 }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_rsa_args[] = { + { .name = "KEYBITS", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_rsa_keybits, + .value.enum_value = &opt_keybits, + .description = "Size of the RSA key in bits:", }, + { .name = "PUBL-EXP", .type = ARG_TYPE_NUMBER, .required = false, + .value.number = &opt_exponent, + .description = "The public exponent for RSA (optional).", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_dh_group[] = { + { .value = "ffdhe2048", .args = NULL, + .private = { .num = NID_ffdhe2048 }, }, + { .value = "ffdhe3072", .args = NULL, + .private = { .num = NID_ffdhe3072 }, }, + { .value = "ffdhe4096", .args = NULL, + .private = { .num = NID_ffdhe4096 }, }, + { .value = "ffdhe6144", .args = NULL, + .private = { .num = NID_ffdhe6144 }, }, + { .value = "ffdhe8192", .args = NULL, + .private = { .num = NID_ffdhe6144 }, }, +#ifdef NID_modp_1536 + { .value = "modp1536", .args = NULL, + .private = { .num = NID_modp_1536 }, }, +#endif +#ifdef NID_modp_2048 + { .value = "modp2048", .args = NULL, + .private = { .num = NID_modp_2048 }, }, +#endif +#ifdef NID_modp_3072 + { .value = "modp3072", .args = NULL, + .private = { .num = NID_modp_3072 }, }, +#endif +#ifdef NID_modp_4096 + { .value = "modp4096", .args = NULL, + .private = { .num = NID_modp_4096 }, }, +#endif +#ifdef NID_modp_6144 + { .value = "modp6144", .args = NULL, + .private = { .num = NID_modp_6144 }, }, +#endif +#ifdef NID_modp_8192 + { .value = "modp8192", .args = NULL, + .private = { .num = NID_modp_8192 }, }, +#endif + { .value = "DH-PARAM-PEM-FILE", .args = NULL, + .private = { .num = 0 }, + .any_value = &opt_pem_file, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_dh_args[] = { + { .name = "GROUP", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_dh_group, + .value.enum_value = &opt_group, + .description = "The Diffie-Hellman FFC group name " + "or the name of a DH parameters PEM file:", }, + { .name = "PRIV-BITS", .type = ARG_TYPE_NUMBER, .required = false, + .value.number = &opt_keybits_num, + .description = "Size of the DH private key in bits (optional).",}, + { .name = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_dsa_args[] = { + { .name = "DSA-PARAM-PEM-FILE", .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_pem_file, + .description = "The name of a DSA parameters PEM file.", }, + { .name = NULL, }, +}; + +#define DECLARE_CURVE_INFO(name, size) \ + static const struct curve_info name ## _info = { \ + .oid = name, .oid_len = sizeof(name), .bitsize = size, \ + } + +#define DECLARE_CURVE_VALUE(name) \ + { .value = # name, .args = NULL, .private = { .ptr = &name ## _info, }, } + +DECLARE_CURVE_INFO(prime256v1, 256); +DECLARE_CURVE_INFO(prime192v1, 192); +DECLARE_CURVE_INFO(secp224r1, 224); +DECLARE_CURVE_INFO(secp384r1, 384); +DECLARE_CURVE_INFO(secp521r1, 521); +DECLARE_CURVE_INFO(secp256k1, 256); +DECLARE_CURVE_INFO(brainpoolP160r1, 160); +DECLARE_CURVE_INFO(brainpoolP160t1, 160); +DECLARE_CURVE_INFO(brainpoolP192r1, 192); +DECLARE_CURVE_INFO(brainpoolP192t1, 192); +DECLARE_CURVE_INFO(brainpoolP224r1, 224); +DECLARE_CURVE_INFO(brainpoolP224t1, 224); +DECLARE_CURVE_INFO(brainpoolP256r1, 256); +DECLARE_CURVE_INFO(brainpoolP256t1, 256); +DECLARE_CURVE_INFO(brainpoolP320r1, 320); +DECLARE_CURVE_INFO(brainpoolP320t1, 320); +DECLARE_CURVE_INFO(brainpoolP384r1, 384); +DECLARE_CURVE_INFO(brainpoolP384t1, 384); +DECLARE_CURVE_INFO(brainpoolP512r1, 512); +DECLARE_CURVE_INFO(brainpoolP512t1, 512); +DECLARE_CURVE_INFO(curve25519, 256); +DECLARE_CURVE_INFO(curve448, 448); +DECLARE_CURVE_INFO(ed25519, 256); +DECLARE_CURVE_INFO(ed448, 448); + +static const struct p11sak_enum_value p11sak_ec_curves[] = { + DECLARE_CURVE_VALUE(prime256v1), + DECLARE_CURVE_VALUE(prime192v1), + DECLARE_CURVE_VALUE(secp224r1), + DECLARE_CURVE_VALUE(secp384r1), + DECLARE_CURVE_VALUE(secp521r1), + DECLARE_CURVE_VALUE(secp256k1), + DECLARE_CURVE_VALUE(brainpoolP160r1), + DECLARE_CURVE_VALUE(brainpoolP160t1), + DECLARE_CURVE_VALUE(brainpoolP192r1), + DECLARE_CURVE_VALUE(brainpoolP192t1), + DECLARE_CURVE_VALUE(brainpoolP224r1), + DECLARE_CURVE_VALUE(brainpoolP224t1), + DECLARE_CURVE_VALUE(brainpoolP256r1), + DECLARE_CURVE_VALUE(brainpoolP256t1), + DECLARE_CURVE_VALUE(brainpoolP320r1), + DECLARE_CURVE_VALUE(brainpoolP320t1), + DECLARE_CURVE_VALUE(brainpoolP384r1), + DECLARE_CURVE_VALUE(brainpoolP384t1), + DECLARE_CURVE_VALUE(brainpoolP512r1), + DECLARE_CURVE_VALUE(brainpoolP512t1), + DECLARE_CURVE_VALUE(curve25519), + DECLARE_CURVE_VALUE(curve448), + DECLARE_CURVE_VALUE(ed25519), + DECLARE_CURVE_VALUE(ed448), + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_ec_args[] = { + { .name = "CURVE", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_ec_curves, + .value.enum_value = &opt_curve, + .description = "The curve name. One of the following:", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_ibm_dilithium_versions[] = { + { .value = "r2_65", .args = NULL, + .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65 }, }, + { .value = "r2_87", .args = NULL, + .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87 }, }, + { .value = "r2_44", .args = NULL, + .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44 }, }, + { .value = "r3_65", .args = NULL, + .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65 }, }, + { .value = "r3_87", .args = NULL, + .private = { .num = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87 }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_ibm_dilithium_args[] = { + { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_ibm_dilithium_versions, + .value.enum_value = &opt_pqc_version, + .description = "The version of the IBM Dilithium key pair:", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_ibm_kyber_versions[] = { + { .value = "r2_768", .args = NULL, + .private = { .num = CK_IBM_KYBER_KEYFORM_ROUND2_768 }, }, + { .value = "r2_1024", .args = NULL, + .private = { .num = CK_IBM_KYBER_KEYFORM_ROUND2_1024 }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_ibm_kyber_args[] = { + { .name = "VERSION", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_ibm_kyber_versions, + .value.enum_value = &opt_pqc_version, + .description = "The version of the IBM Kyber key pair:", }, + { .name = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_generate_key_keytypes[] = { + KEYGEN_KEYTYPES(p11sak_generate), + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_generate_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_generate_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the key. One of the following:", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_list_key_opts[] = { + PKCS11_OPTS, + FILTER_OPTS, + { .short_opt = 'l', .long_opt = "long", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_long, }, + .description = "List keys in long (detailed) format.", }, + { .short_opt = 0, .long_opt = "detailed-uri", .required = false, + .long_opt_val = OPT_DETAILED_URI, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_detailed_uri, }, + .description = "Show detailed PKCS#11 URI.", }, + { .short_opt = 'S', .long_opt = "sort", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_sort, .name = "SORT-SPEC" }, + .description = "Sort the keys by label, key type, object class, and/or " + "key size. Specify a sort selection of up to 4 fields, " + "each represented by its corresponding letter, separated " + "by comma (','):\n" + "- label: 'l'\n" + "- key type: 'k'\n" + "- object class: 'c'\n" + "- key size: 's'\n" + " The sort order ('a' = ascending (default), 'd' = " + "descending) can be appended to the field designator by " + "a colon (':').\n" + "Example: 'l:a,k:d' will sort by label in ascending order " + "and then by key type in descending order.", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +#define null_generic_args NULL +#define null_aes_args NULL +#define null_aes_xts_args NULL +#define null_rsa_args NULL +#define null_dh_args NULL +#define null_dsa_args NULL +#define null_ec_args NULL +#define null_ibm_dilithium_args NULL +#define null_ibm_kyber_args NULL + +static const struct p11sak_enum_value + p11sak_list_remove_set_copy_export_key_keytypes[] = { + KEYGEN_KEYTYPES(null), + GROUP_KEYTYPES, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_list_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, + .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the keys to list (optional). If no key type " + "is specified, all key types are listed.", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_remove_key_opts[] = { + PKCS11_OPTS, + FILTER_OPTS, + { .short_opt = 'f', .long_opt = "force", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_force, }, + .description = "Do not prompt for a confirmation to remove a key. " + "Use with care, all keys matching the filter will be " + "removed!", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_arg p11sak_remove_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, + .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the keys to select for removal (optional). " + "If no key type is specified, all key types are " + "selected.", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_set_key_attr_opts[] = { + PKCS11_OPTS, + FILTER_OPTS, + { .short_opt = 'f', .long_opt = "force", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_force, }, + .description = "Do not prompt for a confirmation to set the attributes " + "of a key. Use with care, all keys matching the filter " + "will be changed!", }, + { .short_opt = 'A', .long_opt = "new-attr", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_attr, .name = "ATTRS", }, + .description = "The boolean attributes to set for the key (optional):\n" + "P L M B Y R E D G C V O W U S A X N T I. " + "Specify a set of these letters without any blanks in " + "between. See below for the meaning of the attribute " + "letters. Restrictions on attribute values may apply.", }, + { .short_opt = 'l', .long_opt = "new-label", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_label, .name = "LABEL", }, + .description = "The new label to set for the key (optional).", }, + { .short_opt = 'I', .long_opt = "new-id", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_id, .name = "ID", }, + .description = "The new ID to set for the key (optional).", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_arg p11sak_set_key_attr_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, + .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the keys to select for update (optional). " + "If no key type is specified, all key types are " + "selected.", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_copy_key_opts[] = { + PKCS11_OPTS, + FILTER_OPTS, + { .short_opt = 'f', .long_opt = "force", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_force, }, + .description = "Do not prompt for a confirmation to copy a key. Use with " + "care, all keys matching the filter will be copied!", }, + { .short_opt = 'A', .long_opt = "new-attr", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_attr, .name = "ATTRS", }, + .description = "The boolean attributes to set for the copied key " + "(optional):\n P L M B Y R E D G C V O W U S A X N T I. " + "Specify a set of these letters without any blanks in " + "between. See below for the meaning of the attribute " + "letters. Restrictions on attribute values may apply.", }, + { .short_opt = 'l', .long_opt = "new-label", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_label, .name = "LABEL", }, + .description = "The new label to set for the copied key (optional).", }, + { .short_opt = 'I', .long_opt = "new-id", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_new_id, .name = "ID", }, + .description = "The new ID to set for the copied key (optional).", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_arg p11sak_copy_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, + .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the keys to select for copying (optional). " + "If no key type is specified, all key types are " + "selected.", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_import_key_opts[] = { + PKCS11_OPTS, + { .short_opt = 'L', .long_opt = "label", .required = true, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_label, .name = "LABEL", }, + .description = "The label of the key to be imported.", }, + { .short_opt = 'a', .long_opt = "attr", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_attr, .name = "ATTRS", }, + .description = "The boolean attributes to set for the key:\n" + "P L M B Y R E D G C V O W U S A X N T I (optional). " + "Specify a set of these letters without any blanks in " + "between. See below for the meaning of the attribute " + "letters.", }, + { .short_opt = 'i', .long_opt = "id", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_id, .name = "ID", }, + .description = "The ID of the key to be imported. Specify a hex string " + "(not prefixed with 0x) of any number of bytes.", }, + { .short_opt = 'F', .long_opt = "file", .required = true, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_file, .name = "FILENAME", }, + .description = "The file name of the file that contains the key to be " + "imported. For symmetric keys, this is a binary file " + "containing the key material in clear. For asymmetric " + "keys, this is an OpenSSL PEM file containing a " + "public or private key. PEM files can optionally be " + "password protected. Specify the PEM password with the " + "'-P'/'--pem-password' option or environment variable " + "P11SAK_PEM_PASSWORD. If the PEM file is password " + "protected, but no PEM password is specified, you will be " + "prompted for the PEM password.", }, + { .short_opt = 'P', .long_opt = "pem-password", .required = false, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_pem_password, .name = "PASSWORD", }, + .description = "The password of the PEM file specified with the " + "'-F'/'--file' option. If the PEM file is password " + "protected, but this option is not specified, nor " + "environment variable P11SAK_PEM_PASSWORD is set, you " + "will be prompted for the PEM password.", }, + { .short_opt = 0, .long_opt = "force-pem-pwd-prompt", .required = false, + .long_opt_val = OPT_FORCE_PEM_PWD_PROMPT, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_force_pem_pwd_prompt, }, + .description = "Enforce PEM password prompt, even if environment " + "variable P11SAK_PEM_PASSWORD is set, or the " + "'-P'/'--pem-password' option is specified.", }, + { .short_opt = 'o', .long_opt = "opaque", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_opaque, }, + .description = "The key material in the file specified with the " + "'-F'/'--file' option is an opaque secure key blob. " + "Not all tokens support this.", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_enum_value p11sak_import_asym_types[] = { + { .value = "public", .args = NULL, .private = { .num = false }, }, + { .value = "private", .args = NULL, .private = { .num = true }, }, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_import_asym_args[] = { + { .name = "KIND", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_import_asym_types, + .value.enum_value = &opt_asym_kind, + .description = "The kind of the asymmetric key to import.", }, + { .name = NULL, }, +}; + +#define IMPORT_KEYTYPES \ + { .value = "des", .args = NULL, \ + .private = { .ptr = &p11sak_des_keytype, }, }, \ + { .value = "3des", .args = NULL, \ + .private = { .ptr = &p11sak_3des_keytype }, }, \ + { .value = "generic", .args = NULL, \ + .private = { .ptr = &p11sak_generic_keytype }, }, \ + { .value = "aes", .args = NULL, \ + .private = { .ptr = &p11sak_aes_keytype }, }, \ + { .value = "aes-xts", .args = NULL, \ + .private = { .ptr = &p11sak_aes_xts_keytype }, }, \ + { .value = "rsa", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_rsa_keytype }, }, \ + { .value = "dh", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_dh_keytype }, }, \ + { .value = "dsa", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_dsa_keytype }, }, \ + { .value = "ec", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_ec_keytype }, }, \ + { .value = "ibm-dilithium", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_ibm_dilithium_keytype }, }, \ + { .value = "ibm-kyber", .args = p11sak_import_asym_args, \ + .private = { .ptr = &p11sak_ibm_kyber_keytype }, } + +static const struct p11sak_enum_value p11sak_import_key_keytypes[] = { + IMPORT_KEYTYPES, + { .value = NULL, }, +}; + +static const struct p11sak_arg p11sak_import_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = true, + .enum_values = p11sak_import_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the key. One of the following:", }, + { .name = NULL }, +}; + +static const struct p11sak_opt p11sak_export_key_opts[] = { + PKCS11_OPTS, + FILTER_OPTS, + { .short_opt = 'f', .long_opt = "force", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_force, }, + .description = "Do not prompt for a confirmation to export a key. " + "Use with care, all keys matching the filter will be " + "exported! See the description of the '-F'/'--file' " + "option about what happens when multiple keys match the " + "filter and are exported into the same file.", }, + { .short_opt = 'F', .long_opt = "file", .required = true, + .arg = { .type = ARG_TYPE_STRING, .required = true, + .value.string = &opt_file, .name = "FILENAME", }, + .description = "The file name of the file to which the keys to be " + "exported are written to. For symmetric keys, this is a " + "binary file where the key material in clear is written " + "to. For asymmetric keys, this is an OpenSSL PEM file " + "where the public or private keys are written to. If " + "multiple asymmetric keys match the filter, the keys " + "are appended to the PEM file specified with the " + "'-F'/'--file' option. If multiple symmetric keys or a " + "mixture of asymmetric and symmetric keys match the " + "filter, then you are prompted to confirm to overwrite " + "the previously created file, unless the '-f'\'--force' " + "option is specified.", }, + { .short_opt = 'o', .long_opt = "opaque", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_opaque, }, + .description = "The key's opaque secure key blob is written to the file " + "specified with the '-F'/'--file' option. Not all tokens " + "support this.", }, + { .short_opt = 'S', .long_opt = "spki", .required = false, + .arg = { .type = ARG_TYPE_PLAIN, .required = false, + .value.plain = &opt_spki, }, + .description = "Export the Subject Public Key Info (SPKI) from the " + "CKA_PUBLIC_KEY_INFO attribute of an asymmetric private " + "key instead of its private key material. This option can " + "only be used with private keys.", }, + { .short_opt = 0, .long_opt = NULL, }, +}; + +static const struct p11sak_arg p11sak_export_key_args[] = { + { .name = "KEYTYPE", .type = ARG_TYPE_ENUM, .required = false, + .enum_values = p11sak_list_remove_set_copy_export_key_keytypes, + .value.enum_value = &opt_keytype, + .description = "The type of the keys to select for export (optional). " + "If no key type is specified, all key types are " + "selected.", }, + { .name = NULL }, +}; + +static const struct p11sak_cmd p11sak_commands[] = { + { .cmd = "generate-key", .cmd_short1 = "gen-key", .cmd_short2 = "gen", + .func = p11sak_generate_key, + .opts = p11sak_generate_key_opts, .args = p11sak_generate_key_args, + .description = "Generate a key.", + .help = print_generate_import_key_attr_help, + .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, + { .cmd = "list-key", .cmd_short1 = "ls-key", .cmd_short2 = "ls", + .func = p11sak_list_key, + .opts = p11sak_list_key_opts, .args = p11sak_list_key_args, + .description = "List keys in the repository.", + .help = print_list_key_attr_help, .session_flags = CKF_SERIAL_SESSION, }, + { .cmd = "remove-key", .cmd_short1 = "rm-key", .cmd_short2 = "rm", + .func = p11sak_remove_key, + .opts = p11sak_remove_key_opts, .args = p11sak_remove_key_args, + .description = "Delete keys in the repository.", + .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, + { .cmd = "set-key-attr", .cmd_short1 = "set-key", .cmd_short2 = "set", + .func = p11sak_set_key_attr, + .opts = p11sak_set_key_attr_opts, .args = p11sak_set_key_attr_args, + .description = "Set attributes of keys in the repository.", + .help = print_set_copy_key_attr_help, + .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, + { .cmd = "copy-key", .cmd_short1 = "copy", .cmd_short2 = "cp", + .func = p11sak_copy_key, + .opts = p11sak_copy_key_opts, .args = p11sak_copy_key_args, + .description = "Copy keys in the repository.", + .help = print_set_copy_key_attr_help, + .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, + { .cmd = "import-key", .cmd_short1 = "import", .cmd_short2 = "imp", + .func = p11sak_import_key, + .opts = p11sak_import_key_opts, .args = p11sak_import_key_args, + .description = "Import a key from a binary file or PEM file.", + .help = print_generate_import_key_attr_help, + .session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, }, + { .cmd = "export-key", .cmd_short1 = "export", .cmd_short2 = "exp", + .func = p11sak_export_key, + .opts = p11sak_export_key_opts, .args = p11sak_export_key_args, + .description = "Export keys to a binary file or PEM file.", + .session_flags = CKF_SERIAL_SESSION, }, + { .cmd = NULL, .func = NULL }, +}; + +#define DECLARE_BOOL_ATTR(attr, ch, sec, pub, priv, set) \ + { .name = # attr, .type = attr, .letter = ch, \ + .secret = sec, .public = pub, .private = priv, \ + .settable = set, .print_short = print_bool_attr_short, \ + .print_long = print_bool_attr_long, } + +static const struct p11sak_attr p11sak_bool_attrs[] = { + DECLARE_BOOL_ATTR(CKA_PRIVATE, 'P', true, true, true, true), + DECLARE_BOOL_ATTR(CKA_LOCAL, 'L', true, true, true, false), + DECLARE_BOOL_ATTR(CKA_MODIFIABLE, 'M', true, true, true, true), + DECLARE_BOOL_ATTR(CKA_COPYABLE, 'B', true, true, true, true), + DECLARE_BOOL_ATTR(CKA_DESTROYABLE, 'Y', true, true, true, true), + DECLARE_BOOL_ATTR(CKA_DERIVE, 'R', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_ENCRYPT, 'E', true, true, false, true), + DECLARE_BOOL_ATTR(CKA_DECRYPT, 'D', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_SIGN, 'G', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_SIGN_RECOVER, 'C', false, false, true, true), + DECLARE_BOOL_ATTR(CKA_VERIFY, 'V', true, true, false, true), + DECLARE_BOOL_ATTR(CKA_VERIFY_RECOVER, 'O', false, true, false, true), + DECLARE_BOOL_ATTR(CKA_WRAP, 'W', true, true, false, true), + DECLARE_BOOL_ATTR(CKA_UNWRAP, 'U', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_SENSITIVE, 'S', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_ALWAYS_SENSITIVE, 'A', true, false, true, false), + DECLARE_BOOL_ATTR(CKA_EXTRACTABLE, 'X', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_NEVER_EXTRACTABLE, 'N', true, false, true, false), + DECLARE_BOOL_ATTR(CKA_TRUSTED, 'T', true, true, true, false), + DECLARE_BOOL_ATTR(CKA_WRAP_WITH_TRUSTED, 'I', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_IBM_PROTKEY_EXTRACTABLE, + 'K', true, false, true, true), + DECLARE_BOOL_ATTR(CKA_IBM_PROTKEY_NEVER_EXTRACTABLE, + 'Z', true, false, true, false), + { .name = NULL, }, +}; + +static const struct p11sak_custom_attr_type custom_attr_types[] = { + { .type = P11SAK_CONFIG_TYPE_BOOL, .print_long = print_bool_attr_long, }, + { .type = P11SAK_CONFIG_TYPE_ULONG, .print_long = print_ulong_attr, }, + { .type = P11SAK_CONFIG_TYPE_BYTE, .print_long = print_byte_array_attr, }, + { .type = P11SAK_CONFIG_TYPE_DATE, .print_long = print_date_attr, }, + { .type = NULL, }, +}; -static void *pkcs11lib = NULL; -static CK_FUNCTION_LIST *funcs = NULL; +static const struct p11sak_cmd *find_command(const char *cmd) +{ + unsigned int i; -static struct ConfigBaseNode *cfg = NULL; + for (i = 0; p11sak_commands[i].cmd != NULL; i++) { + if (strcasecmp(cmd, p11sak_commands[i].cmd) == 0) + return &p11sak_commands[i]; + if (p11sak_commands[i].cmd_short1 != NULL && + strcasecmp(cmd, p11sak_commands[i].cmd_short1) == 0) + return &p11sak_commands[i]; + if (p11sak_commands[i].cmd_short2 != NULL && + strcasecmp(cmd, p11sak_commands[i].cmd_short2) == 0) + return &p11sak_commands[i]; + } + + return NULL; +} + +static void count_opts(const struct p11sak_opt *opts, + unsigned int *optstring_len, + unsigned int *longopts_count) +{ + const struct p11sak_opt *opt; + + for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { + if (opt->short_opt != 0) { + (*optstring_len)++; + if (opt->arg.type != ARG_TYPE_PLAIN) { + (*optstring_len)++; + if (!opt->arg.required) + (*optstring_len)++; + } + } -static void error_hook(int line, int col, const char *msg) -{ - fprintf(stderr, "PARSE ERROR: %d:%d: %s\n", line, col, msg); + if (opt->long_opt != NULL) + (*longopts_count)++; + } } -void dump_attr(CK_ATTRIBUTE_PTR a) +static CK_RV build_opts(const struct p11sak_opt *opts, + char *optstring, + struct option *longopts) { - const char *typestr; - typestr = p11_get_cka(a->type); - unsigned char *p = a->pValue; - unsigned int z; + const struct p11sak_opt *opt; + unsigned int opts_idx, long_idx; - switch (a->ulValueLen) { - case 0: - printf(" %s: no value\n", typestr); - break; - default: - printf(" %s: len=%lu value:", typestr, a->ulValueLen); - for (z = 0; z < a->ulValueLen; z++) { - if (z % 16 == 0) { - printf("\n %02X ", p[z]); - } - else { - printf("%02X ", p[z]); + opts_idx = strlen(optstring); + + for (long_idx = 0; longopts[long_idx].name != NULL; long_idx++) + ; + + for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { + if (opt->short_opt != 0) { + optstring[opts_idx++] = opt->short_opt; + if (opt->arg.type != ARG_TYPE_PLAIN) { + optstring[opts_idx++] = ':'; + if (!opt->arg.required) + optstring[opts_idx++] = ':'; } } - printf("\n"); - break; + + if (opt->long_opt != NULL) { + longopts[long_idx].name = opt->long_opt; + longopts[long_idx].has_arg = opt->arg.type != ARG_TYPE_PLAIN ? + (opt->arg.required ? + required_argument : optional_argument ) : + no_argument; + longopts[long_idx].flag = NULL; + longopts[long_idx].val = opt->short_opt != 0 ? + opt->short_opt : opt->long_opt_val; + long_idx++; + } } -} -static void unload_pkcs11lib(void) -{ - if (pkcs11lib) - dlclose(pkcs11lib); + return CKR_OK; } -static void load_pkcs11lib(void) +static CK_RV build_cmd_opts(const struct p11sak_opt *cmd_opts, + char **optstring, struct option **longopts) { + unsigned int optstring_len = 0, longopts_count = 0; CK_RV rc; - CK_RV (*getfunclist)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); - const char *libname; - /* check for environment variable PKCSLIB */ - libname = secure_getenv("PKCSLIB"); - if (libname == NULL || strlen(libname) < 1) - libname = default_pkcs11lib; + count_opts(p11sak_generic_opts, &optstring_len, &longopts_count); + if (cmd_opts != NULL) + count_opts(cmd_opts, &optstring_len, &longopts_count); - /* try to load the pkcs11 lib */ - pkcs11lib = dlopen(libname, RTLD_NOW); - if (!pkcs11lib) { - fprintf(stderr, "Error: failed to open pkcs11 lib '%s'\n", libname); - exit(99); + *optstring = calloc(1 + optstring_len + 1, 1); + *longopts = calloc(longopts_count + 1, sizeof(struct option)); + if (*optstring == NULL || *longopts == NULL) { + rc = CKR_HOST_MEMORY; + goto error; } - /* get function list */ - *(void**) (&getfunclist) = dlsym(pkcs11lib, "C_GetFunctionList"); - if (!getfunclist) { - dlclose(pkcs11lib); - fprintf(stderr, "Error: failed to resolve symbol '%s' from pkcs11 lib '%s'\n", - "C_GetFunctionList", libname); - exit(99); - } - rc = getfunclist(&funcs); - if (rc != CKR_OK) { - dlclose(pkcs11lib); - fprintf(stderr, "Error: C_GetFunctionList() on pkcs11 lib '%s' failed with rc = 0x%lX - %s)\n", - libname, rc, p11_get_ckr(rc)); - exit(99); + (*optstring)[0] = ':'; /* Let getopt return ':' on missing argument */ + + rc = build_opts(p11sak_generic_opts, *optstring, *longopts); + if (rc != CKR_OK) + goto error; + + if (cmd_opts != NULL) { + rc = build_opts(cmd_opts, *optstring, *longopts); + if (rc != CKR_OK) + goto error; } - atexit(unload_pkcs11lib); + return CKR_OK; + +error: + if (*optstring != NULL) + free(*optstring); + *optstring = NULL; + + if (*longopts != NULL) + free(*longopts); + *longopts = NULL; + + return rc; } -/** - * Translates the given key type to its string representation. - */ -static const char* kt2str(p11sak_kt ktype) +static CK_RV process_plain_argument(const struct p11sak_arg *arg) { - switch (ktype) { - case kt_DES: - return "DES"; - case kt_3DES: - return "3DES"; - case kt_AES: - return "AES"; - case kt_AES_XTS: - return "AES-XTS"; - case kt_RSAPKCS: - return "RSA_PKCS"; - case kt_EC: - return "EC"; - case kt_IBM_DILITHIUM: - return "IBM DILITHIUM"; - case kt_IBM_KYBER: - return "IBM KYBER"; - case kt_GENERIC: - return "GENERIC"; - case kt_SECRET: - return "SECRET"; - case kt_PUBLIC: - return "PUBLIC"; - case kt_PRIVATE: - return "PRIVATE"; - case kt_ALL: - return "ALL"; - case no_key_type: - return "NO_KEYTYPE"; - default: - return "NO_KEYTYPE"; + *arg->value.plain = true; + + return CKR_OK; +} + +static CK_RV process_string_argument(const struct p11sak_arg *arg, char *val) +{ + *arg->value.string = val; + + return CKR_OK; +} + +static CK_RV process_enum_argument(const struct p11sak_arg *arg, char *val) +{ + const struct p11sak_enum_value *enum_val, *any_val = NULL; + + for (enum_val = arg->enum_values; enum_val->value != NULL; enum_val++) { + + if (enum_val->any_value != NULL) { + any_val = enum_val; + } else if (arg->case_sensitive ? + strcasecmp(val, enum_val->value) == 0 : + strcmp(val, enum_val->value) == 0) { + + *arg->value.enum_value = (struct p11sak_enum_value *)enum_val; + return CKR_OK; + } } + + /* process ANY enumeration value after all others */ + if (any_val != NULL) { + *any_val->any_value = val; + *arg->value.enum_value = (struct p11sak_enum_value *)any_val; + return CKR_OK; + } + + return CKR_ARGUMENTS_BAD; } -/** - * Translates the given key type to its CK_KEY_TYPE - */ -static CK_RV kt2CKK(p11sak_kt ktype, CK_KEY_TYPE *a_key_type) + +static CK_RV process_number_argument(const struct p11sak_arg *arg, char *val) { - switch (ktype) { - case kt_DES: - *a_key_type = CKK_DES; - break; - case kt_3DES: - *a_key_type = CKK_DES3; - break; - case kt_AES: - *a_key_type = CKK_AES; - break; - case kt_AES_XTS: - *a_key_type = CKK_AES_XTS; - break; - case kt_RSAPKCS: - *a_key_type = CKK_RSA; - break; - case kt_EC: - *a_key_type = CKK_EC; - break; - case kt_IBM_DILITHIUM: - *a_key_type = CKK_IBM_PQC_DILITHIUM; - break; - case kt_IBM_KYBER: - *a_key_type = CKK_IBM_PQC_KYBER; - break; - case kt_GENERIC: - *a_key_type = CKK_GENERIC_SECRET; - break; - default: + char *endptr; + + *arg->value.number = strtoul(val, &endptr, 0); + + if ((errno == ERANGE && *arg->value.number == ULONG_MAX) || + (errno != 0 && *arg->value.number == 0) || + endptr == val) { return CKR_ARGUMENTS_BAD; } + return CKR_OK; } -/** - * Translates the given key type to its CK_OBJECT_CLASS - */ -static CK_RV kt2CKO(p11sak_kt ktype, CK_OBJECT_CLASS *a_cko) + +static CK_RV processs_argument(const struct p11sak_arg *arg, char *val) { - switch (ktype) { - case kt_SECRET: - *a_cko = CKO_SECRET_KEY; - break; - case kt_PUBLIC: - *a_cko = CKO_PUBLIC_KEY; - break; - case kt_PRIVATE: - *a_cko = CKO_PRIVATE_KEY; - break; + switch (arg->type) { + case ARG_TYPE_PLAIN: + return process_plain_argument(arg); + case ARG_TYPE_STRING: + return process_string_argument(arg, val); + case ARG_TYPE_ENUM: + return process_enum_argument(arg, val); + case ARG_TYPE_NUMBER: + return process_number_argument(arg, val); default: return CKR_ARGUMENTS_BAD; } - return CKR_OK; } -/** - * Translates the given p11sak command to its string representation. - * no_cmd, gen_key, list_key - */ -static const char* cmd2str(p11sak_cmd cmd) + +static bool argument_is_set(const struct p11sak_arg *arg) { - switch (cmd) { - case no_cmd: - return "no_cmd"; - case gen_key: - return "generate-key"; - case list_key: - return "list-key"; - case remove_key: - return "remove-key"; + if (arg->is_set != NULL) + return arg->is_set(arg); + + switch (arg->type) { + case ARG_TYPE_PLAIN: + return *arg->value.plain; + case ARG_TYPE_STRING: + return *arg->value.string != NULL; + case ARG_TYPE_ENUM: + return *arg->value.enum_value != NULL; + case ARG_TYPE_NUMBER: + return *arg->value.number != 0; default: - return "unknown p11sak cmd"; + return false; } } -/** - * Translates the given attribute type to its long name. - */ -static const char* CKA2a(CK_ATTRIBUTE_TYPE attr_type) + +static void option_arg_error(const struct p11sak_opt *opt, const char *arg) { - switch (attr_type) { - case CKA_TOKEN: - return "CKA_TOKEN"; - case CKA_PRIVATE: - return "CKA_PRIVATE"; - case CKA_MODIFIABLE: - return "CKA_MODIFIABLE"; - case CKA_DERIVE: - return "CKA_DERIVE"; - case CKA_LOCAL: - return "CKA_LOCAL"; - case CKA_SENSITIVE: - return "CKA_SENSITIVE"; - case CKA_ENCRYPT: - return "CKA_ENCRYPT"; - case CKA_DECRYPT: - return "CKA_DECRYPT"; - case CKA_SIGN: - return "CKA_SIGN"; - case CKA_VERIFY: - return "CKA_VERIFY"; - case CKA_WRAP: - return "CKA_WRAP"; - case CKA_UNWRAP: - return "CKA_UNWRAP"; - case CKA_ALWAYS_SENSITIVE: - return "CKA_ALWAYS_SENSITIVE"; - case CKA_EXTRACTABLE: - return "CKA_EXTRACTABLE"; - case CKA_NEVER_EXTRACTABLE: - return "CKA_NEVER_EXTRACTABLE"; - case CKA_TRUSTED: - return "CKA_TRUSTED"; - default: - return "unknown attribute"; + if (opt->short_opt != 0 && opt->long_opt != NULL) + warnx("Invalid argument '%s' for option '-%c/--%s'", arg, + opt->short_opt, opt->long_opt); + else if (opt->long_opt != NULL) + warnx("Invalid argument '%s' for option '--%s'", arg, opt->long_opt); + else + warnx("Invalid argument '%s' for option '-%c'", arg, opt->short_opt); +} + +static void option_missing_error(const struct p11sak_opt *opt) +{ + if (opt->short_opt != 0 && opt->long_opt != NULL) + warnx("Option '-%c/--%s' is required but not specified", opt->short_opt, + opt->long_opt); + else if (opt->long_opt != NULL) + warnx("Option '--%s is required but not specified'", opt->long_opt); + else + warnx("Option '-%c' is required but not specified", opt->short_opt); +} + +static CK_RV process_option(const struct p11sak_opt *opts, int ch, char *val) +{ + const struct p11sak_opt *opt; + CK_RV rc; + + for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { + if (ch == (opt->short_opt != 0 ? opt->short_opt : opt->long_opt_val)) { + rc = processs_argument(&opt->arg, val); + if (rc != CKR_OK) { + option_arg_error(opt, val); + return rc; + } + + return CKR_OK; + } } + + return CKR_ARGUMENTS_BAD; } -/** - * Translates the given key type to its related char string. - */ -static const char* CKK2a(CK_KEY_TYPE t) + +static CK_RV process_cmd_option(const struct p11sak_opt *cmd_opts, + int opt, char *arg) { - // if new cases are added, the buffer = malloc() - // in tok_key_get_key_type() needs to be updated - switch (t) { - case CKK_DES: - return "DES"; - case CKK_DES3: - return "3DES"; - case CKK_AES: - return "AES"; - case CKK_AES_XTS: - return "AES-XTS"; - case CKK_EC: - return "EC"; - case CKK_IBM_PQC_DILITHIUM: - return "IBM DILILTHIUM"; - case CKK_IBM_PQC_KYBER: - return "IBM KYBER"; - case CKK_RSA: - return "RSA"; - case CKK_DH: - return "DH"; - case CKK_DSA: - return "DSA"; - case CKK_GENERIC_SECRET: - return "generic"; - default: - return "unknown key type"; + CK_RV rc; + + rc = process_option(p11sak_generic_opts, opt, arg); + if (rc == CKR_OK) + return CKR_OK; + + if (cmd_opts != NULL) { + rc = process_option(cmd_opts, opt, arg); + if (rc == CKR_OK) + return CKR_OK; } + + return rc; } -/** - * Translates the given bool to its related char string. - */ -static const char* CK_BBOOL2a(CK_BBOOL b) + +static CK_RV check_required_opts(const struct p11sak_opt *opts) { - switch (b) { - case 0: - return "CK_FALSE"; - case 1: - return "CK_TRUE"; - default: - return "unknown value"; + const struct p11sak_opt *opt; + CK_RV rc = CKR_OK; + + for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { + if (opt->required && opt->arg.required && + argument_is_set(&opt->arg) == false) { + option_missing_error(opt); + rc = CKR_ARGUMENTS_BAD; + /* No break, report all missing options */ + } } + + return rc; } -/** - * Translates the given ULONG value to a byte string. - */ -static CK_BYTE* CK_ULONG2bigint(CK_ULONG ul, CK_BYTE *bytes, CK_ULONG *len) + +static CK_RV check_required_cmd_opts(const struct p11sak_opt *cmd_opts) +{ + CK_RV rc; + + rc = check_required_opts(p11sak_generic_opts); + if (rc != CKR_OK) + return rc; + + if (cmd_opts != NULL) { + rc = check_required_opts(cmd_opts); + if (rc != CKR_OK) + return rc; + } + + return CKR_OK; +} + +static CK_RV parse_cmd_options(const struct p11sak_cmd *cmd, + int argc, char *argv[]) { - CK_BYTE *ulp; - CK_ULONG tul = 1; - CK_BYTE *tulp; - int i, j, s; + char *optstring = NULL; + struct option *longopts = NULL; + CK_RV rc; + int c; - s = 0; - ulp = (CK_BYTE*) &ul; - tulp = (CK_BYTE*) &tul; + rc = build_cmd_opts(cmd != NULL ? cmd->opts : NULL, &optstring, &longopts); + if (rc != CKR_OK) + goto done; + + opterr = 0; + while (1) { + c = getopt_long(argc, argv, optstring, longopts, NULL); + if (c == -1) + break; + + switch (c) { + case ':': + warnx("Option '%s' requires an argument", argv[optind - 1]); + rc = CKR_ARGUMENTS_BAD; + goto done; + + case '?': /* An invalid option has been specified */ + if (optopt) + warnx("Invalid option '-%c'", optopt); + else + warnx("Invalid option '%s'", argv[optind - 1]); + rc = CKR_ARGUMENTS_BAD; + goto done; - if (tulp[0] == 1) { - for (j = sizeof(CK_ULONG) - 1, i = 0; j >= 0; j--, i++) { - bytes[i] = ulp[j]; - if (s == 0 && bytes[i] != 0) - s = i; + default: + rc = process_cmd_option(cmd != NULL ? cmd->opts : NULL, c, optarg); + if (rc != CKR_OK) + goto done; + break; } - } else { - for (i = 0; i <= (int) sizeof(CK_ULONG) - 1; i++) { - bytes[i] = ulp[i]; - if (s == 0 && bytes[i] != 0) - s = i; + } + + if (optind < argc) { + warnx("Invalid argument '%s'", argv[optind]); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + +done: + if (optstring != NULL) + free(optstring); + if (longopts != NULL) + free(longopts); + + return rc; +} + +static CK_RV check_required_args(const struct p11sak_arg *args) +{ + const struct p11sak_arg *arg; + CK_RV rc2, rc = CKR_OK; + + for (arg = args; arg != NULL && arg->name != NULL; arg++) { + if (arg->required && argument_is_set(arg) == false) { + warnx("Argument '%s' is required but not specified", arg->name); + rc = CKR_ARGUMENTS_BAD; + /* No break, report all missing arguments */ + } + + /* Check enumeration value specific arguments (if any) */ + if (arg->type == ARG_TYPE_ENUM && *arg->value.enum_value != NULL && + (*arg->value.enum_value)->args != NULL) { + rc2 = check_required_args((*arg->value.enum_value)->args); + if (rc2 != CKR_OK) + rc = rc2; + /* No break, report all missing arguments */ } } - *len = sizeof(CK_ULONG) - s; - memmove(&bytes[0], &bytes[s], *len); - return &bytes[0]; + + return rc; } -/** - * print help functions - */ -static void print_cmd_help(void) + +static CK_RV parse_arguments(const struct p11sak_arg *args, + int *argc, char **argv[]) +{ + const struct p11sak_arg *arg; + CK_RV rc = CKR_OK; + + for (arg = args; arg->name != NULL; arg++) { + if (*argc < 2 || strncmp((*argv)[1], "-", 1) == 0) + break; + + rc = processs_argument(arg, (*argv)[1]); + if (rc != CKR_OK) { + if (rc == CKR_ARGUMENTS_BAD) + warnx("Invalid argument '%s' for '%s'", (*argv)[1], arg->name); + break; + } + + (*argc)--; + (*argv)++; + + /* Process enumeration value specific arguments (if any) */ + if (arg->type == ARG_TYPE_ENUM && *arg->value.enum_value != NULL && + (*arg->value.enum_value)->args != NULL) { + rc = parse_arguments((*arg->value.enum_value)->args, argc, argv); + if (rc != CKR_OK) + break; + } + } + + return rc; +} + +static CK_RV parse_cmd_arguments(const struct p11sak_cmd *cmd, + int *argc, char **argv[]) { - printf("\n Usage: p11sak COMMAND [ARGS] [OPTIONS]\n"); - printf("\n Commands:\n"); - printf(" generate-key Generate a key\n"); - printf(" list-key List keys in the repository\n"); - printf(" remove-key Delete keys in the repository\n"); - printf("\n Options:\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_listkeys_help(void) -{ - printf("\n Usage: p11sak list-key [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" des\n"); - printf(" 3des\n"); - printf(" aes\n"); - printf(" aes-xts\n"); - printf(" rsa\n"); - printf(" ec\n"); - printf(" ibm-dilithium\n"); - printf(" ibm-kyber\n"); - printf(" public\n"); - printf(" private\n"); - printf(" secret\n"); - printf(" all\n"); - printf("\n Options:\n"); - printf(" -l, --long list output with long format\n"); - printf(" --detailed-uri enable detailed PKCS#11 URI\n"); - printf(" --label LABEL filter keys by key label\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_help(void) -{ - printf("\n Usage: p11sak generate-key [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" des\n"); - printf(" 3des\n"); - printf(" aes [128 | 192 | 256]\n"); - printf(" aes-xts [128 | 256]\n"); - printf(" rsa [1024 | 2048 | 4096]\n"); - printf(" ec [prime256v1 | prime192v1 | secp224r1 | secp384r1 | secp521r1 | secp256k1 | \n"); - printf(" brainpoolP160r1 | brainpoolP160t1 | brainpoolP192r1 | brainpoolP192t1 | \n"); - printf(" brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 | \n"); - printf(" brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | \n"); - printf(" brainpoolP512r1 | brainpoolP512t1 | curve25519 | curve448 | ed25519 | \n"); - printf(" ed448]\n"); - printf(" ibm-dilithium [r2_65 | r2_87 | r3_44 | r3_65 | r3_87]\n"); - printf(" ibm-kyber [r2_768 | r2_1024]\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --label PUB_LABEL:PRIV_LABEL\n"); - printf(" for asymmetric keys: set individual labels for public and private key\n"); - printf(" --exponent EXP set RSA exponent EXP\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" --attr [[pub_attrs]:[priv_attrs]] \n"); - printf(" for asymmetric keys: set individual key attributes, values see above\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_removekeys_help(void) -{ - printf("\n Usage: p11sak remove-key [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" des\n"); - printf(" 3des\n"); - printf(" aes\n"); - printf(" aes-xts\n"); - printf(" rsa\n"); - printf(" ec\n"); - printf(" ibm-dilithium\n"); - printf(" ibm-kyber\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL Key label LABEL to be removed\n"); - printf(" -f, --force Force remove all keys of given cipher type\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_des_help(void) -{ - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_aes_help(void) -{ - printf("\n Usage: p11sak generate-key aes [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" 128\n"); - printf(" 192\n"); - printf(" 256\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_aes_xts_help(void) -{ - printf("\n Usage: p11sak generate-key aes-xts [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" 128\n"); - printf(" 256\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_rsa_help(void) -{ - printf("\n Usage: p11sak generate-key rsa [ARGS] [OPTIONS] [ARGS]\n"); - printf("\n Args:\n"); - printf(" 1024\n"); - printf(" 2048\n"); - printf(" 4096\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --label PUB_LABEL:PRIV_LABEL\n"); - printf(" for asymmetric keys: set individual labels for public and private key\n"); - printf(" --exponent EXP set RSA exponent EXP\n"); - printf(" --attr [S D G U X] set key attributes\n"); - printf(" --attr [[pub_attrs]:[priv_attrs]] \n"); - printf(" for asymmetric keys: set individual key attributes, values see above\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_ec_help(void) -{ - printf("\n Usage: p11sak generate-key ec [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" prime256v1\n"); - printf(" prime192v1\n"); - printf(" secp224r1\n"); - printf(" secp384r1\n"); - printf(" secp521r1\n"); - printf(" secp265k1\n"); - printf(" brainpoolP160r1\n"); - printf(" brainpoolP160t1\n"); - printf(" brainpoolP192r1\n"); - printf(" brainpoolP192t1\n"); - printf(" brainpoolP224r1\n"); - printf(" brainpoolP224t1\n"); - printf(" brainpoolP256r1\n"); - printf(" brainpoolP256t1\n"); - printf(" brainpoolP320r1\n"); - printf(" brainpoolP320t1\n"); - printf(" brainpoolP384r1\n"); - printf(" brainpoolP384t1\n"); - printf(" brainpoolP512r1\n"); - printf(" brainpoolP512t1\n"); - printf(" curve25519\n"); - printf(" curve448\n"); - printf(" ed25519\n"); - printf(" ed448\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --label PUB_LABEL:PRIV_LABEL\n"); - printf(" for asymmetric keys: set individual labels for public and private key\n"); - printf(" --attr [S D G U X] set key attributes\n"); - printf(" --attr [[pub_attrs]:[priv_attrs]] \n"); - printf(" for asymmetric keys: set individual key attributes, values see above\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_ibm_dilithium_help(void) -{ - printf("\n Usage: p11sak generate-key ibm-dilithium [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" r2_65\n"); - printf(" r2_87\n"); - printf(" r3_44\n"); - printf(" r3_65\n"); - printf(" r3_87\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --label PUB_LABEL:PRIV_LABEL\n"); - printf(" for asymmetric keys: set individual labels for public and private key\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" --attr [[pub_attrs]:[priv_attrs]] \n"); - printf(" for asymmetric keys: set individual key attributes, values see above\n"); - printf(" -h, --help Show this help\n\n"); -} - -static void print_gen_ibm_kyber_help(void) -{ - printf("\n Usage: p11sak generate-key ibm-kyber [ARGS] [OPTIONS]\n"); - printf("\n Args:\n"); - printf(" r2_768\n"); - printf(" r2_1024\n"); - printf("\n Options:\n"); - printf(" --slot SLOTID openCryptoki repository token SLOTID.\n"); - printf(" --pin PIN pkcs11 user PIN\n"); - printf(" --force-pin-prompt enforce user PIN prompt\n"); - printf(" --label LABEL key label LABEL to be listed\n"); - printf(" --label PUB_LABEL:PRIV_LABEL\n"); - printf(" for asymmetric keys: set individual labels for public and private key\n"); - printf(" --attr [M R L S E D G V W U A X N] set key attributes\n"); - printf(" --attr [[pub_attrs]:[priv_attrs]] \n"); - printf(" for asymmetric keys: set individual key attributes, values see above\n"); - printf(" -h, --help Show this help\n\n"); + if (cmd == NULL) + return CKR_OK; + + return parse_arguments(cmd->args, argc, argv); } -/** - * Print help for generate-key command - */ -static CK_RV print_gen_keys_help(p11sak_kt *kt) +static void print_indented(const char *str, int indent) { + char *word, *line, *desc, *desc_ptr; + int word_len, pos = indent; - switch (*kt) { - case kt_DES: - printf("\n Usage: p11sak generate-key des [ARGS] [OPTIONS]\n"); - print_gen_des_help(); - break; - case kt_3DES: - printf("\n Usage: p11sak generate-key 3des [ARGS] [OPTIONS]\n"); - print_gen_des_help(); - break; - case kt_AES: - print_gen_aes_help(); - break; - case kt_AES_XTS: - print_gen_aes_xts_help(); - break; - case kt_RSAPKCS: - print_gen_rsa_help(); - break; - case kt_EC: - print_gen_ec_help(); - break; - case kt_IBM_DILITHIUM: - print_gen_ibm_dilithium_help(); - break; - case kt_IBM_KYBER: - print_gen_ibm_kyber_help(); - break; - case no_key_type: - print_gen_help(); - break; - default: - print_gen_help(); + desc = desc_ptr = strdup(str); + if (desc == NULL) + return; + + line = strsep(&desc, "\n"); + while (line != NULL) { + word = strsep(&line, " "); + pos = indent; + while (word != NULL) { + word_len = strlen(word); + if (pos + word_len + 1 > MAX_PRINT_LINE_LENGTH) { + printf("\n%*s", indent, ""); + pos = indent; + } + if (pos == indent) + printf("%s", word); + else + printf(" %s", word); + pos += word_len + 1; + word = strsep(&line, " "); + } + if (desc) + printf("\n%*s", indent, ""); + line = strsep(&desc, "\n"); } - return CKR_OK; + printf("\n"); + free(desc_ptr); } -/** - * Print help for attributes - */ -static void print_gen_attr_help(void) + +static void print_options_help(const struct p11sak_opt *opts) +{ + const struct p11sak_opt *opt; + char tmp[200]; + int len; + + for (opt = opts; opt->short_opt != 0 || opt->long_opt != NULL; opt++) { + if (opt->short_opt != 0 && opt->long_opt != NULL) + len = snprintf(tmp, sizeof(tmp), "-%c, --%s", opt->short_opt, + opt->long_opt); + else if (opt->short_opt == 0 && opt->long_opt != NULL) + len = snprintf(tmp, sizeof(tmp)," --%s", opt->long_opt); + else + len = snprintf(tmp, sizeof(tmp),"-%c", opt->short_opt); + + if (opt->arg.type != ARG_TYPE_PLAIN) { + if (opt->arg.required) + snprintf(&tmp[len], sizeof(tmp) - len, " %s", opt->arg.name); + else if (opt->long_opt == NULL) + snprintf(&tmp[len], sizeof(tmp) - len, "[%s]", opt->arg.name); + else + snprintf(&tmp[len], sizeof(tmp) - len, "[=%s]", opt->arg.name); + } + + printf(" %-30.30s ", tmp); + print_indented(opt->description, PRINT_INDENT_POS); + } +} + +static void print_arguments_help(const struct p11sak_cmd *cmd, + const struct p11sak_arg *args, + int indent) +{ + const struct p11sak_arg *arg; + const struct p11sak_enum_value *val; + int width; + bool newline = false; + + if (indent > 0) { + for (arg = args; arg->name != NULL; arg++) { + if (arg->required) + printf(" %s", arg->name); + else + printf(" [%s]", arg->name); + } + printf("\n\n"); + } + + for (arg = args; arg->name != NULL; arg++) { + width = 30 - indent; + if (width < (int)strlen(arg->name)) + width = (int)strlen(arg->name); + + printf("%*s %-*.*s ", indent, "", width, width, arg->name); + print_indented(arg->description, PRINT_INDENT_POS); + + newline = false; + + if (arg->type != ARG_TYPE_ENUM) + continue; + + /* Enumeration: print possible values */ + for (val = arg->enum_values; val->value != NULL; val++) { + if (arg == cmd->args && argument_is_set(arg) && + *arg->value.enum_value != val) + continue; + + newline = true; + + printf("%*s %s", indent, "", val->value); + + if (val->args != NULL) { + print_arguments_help(cmd, val->args, indent + 8); + newline = false; + } else { + printf("\n"); + } + } + } + + if (indent > 0 || newline) + printf("\n"); +} + +static void print_help(void) { + const struct p11sak_cmd *cmd; + printf("\n"); - printf(" Setting CK_ATTRIBUTE\n"); + printf("Usage: p11sak COMMAND [ARGS] [OPTIONS]\n"); + printf("\n"); + printf("COMMANDS:\n"); + for (cmd = p11sak_commands; cmd->cmd != NULL; cmd++) { + printf(" %-30.30s ", cmd->cmd); + print_indented(cmd->description, PRINT_INDENT_POS); + } printf("\n"); - printf(" 'P': CKA_PRIVATE\n"); - printf(" 'M': CKA_MODIFIABLE\n"); - printf(" 'R': CKA_DERIVE\n"); - printf(" 'L': CKA_LOCAL\n"); - printf(" 'S': CKA_SENSITIVE\n"); - printf(" 'E': CKA_ENCRYPT\n"); - printf(" 'D': CKA_DECRYPT\n"); - printf(" 'G': CKA_SIGN\n"); - printf(" 'V': CKA_VERIFY\n"); - printf(" 'W': CKA_WRAP\n"); - printf(" 'U': CKA_UNWRAP\n"); - printf(" 'A': CKA_ALWAYS_SENSITIVE\n"); - printf(" 'X': CKA_EXTRACTABLE\n"); - printf(" 'N': CKA_NEVER_EXTRACTABLE\n"); + printf("COMMON OPTIONS\n"); + print_options_help(p11sak_generic_opts); printf("\n"); - printf(" CKA_TOKEN is set by default.\n"); - printf(" If an attribute is not set explicitly, the default values are used.\n"); - printf(" For multiple attributes add char without white space, e. g. 'MLD')\n"); + printf("For more information use 'p11sak COMMAND --help'.\n"); printf("\n"); +} +static void print_command_help(const struct p11sak_cmd *cmd) +{ + printf("\n"); + printf("Usage: p11sak %s [ARGS] [OPTIONS]\n", cmd->cmd); + printf("\n"); + printf("ARGS:\n"); + print_arguments_help(cmd, cmd->args, 0); + printf("OPTIONS:\n"); + print_options_help(cmd->opts); + print_options_help(p11sak_generic_opts); printf("\n"); + if (cmd->help != NULL) + cmd->help(); } -/** - * Builds an attribute from the given modulus bits and exponent. - * pubattr >= x elements, prvattr >= y elements - */ -static CK_RV read_rsa_args(CK_ULONG modulusbits, CK_ULONG exponent, - CK_ATTRIBUTE *pubattr, CK_ULONG *pubcount) + +static void print_generate_import_key_attr_help(void) { - CK_ULONG *mod_bits; - CK_ULONG ulpubexp; - CK_BYTE *pubexp; - CK_BYTE *spubexp; - CK_ULONG spubexplen; + const struct p11sak_attr *attr; - if (!(mod_bits = malloc(sizeof(CK_ULONG)))) { - fprintf(stderr, "Error: failed to allocate memory for mod_bits.\n"); - return CKR_HOST_MEMORY; + printf("ATTRIBUTES:\n"); + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { + if (attr->settable) + printf(" '%c': %s\n", attr->letter, attr->name); } - *mod_bits = modulusbits; + printf("\n"); - pubattr[*pubcount].type = CKA_MODULUS_BITS; - pubattr[*pubcount].pValue = mod_bits; - pubattr[*pubcount].ulValueLen = sizeof(CK_ULONG); - (*pubcount)++; + printf(" "); + print_indented("An uppercase letter sets the corresponding attribute to " + "CK_TRUE, a lower case letter to CK_FALSE.\n" + "If an attribute is not set explicitly, its default value " + "is used.\n" + "Not all attributes may be accepted for all key types.\n" + "Attribute CKA_TOKEN is always set to CK_TRUE.", 4); + printf("\n"); +} - if (exponent > 0) - ulpubexp = exponent; - else - ulpubexp = 65537; /* default for RSA_PKCS */ +static void print_list_key_attr_help(void) +{ + const struct p11sak_attr *attr; + + printf("ATTRIBUTES:\n"); + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) + printf(" '%c': %s\n", attr->letter, attr->name); + printf("\n"); + + printf(" "); + print_indented("Not all attributes may be defined for all key types.\n" + "Attribute CKA_TOKEN is always CK_TRUE for all keys listed.", + 4); + printf("\n"); +} + +static void print_set_copy_key_attr_help(void) +{ + const struct p11sak_attr *attr; + + printf("ATTRIBUTES:\n"); + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { + if (attr->settable) + printf(" '%c': %s\n", attr->letter, attr->name); + } + printf("\n"); + + printf(" "); + print_indented("An uppercase letter sets the corresponding attribute to " + "CK_TRUE, a lower case letter to CK_FALSE.\n" + "If an attribute is not set explicitly, its value is not " + "changed.\n" + "Not all attributes may be allowed to be changed for all " + "key types, or to all values.\n", 4); + printf("\n"); +} + +static void print_version(void) +{ + printf("p11sak version %s\n", PACKAGE_VERSION); +} + +static bool opt_slot_is_set(const struct p11sak_arg *arg) +{ + return (*arg->value.number != (CK_ULONG)-1); +} + +static int openssl_err_cb(const char *str, size_t len, void *u) +{ + UNUSED(u); + + if (str[len - 1] == '\n') + len--; + + warnx("OpenSSL error: %.*s", (int)len, str); + return 1; +} + +static bool is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session) +{ + CK_SESSION_INFO info; + CK_RV rc; + + if (ret_code != CKR_FUNCTION_FAILED) + return false; + + rc = pkcs11_funcs->C_GetSessionInfo(session, &info); + if (rc != CKR_OK) { + warnx("C_GetSessionInfo failed: 0x%lX: %s", rc, p11_get_ckr(rc)); + return false; + } + + return (info.ulDeviceError == CKR_POLICY_VIOLATION); +} + +static CK_RV check_mech_supported(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + rc = pkcs11_funcs->C_GetMechanismInfo(opt_slot, + keytype->keygen_mech.mechanism, + &mech_info); + if (rc != CKR_OK) { + warnx("Token in slot %lu does not support mechanism %s", opt_slot, + p11_get_ckm(&mechtable_funcs, keytype->keygen_mech.mechanism)); + return rc; + } + + if ((mech_info.flags & (keytype->is_asymmetric ? + CKF_GENERATE_KEY_PAIR : CKF_GENERATE)) == 0) { + warnx("Mechanism %s does not support to generate keys", + p11_get_ckm(&mechtable_funcs, keytype->keygen_mech.mechanism)); + return CKR_MECHANISM_INVALID; + } + + if (keysize != 0 && + mech_info.ulMinKeySize != 0 && mech_info.ulMaxKeySize != 0) { + if (keysize < mech_info.ulMinKeySize || + keysize > mech_info.ulMaxKeySize) { + warnx("Mechanism %s does not support to generate keys of size %lu", + p11_get_ckm(&mechtable_funcs, keytype->keygen_mech.mechanism), + keysize); + return CKR_KEY_SIZE_RANGE; + } + } + + return CKR_OK; +} + +static CK_RV add_attribute(CK_ATTRIBUTE_TYPE type, const void *value, + CK_ULONG value_len, CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs) +{ + CK_ATTRIBUTE *tmp; + + tmp = realloc(*attrs, (*num_attrs + 1) * sizeof(CK_ATTRIBUTE)); + if (tmp == NULL) { + warnx("Failed to allocate memory for attribute list"); + return CKR_HOST_MEMORY; + } + + *attrs = tmp; - if (!(pubexp = malloc(sizeof(CK_ULONG)))) { - fprintf(stderr, "Error: failed to allocate memory for public exponent.\n"); - free(mod_bits); + tmp[*num_attrs].type = type; + tmp[*num_attrs].ulValueLen = value_len; + tmp[*num_attrs].pValue = malloc(value_len); + if (tmp[*num_attrs].pValue == NULL) { + warnx("Failed to allocate memory attribute to add to list"); return CKR_HOST_MEMORY; } + memcpy(tmp[*num_attrs].pValue, value, value_len); - spubexp = CK_ULONG2bigint(ulpubexp, pubexp, &spubexplen); - pubattr[*pubcount].type = CKA_PUBLIC_EXPONENT; - pubattr[*pubcount].pValue = spubexp; - pubattr[*pubcount].ulValueLen = spubexplen; - (*pubcount)++; + (*num_attrs)++; return CKR_OK; } -/** - * Builds the CKA_EC_PARAMS attribute from the given ECcurve. - */ -static CK_RV read_ec_args(const char *ECcurve, CK_ATTRIBUTE *pubattr, - CK_ULONG *pubcount, CK_ULONG *keybits) + +static CK_RV generic_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) { - pubattr[*pubcount].type = CKA_EC_PARAMS; - if (strcmp(ECcurve, "prime256v1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) prime256v1; - pubattr[*pubcount].ulValueLen = sizeof(prime256v1); - *keybits = 256; - } else if (strcmp(ECcurve, "prime192v1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) prime192v1; - pubattr[*pubcount].ulValueLen = sizeof(prime192v1); - *keybits = 192; - } else if (strcmp(ECcurve, "secp224r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) secp224r1; - pubattr[*pubcount].ulValueLen = sizeof(secp224r1); - *keybits = 224; - } else if (strcmp(ECcurve, "secp384r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) secp384r1; - pubattr[*pubcount].ulValueLen = sizeof(secp384r1); - *keybits = 384; - } else if (strcmp(ECcurve, "secp521r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) secp521r1; - pubattr[*pubcount].ulValueLen = sizeof(secp521r1); - *keybits = 521; - } else if (strcmp(ECcurve, "secp265k1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) secp256k1; - pubattr[*pubcount].ulValueLen = sizeof(secp256k1); - *keybits = 256; - } else if (strcmp(ECcurve, "brainpoolP160r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP160r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP160r1); - *keybits = 160; - } else if (strcmp(ECcurve, "brainpoolP160t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP160t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP160t1); - *keybits = 160; - } else if (strcmp(ECcurve, "brainpoolP192r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP192r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP192r1); - *keybits = 192; - } else if (strcmp(ECcurve, "brainpoolP192t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP192t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP192t1); - *keybits = 192; - } else if (strcmp(ECcurve, "brainpoolP224r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP224r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP224r1); - *keybits = 224; - } else if (strcmp(ECcurve, "brainpoolP224t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP224t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP224t1); - *keybits = 224; - } else if (strcmp(ECcurve, "brainpoolP256r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP256r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP256r1); - *keybits = 256; - } else if (strcmp(ECcurve, "brainpoolP256t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP256t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP256t1); - *keybits = 256; - } else if (strcmp(ECcurve, "brainpoolP320r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP320r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP320r1); - *keybits = 320; - } else if (strcmp(ECcurve, "brainpoolP320t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP320t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP320t1); - *keybits = 320; - } else if (strcmp(ECcurve, "brainpoolP384r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP384r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP384r1); - *keybits = 384; - } else if (strcmp(ECcurve, "brainpoolP384t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP384t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP384t1); - *keybits = 384; - } else if (strcmp(ECcurve, "brainpoolP512r1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP512r1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP512r1); - *keybits = 512; - } else if (strcmp(ECcurve, "brainpoolP512t1") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP512t1; - pubattr[*pubcount].ulValueLen = sizeof(brainpoolP512t1); - *keybits = 512; - } else if (strcmp(ECcurve, "curve25519") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) curve25519; - pubattr[*pubcount].ulValueLen = sizeof(curve25519); - *keybits = 256; - } else if (strcmp(ECcurve, "curve448") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) curve448; - pubattr[*pubcount].ulValueLen = sizeof(curve448); - *keybits = 456; - } else if (strcmp(ECcurve, "ed25519") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) ed25519; - pubattr[*pubcount].ulValueLen = sizeof(ed25519); - *keybits = 256; - } else if (strcmp(ECcurve, "ed448") == 0) { - pubattr[*pubcount].pValue = (CK_BYTE*) ed448; - pubattr[*pubcount].ulValueLen = sizeof(ed448); - *keybits = 448; - } else { - fprintf(stderr, "Unexpected case while parsing EC curves.\n"); - fprintf(stderr, "Note: not all tokens support all curves.\n"); - return CKR_ARGUMENTS_BAD; + UNUSED(private); + UNUSED(keytype); + + *keysize = opt_keybits_num; + + return CKR_OK; +} + +static CK_RV generic_add_secret_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + CK_ULONG value_len = opt_keybits_num / 8; + + UNUSED(private); + UNUSED(keytype); + + return add_attribute(CKA_VALUE_LEN, &value_len, sizeof(value_len), + attrs, num_attrs); +} + +static CK_ULONG generic_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return keysize * 8; +} + +static CK_RV aes_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) +{ + UNUSED(private); + UNUSED(keytype); + + *keysize = opt_keybits->private.num / 8; + + return CKR_OK; +} + +static CK_RV aes_add_secret_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + CK_ULONG value_len = opt_keybits->private.num / 8; + + UNUSED(private); + UNUSED(keytype); + + return add_attribute(CKA_VALUE_LEN, &value_len, sizeof(value_len), + attrs, num_attrs); +} + +static CK_ULONG aes_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return keysize * 8; +} + +static CK_ULONG aes_xts_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return (keysize * 8) / 2; +} + +static CK_ULONG rsa_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return keysize * 8; +} + +static CK_ULONG dh_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return keysize * 8; +} + +static CK_ULONG dsa_keysize_adjust(const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + UNUSED(keytype); + + return keysize * 8; +} + +static CK_RV rsa_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) +{ + UNUSED(private); + UNUSED(keytype); + + *keysize = opt_keybits->private.num; + + return CKR_OK; +} + +static CK_RV rsa_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + CK_RV rc; + CK_BYTE *b; + CK_ULONG val; + unsigned int i; + + UNUSED(private); + UNUSED(keytype); + + rc = add_attribute(CKA_MODULUS_BITS, &opt_keybits->private.num, + sizeof(opt_keybits->private.num), attrs, num_attrs); + if (rc != CKR_OK) + return rc; + + if (opt_exponent != 0) { + /* Convert CK_ULOING to big-endian byte array */ + val = htobe64(opt_exponent); + for (i = 0, b = (CK_BYTE *)&val; i < sizeof(val) && *b == 0; i++, b++) + ; + + rc = add_attribute(CKA_PUBLIC_EXPONENT, b, sizeof(val) - i, + attrs, num_attrs); + if (rc != CKR_OK) + return rc; } - (*pubcount)++; return CKR_OK; } -/** - * Builds the CKA_IBM_DILITHIUM_KEYFORM attribute from the given version. - */ -static CK_RV read_dilithium_args(const char *dilithium_ver, CK_ULONG *keyform, - CK_ATTRIBUTE *pubattr, CK_ULONG *pubcount) + +static CK_RV ec_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) { - if (strcasecmp(dilithium_ver, "r2_65") == 0) { - *keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_65; - } else if (strcasecmp(dilithium_ver, "r2_87") == 0) { - *keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND2_87; - } else if (strcasecmp(dilithium_ver, "r3_44") == 0) { - *keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_44; - } else if (strcasecmp(dilithium_ver, "r3_65") == 0) { - *keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_65; - } else if (strcasecmp(dilithium_ver, "r3_87") == 0) { - *keyform = CK_IBM_DILITHIUM_KEYFORM_ROUND3_87; - } else { - fprintf(stderr, "Unexpected case while parsing dilithium version.\n"); - fprintf(stderr, "Note: not all tokens support all versions.\n"); + const struct curve_info *curve = opt_curve->private.ptr; + + UNUSED(private); + UNUSED(keytype); + + *keysize = curve->bitsize; + + return CKR_OK; +} + +static CK_RV ec_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + const struct curve_info *curve = opt_curve->private.ptr; + + UNUSED(private); + UNUSED(keytype); + + return add_attribute(CKA_EC_PARAMS, curve->oid, curve->oid_len, + attrs, num_attrs); +} + +static CK_RV dh_dsa_read_params_pem(const char *pem_file, bool is_dsa, + EVP_PKEY **pkey) +{ + CK_RV rc = CKR_OK; + EVP_PKEY *param = NULL; + BIO *f; + + f = BIO_new_file(pem_file, "r"); + if (f == NULL) { + warnx("Failed to open PEM file '%s'.", pem_file); + ERR_print_errors_cb(openssl_err_cb, NULL); return CKR_ARGUMENTS_BAD; } - pubattr[*pubcount].type = CKA_IBM_DILITHIUM_KEYFORM; - pubattr[*pubcount].ulValueLen = sizeof(CK_ULONG); - pubattr[*pubcount].pValue = keyform; - (*pubcount)++; + param = PEM_read_bio_Parameters(f, NULL); + if (param == NULL || + EVP_PKEY_base_id(param) != (is_dsa ? EVP_PKEY_DSA : EVP_PKEY_DH)) { + warnx("Failed to read %s PEM file '%s'.", is_dsa ? "DSA" : "DH", + pem_file); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } - return CKR_OK; + *pkey = param; + param = NULL; + +done: + BIO_free(f); + if (param != NULL) + EVP_PKEY_free(param); + + return rc; } -/** - * Builds the CKA_IBM_KYBER_KEYFORM attribute from the given version. - */ -static CK_RV read_kyber_args(const char *kyber_ver, CK_ULONG *keyform, - CK_ATTRIBUTE *pubattr, CK_ULONG *pubcount) + +static CK_RV dh_group_params(int group_nid, EVP_PKEY **pkey) +{ + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *param = NULL; + CK_RV rc = CKR_OK; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); + if (ctx == NULL) { + warnx("Failed to set up an EVP context for DH."); + ERR_print_errors_cb(openssl_err_cb, NULL); + return CKR_FUNCTION_FAILED; + } + + if (EVP_PKEY_paramgen_init(ctx) <= 0) { + warnx("Failed to initialize a DH paramgen context."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (EVP_PKEY_CTX_set_dh_nid(ctx, group_nid) <= 0) { + warnx("Failed to set group for DH paramgen context."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (EVP_PKEY_paramgen(ctx, ¶m) <= 0) { + warnx("Failed to generate the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + *pkey = param; + param = NULL; + +done: + if (param != NULL) + EVP_PKEY_free(param); + EVP_PKEY_CTX_free(ctx); + + return rc; +} + +static CK_RV add_bignum_attr(CK_ATTRIBUTE_TYPE type, const BIGNUM* bn, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { - if (strcasecmp(kyber_ver, "r2_768") == 0) { - *keyform = CK_IBM_KYBER_KEYFORM_ROUND2_768; - } else if (strcasecmp(kyber_ver, "r2_1024") == 0) { - *keyform = CK_IBM_KYBER_KEYFORM_ROUND2_1024; + int len; + CK_BYTE *buff = NULL; + CK_RV rc; + + len = BN_num_bytes(bn); + buff = calloc(len, 1); + if (buff == NULL || len == 0) { + warnx("Failed to allocate a buffer for a bignum"); + if (buff != NULL) + free(buff); + return CKR_HOST_MEMORY; + } + + if (BN_bn2bin(bn, buff) != len) { + warnx("Failed to get a bignum."); + ERR_print_errors_cb(openssl_err_cb, NULL); + free(buff); + return CKR_FUNCTION_FAILED; + } + + rc = add_attribute(type, buff, len, attrs, num_attrs); + free(buff); + + return rc; +} + +static CK_RV dh_dsa_add_public_attrs(CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + EVP_PKEY *pkey, bool is_dsa) +{ + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; +#else + const DH *dh; + const DSA *dsa; + const BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; +#endif + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || + (is_dsa && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_Q, &bn_q)) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g)) { + warnx("Failed to get the %s params.", is_dsa ? "DSA" : "DH"); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + if (is_dsa) { + dsa = EVP_PKEY_get0_DSA(pkey); + if (dsa == NULL) { + warnx("Failed to get the DSA params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); + if (bn_p == NULL || (dsa && bn_q == NULL) || bn_g == NULL) { + warnx("Failed to get the DSA params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } } else { - fprintf(stderr, "Unexpected case while parsing kyber version.\n"); - fprintf(stderr, "Note: not all tokens support all versions.\n"); - return CKR_ARGUMENTS_BAD; + dh = EVP_PKEY_get0_DH(pkey); + if (dh == NULL) { + warnx("Failed to get the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + DH_get0_pqg(dh, &bn_p, NULL, &bn_g); + if (bn_p == NULL || bn_g == NULL) { + warnx("Failed to get the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } } +#endif + + rc = add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + if (is_dsa) { + rc = add_bignum_attr(CKA_SUBPRIME, bn_q, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + } + + rc = add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + +done: +#if OPENSSL_VERSION_PREREQ(3, 0) + if (bn_p != NULL) + BN_free(bn_p); + if (bn_q != NULL) + BN_free(bn_q); + if (bn_g != NULL) + BN_free(bn_g); +#endif - pubattr[*pubcount].type = CKA_IBM_KYBER_KEYFORM; - pubattr[*pubcount].ulValueLen = sizeof(CK_ULONG); - pubattr[*pubcount].pValue = keyform; - (*pubcount)++; + return rc; +} + +static CK_RV dh_prepare(const struct p11sak_keytype *keytype, void **private) +{ + CK_RV rc; + EVP_PKEY *pkey = NULL; + + UNUSED(keytype); + + if (opt_pem_file != NULL) + rc = dh_dsa_read_params_pem(opt_pem_file, false, &pkey); + else + rc = dh_group_params(opt_group->private.num, &pkey); + + if (rc != CKR_OK) + return rc; + + *private = pkey; return CKR_OK; } -/** - * Builds two CKA_LABEL attributes from given label. - * By default the specified label is extended with ":pub" and ":prv" for the - * public and private key objects. - * To set 2 different labels for public and private keys, separate them by - * colon: "pub-label:prv-label". - * To set the exact same label for public and private key, use "pub-label:=" - * To specify a colon or a equal character within a label, it must be escaped - * by a back slash: * "abc\:xyz" results in "abc:xyz". - */ -static CK_RV set_labelpair_attr(const char *label, CK_ATTRIBUTE *pubattr, - CK_ULONG *pubcount, CK_ATTRIBUTE *prvattr, - CK_ULONG *prvcount) + +static void dh_cleanup(const struct p11sak_keytype *keytype, void *private) +{ + EVP_PKEY *pkey = private; + + UNUSED(keytype); + + EVP_PKEY_free(pkey); +} + +static CK_RV dh_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) +{ + EVP_PKEY *pkey = private; + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_p = NULL; +#else + const DH *dh; + const BIGNUM *bn_p = NULL; +#endif + + UNUSED(keytype); + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p)) { + warnx("Failed to get the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + dh = EVP_PKEY_get0_DH(pkey); + if (dh == NULL) { + warnx("Failed to get the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + DH_get0_pqg(dh, &bn_p, NULL, NULL); + if (bn_p == NULL) { + warnx("Failed to get the DH params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#endif + + *keysize = BN_num_bits(bn_p); + +done: +#if OPENSSL_VERSION_PREREQ(3, 0) + if (bn_p != NULL) + BN_free(bn_p); +#endif + + return rc; +} + +static CK_RV dh_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + EVP_PKEY *pkey = private; + + UNUSED(keytype); + + return dh_dsa_add_public_attrs(attrs, num_attrs, pkey, false); +} + +static CK_RV dh_add_private_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) +{ + UNUSED(private); + UNUSED(keytype); + + if (opt_keybits_num == 0) + return CKR_OK; + + return add_attribute(CKA_VALUE_BITS, &opt_keybits_num, + sizeof(opt_keybits_num), attrs, num_attrs); +} + +static CK_RV dsa_prepare(const struct p11sak_keytype *keytype, void **private) +{ + CK_RV rc; + EVP_PKEY *pkey = NULL; + + UNUSED(keytype); + + rc = dh_dsa_read_params_pem(opt_pem_file, true, &pkey); + if (rc != CKR_OK) + return rc; + + *private = pkey; + + return CKR_OK; +} + +static void dsa_cleanup(const struct p11sak_keytype *keytype, void *private) +{ + EVP_PKEY *pkey = private; + + UNUSED(keytype); + + EVP_PKEY_free(pkey); +} + +static CK_RV dsa_get_key_size(const struct p11sak_keytype *keytype, + void *private, CK_ULONG *keysize) +{ + EVP_PKEY *pkey = private; + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_p = NULL; +#else + const DSA *dsa; + const BIGNUM *bn_p = NULL; +#endif + + UNUSED(keytype); + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p)) { + warnx("Failed to get the DSA params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + dsa = EVP_PKEY_get0_DSA(pkey); + if (dsa == NULL) { + warnx("Failed to get the DSA params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + DSA_get0_pqg(dsa, &bn_p, NULL, NULL); + if (bn_p == NULL) { + warnx("Failed to get the DSA params."); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#endif + + *keysize = BN_num_bits(bn_p); + +done: +#if OPENSSL_VERSION_PREREQ(3, 0) + if (bn_p != NULL) + BN_free(bn_p); +#endif + + return rc; +} + +static CK_RV dsa_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private) { - char *publabel = NULL; - char *prvlabel = NULL; + EVP_PKEY *pkey = private; + + UNUSED(keytype); + + return dh_dsa_add_public_attrs(attrs, num_attrs, pkey, true); +} + +static CK_RV ibm_dilithium_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs, + void *private) +{ + UNUSED(private); + UNUSED(keytype); + + return add_attribute(CKA_IBM_DILITHIUM_KEYFORM, + &opt_pqc_version->private.num, + sizeof(opt_pqc_version->private.num), + attrs, num_attrs); +} + +static CK_RV ibm_kyber_add_public_attrs(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs, + void *private) +{ + UNUSED(private); + UNUSED(keytype); + + return add_attribute(CKA_IBM_KYBER_KEYFORM, + &opt_pqc_version->private.num, + sizeof(opt_pqc_version->private.num), + attrs, num_attrs); +} + +static CK_RV parse_key_pair_label(const char *label, char **pub_label, + char** priv_label) +{ + char *pub = NULL; + char *priv = NULL; unsigned int i; for (i = 0; i < strlen(label); i++) { @@ -889,2478 +2878,4439 @@ } if (label[i] == ':') { - if (!(publabel = strndup(label, i))) { - fprintf(stderr, "Error allocating space for publabel\n"); + if (!(pub = strndup(label, i))) { + warnx("Failed to allocate memory for pub label"); return CKR_HOST_MEMORY; } - if (!(prvlabel = strdup(&label[i + 1]))) { - fprintf(stderr, "Error allocating space for prvlabel\n"); - free(publabel); + if (!(priv = strdup(&label[i + 1]))) { + warnx("Failed to allocate memory for priv label"); + free(pub); return CKR_HOST_MEMORY; } break; } } - if (publabel != NULL && prvlabel != NULL) { - if (strcmp(prvlabel, "=") == 0) { - free(prvlabel); - if (!(prvlabel = strdup(publabel))) { - fprintf(stderr, "Error allocating space for prvlabel\n"); - free(publabel); + if (pub != NULL && priv != NULL) { + if (strcmp(priv, "=") == 0) { + free(priv); + if (!(priv = strdup(pub))) { + warnx("Failed to allocate memory for priv label"); + free(pub); return CKR_HOST_MEMORY; } } } else { - if (!(publabel = malloc(strlen(label) + 5))) { - fprintf(stderr, "Error allocating space for publabel\n"); + if (!(pub = malloc(strlen(label) + 5))) { + warnx("Failed to allocate memory for pub label"); return CKR_HOST_MEMORY; } - publabel = strcpy(publabel, label); - publabel = strcat(publabel, ":pub"); + pub = strcpy(pub, label); + pub = strcat(pub, ":pub"); - if (!(prvlabel = malloc(strlen(label) + 5))) { - fprintf(stderr, "Error allocating space for prvlabel\n"); - free(publabel); + if (!(priv = malloc(strlen(label) + 5))) { + warnx("Failed to allocate memory for priv label"); + free(pub); return CKR_HOST_MEMORY; } - prvlabel = strcpy(prvlabel, label); - prvlabel = strcat(prvlabel, ":prv"); + priv = strcpy(priv, label); + priv = strcat(priv, ":prv"); + } + + for (i = 0; i < strlen(pub); i++) { + if (pub[i] == '\\') + memmove(&pub[i], &pub[i + 1], + strlen(&pub[i + 1]) + 1); + } + + for (i = 0; i < strlen(priv); i++) { + if (priv[i] == '\\') + memmove(&priv[i], &priv[i + 1], + strlen(&priv[i + 1]) + 1); } - for (i = 0; i < strlen(publabel); i++) { - if (publabel[i] == '\\') - memmove(&publabel[i], &publabel[i + 1], - strlen(&publabel[i + 1]) + 1); + *pub_label = pub; + *priv_label = priv; + + return CKR_OK; +} + +static CK_RV parse_key_pair_attrs(const char *attrs, char **pub_attrs, + char** priv_attrs) +{ + char *ch, *pub, *priv; + + if (attrs == NULL) { + *pub_attrs = NULL; + *priv_attrs = NULL; + return CKR_OK; } - for (i = 0; i < strlen(prvlabel); i++) { - if (prvlabel[i] == '\\') - memmove(&prvlabel[i], &prvlabel[i + 1], - strlen(&prvlabel[i + 1]) + 1); + ch = strchr(attrs, ':'); + + if (ch == NULL) { + pub = strdup(attrs); + priv = strdup(attrs); + } else { + pub = strndup(attrs, ch - attrs); + priv = strdup(ch + 1); } - pubattr[*pubcount].type = CKA_LABEL; - pubattr[*pubcount].pValue = publabel; - pubattr[*pubcount].ulValueLen = strlen(publabel); - (*pubcount)++; + if (pub == NULL || priv == NULL) { + warnx("Failed to allocate memory for pub/priv labels"); + free(pub); + free(priv); + return CKR_HOST_MEMORY; + } - prvattr[*prvcount].type = CKA_LABEL; - prvattr[*prvcount].pValue = prvlabel; - prvattr[*prvcount].ulValueLen = strlen(prvlabel); - (*prvcount)++; + *pub_attrs = pub; + *priv_attrs = priv; return CKR_OK; } -/** - * Set mechanism according to given key type. - */ -static CK_RV key_pair_gen_mech(p11sak_kt kt, CK_MECHANISM *pmech) + +static const struct p11sak_attr *find_attr_by_letter(char letter) { - pmech->pParameter = NULL_PTR; - pmech->ulParameterLen = 0; - switch (kt) { - case kt_DES: - pmech->mechanism = CKM_DES_KEY_GEN; - break; - case kt_3DES: - pmech->mechanism = CKM_DES3_KEY_GEN; - break; - case kt_AES: - pmech->mechanism = CKM_AES_KEY_GEN; - break; - case kt_AES_XTS: - pmech->mechanism = CKM_AES_XTS_KEY_GEN; - break; - case kt_RSAPKCS: - pmech->mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; - break; - case kt_EC: - pmech->mechanism = CKM_EC_KEY_PAIR_GEN; - break; - case kt_IBM_DILITHIUM: - pmech->mechanism = CKM_IBM_DILITHIUM; - break; - case kt_IBM_KYBER: - pmech->mechanism = CKM_IBM_KYBER; - break; + const struct p11sak_attr *attr; + + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { + if (attr->letter == toupper(letter)) + return attr; + } + + return NULL; +} + +static bool attr_applicaple_for_keytype(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr) +{ + switch (attr->type) { + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + return keytype->sign_verify; + + case CKA_ENCRYPT: + case CKA_DECRYPT: + return keytype->encrypt_decrypt; + + case CKA_WRAP: + case CKA_WRAP_WITH_TRUSTED: + case CKA_UNWRAP: + return keytype->wrap_unwrap; + + case CKA_DERIVE: + return keytype->derive; + default: - return CKR_MECHANISM_INVALID; - break; + return true; + } +} + +static bool secret_attr_applicable(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr) +{ + return attr->secret && attr_applicaple_for_keytype(keytype, attr); +} + +static bool public_attr_applicable(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr) +{ + UNUSED(keytype); + + return attr->public && attr_applicaple_for_keytype(keytype, attr); +} + +static bool private_attr_applicable(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr) +{ + UNUSED(keytype); + + return attr->private && attr_applicaple_for_keytype(keytype, attr); +} + +static CK_RV parse_boolean_attrs(const struct p11sak_keytype *keytype, + const char *attr_string, CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs, bool check_settable, + bool (*attr_aplicable)( + const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr)) +{ + const struct p11sak_attr *attr; + unsigned int i = 0; + CK_BBOOL val; + CK_RV rc; + + if (attr_string == NULL) + return CKR_OK; + + for (i = 0; attr_string[i] != '\0'; i++) { + attr = find_attr_by_letter(attr_string[i]); + if (attr == NULL) { + warnx("Attribute '%c' is not valid", attr_string[i]); + return CKR_ARGUMENTS_BAD; + } + + /* silently ignore attributes that are not settable or not applicable */ + if ((check_settable && !attr->settable) || + (attr_aplicable != NULL && keytype != NULL && + !attr_aplicable(keytype, attr))) + continue; + + val = isupper(attr_string[i]) ? CK_TRUE : CK_FALSE; + + rc = add_attribute(attr->type, &val, sizeof(val), attrs, num_attrs); + if (rc != CKR_OK) + return rc; } return CKR_OK; } -/** - * returns 1 if the given attribute is not applicable for the - * given key type, 0 otherwise. - */ -static CK_BBOOL attr_na(const CK_ULONG attr_type, p11sak_kt ktype) +static CK_RV parse_id(const char *id_string, CK_ATTRIBUTE **attrs, + CK_ULONG *num_attrs) { - switch (ktype) { - case kt_DES: - case kt_3DES: - case kt_AES: - case kt_AES_XTS: - case kt_SECRET: - switch (attr_type) { - case CKA_TRUSTED: - return 1; - default: - return 0; + unsigned char *buf = NULL; + BIGNUM *b = NULL; + int len; + CK_RV rc = CKR_OK; + + len = BN_hex2bn(&b, id_string); + if (len < (int)strlen(id_string)) { + warnx("Hex string '%s' is not valid", id_string); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + len = len / 2 + (len % 2 > 0 ? 1 : 0); + buf = calloc(1, len); + if (buf == NULL) { + warnx("Failed to allocate memory for CKA_ID attribute"); + rc = CKR_HOST_MEMORY; + goto done; + } + + if (BN_bn2binpad(b, buf, len) != len) { + warnx("Failed to prepare the value for CKA_ID attribute"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = add_attribute(CKA_ID, buf, len, attrs, num_attrs); + if (rc != CKR_OK) { + warnx("Failed to add attribute CKA_ID: 0x%lX: %s", rc, p11_get_ckr(rc)); + goto done; + } + +done: + if (buf != NULL) + free(buf); + if (b != NULL) + BN_free(b); + + return rc; +} + +static CK_RV add_attributes(const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + const char *label, const char *attr_string, + const char *id, bool is_sensitive, + CK_RV (*add_attrs)( + const struct p11sak_keytype *keytype, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs, + void *private), + void *private, + bool (*attr_aplicable)( + const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr)) +{ + const CK_BBOOL ck_true = TRUE; + bool found; + CK_ULONG i; + CK_RV rc; + + rc = add_attribute(CKA_LABEL, label, strlen(label), attrs, num_attrs); + if (rc != CKR_OK) { + warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + return rc; + } + + rc = add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), attrs, num_attrs); + if (rc != CKR_OK) { + warnx("Failed to add %s key attribute CKA_TOKEN: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + return rc; + } + + rc = parse_boolean_attrs(keytype, attr_string, attrs, num_attrs, + true, attr_aplicable); + if (rc != CKR_OK) + return rc; + + if (id != NULL) { + rc = parse_id(id, attrs, num_attrs); + if (rc != CKR_OK) + return rc; + } + + if (add_attrs != NULL) { + rc = add_attrs(keytype, attrs, num_attrs, private); + if (rc != CKR_OK) { + warnx("Failed to add %s key attributes: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + return rc; } - break; - case kt_PUBLIC: - switch (attr_type) { - case CKA_SENSITIVE: - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_UNWRAP: - case CKA_EXTRACTABLE: - case CKA_ALWAYS_SENSITIVE: - case CKA_NEVER_EXTRACTABLE: - return 1; - default: - return 0; + } + + if (is_sensitive) { + /* Add CKA_SENSITIVE=TRUE if its not already in attribute list */ + for (i = 0, found = false; i < *num_attrs && !found; i++) { + if ((*attrs)[i].type == CKA_SENSITIVE) + found = true; } - break; - case kt_PRIVATE: - switch (attr_type) { - case CKA_ENCRYPT: - case CKA_VERIFY: - case CKA_WRAP: - return 1; - default: - return 0; + + if (!found) { + rc = add_attribute(CKA_SENSITIVE, &ck_true, sizeof(ck_true), + attrs, num_attrs); + if (rc != CKR_OK) { + warnx("Failed to add %s key attribute CKA_SENSITIVE: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + return rc; + } } - break; - default: - /* key type not handled here */ - return 0; } + + return CKR_OK; +} + +static void free_attributes(CK_ATTRIBUTE *attrs, CK_ULONG num_attrs) +{ + CK_ULONG i; + + if (attrs == NULL) + return; + + for (i = 0; i < num_attrs; i++) { + if (attrs[i].pValue != NULL) + free(attrs[i].pValue); + } + + free(attrs); } -static CK_ULONG char2attrtype(char c) +static bool is_attr_array_attr(CK_ATTRIBUTE *attr) { - switch (c) { - case 'T': - return CKA_TOKEN; - case 'P': - return CKA_PRIVATE; - case 'M': - return CKA_MODIFIABLE; - case 'R': - return CKA_DERIVE; - case 'L': - return CKA_LOCAL; - case 'S': - return CKA_SENSITIVE; - case 'E': - return CKA_ENCRYPT; - case 'D': - return CKA_DECRYPT; - case 'G': - return CKA_SIGN; - case 'V': - return CKA_VERIFY; - case 'W': - return CKA_WRAP; - case 'U': - return CKA_UNWRAP; - case 'X': - return CKA_EXTRACTABLE; - case 'A': - return CKA_ALWAYS_SENSITIVE; - case 'N': - return CKA_NEVER_EXTRACTABLE; + switch (attr->type) { + case CKA_WRAP_TEMPLATE: + case CKA_UNWRAP_TEMPLATE: + case CKA_DERIVE_TEMPLATE: + return true; + default: - return 0; + return false; } } -static void set_bool_attr_from_string(CK_ATTRIBUTE *attr, char attr_char) +static void free_attr_array_attr(CK_ATTRIBUTE *attr) { - if (!attr_char) - return; - - attr->type = char2attrtype(toupper(attr_char)); - attr->ulValueLen = sizeof(CK_BBOOL); - if (isupper(attr_char) == 0) { - attr->pValue = &ckb_false; - } else { - attr->pValue = &ckb_true; + CK_ULONG i, num; + CK_ATTRIBUTE *elem; + + num = attr->ulValueLen / sizeof(CK_ATTRIBUTE); + for (i = 0, elem = attr->pValue; elem != NULL && i < num; i++, elem++) { + if (elem->pValue != NULL) { + if (is_attr_array_attr(elem)) + free_attr_array_attr(elem); + free(elem->pValue); + elem->pValue = NULL; + } } } -/** - * Set default asymmetric key attributes. - */ -static CK_RV set_battr(const char *attr_string, CK_ATTRIBUTE *attr, - CK_ULONG *count, int prv) +static CK_RV alloc_attr_array_attr(CK_ATTRIBUTE *attr, bool *allocated) { - int i = 0; + CK_ULONG i, num; + CK_ATTRIBUTE *elem; + CK_RV rc; + + *allocated = false; - attr[*count].type = CKA_TOKEN; - attr[*count].pValue = &ckb_true; - attr[*count].ulValueLen = sizeof(CK_BBOOL); - (*count)++; - - if (attr_string) { - for (i = 0; i < (int) strlen(attr_string); i++) { - // attr_string length is checked in parse_gen_key_args to avoid memory problems - if (prv == 1 && attr_na(char2attrtype(toupper(attr_string[i])), kt_PRIVATE) == 0) { - set_bool_attr_from_string(&attr[*count], attr_string[i]); - (*count)++; - } - if (prv == 0 && attr_na(char2attrtype(toupper(attr_string[i])), kt_PUBLIC) == 0) { - set_bool_attr_from_string(&attr[*count], attr_string[i]); - (*count)++; + num = attr->ulValueLen / sizeof(CK_ATTRIBUTE); + for (i = 0, elem = attr->pValue; i < num; i++, elem++) { + if (elem->ulValueLen > 0 && elem->pValue == NULL) { + elem->pValue = calloc(elem->ulValueLen, 1); + if (elem->pValue == NULL) { + free_attr_array_attr(attr); + return CKR_HOST_MEMORY; + } + + *allocated = true; + continue; + } + + if (is_attr_array_attr(elem)) { + rc = alloc_attr_array_attr(elem, allocated); + if (rc != CKR_OK) { + free_attr_array_attr(attr); + return CKR_HOST_MEMORY; } } } + return CKR_OK; } -CK_BBOOL is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session) +static CK_RV get_attribute(CK_OBJECT_HANDLE key, CK_ATTRIBUTE *attr) { - CK_SESSION_INFO info; + bool allocated; CK_RV rc; - if (ret_code != CKR_FUNCTION_FAILED) - return CK_FALSE; + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, attr, 1); + if (rc != CKR_OK) + return rc; - rc = funcs->C_GetSessionInfo(session, &info); - if (rc != CKR_OK) { - fprintf(stderr, "C_GetSessionInfo failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return CK_FALSE; + if (attr->pValue == NULL && attr->ulValueLen > 0) { + attr->pValue = calloc(attr->ulValueLen, 1); + if (attr->pValue == NULL) + return CKR_HOST_MEMORY; + + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, attr, 1); + } + + if (is_attr_array_attr(attr) && rc == CKR_OK && + attr->pValue != NULL && attr->ulValueLen > 0) { + do { + allocated = false; + rc = alloc_attr_array_attr(attr, &allocated); + if (rc != CKR_OK) + return rc; + + if (!allocated) + break; + + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + attr, 1); + } while (rc == CKR_OK); } - return (info.ulDeviceError == CKR_POLICY_VIOLATION) ? CK_TRUE : CK_FALSE; + return rc; } -CK_BBOOL is_mech_supported(CK_SLOT_ID slot, CK_MECHANISM *pmech, - CK_ULONG keybits) +static CK_RV get_bignum_attr(CK_OBJECT_HANDLE key, CK_ATTRIBUTE_TYPE type, + BIGNUM **bn) { - CK_MECHANISM_INFO mech_info; - int rc; + CK_ATTRIBUTE attr; + CK_RV rc; + + attr.type = type; + attr.pValue = NULL; + attr.ulValueLen = 0; - rc = funcs->C_GetMechanismInfo(slot, pmech->mechanism, &mech_info); + if (is_attr_array_attr(&attr)) + return CKR_ATTRIBUTE_TYPE_INVALID; + + rc = get_attribute(key, &attr); if (rc != CKR_OK) - return CK_FALSE; + return rc; - if ((mech_info.flags & (CKF_GENERATE | CKF_GENERATE_KEY_PAIR)) == 0) - return CK_FALSE; + if (attr.ulValueLen == 0 || attr.pValue == NULL) + return CKR_ATTRIBUTE_VALUE_INVALID; - if (keybits > 0) { - switch (pmech->mechanism) { - case CKM_DES_KEY_GEN: - case CKM_DES3_KEY_GEN: - case CKM_AES_KEY_GEN: - case CKM_AES_XTS_KEY_GEN: - keybits /= 8; /* mechinfo reports key size in bytes */ - break; + *bn = BN_new(); + if (*bn == NULL) { + rc = CKR_HOST_MEMORY; + goto done; + } + + if (BN_bin2bn((unsigned char *)attr.pValue, attr.ulValueLen, *bn) == NULL) { + rc = CKR_FUNCTION_FAILED; + BN_free(*bn); + *bn = NULL; + goto done; + } + +done: + free(attr.pValue); + + return rc; +} + +static const struct p11sak_keytype *find_keytype(CK_KEY_TYPE ktype) +{ + const struct p11sak_keytype **kt; + + for (kt = p11sak_keytypes; (*kt)->name != NULL; kt++) { + if ((*kt)->type == ktype) + return *kt; + } + + return NULL; +} + +static CK_RV get_key_infos(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS *class, + CK_KEY_TYPE *ktype, CK_ULONG *keysize, + char** label, char** typestr, + const struct p11sak_keytype **keytype) +{ + CK_RV rc; + CK_ULONG i; + CK_OBJECT_CLASS class_val = 0; + CK_KEY_TYPE ktype_val = 0; + CK_ATTRIBUTE attrs[] = { + { CKA_LABEL, NULL, 0 }, /* label must be first one */ + { CKA_CLASS, &class_val, sizeof(class_val) }, + { CKA_KEY_TYPE, &ktype_val, sizeof(ktype_val) }, + }; + const CK_ULONG num_attrs = sizeof(attrs) / sizeof(CK_ATTRIBUTE); + const struct p11sak_keytype *keytype_val; + CK_ULONG keysize_val = 0; + CK_ATTRIBUTE keysize_attr; + int rv; + + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + attrs, num_attrs); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID && + rc != CKR_ATTRIBUTE_SENSITIVE) { + warnx("Failed to get attributes: C_GetAttributeValue: 0x%lX: %s", + rc, p11_get_ckr(rc)); + return rc; + } + + if (attrs[0].ulValueLen != 0 && + attrs[0].ulValueLen != CK_UNAVAILABLE_INFORMATION) { + attrs[0].pValue = calloc(attrs[0].ulValueLen + 1, 1); + if (attrs[0].pValue == NULL) { + warnx("Failed to allocate memory for label attribute"); + return CKR_HOST_MEMORY; + } + + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + attrs, num_attrs); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID && + rc != CKR_ATTRIBUTE_SENSITIVE) { + warnx("Failed to get attributes: C_GetAttributeValue: 0x%lX: %s", + rc, p11_get_ckr(rc)); + free(attrs[0].pValue); + return rc; + } + } else { + attrs[0].pValue = strdup(""); + if (attrs[0].pValue == NULL) { + warnx("Failed to allocate memory for label attribute"); + return CKR_HOST_MEMORY; } + } + + for (i = 0; i < num_attrs; i++) { + if (attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + warnx("Attribute %s is not available in key object", + p11_get_cka(attrs[i].type)); + free(attrs[0].pValue); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + if (class != NULL) + *class = class_val; + if (ktype != NULL) + *ktype = ktype_val; + + keytype_val = find_keytype(ktype_val); + if (keytype_val == NULL) { + warnx("Key object \"%s\" has an unsupported key type: %lu", + (char *)attrs[0].pValue, ktype_val); + free(attrs[0].pValue); + return CKR_KEY_TYPE_INCONSISTENT; + } + + if (keytype != NULL) + *keytype = keytype_val; + + if (keytype_val->keysize_attr != (CK_ATTRIBUTE_TYPE)-1) { + keysize_attr.type = keytype_val->keysize_attr; + if (!keytype_val->keysize_attr_value_len) { + keysize_attr.ulValueLen = sizeof(keysize_val); + keysize_attr.pValue = &keysize_val; + } else { + /* Query attribute length only */ + keysize_attr.ulValueLen = 0; + keysize_attr.pValue = NULL; + } + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + &keysize_attr, 1); + if (rc != CKR_OK) { + warnx("Attribute %s is not available in key object", + p11_get_cka( keysize_attr.type)); + free(attrs[0].pValue); + return rc; + } + + if (keytype_val->keysize_attr_value_len) + keysize_val = keysize_attr.ulValueLen; + + if (keytype_val->key_keysize_adjust != NULL) + keysize_val = keytype_val->key_keysize_adjust(keytype_val, + keysize_val); + } + + if (keysize != NULL) + *keysize = keysize_val; - if (mech_info.ulMinKeySize == 0 && mech_info.ulMaxKeySize == 0) - return CK_TRUE; - if (mech_info.ulMinKeySize > keybits) - return CK_FALSE; - if (mech_info.ulMaxKeySize < keybits) - return CK_FALSE; + if (typestr != NULL) { + switch (class_val) { + case CKO_SECRET_KEY: + if (keysize_val != 0) + rv = asprintf(typestr, "%s %lu", keytype_val->name, keysize_val); + else + rv = asprintf(typestr, "%s", keytype_val->name); + break; + case CKO_PUBLIC_KEY: + if (keysize_val != 0) + rv = asprintf(typestr, "public %s %lu", keytype_val->name, keysize_val); + else + rv = asprintf(typestr, "public %s", keytype_val->name); + break; + case CKO_PRIVATE_KEY: + if (keysize_val != 0) + rv = asprintf(typestr, "private %s %lu", keytype_val->name, keysize_val); + else + rv = asprintf(typestr, "private %s", keytype_val->name); + break; + default: + warnx("Key object \"%s\" has an unsupported object class: %lu", + (char *)attrs[0].pValue, class_val); + free(attrs[0].pValue); + return CKR_KEY_TYPE_INCONSISTENT; + } + if (*typestr == NULL || rv < 0) { + warnx("Failed to allocate type string buffer"); + free(attrs[0].pValue); + return CKR_HOST_MEMORY; + } } - return CK_TRUE; + if (label != NULL) + *label = attrs[0].pValue; + else + free(attrs[0].pValue); + + return CKR_OK; } -/** - * Generation of the symmetric key - */ -static CK_RV tok_key_gen(CK_SESSION_HANDLE session, CK_SLOT_ID slot, - CK_ULONG keylength, CK_MECHANISM *pmech, - char *attr_string, CK_OBJECT_HANDLE *phkey, - char *label) + +static int iterate_compare(const void *a, const void *b, void *private) { + struct p11sak_iterate_compare_data *data = private; + const CK_OBJECT_HANDLE *key1 = a; + const CK_OBJECT_HANDLE *key2 = b; + int result = 0; CK_RV rc; - int i = 0; - /* Boolean attributes (cannot be specified by user) */ - CK_BBOOL a_token = ckb_true; // always true + if (data->rc!= CKR_OK) + return 0; - /* Non-boolean attributes */ - CK_ULONG a_value_len = keylength / 8; + rc = data->compare_key(*key1, *key2, &result, data->private); + if (rc != CKR_OK) + data->rc = rc; - /* Standard template */ - CK_ATTRIBUTE key_attr[3 + KEY_MAX_BOOL_ATTR_COUNT] = { - { CKA_TOKEN, &a_token, sizeof(CK_BBOOL) }, - { CKA_VALUE_LEN, &a_value_len, sizeof(CK_ULONG) }, - { CKA_LABEL, label, strlen(label) } - }; - CK_ULONG num_attrs = 3; - - /* set boolean attributes, set template from string - attr_string length is checked in parse_gen_key_args to avoid memory problems */ - if (attr_string) { - for (i = 0; i < (int) strlen(attr_string); i++) { - set_bool_attr_from_string(&key_attr[i+num_attrs], attr_string[i]); - } - num_attrs += strlen(attr_string); - } - - if (!is_mech_supported(slot, pmech, keylength)) { - fprintf(stderr, "Key generation mechanism %s with key length %lu is not supported by slot %lu\n", - p11_get_ckm(&mechtable_funcs, pmech->mechanism), a_value_len, - slot); - return CKR_MECHANISM_INVALID; + return result; +} + +static CK_RV iterate_key_objects(const struct p11sak_keytype *keytype, + const char *label_filter, + const char *id_filter, + const char *attr_filter, + CK_RV (*compare_key)(CK_OBJECT_HANDLE key1, + CK_OBJECT_HANDLE key2, + int *result, + void *private), + CK_RV (*handle_key)(CK_OBJECT_HANDLE key, + CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + CK_ULONG keysize, + const char *typestr, + const char* label, + void *private), + void *private) +{ + CK_RV rc, rc2; + CK_ATTRIBUTE *attrs = NULL; + CK_ULONG num_attrs = 0; + const CK_BBOOL ck_true = CK_TRUE; + CK_OBJECT_HANDLE keys[FIND_OBJECTS_COUNT]; + CK_ULONG i, num_keys; + bool manual_filtering = false; + CK_OBJECT_CLASS class; + CK_KEY_TYPE ktype; + CK_ULONG keysize = 0; + char *label = NULL; + char *typestr = NULL; + const struct p11sak_keytype *type; + CK_OBJECT_HANDLE *matched_keys = NULL, *tmp; + CK_ULONG num_matched_keys = 0; + CK_ULONG alloc_matched_keys = 0; + struct p11sak_iterate_compare_data data; + + rc = add_attribute(CKA_TOKEN, &ck_true, sizeof(ck_true), &attrs, &num_attrs); + if (rc != CKR_OK) + goto done; + + if (keytype != NULL && keytype->filter_attr != (CK_ATTRIBUTE_TYPE)-1) { + rc = add_attribute(keytype->filter_attr, &keytype->filter_value, + sizeof(keytype->filter_value), &attrs, &num_attrs); + if (rc != CKR_OK) + goto done; + } + + if (label_filter != NULL) { + manual_filtering = (strpbrk(label_filter, "*?\\") != NULL); + if (!manual_filtering) { + /* add label filter only if no escapes are used */ + rc = add_attribute(CKA_LABEL, label_filter, strlen(label_filter), + &attrs, &num_attrs); + if (rc != CKR_OK) + goto done; + } } - /* generate key */ - rc = funcs->C_GenerateKey(session, pmech, key_attr, num_attrs, phkey); + if (id_filter != NULL) { + rc = parse_id(id_filter, &attrs, &num_attrs); + if (rc != CKR_OK) + return rc; + } + + if (attr_filter != NULL) { + rc = parse_boolean_attrs(NULL, opt_attr, &attrs, &num_attrs, + false, NULL); + if (rc != CKR_OK) + return rc; + } + + rc = pkcs11_funcs->C_FindObjectsInit(pkcs11_session, attrs, num_attrs); if (rc != CKR_OK) { - if (is_rejected_by_policy(rc, session)) { - fprintf(stderr, "Key generation of key of length %lu bytes is rejected by policy\n", - a_value_len); - } else { - fprintf(stderr, "Key generation of key of length %lu bytes failed\n", - a_value_len); - fprintf(stderr, "in tok_key_gen() (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); + warnx("Failed to initialize the find operation: C_FindObjectsInit: 0x%lX: %s", + rc, p11_get_ckr(rc)); + goto done; + } + + while (1) { + memset(keys, 0, sizeof(keys)); + num_keys = 0; + + rc = pkcs11_funcs->C_FindObjects(pkcs11_session, keys, + FIND_OBJECTS_COUNT, &num_keys); + if (rc != CKR_OK) { + warnx("Failed to find objects: C_FindObjects: 0x%lX: %s", + rc, p11_get_ckr(rc)); + goto done_find; } + + if (num_keys == 0) + break; + + for (i = 0; i < num_keys; i++) { + if (manual_filtering) { + rc = get_key_infos(keys[i], NULL, NULL, NULL, &label, + NULL, NULL); + if (rc != CKR_OK) + break; + + if (fnmatch(label_filter, label, 0) != 0) + goto next; + } + + if (num_matched_keys >= alloc_matched_keys) { + tmp = realloc(matched_keys, + (alloc_matched_keys + FIND_OBJECTS_COUNT) * + sizeof(CK_OBJECT_HANDLE)); + if (tmp == NULL) { + warnx("Failed to allocate a list of matched keys."); + rc = CKR_HOST_MEMORY; + goto done_find; + } + + matched_keys = tmp; + alloc_matched_keys += FIND_OBJECTS_COUNT; + } + + matched_keys[num_matched_keys++] = keys[i]; + +next: + if (label != NULL) + free(label); + label = NULL; + } + } + +done_find: + rc2 = pkcs11_funcs->C_FindObjectsFinal(pkcs11_session); + if (rc2 != CKR_OK) { + warnx("Failed to finalize the find operation: C_FindObjectsFinal: 0x%lX: %s", + rc2, p11_get_ckr(rc2)); + if (rc == CKR_OK) + rc = rc2; + } + + if (rc != CKR_OK) + goto done; + + if (compare_key != NULL && num_matched_keys > 0) { + data.compare_key = compare_key; + data.private = private; + data.rc = CKR_OK; + + qsort_r(matched_keys, num_matched_keys, sizeof(CK_OBJECT_HANDLE), + iterate_compare, &data); + + rc = data.rc; + if (rc != CKR_OK) + goto done; + } + + for (i = 0; i < num_matched_keys; i++) { + rc = get_key_infos(matched_keys[i], &class, &ktype, &keysize, + &label, &typestr, &type); + if (rc != CKR_OK) + break; + + rc = handle_key(matched_keys[i], class, type, keysize, typestr, label, + private); + if (rc != CKR_OK) + break; + + if (label != NULL) + free(label); + label = NULL; + if (typestr != NULL) + free(typestr); + typestr = NULL; } + +done: + free_attributes(attrs, num_attrs); + + if (label != NULL) + free(label); + if (typestr != NULL) + free(typestr); + if (matched_keys != NULL) + free(matched_keys); + return rc; } -/** - * Generation of the asymmetric key pair - */ -static CK_RV key_pair_gen(CK_SESSION_HANDLE session, CK_SLOT_ID slot, - p11sak_kt kt, CK_MECHANISM_PTR pmech, - CK_ATTRIBUTE *pubattr, CK_ULONG pubcount, - CK_ATTRIBUTE *prvattr, CK_ULONG prvcount, - CK_OBJECT_HANDLE_PTR phpubkey, - CK_OBJECT_HANDLE_PTR phprvkey, CK_ULONG keybits) + +static CK_RV p11sak_generate_key(void) { - CK_RV rc; + const struct p11sak_keytype *keytype; + void *private = NULL; + CK_RV rc = CKR_OK; + CK_ULONG keysize = 0; + char *pub_label = NULL, *priv_label = NULL; + char *pub_attrs = NULL, *priv_attrs = NULL; + CK_ATTRIBUTE *secret_attrs = NULL; + CK_ULONG num_secret_attrs = 0; + CK_ATTRIBUTE *public_attrs = NULL; + CK_ULONG num_public_attrs = 0; + CK_ATTRIBUTE *private_attrs = NULL; + CK_ULONG num_private_attrs = 0; + CK_OBJECT_HANDLE pub_key, priv_key, secret_key; - printf("Generate asymmetric key: %s\n", kt2str(kt)); + if (opt_keytype == NULL || opt_keytype->private.ptr == NULL) + return CKR_ARGUMENTS_BAD; - if (!is_mech_supported(slot, pmech, keybits)) { - fprintf(stderr, "Key generation mechanism %s with key length %lu is not supported by slot %lu\n", - p11_get_ckm(&mechtable_funcs, pmech->mechanism), keybits, slot); - return CKR_MECHANISM_INVALID; + keytype = opt_keytype->private.ptr; + + if (keytype->keygen_prepare != NULL) { + rc = keytype->keygen_prepare(keytype, &private); + if (rc != CKR_OK) { + warnx("Failed to prepare key type %s: 0x%lX: %s", keytype->name, + rc, p11_get_ckr(rc)); + return rc; + } + } + + if (keytype->keygen_get_key_size != NULL) { + rc = keytype->keygen_get_key_size(keytype, private, &keysize); + if (rc != CKR_OK) { + warnx("Failed to get key size for key type %s: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + goto done; + } + } + + rc = check_mech_supported(keytype, keysize); + if (rc != CKR_OK) + goto done; + + if (keytype->is_asymmetric) { + rc = parse_key_pair_label(opt_label, &pub_label, &priv_label); + if (rc != CKR_OK) + goto done; + + rc = parse_key_pair_attrs(opt_attr, &pub_attrs, &priv_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_attributes(keytype, &public_attrs, &num_public_attrs, + pub_label, pub_attrs, opt_id, false, + keytype->keygen_add_public_attrs, private, + public_attr_applicable); + if (rc != CKR_OK) + goto done; + + rc = add_attributes(keytype, &private_attrs, &num_private_attrs, + priv_label, priv_attrs, opt_id, true, + keytype->keygen_add_private_attrs, private, + private_attr_applicable); + if (rc != CKR_OK) + goto done; + } else { + rc = add_attributes(keytype, &secret_attrs, &num_secret_attrs, + opt_label, opt_attr, opt_id, true, + keytype->keygen_add_secret_attrs, private, + secret_attr_applicable); + if (rc != CKR_OK) + goto done; } - rc = funcs->C_GenerateKeyPair(session, pmech, pubattr, pubcount, prvattr, - prvcount, phpubkey, phprvkey); + if (keytype->is_asymmetric) + rc = pkcs11_funcs->C_GenerateKeyPair(pkcs11_session, + (CK_MECHANISM *)&keytype->keygen_mech, + public_attrs, num_public_attrs, + private_attrs, num_private_attrs, + &pub_key, &priv_key); + else + rc = pkcs11_funcs->C_GenerateKey(pkcs11_session, + (CK_MECHANISM *)&keytype->keygen_mech, + secret_attrs, num_secret_attrs, + &secret_key); if (rc != CKR_OK) { - if (is_rejected_by_policy(rc, session)) - fprintf(stderr, "Key pair generation rejected by policy\n"); - else if (kt == kt_IBM_DILITHIUM && rc == CKR_KEY_SIZE_RANGE) - fprintf(stderr, "IBM Dilithum version is not supported\n"); - else if (kt == kt_IBM_KYBER && rc == CKR_KEY_SIZE_RANGE) - fprintf(stderr, "IBM Kyber version is not supported\n"); + if (is_rejected_by_policy(rc, pkcs11_session)) { + if (keysize == 0) + warnx("Key generation of a %s key is rejected by policy", + keytype->name); + else + warnx("Key generation of a %s key of size %lu is rejected by policy", + keytype->name, keysize); + } else { + if (keysize == 0) + warnx("Key generation of a %s key failed: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + else + warnx("Key generation of a %s key of size %lu failed: 0x%lX: %s", + keytype->name, keysize, rc, p11_get_ckr(rc)); + } + goto done; + } + + if (keytype->is_asymmetric) + printf("Successfully generated a %s key pair with labels \"%s\":\"%s\".\n", + keytype->name, pub_label, priv_label); + else + printf("Successfully generated a %s key with label \"%s\".\n", + keytype->name, opt_label); + +done: + if (keytype->keygen_cleanup != NULL) + keytype->keygen_cleanup(keytype, private); + + if (pub_label != NULL) + free(pub_label); + if (priv_label != NULL) + free(priv_label); + if (pub_attrs != NULL) + free(pub_attrs); + if (priv_attrs != NULL) + free(priv_attrs); + + free_attributes(secret_attrs, num_secret_attrs); + free_attributes(public_attrs, num_public_attrs); + free_attributes(private_attrs, num_private_attrs); + + return rc; +} + +static void print_bool_attr_short(const CK_ATTRIBUTE *val, bool applicable) +{ + if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION || + val->ulValueLen != sizeof(CK_BBOOL)) + applicable = false; + printf("%c ", applicable ? (*(CK_BBOOL *)(val->pValue) ? '1' : '0') : '-'); +} + +static void print_bool_attr_long(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive)|| + val->ulValueLen != sizeof(CK_BBOOL)) + return; + + printf("%*s%s: %s\n", indent, "", attr, + sensitive ? "[sensitive]" : + *(CK_BBOOL *)(val->pValue) ? "CK_TRUE" : "CK_FALSE"); +} + +static void print_utf8_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else if (val->ulValueLen == 0) { + printf("%*s%s: [no value]\n", indent, "", attr); + } else { + printf("%*s%s: \"%.*s\"\n", indent, "", attr, (int)val->ulValueLen, + (char *)val->pValue); + } +} + +static void print_dump(CK_BYTE *p, CK_ULONG len, int indent) +{ + CK_ULONG i; + + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("\n%*s%02X ", indent, "", p[i]); else - fprintf(stderr, "Key pair generation failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + printf("%02X ", p[i]); } + printf("\n"); +} - printf("Asymmetric key pair generation successful!\n"); +static void print_byte_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) + return; - return CKR_OK; + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else if (val->ulValueLen == 0) { + printf("%*s%s: [no value]\n", indent, "", attr); + } else { + printf("%*s%s: len=%lu value:", indent, "", attr, + val->ulValueLen); + print_dump((CK_BYTE *)val->pValue, val->ulValueLen, indent + 4); + } } -/** - * Initialize key object list - */ -static CK_RV tok_key_list_init(CK_SESSION_HANDLE session, p11sak_kt kt, - char *label) + +static void print_ulong_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) { - CK_RV rc; - CK_ULONG count = 0; + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + val->ulValueLen != sizeof(CK_ULONG)) + return; - /* Boolean Attributes */ - CK_BBOOL a_token; - CK_ULONG bs = sizeof(CK_BBOOL); + if (sensitive) + printf("%*s%s: [sensitive]\n", indent, "", attr); + else + printf("%*s%s: %lu (0x%lX)\n", indent, "", attr, + *(CK_ULONG *)(val->pValue), *(CK_ULONG *)(val->pValue)); +} - /* key Type attributes */ - CK_KEY_TYPE a_key_type; - CK_OBJECT_CLASS a_cko; +static void print_date_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + val->ulValueLen != sizeof(CK_DATE)) + return; - CK_ATTRIBUTE tmplt[3]; + if (sensitive) + printf("%*s%s: [sensitive]\n", indent, "", attr); + else + printf("%*s%s: %.4s-%.2s-%.2s\n", indent, "", attr, + ((CK_DATE *)(val->pValue))->year, + ((CK_DATE *)(val->pValue))->month, + ((CK_DATE *)(val->pValue))->day); +} - a_token = CK_TRUE; - tmplt[count].type = CKA_TOKEN; - tmplt[count].pValue = &a_token; - tmplt[count].ulValueLen = bs; - count++; +static void print_mech_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + val->ulValueLen != sizeof(CK_MECHANISM_TYPE)) + return; - if (kt < kt_SECRET) { - rc = kt2CKK(kt, &a_key_type); - if (rc != CKR_OK) { - fprintf(stderr, "Keytype could not be set (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + if (sensitive) + printf("%*s%s: [sensitive]\n", indent, "", attr); + else if (*(CK_MECHANISM_TYPE *)(val->pValue) == CK_UNAVAILABLE_INFORMATION) + printf("%*s%s: [information unavailable]\n", indent, "", attr); + else + printf("%*s%s: %s (0x%lX)\n", indent, "", attr, + p11_get_ckm(&mechtable_funcs, + *(CK_MECHANISM_TYPE *)(val->pValue)), + *(CK_MECHANISM_TYPE *)(val->pValue)); +} + +static void print_mech_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + unsigned int i, num; + + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + (val->ulValueLen % sizeof(CK_MECHANISM_TYPE)) != 0) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else { + num = val->ulValueLen / sizeof(CK_MECHANISM_TYPE); + if (num == 0 && val->type == CKA_ALLOWED_MECHANISMS) { + printf("%*s%s: [no restriction]\n", indent, "", attr); + return; } - } else if (kt != kt_ALL) { - rc = kt2CKO(kt, &a_cko); - if (rc != CKR_OK) { - fprintf(stderr, "Keyobject could not be set (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + + printf("%*s%s: %u mechanisms\n", indent, "", attr, num); + for (i = 0; i < num; i++) { + printf("%*s- %s (0x%lX)\n", indent + 4, "", + p11_get_ckm(&mechtable_funcs, + ((CK_MECHANISM_TYPE *)(val->pValue))[i]), + ((CK_MECHANISM_TYPE *)(val->pValue))[i]); } } +} - /* Set template */ - switch (kt) { - case kt_DES: - case kt_3DES: - case kt_AES: - case kt_AES_XTS: - case kt_GENERIC: - case kt_RSAPKCS: - case kt_EC: - case kt_IBM_DILITHIUM: - case kt_IBM_KYBER: - tmplt[count].type = CKA_KEY_TYPE; - tmplt[count].pValue = &a_key_type; - tmplt[count].ulValueLen = sizeof(CK_KEY_TYPE); - count++; - break; - case kt_SECRET: - case kt_PUBLIC: - case kt_PRIVATE: - tmplt[count].type = CKA_CLASS; - tmplt[count].pValue = &a_cko; - tmplt[count].ulValueLen = sizeof(CK_OBJECT_CLASS); - count++; - break; - case kt_ALL: - break; - default: - fprintf(stderr, "Unknown key type\n"); - return CKR_ARGUMENTS_BAD; +static void print_oid(const CK_BYTE *oid, CK_ULONG oid_len, bool long_name) +{ + ASN1_OBJECT *obj = NULL; + char buf[250]; + int nid; + + if (d2i_ASN1_OBJECT(&obj, &oid, oid_len) == NULL) { + printf("[invalid object ID]"); + return; } - if (label != NULL_PTR) { - tmplt[count].type = CKA_LABEL; - tmplt[count].pValue = label; - tmplt[count].ulValueLen = strlen(label); - count++; + nid = OBJ_obj2nid(obj); + + if (OBJ_obj2txt(buf, sizeof(buf), obj, 1) <= 0) { + printf("[error]"); + ASN1_OBJECT_free(obj); + return; } - rc = funcs->C_FindObjectsInit(session, tmplt, count); - if (rc != CKR_OK) { - fprintf(stderr, "C_FindObjectInit failed\n"); - fprintf(stderr, "in tok_key_list_init() (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + printf("oid=%s", buf); + if (long_name && nid != NID_undef) + printf(" (%s)", OBJ_nid2ln(nid)); + + ASN1_OBJECT_free(obj); +} + +static void print_ibm_dilithium_keyform_attr(const char *attr, + const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + const struct p11sak_enum_value *eval; + const char *name = "[unknown]"; + + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || + val->ulValueLen != sizeof (CK_ULONG)) && + !sensitive) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else if (val->ulValueLen == 0) { + printf("%*s%s: [no value]\n", indent, "", attr); + } else { + for (eval = p11sak_ibm_dilithium_versions; eval->value != NULL; eval++) { + if (eval->private.num == *(CK_ULONG *)(val->pValue)) { + name = eval->value; + break; + } + } + printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, + *(CK_ULONG *)(val->pValue)); } +} - return CKR_OK; +static void print_ibm_kyber_keyform_attr(const char *attr, + const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + const struct p11sak_enum_value *eval; + const char *name = "[unknown]"; + + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION || + val->ulValueLen != sizeof (CK_ULONG)) && + !sensitive) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else if (val->ulValueLen == 0) { + printf("%*s%s: [no value]\n", indent, "", attr); + } else { + for (eval = p11sak_ibm_kyber_versions; eval->value != NULL; eval++) { + if (eval->private.num == *(CK_ULONG *)(val->pValue)) { + name = eval->value; + break; + } + } + printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, + *(CK_ULONG *)(val->pValue)); + } } -/** - * Columns: T P M R L S E D G V W U X A N * - */ -static CK_ATTRIBUTE_TYPE col2type(int col) +static void print_class_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) { - switch (col) { - case 0: - return CKA_TOKEN; - case 1: - return CKA_PRIVATE; - case 2: - return CKA_MODIFIABLE; - case 3: - return CKA_DERIVE; - case 4: - return CKA_LOCAL; - case 5: - return CKA_SENSITIVE; - case 6: - return CKA_ENCRYPT; - case 7: - return CKA_DECRYPT; - case 8: - return CKA_SIGN; - case 9: - return CKA_VERIFY; - case 10: - return CKA_WRAP; - case 11: - return CKA_UNWRAP; - case 12: - return CKA_EXTRACTABLE; - case 13: - return CKA_ALWAYS_SENSITIVE; - case 14: - return CKA_NEVER_EXTRACTABLE; - default: - return 0; + const struct p11sak_class *cls; + const char *name = NULL; + + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + val->ulValueLen != sizeof(CK_OBJECT_CLASS)) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + return; + } + + for (cls = p11sak_classes; cls->name != NULL; cls++) { + if (*(CK_OBJECT_CLASS *)(val->pValue) == cls->class) { + name = cls->name; + break; + } } + + if (name != NULL) + printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, + *(CK_OBJECT_CLASS *)(val->pValue)); + else + printf("%*s%s: 0x%lX\n", indent, "", attr, + *(CK_OBJECT_CLASS *)(val->pValue)); } -/** - * Print in p11sak_defined_attrs.conf defined attributes in long format - */ -static CK_RV print_custom_attrs(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE hkey, int long_print) +static void print_key_type_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) { - CK_RV rc = CKR_OK; + const struct p11sak_keytype *ktype; + const char *name = NULL; + + if ((val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) || + val->ulValueLen != sizeof(CK_KEY_TYPE)) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + return; + } + + ktype = find_keytype(*(CK_KEY_TYPE *)(val->pValue)); + if (ktype != NULL) + name = ktype->ckk_name; + + if (name != NULL) + printf("%*s%s: %s (0x%lX)\n", indent, "", attr, name, + *(CK_KEY_TYPE *)(val->pValue)); + else + printf("%*s%s: 0x%lX\n", indent, "", attr, + *(CK_KEY_TYPE *)(val->pValue)); +} + +static void print_oid_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION && !sensitive) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else if (val->ulValueLen == 0) { + printf("%*s%s: [no value]\n", indent, "", attr); + } else { + printf("%*s%s: ", indent, "", attr); + print_oid(val->pValue, val->ulValueLen, true); + printf(" len=%lu value:", val->ulValueLen); + print_dump((CK_BYTE *)val->pValue,val->ulValueLen, indent + 4); + } +} + +static const struct p11sak_attr *find_attribute(CK_ATTRIBUTE_TYPE type) +{ + const struct p11sak_attr *attr; + const struct p11sak_keytype **keytype; + + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) { + if (attr->type == type) + return attr; + } + + for (keytype = p11sak_keytypes; (*keytype)->name != NULL; keytype++) { + for (attr = (*keytype)->secret_attrs; + attr != NULL && attr->name != NULL; attr++) { + if (attr->type == type) + return attr; + } + + for (attr = (*keytype)->public_attrs; + attr != NULL && attr->name != NULL; attr++) { + if (attr->type == type) + return attr; + } + + for (attr = (*keytype)->private_attrs; + attr != NULL && attr->name != NULL; attr++) { + if (attr->type == type) + return attr; + } + } + + return NULL; +} + +static void print_attr_array_attr(const char *attr, const CK_ATTRIBUTE *val, + int indent, bool sensitive) +{ + const struct p11sak_attr *a; + unsigned int i, num; + + if (val->ulValueLen == CK_UNAVAILABLE_INFORMATION || + (val->ulValueLen % sizeof(CK_ATTRIBUTE)) != 0) + return; + + if (sensitive) { + printf("%*s%s: [sensitive]\n", indent, "", attr); + } else { + num = val->ulValueLen / sizeof(CK_ATTRIBUTE); + printf("%*s%s: %u attributes\n", indent, "", attr, num); + for (i = 0; i < num; i++) { + a = find_attribute(((CK_ATTRIBUTE *)(val->pValue))[i].type); + if (a == NULL || a->print_long == NULL) + printf("%*s%s: [attribute not supported]", indent + 4, "", + p11_get_cka(((CK_ATTRIBUTE *)(val->pValue))[i].type)); + else + a->print_long(p11_get_cka( + ((CK_ATTRIBUTE *)(val->pValue))[i].type), + &((CK_ATTRIBUTE *)(val->pValue))[i], + indent + 4, false); + } + } +} + +static void print_custom_attrs(CK_OBJECT_HANDLE key, + const struct p11sak_attr *standard_attrs, + int indent) +{ + CK_RV rc; int f; - struct ConfigBaseNode *c, *name, *hex_string, *type; + struct ConfigBaseNode *c, *name, *id, *type; struct ConfigStructNode *structnode; - int def_attr = 0; - - if (cfg != NULL) - { - confignode_foreach(c, cfg, f) { - if (confignode_hastype(c, CT_STRUCT) && strcmp(c->key, "attribute") == 0) { - // parse... - structnode = confignode_to_struct(c); - name = confignode_find(structnode->value, "name"); - hex_string = confignode_find(structnode->value, "id"); - type = confignode_find(structnode->value, "type"); - - // checking syntax of attribute... - if (name == NULL) { - fprintf(stderr, "Missing name in Attribute in line %hu\n", c->line); - return CKR_DATA_INVALID; - } else if (!confignode_hastype(name, CT_BAREVAL)) { - fprintf(stderr, "Invalid name in Attribute in line %hu\n", name->line); - return CKR_DATA_INVALID; - } else if (hex_string == NULL) { - fprintf(stderr, "Missing value in Attribute in line %hu\n", c->line); - return CKR_DATA_INVALID; - } else if (!confignode_hastype(hex_string, CT_INTVAL)) { - fprintf(stderr, "Invalid name in Attribute in line %hu\n", hex_string->line); - return CKR_DATA_INVALID; - } else if (type == NULL) { - fprintf(stderr, "Missing type in Attribute in line %hu\n", c->line); - return CKR_DATA_INVALID; - } else if (!confignode_hastype(type, CT_BAREVAL)) { - fprintf(stderr, "Invalid name in Attribute in line %hu\n", type->line); - return CKR_DATA_INVALID; - } + const struct p11sak_custom_attr_type *atype; + const struct p11sak_attr *attr; + CK_ATTRIBUTE val; + bool skip; + + confignode_foreach(c, p11sak_cfg, f) { + if (!confignode_hastype(c, CT_STRUCT) || + strcmp(c->key, P11SAK_CONFIG_KEYWORD_ATTRIBUTE) != 0) + continue; + + structnode = confignode_to_struct(c); + name = confignode_find(structnode->value, + P11SAK_CONFIG_KEYWORD_NAME); + id = confignode_find(structnode->value, + P11SAK_CONFIG_KEYWORD_ID); + type = confignode_find(structnode->value, + P11SAK_CONFIG_KEYWORD_TYPE); + + if (name == NULL || !confignode_hastype(name, CT_BAREVAL)) { + warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", + P11SAK_CONFIG_KEYWORD_NAME, c->line); + return; + } + if (id == NULL || !confignode_hastype(id, CT_INTVAL)) { + warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", + P11SAK_CONFIG_KEYWORD_ID, c->line); + return; + } + if (type == NULL || !confignode_hastype(type, CT_BAREVAL)) { + warnx("Sytax error in config file: Missing '%s' in attribute at line %hu\n", + P11SAK_CONFIG_KEYWORD_TYPE, c->line); + return; + } - def_attr = 1; - - // print attribute by type - unsigned int hex = confignode_to_intval(hex_string)->value; - if (strcmp(confignode_to_bareval(type)->value, "CK_BBOOL") == 0) { - // build template - CK_BBOOL a_bool; - CK_ATTRIBUTE temp = {hex, &a_bool, sizeof(a_bool)}; - - // get attribute value - rc = funcs->C_GetAttributeValue(session, hkey, &temp, 1); - if (rc == CKR_OK) { - if (temp.ulValueLen != sizeof(CK_BBOOL)) { - fprintf(stderr, " Error in retrieving Attribute %s: %lu\n", - confignode_to_bareval(name)->value, temp.ulValueLen); - } else { - if (long_print) { - printf(" %s: %s\n", confignode_to_bareval(name)->value, - CK_BBOOL2a(*(CK_BBOOL*) temp.pValue)); - } else if (strcmp(CK_BBOOL2a(*(CK_BBOOL*) temp.pValue), "CK_TRUE") == 0) { - printf(" 1 "); - return CKR_OK; - } - } - } else if (rc == CKR_ATTRIBUTE_SENSITIVE && long_print) { - printf(" %s: SENSITIVE\n", confignode_to_bareval(name)->value); - } else if (rc != CKR_ATTRIBUTE_TYPE_INVALID) { - return rc; - } - } else if (strcmp((confignode_to_bareval(type)->value), "CK_ULONG") == 0) { - // build template - CK_ULONG a_ulong; - CK_ATTRIBUTE temp = {hex, &a_ulong, sizeof(a_ulong)}; - - // get attribute value - rc = funcs->C_GetAttributeValue(session, hkey, &temp, 1); - if (rc == CKR_OK) { - if (temp.ulValueLen != sizeof(CK_ULONG)) { - fprintf(stderr, " Error in retrieving Attribute %s: %lu\n", - confignode_to_bareval(name)->value, temp.ulValueLen); - } else { - if (long_print) { - printf(" %s: %lu (0x%lX)\n", confignode_to_bareval(name)->value, - *(CK_ULONG*) temp.pValue, *(CK_ULONG*) temp.pValue); - } else { - printf(" 1 "); - return CKR_OK; - } - } - } else if (rc == CKR_ATTRIBUTE_SENSITIVE && long_print) { - printf(" %s: SENSITIVE\n", confignode_to_bareval(name)->value); - } else if (rc != CKR_ATTRIBUTE_TYPE_INVALID) { - return rc; - } - } else if (strcmp((confignode_to_bareval(type)->value), "CK_BYTE") == 0) { - // get length - CK_ATTRIBUTE temp = {hex, NULL, 0}; - rc = funcs->C_GetAttributeValue(session, hkey, &temp, 1); - if (rc == CKR_ATTRIBUTE_SENSITIVE && long_print) { - printf(" %s: SENSITIVE\n", confignode_to_bareval(name)->value); - } else if (rc != CKR_ATTRIBUTE_TYPE_INVALID && rc != CKR_OK) { - return rc; - } else if (rc == CKR_OK && temp.ulValueLen != CK_UNAVAILABLE_INFORMATION) { - // build template - unsigned long a_byte_array = temp.ulValueLen; - temp.pValue = malloc(a_byte_array); - if (!temp.pValue) { - fprintf(stderr, "Error: cannot malloc storage for attribute value.\n"); - return CKR_HOST_MEMORY; - } - - // get attribute value - rc = funcs->C_GetAttributeValue(session, hkey, &temp, 1); - if (rc == CKR_OK) { - if (temp.ulValueLen != a_byte_array) { - fprintf(stderr, " Error in retrieving Attribute %s: %lu\n", - confignode_to_bareval(name)->value, temp.ulValueLen); - } else { - if (long_print) { - dump_attr(&temp); - } else { - printf(" 1 "); - free(temp.pValue); - return CKR_OK; - } - } - } - free(temp.pValue); - } - } else { - fprintf(stderr, "Error: Attribute type [%s] invalid.\n", confignode_to_bareval(type)->value); - } - } + for (atype = custom_attr_types; atype->type != NULL; atype ++) { + if (strcmp(atype->type, + confignode_to_bareval(type)->value) == 0) + break; + } + if (atype->type == NULL) { + warnx("Sytax error in config file: Invalid '%s' value in attribute at line %hu\n", + P11SAK_CONFIG_KEYWORD_TYPE, c->line); + return; } + + /* Ignore any standard attributes also defined in the config file */ + for (skip = false, attr = standard_attrs; attr->name != NULL; attr++) { + if (attr->type == confignode_to_intval(id)->value) { + skip = true; + break; + } + } + if (skip) + continue; + + val.type = confignode_to_intval(id)->value; + val.ulValueLen = 0; + val.pValue = NULL; + rc = get_attribute(key, &val); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE) + continue; + + atype->print_long(p11_get_cka(confignode_to_intval(id)->value), + &val, indent, rc == CKR_ATTRIBUTE_SENSITIVE); + + if (is_attr_array_attr(&val)) + free_attr_array_attr(&val); + if (val.pValue != NULL) + free(val.pValue); } - if (!long_print) - printf(" %s ", def_attr ? "0" : "-"); - - return CKR_OK; } -/** - * Print standard attributes - */ -static void short_print(int col, CK_ATTRIBUTE attr[], p11sak_kt ktype) +static void print_key_attrs(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, int indent) { - int j = 0; - int attr_count = 0; + const struct p11sak_attr *attrs, *attr; + CK_ATTRIBUTE val; + CK_RV rc; - switch (ktype) { - case kt_SECRET: - attr_count = SEC_KEY_MAX_BOOL_ATTR_COUNT; + switch (class) { + case CKO_SECRET_KEY: + attrs = keytype->secret_attrs; break; - case kt_PUBLIC: - attr_count = PUB_KEY_MAX_BOOL_ATTR_COUNT; + case CKO_PUBLIC_KEY: + attrs = keytype->public_attrs; break; - case kt_PRIVATE: - attr_count = PRV_KEY_MAX_BOOL_ATTR_COUNT; + case CKO_PRIVATE_KEY: + attrs = keytype->private_attrs; break; default: - attr_count = PUB_KEY_MAX_BOOL_ATTR_COUNT; + attrs = NULL; + break; } - for (j = 0; j < attr_count; j++) { - if (attr[j].type == col2type(col) && !attr_na(attr[j].type, ktype)) { - printf(" %d ", *(CK_BBOOL*) attr[j].pValue); - return; - } + for (attr = attrs; attr != NULL && attr->name != NULL; attr++) { + val.type = attr->type; + val.ulValueLen = 0; + val.pValue = NULL; + + rc = get_attribute(key, &val); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE) + continue; + + attr->print_long(attr->name, &val, indent, + rc == CKR_ATTRIBUTE_SENSITIVE); + + if (is_attr_array_attr(&val)) + free_attr_array_attr(&val); + if (val.pValue != NULL) + free(val.pValue); } - printf(" - "); - return; + print_custom_attrs(key, attrs, indent); } -/** - * Print attributes of secure keys - */ -static CK_RV sec_key_print_attributes(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE hkey, int long_print) + +static CK_RV print_boolean_attrs(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + const char *typestr, const char* label, + struct p11sak_list_data *data) { + const struct p11sak_attr *attr; + bool applicable; + CK_ULONG i; CK_RV rc; - int i; - /* Boolean Attributes */ - CK_BBOOL a_token; - CK_BBOOL a_private; - CK_BBOOL a_modifiable; - CK_BBOOL a_derive; - CK_BBOOL a_local; - CK_BBOOL a_sensitive; - CK_BBOOL a_encrypt; - CK_BBOOL a_decrypt; - CK_BBOOL a_sign; - CK_BBOOL a_verify; - CK_BBOOL a_wrap; - CK_BBOOL a_unwrap; - CK_BBOOL a_extractable; - CK_BBOOL a_always_sensitive; - CK_BBOOL a_never_extractable; - - CK_ATTRIBUTE bool_tmplt[] = { - { CKA_TOKEN, &a_token, sizeof(a_token) }, - { CKA_PRIVATE, &a_private, sizeof(a_private) }, - { CKA_MODIFIABLE, &a_modifiable, sizeof(a_modifiable) }, - { CKA_DERIVE, &a_derive, sizeof(a_derive) }, - { CKA_LOCAL, &a_local, sizeof(a_local) }, - { CKA_SENSITIVE, &a_sensitive, sizeof(a_sensitive) }, - { CKA_ENCRYPT, &a_encrypt, sizeof(a_encrypt) }, - { CKA_DECRYPT, &a_decrypt, sizeof(a_decrypt) }, - { CKA_SIGN, &a_sign, sizeof(a_sign) }, - { CKA_VERIFY, &a_verify, sizeof(a_verify) }, - { CKA_WRAP, &a_wrap, sizeof(a_wrap) }, - { CKA_UNWRAP, &a_unwrap, sizeof(a_unwrap) }, - { CKA_EXTRACTABLE, &a_extractable, sizeof(a_extractable) }, - { CKA_ALWAYS_SENSITIVE, &a_always_sensitive, sizeof(a_always_sensitive) }, - { CKA_NEVER_EXTRACTABLE, &a_never_extractable, sizeof(a_never_extractable) } }; - CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); - - rc = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + data->bool_attrs, + data->num_bool_attrs); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) { + warnx("Failed to get boolean attributes for %s key \"%s\": 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); return rc; } - if (long_print) { - for (i = 0; i < (int) count; i++) { - if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { - fprintf(stderr, " Error in retrieving Attribute %s\n", - CKA2a(bool_tmplt[i].type)); - } else { - printf(" %s: %s\n", CKA2a(bool_tmplt[i].type), - CK_BBOOL2a(*(CK_BBOOL*) bool_tmplt[i].pValue)); - } - } - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + for (attr = p11sak_bool_attrs, i = 0; attr->name != NULL; attr++, i++) { + switch (class) { + case CKO_SECRET_KEY: + applicable = secret_attr_applicable(keytype, attr); + break; + case CKO_PUBLIC_KEY: + applicable = public_attr_applicable(keytype, attr); + break; + case CKO_PRIVATE_KEY: + applicable = private_attr_applicable(keytype, attr); + break; + default: + applicable = false; + break; } - } else { - printf(" |"); - for (i = 1; i < KEY_MAX_BOOL_ATTR_COUNT; i++) - short_print(i, bool_tmplt, kt_SECRET); - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + + if (data->bool_attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) + applicable = false; + + if (opt_long) { + if (!applicable) + continue; + + attr->print_long(attr->name, &data->bool_attrs[i], 8, false); + } else { + attr->print_short(&data->bool_attrs[i], applicable); } - printf("|"); } return CKR_OK; } -/** - * Print attributes of private keys - */ -static CK_RV priv_key_print_attributes(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE hkey, int long_print) + +static CK_RV prepare_uri(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS *class, + const char *typestr, const char* label, + struct p11_uri **uri) { + struct p11_uri *u; CK_RV rc; - int i = 0; - /* Boolean Attributes */ - CK_BBOOL a_token; - CK_BBOOL a_private; - CK_BBOOL a_modifiable; - CK_BBOOL a_derive; - CK_BBOOL a_local; - CK_BBOOL a_sensitive; - CK_BBOOL a_decrypt; - CK_BBOOL a_sign; - CK_BBOOL a_unwrap; - CK_BBOOL a_extractable; - CK_BBOOL a_always_sensitive; - CK_BBOOL a_never_extractable; - - CK_ATTRIBUTE bool_tmplt[] = { - { CKA_TOKEN, &a_token, sizeof(a_token) }, - { CKA_PRIVATE, &a_private, sizeof(a_private) }, - { CKA_MODIFIABLE, &a_modifiable, sizeof(a_modifiable) }, - { CKA_DERIVE, &a_derive, sizeof(a_derive) }, - { CKA_LOCAL, &a_local, sizeof(a_local) }, - { CKA_SENSITIVE, &a_sensitive, sizeof(a_sensitive) }, - { CKA_DECRYPT, &a_decrypt, sizeof(a_decrypt) }, - { CKA_SIGN, &a_sign, sizeof(a_sign) }, - { CKA_UNWRAP, &a_unwrap, sizeof(a_unwrap) }, - { CKA_EXTRACTABLE, &a_extractable, sizeof(a_extractable) }, - { CKA_ALWAYS_SENSITIVE, &a_always_sensitive, sizeof(a_always_sensitive) }, - { CKA_NEVER_EXTRACTABLE, &a_never_extractable, sizeof(a_never_extractable) } }; - CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); - - rc = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + u = p11_uri_new(); + if (u == NULL) { + warnx("Failed to allocate URI for %s key \"%s\"", typestr, label); + return CKR_HOST_MEMORY; } - /* Long print */ - if (long_print) { - for (i = 0; i < (int) count; i++) { - if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { - fprintf(stderr, " Error in retrieving Attribute %s\n", - CKA2a(bool_tmplt[i].type)); - } else { - printf(" %s: %s\n", CKA2a(bool_tmplt[i].type), - CK_BBOOL2a(*(CK_BBOOL*) bool_tmplt[i].pValue)); - } - } - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; - } - } else { - /* Short print */ - printf(" |"); - for (i = 1; i < KEY_MAX_BOOL_ATTR_COUNT; i++) - short_print(i, bool_tmplt, kt_PRIVATE); - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; - } - printf("|"); + if (opt_detailed_uri) { + /* include library and slot information only in detailed URIs */ + u->info = &pkcs11_info; + u->slot_id = opt_slot; + u->slot_info = &pkcs11_slotinfo; + } + u->token_info = &pkcs11_tokeninfo; + + u->obj_class[0].ulValueLen = sizeof(*class); + u->obj_class[0].pValue = class; + + u->obj_label[0].ulValueLen = label != NULL ? strlen(label) : 0; + u->obj_label[0].pValue = (char *)label; + + rc = get_attribute(key, &u->obj_id[0]); + if (rc != CKR_OK) { + warnx("Failed to get CKA_ID for %s key \"%s\": 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); + if (u->obj_id[0].pValue != NULL) + free(u->obj_id[0].pValue); + p11_uri_free(u); + return rc; } + *uri = u; + return CKR_OK; } -/** - * Print attributes of public keys - */ -static CK_RV pub_key_print_attributes(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE hkey, int long_print) + +static CK_RV handle_key_list(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + CK_ULONG keysize, const char *typestr, + const char* label, void *private) { + struct p11sak_list_data *data = private; + struct p11_uri *uri = NULL; CK_RV rc; - int i = 0; - /* Boolean Attributes */ - CK_BBOOL a_token; - CK_BBOOL a_private; - CK_BBOOL a_modifiable; - CK_BBOOL a_derive; - CK_BBOOL a_local; - CK_BBOOL a_encrypt; - CK_BBOOL a_verify; - CK_BBOOL a_wrap; - - CK_ATTRIBUTE bool_tmplt[] = { - { CKA_TOKEN, &a_token, sizeof(a_token) }, - { CKA_PRIVATE, &a_private, sizeof(a_private) }, - { CKA_MODIFIABLE, &a_modifiable, sizeof(a_modifiable) }, - { CKA_DERIVE, &a_derive, sizeof(a_derive) }, - { CKA_LOCAL, &a_local, sizeof(a_local) }, - { CKA_ENCRYPT, &a_encrypt, sizeof(a_encrypt) }, - { CKA_VERIFY, &a_verify, sizeof(a_verify) }, - { CKA_WRAP, &a_wrap, sizeof(a_wrap) }, }; - CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); - - rc = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); + UNUSED(keysize); + + rc = pkcs11_funcs->C_GetAttributeValue(pkcs11_session, key, + data->bool_attrs, + data->num_bool_attrs); + if (rc != CKR_OK && rc != CKR_ATTRIBUTE_TYPE_INVALID) { + warnx("Failed to get boolean attributes for %s key \"%s\": 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); return rc; } - /* Long print */ - if (long_print) { - for (i = 0; i < (int) count; i++) { - if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { - fprintf(stderr, " Error in retrieving Attribute %s\n", - CKA2a(bool_tmplt[i].type)); - } else { - printf(" %s: %s\n", CKA2a(bool_tmplt[i].type), - CK_BBOOL2a(*(CK_BBOOL*) bool_tmplt[i].pValue)); - } - } - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; - } + if (opt_long) { + rc = prepare_uri(key, &class, typestr, label, &uri); + if (rc != CKR_OK) + goto done; + + printf("Label: \"%s\"\n", label); + printf(" URI: %s\n", p11_uri_format(uri)); + printf(" Key: %s\n", typestr); + printf(" Attributes:\n"); + printf(" CKA_TOKEN: CK_TRUE\n"); } else { - /* Short print */ - printf(" |"); - for (i = 1; i < KEY_MAX_BOOL_ATTR_COUNT; i++) - short_print(i, bool_tmplt, kt_PUBLIC); - rc = print_custom_attrs(session, hkey, long_print); - if (rc != CKR_OK) { - fprintf(stderr, "Attribute retrieval failed (error code 0x%lX: %s)\n", rc, - p11_get_ckr(rc)); - return rc; + printf("| "); + } + + rc = print_boolean_attrs(key, class, keytype, typestr, label, data); + if (rc != CKR_OK) + goto done; + + if (opt_long) + print_key_attrs(key, class, keytype, 8); + else + printf("| %*s | \"%s\"\n", LIST_KEYTYPE_CELL_SIZE, typestr, label); + + data->num_displayed++; + rc = CKR_OK; + +done: + if (uri != NULL) { + if (uri->obj_id[0].pValue != NULL) + free(uri->obj_id[0].pValue); + p11_uri_free(uri); + } + + return rc; +} + +static CK_RV p11sak_list_key_compare(CK_OBJECT_HANDLE key1, + CK_OBJECT_HANDLE key2, + int *result, void *private) +{ + struct p11sak_list_data *data = private; + CK_OBJECT_CLASS class1, class2; + CK_KEY_TYPE ktype1, ktype2; + CK_ULONG keysize1, keysize2; + char *label1 = NULL, *label2 = NULL; + CK_RV rc; + int i; + + *result = 0; + + rc = get_key_infos(key1, &class1, &ktype1, &keysize1, &label1, NULL, NULL); + if (rc != CKR_OK) + goto done; + + rc = get_key_infos(key2, &class2, &ktype2, &keysize2, &label2, NULL, NULL); + if (rc != CKR_OK) + goto done; + + for (i = 0; i < MAX_SORT_FIELDS; i++) { + switch (data->sort_info[i].field) { + case SORT_LABEL: + *result = strcmp(label1, label2); + break; + case SORT_KEYTYPE: + *result = (long)ktype1 - (long)ktype2; + break; + case SORT_CLASS: + *result = (long)class1 - (long)class2; + break; + case SORT_KEYSIZE: + *result = (long)keysize1 - (long)keysize2; + break; + case SORT_NONE: + default: + break; } - printf("|"); + + if (data->sort_info[i].descending) + *result = -*result; + + if (*result != 0) + break; } - return CKR_OK; +done: + if (label1 != NULL) + free(label1); + if (label2 != NULL) + free(label2); + + return rc; } -/** - * Alloc attribute - */ -static CK_RV tok_attribute_alloc(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE hkey, - CK_ATTRIBUTE_PTR attribute) +static CK_RV parse_sort_specification(const char *sort_spec, + struct p11sak_list_data *data) { - CK_RV rv; - void *tmp; + CK_RV rc = CKR_OK; + char *tok; + unsigned int i = 0; + char *spec; + + spec = strdup(sort_spec); + if (spec == NULL) { + warnx("Failed to allocate the sort specification string."); + return CKR_HOST_MEMORY; + } - if (!attribute) - return CKR_ARGUMENTS_BAD; + tok = strtok(spec, ","); + while (tok != NULL) { + if (i >= MAX_SORT_FIELDS) { + warnx("Too many sort field designators."); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + switch (tolower(*tok)) { + case 'l': + data->sort_info[i].field = SORT_LABEL; + break; + case 'k': + data->sort_info[i].field = SORT_KEYTYPE; + break; + case 'c': + data->sort_info[i].field = SORT_CLASS; + break; + case 's': + data->sort_info[i].field = SORT_KEYSIZE; + break; + default: + warnx("Invalid sort field designator: '%c'.", *tok); + rc = CKR_ARGUMENTS_BAD; + goto done; + } - if (attribute->pValue) - return CKR_CANCEL; + tok++; + if (*tok == ':') { + tok++; + switch (tolower(*tok)) { + case 'a': + data->sort_info[i].descending = false; + break; + case 'd': + data->sort_info[i].descending = true; + break; + default: + warnx("Invalid sort order designator: '%c'.", *tok); + rc = CKR_ARGUMENTS_BAD; + goto done; + } - if (attribute->ulValueLen) - goto alloc; + tok++; + if (*tok != '\0') { + warnx("Invalid character(s) after sort order designator: '%s'.", + tok); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + } else if (*tok == '\0') { + data->sort_info[i].descending = false; + } else { + warnx("Invalid character(s) after sort field designator: '%s'.", + tok); + rc = CKR_ARGUMENTS_BAD; + goto done; + } - /* lookup size */ - rv = funcs->C_GetAttributeValue(session, hkey, attribute, 1); - if ((rv == CKR_ATTRIBUTE_SENSITIVE) || - (attribute->ulValueLen == 0) || - (attribute->ulValueLen == CK_UNAVAILABLE_INFORMATION)) { - /** - * REVISIT if the attribute is not available, the first - * returns with ulValueLen == 0. According to the spec a - * return value CKR_ATTRIBUTE_SENSITIVE is expected. Check - * implementation and spec for clarification. - **/ - attribute->pValue = NULL_PTR; - attribute->ulValueLen = 0; - return CKR_ATTRIBUTE_SENSITIVE; - } - if (rv != CKR_OK) { - fprintf(stderr, - "Object can not lookup attribute length " - "(error code 0x%lX: %s)\n", rv, p11_get_ckr(rv)); - return rv; - } - -alloc: - tmp = malloc((size_t) attribute->ulValueLen); - if (!tmp) - return CKR_HOST_MEMORY; + tok = strtok(NULL, ","); + i++; + } - attribute->pValue = tmp; +done: + free(spec); - return CKR_OK; + return rc; } -/** - * Get label attribute of key - */ -static CK_RV tok_key_get_label_attr(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE hkey, char **plabel) +static CK_RV p11sak_list_key(void) { + const struct p11sak_keytype *keytype = NULL; + const struct p11sak_attr *attr; + struct p11sak_list_data data = { 0 }; + unsigned int i; + CK_BYTE *attr_data = NULL; CK_RV rc; - char *label; - CK_ATTRIBUTE template[1] = { { CKA_LABEL, NULL_PTR, 0 } }; - CK_ULONG label_len; - rc = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (opt_keytype != NULL) + keytype = opt_keytype->private.ptr; + + for (attr = p11sak_bool_attrs, data.num_bool_attrs = 0; attr->name != NULL; + attr++, data.num_bool_attrs++) + ; + attr_data = calloc(data.num_bool_attrs, sizeof(CK_BBOOL)); + data.bool_attrs = calloc(data.num_bool_attrs, sizeof(CK_ATTRIBUTE)); + if (attr_data == NULL || data.bool_attrs == NULL) { + warnx("Failed to allocate memory for the attributes"); + rc = CKR_HOST_MEMORY; + goto done; + } + for (attr = p11sak_bool_attrs, i = 0; attr->name != NULL; attr++, i++) { + data.bool_attrs[i].type = attr->type; + data.bool_attrs[i].ulValueLen = sizeof(CK_BBOOL); + data.bool_attrs[i].pValue = &attr_data[i]; + } + + if (opt_sort) { + rc = parse_sort_specification(opt_sort, &data); + if (rc != CKR_OK) + goto done; + } + + if (!opt_long) { + printf("| "); + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) + printf("%c ", attr->letter); + printf("| %*s | LABEL\n", LIST_KEYTYPE_CELL_SIZE, "KEY TYPE"); + printf("|-"); + for (attr = p11sak_bool_attrs; attr->name != NULL; attr++) + printf("--"); + printf("+-"); + for (i = 0; i < LIST_KEYTYPE_CELL_SIZE; i++) + printf("-"); + printf("-+--------------------\n"); + } + + rc = iterate_key_objects(keytype, opt_label, opt_id, opt_attr, + opt_sort != NULL ? p11sak_list_key_compare : NULL, + handle_key_list, &data); if (rc != CKR_OK) { - fprintf(stderr, "Key cannot show CKA_LABEL attribute (error code 0x%lX: %s)\n", - rc, p11_get_ckr(rc)); - return rc; + warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", + keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); + goto done; } - if (template[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) { - /* assume empty label */ - *plabel = strdup(""); - if (!*plabel) { - fprintf(stderr, "Error: cannot malloc storage for label.\n"); - return CKR_HOST_MEMORY; + printf("\n"); + printf("%lu key(s) displayed\n", data.num_displayed); + +done: + if (data.bool_attrs != NULL) + free(data.bool_attrs); + if (attr_data != NULL) + free(attr_data); + + return rc; +} + +static char prompt_user(const char *message, char* allowed_chars) +{ + int len; + size_t linelen = 0; + char *line = NULL; + char ch = '\0'; + + printf("%s", message); + + while (1) { + len = getline(&line, &linelen, stdin); + if (len == -1) + break; + + if (strlen(line) == 2 && strpbrk(line, allowed_chars) != 0) { + ch = line[0]; + break; } + + warnx("Improper reply, try again"); + } + + if (line != NULL) + free(line); + + return ch; +} + +static CK_RV handle_key_remove(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + CK_ULONG keysize, const char *typestr, + const char* label, void *private) +{ + struct p11sak_remove_data *data = private; + char *msg = NULL; + char ch; + CK_RV rc; + + UNUSED(class); + UNUSED(keysize); + UNUSED(keytype); + + if (data->skip_all) { + data->num_skipped++; return CKR_OK; } - label_len = template[0].ulValueLen; - label = malloc(label_len + 1); - if (!label) { - fprintf(stderr, "Error: cannot malloc storage for label.\n"); - return CKR_HOST_MEMORY; + if (!data->remove_all) { + if (asprintf(&msg, "Are you sure you want to remove %s key object \"%s\" [y/n/a/c]? ", + typestr, label) < 0 || + msg == NULL) { + warnx("Failed to allocate memory for a message"); + return CKR_HOST_MEMORY; + } + ch = prompt_user(msg, "ynac"); + free(msg); + + switch (ch) { + case 'n': + data->num_skipped++; + return CKR_OK; + case 'c': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; + case 'a': + data->remove_all = true; + break; + default: + break; + } } - template[0].pValue = label; - rc = funcs->C_GetAttributeValue(session, hkey, template, 1); + rc = pkcs11_funcs->C_DestroyObject(pkcs11_session, key); if (rc != CKR_OK) { - fprintf(stderr, "Error retrieving CKA_LABEL attribute (error code 0x%lX: %s)\n", - rc, p11_get_ckr(rc)); - free(label); - return rc; + warnx("Failed to remove %s key object \"%s\": C_DestroyObject: 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); + data->num_failed++; + return CKR_OK; } - label[label_len] = 0; - *plabel = label; + printf("Successfully removed %s key object \"%s\".\n", typestr, label); + data->num_removed++; return CKR_OK; } -/** - * Get key type - */ -static CK_RV tok_key_get_key_type(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE hkey, - CK_OBJECT_CLASS *keyclass, char **ktype, - CK_ULONG *klength) + +static CK_RV p11sak_remove_key(void) { + const struct p11sak_keytype *keytype = NULL; + struct p11sak_remove_data data = { 0 }; CK_RV rc; - char *buffer; - CK_OBJECT_CLASS oclass; - CK_KEY_TYPE kt; - CK_ULONG vl; - CK_ATTRIBUTE template[1] = - { { CKA_CLASS, &oclass, sizeof(CK_OBJECT_CLASS) } }; + if (opt_keytype != NULL) + keytype = opt_keytype->private.ptr; - rc = funcs->C_GetAttributeValue(session, hkey, template, 1); + data.remove_all = opt_force; + + rc = iterate_key_objects(keytype, opt_label, opt_id, opt_attr, NULL, + handle_key_remove, &data); if (rc != CKR_OK) { - fprintf(stderr, - "Object does not have CKA_CLASS attribute (error code 0x%lX: %s)\n", - rc, p11_get_ckr(rc)); + warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", + keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); return rc; } - // the buffer holds the following string - // "public " + CKK2a(kt) with kt = "unknown key type" being the longest kt string - // or "private " + CKK2a(kt) with kt = "unknown key type" being the longest kt string - // Hence, the size of the string is 25 Bytes including the '\0' character - // Use 32 Bytes as multiple of 8 - buffer = malloc(32); - if (!buffer) { - return CKR_HOST_MEMORY; + printf("%lu key object(s) removed.\n", data.num_removed); + if (data.num_skipped > 0) + printf("%lu key object(s) skipped.\n", data.num_skipped); + if (data.num_failed > 0) + printf("%lu key object(s) failed to remove.\n", data.num_failed); + + return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; +} + +static CK_RV handle_key_set_attr(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + CK_ULONG keysize, const char *typestr, + const char* label, void *private) +{ + struct p11sak_set_attr_data *data = private; + CK_ATTRIBUTE *attrs = NULL; + CK_ULONG num_attrs = 0; + char *msg = NULL; + char ch; + CK_RV rc; + bool (*attr_aplicable)(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr); + + UNUSED(keysize); + + if (data->skip_all) { + data->num_skipped++; + return CKR_OK; } - switch (oclass) { + if (!data->set_all) { + if (asprintf(&msg, "Are you sure you want to change %s key object \"%s\" [y/n/a/c]? ", + typestr, label) < 0 || + msg == NULL) { + warnx("Failed to allocate memory for a message"); + return CKR_HOST_MEMORY; + } + ch = prompt_user(msg, "ynac"); + free(msg); + + switch (ch) { + case 'n': + data->num_skipped++; + return CKR_OK; + case 'c': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; + case 'a': + data->set_all = true; + break; + default: + break; + } + } + + switch (class) { case CKO_SECRET_KEY: - buffer[0] = 0; + attr_aplicable = secret_attr_applicable; break; case CKO_PUBLIC_KEY: - strcpy(buffer, "public "); + attr_aplicable = public_attr_applicable; break; case CKO_PRIVATE_KEY: - strcpy(buffer, "private "); + attr_aplicable = private_attr_applicable; break; default: - /* its not a key */ + warnx("Key object \"%s\" has an unsupported object class: %lu", + label, class); rc = CKR_KEY_TYPE_INCONSISTENT; - free(buffer); - return rc; + goto done; } - template[0].type = CKA_KEY_TYPE; - template[0].pValue = &kt; - template[0].ulValueLen = sizeof(CK_KEY_TYPE); - rc = funcs->C_GetAttributeValue(session, hkey, template, 1); - if (rc != CKR_OK) { - fprintf(stderr, "Object does not have CKA_KEY_TYPE attribute (error code 0x%lX: %s)\n", - rc, p11_get_ckr(rc)); - free(buffer); - return rc; - } + if (opt_new_attr != NULL) { + rc = parse_boolean_attrs(keytype, opt_new_attr, &attrs, &num_attrs, + true, attr_aplicable); + if (rc != CKR_OK) { + data->num_failed++; + goto done; + } - strcat(buffer, CKK2a(kt)); + if (num_attrs == 0) { + warnx("None of the specified attributes apply to %s key object \"%s\".", + typestr, label); + data->num_skipped++; + goto done; + } + } - *klength = 0; - switch (kt) { - case CKK_AES: - case CKK_AES_XTS: - case CKK_GENERIC_SECRET: - template[0].type = CKA_VALUE_LEN; - template[0].pValue = &vl; - template[0].ulValueLen = sizeof(CK_ULONG); - rc = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (opt_new_label != NULL) { + rc = add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), + &attrs, &num_attrs); if (rc != CKR_OK) { - fprintf(stderr, "Object does not have CKA_VALUE_LEN attribute (error code 0x%lX: %s)\n", - rc, p11_get_ckr(rc)); - free(buffer); + warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); return rc; } - *klength = vl * 8; - if (kt == CKK_AES_XTS) - *klength /= 2; - break; - default: - // Fall through - template values set above - break; } - *ktype = buffer; - *keyclass = oclass; + if (opt_new_id != NULL) { + rc = parse_id(opt_new_id, &attrs, &num_attrs); + if (rc != CKR_OK) + return rc; + } - return CKR_OK; + rc = pkcs11_funcs->C_SetAttributeValue(pkcs11_session, key, + attrs, num_attrs); + if (rc != CKR_OK) { + warnx("Failed to change %s key object \"%s\": C_SetAttributeValue: 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); + data->num_failed++; + rc = CKR_OK; + goto done; + } + + printf("Successfully changed %s key object \"%s\".\n", typestr, label); + data->num_set++; + +done: + free_attributes(attrs, num_attrs); + return rc; } -/** - * Check args for gen_key command. - */ -static CK_RV check_args_gen_key(p11sak_kt *kt, CK_ULONG keylength, - char *ECcurve, char *pqc_ver) +static CK_RV p11sak_set_key_attr(void) { - switch (*kt) { - case kt_DES: - case kt_3DES: - break; - case kt_IBM_DILITHIUM: - if (pqc_ver == NULL) { - fprintf(stderr, - "Cipher key type [%d] supported but Dilithium version not set in arguments. Try adding argument , , , , or \n", - *kt); - return CKR_ARGUMENTS_BAD; + const struct p11sak_keytype *keytype = NULL; + struct p11sak_set_attr_data data = { 0 }; + CK_RV rc; + + if (opt_keytype != NULL) + keytype = opt_keytype->private.ptr; + + if (opt_new_attr == NULL && opt_new_label == NULL && opt_new_id == NULL) { + warnx("At least one of the following options must be specified:"); + warnx("'-A'/'--new-attr', '-l'/'--new-label', or '-I'/'--new-id'"); + return CKR_ARGUMENTS_BAD; + } + + data.set_all = opt_force; + + rc = iterate_key_objects(keytype, opt_label, opt_id, opt_attr, NULL, + handle_key_set_attr, &data); + if (rc != CKR_OK) { + warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", + keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); + return rc; + } + + printf("%lu key object(s) updated.\n", data.num_set); + if (data.num_skipped > 0) + printf("%lu key object(s) skipped.\n", data.num_skipped); + if (data.num_failed > 0) + printf("%lu key object(s) failed to update.\n", data.num_failed); + + return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; +} + +static CK_RV handle_key_copy(CK_OBJECT_HANDLE key, CK_OBJECT_CLASS class, + const struct p11sak_keytype *keytype, + CK_ULONG keysize, const char *typestr, + const char* label, void *private) +{ + struct p11sak_copy_data *data = private; + CK_ATTRIBUTE *attrs = NULL; + CK_ULONG num_attrs = 0; + CK_OBJECT_HANDLE new_key = CK_INVALID_HANDLE; + char *msg = NULL; + char ch; + CK_RV rc; + bool (*attr_aplicable)(const struct p11sak_keytype *keytype, + const struct p11sak_attr *attr); + + UNUSED(keysize); + + if (data->skip_all) { + data->num_skipped++; + return CKR_OK; + } + + if (!data->copy_all) { + if (asprintf(&msg, "Are you sure you want to copy %s key object \"%s\" [y/n/a/c]? ", + typestr, label) < 0 || + msg == NULL) { + warnx("Failed to allocate memory for a message"); + return CKR_HOST_MEMORY; } - if (strcasecmp(pqc_ver, "r2_65") == 0 || - strcasecmp(pqc_ver, "r2_87") == 0 || - strcasecmp(pqc_ver, "r3_44") == 0 || - strcasecmp(pqc_ver, "r3_65") == 0 || - strcasecmp(pqc_ver, "r3_87") == 0) { + ch = prompt_user(msg, "ynac"); + free(msg); + + switch (ch) { + case 'n': + data->num_skipped++; + return CKR_OK; + case 'c': + data->skip_all = true; + data->num_skipped++; + return CKR_OK; + case 'a': + data->copy_all = true; break; - } else { - fprintf(stderr, "IBM Dilithium version [%s] not supported \n", pqc_ver); - return CKR_ARGUMENTS_BAD; - } - break; - case kt_IBM_KYBER: - if (pqc_ver == NULL) { - fprintf(stderr, - "Cipher key type [%d] supported but Kyber version not set in arguments. Try adding argument or \n", - *kt); - return CKR_ARGUMENTS_BAD; - } - if (strcasecmp(pqc_ver, "r2_768") == 0 || - strcasecmp(pqc_ver, "r2_1024") == 0) { + default: break; - } else { - fprintf(stderr, "IBM Kyber version [%s] not supported \n", pqc_ver); - return CKR_ARGUMENTS_BAD; } + } + + switch (class) { + case CKO_SECRET_KEY: + attr_aplicable = secret_attr_applicable; break; - case kt_AES: - if ((keylength == 128) || (keylength == 192) || (keylength == 256)) { - break; - } else { - fprintf(stderr, - "Cipher key type [%d] and key bit length %lu is not supported. Try adding argument <128|192|256>\n", - *kt, keylength); - return CKR_ARGUMENTS_BAD; - } + case CKO_PUBLIC_KEY: + attr_aplicable = public_attr_applicable; break; - case kt_AES_XTS: - if ((keylength == 128) || (keylength == 256)) { - break; - } else { - fprintf(stderr, - "Cipher key type [%d] and key bit length %lu is not supported. Try adding argument <128|256>\n", - *kt, keylength); - return CKR_ARGUMENTS_BAD; - } + case CKO_PRIVATE_KEY: + attr_aplicable = private_attr_applicable; break; - case kt_RSAPKCS: - if ((keylength == 1024) || (keylength == 2048) || (keylength == 4096)) { - break; - } else { - fprintf(stderr, - "[%d] RSA modulus bit length %lu NOT supported. Try adding argument <1024|2048|4096>\n", - *kt, keylength); + default: + warnx("Key object \"%s\" has an unsupported object class: %lu", + label, class); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + + if (opt_new_attr != NULL) { + rc = parse_boolean_attrs(keytype, opt_new_attr, &attrs, &num_attrs, + true, attr_aplicable); + if (rc != CKR_OK) { + data->num_failed++; + goto done; } - break; - case kt_EC: - if (ECcurve == NULL) { - fprintf(stderr, - "Cipher key type [%d] supported but EC curve not set in arguments. Try argument \n", - *kt); - return CKR_ARGUMENTS_BAD; + } + + if (opt_new_label != NULL) { + rc = add_attribute(CKA_LABEL, opt_new_label, strlen(opt_new_label), + &attrs, &num_attrs); + if (rc != CKR_OK) { + warnx("Failed to add %s key attribute CKA_LABEL: 0x%lX: %s", + keytype->name, rc, p11_get_ckr(rc)); + return rc; } - break; - case kt_GENERIC: - case kt_SECRET: - case kt_PUBLIC: - case kt_PRIVATE: - break; - default: - fprintf(stderr, "Cipher key type [%d] is not set or not supported\n", *kt); - print_gen_help(); + } + + if (opt_new_id != NULL) { + rc = parse_id(opt_new_id, &attrs, &num_attrs); + if (rc != CKR_OK) + return rc; + } + + rc = pkcs11_funcs->C_CopyObject(pkcs11_session, key, attrs, num_attrs, + &new_key); + if (rc != CKR_OK) { + warnx("Failed to copy %s key object \"%s\": C_CopyObject: 0x%lX: %s", + typestr, label, rc, p11_get_ckr(rc)); + data->num_failed++; + rc = CKR_OK; + goto done; + } + + printf("Successfully copied %s key object \"%s\".\n", typestr, label); + data->num_copied++; + +done: + free_attributes(attrs, num_attrs); + return rc; +} + + +static CK_RV p11sak_copy_key(void) +{ + const struct p11sak_keytype *keytype = NULL; + struct p11sak_copy_data data = { 0 }; + CK_RV rc; + + if (opt_keytype != NULL) + keytype = opt_keytype->private.ptr; + + data.copy_all = opt_force; + + rc = iterate_key_objects(keytype, opt_label, opt_id, opt_attr, NULL, + handle_key_copy, &data); + if (rc != CKR_OK) { + warnx("Failed to iterate over key objects for key type %s: 0x%lX: %s", + keytype != NULL ? keytype->name : "All", rc, p11_get_ckr(rc)); + return rc; + } + + printf("%lu key object(s) copied.\n", data.num_copied); + if (data.num_skipped > 0) + printf("%lu key object(s) skipped.\n", data.num_skipped); + if (data.num_failed > 0) + printf("%lu key object(s) failed to copy.\n", data.num_failed); + + return data.num_failed == 0 ? CKR_OK : CKR_FUNCTION_FAILED; +} + +static CK_RV p11sak_import_check_des_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + if (keysize != 8) { + warnx("Size of %s key is invalid, expected 8 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } -/** - * Check args for list_key command. - */ -static CK_RV check_args_list_key(p11sak_kt *kt) + +static CK_RV p11sak_import_check_3des_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize) { - switch (*kt) { - case kt_AES: - case kt_AES_XTS: - case kt_RSAPKCS: - case kt_DES: - case kt_3DES: - case kt_EC: - case kt_IBM_DILITHIUM: - case kt_IBM_KYBER: - case kt_GENERIC: - case kt_SECRET: - case kt_PUBLIC: - case kt_PRIVATE: - case kt_ALL: - break; - default: - fprintf(stderr, "Cipher key type [%d] is not set or not supported\n", *kt); - print_listkeys_help(); + if (keysize != 24) { + warnx("Size of %s key is invalid, expected 24 bytes", keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } -/** - * Check args for remove-key command. - */ -static CK_RV check_args_remove_key(p11sak_kt *kt) -{ - switch (*kt) { - case kt_DES: - case kt_3DES: - case kt_AES: - case kt_AES_XTS: - case kt_RSAPKCS: - case kt_EC: - case kt_IBM_DILITHIUM: - case kt_IBM_KYBER: - case kt_GENERIC: - case kt_SECRET: - case kt_PUBLIC: - case kt_PRIVATE: - break; - default: - fprintf(stderr, "Cipher key type [%d] is not set or not supported\n", *kt); - print_gen_help(); + +static CK_RV p11sak_import_check_generic_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + if (keysize == 0) { + warnx("Size of %s key is invalid, expected at least one byte", + keytype->name); return CKR_ARGUMENTS_BAD; } return CKR_OK; } -/** - * Parse p11sak command from argv. - */ -static p11sak_cmd parse_cmd(const char *arg) -{ - p11sak_cmd cmd = no_cmd; - if ((strcmp(arg, "generate-key") == 0) || (strcmp(arg, "gen-key") == 0) - || (strcmp(arg, "gen") == 0)) { - cmd = gen_key; - } else if ((strcmp(arg, "list-key") == 0) || (strcmp(arg, "ls-key") == 0) - || (strcmp(arg, "ls") == 0)) { - cmd = list_key; - } else if ((strcmp(arg, "remove-key") == 0) || (strcmp(arg, "rm-key") == 0) - || (strcmp(arg, "rm") == 0)) { - cmd = remove_key; - } else { - fprintf(stderr, "Unknown command %s\n", cmd2str(cmd)); - cmd = no_cmd; +static CK_RV p11sak_import_check_aes_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + if (keysize != 16 && keysize != 24 && keysize != 32) { + warnx("Size of %s key is invalid, expected 16, 24, or 32 bytes", + keytype->name); + return CKR_ARGUMENTS_BAD; } - return cmd; + + return CKR_OK; } -static CK_BBOOL last_parm_is_help(char *argv[], int argc) -{ - if (strcmp(argv[argc - 1], "-h") == 0 - || strcmp(argv[argc - 1], "--help") == 0) { - return 1; +static CK_RV p11sak_import_check_aes_xts_keysize( + const struct p11sak_keytype *keytype, + CK_ULONG keysize) +{ + if (keysize != 32 && keysize != 64) { + warnx("Size of %s key is invalid, expected 32 or 64 bytes", + keytype->name); + return CKR_ARGUMENTS_BAD; } - return 0; + return CKR_OK; } -static CK_ULONG get_ulong_arg(int pos, char *argv[], int argc) +static CK_RV p11sak_import_sym_clear_des_3des_aes_generic( + const struct p11sak_keytype *keytype, + CK_BYTE *data, CK_ULONG data_len, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { - if (pos < argc) - return atol(argv[pos]); - else - return 0; + UNUSED(keytype); + + return add_attribute(CKA_VALUE, data, data_len, attrs, num_attrs); } -static char* get_string_arg(int pos, char *argv[], int argc) +static CK_RV p11sak_import_rsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { - if (pos < argc) - return argv[pos]; - else - return NULL; + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL; + BIGNUM *bn_p = NULL, *bn_q = NULL; + BIGNUM *bn_dmp1 = NULL, *bn_dmq1 = NULL, *bn_iqmp = NULL; +#else + const RSA *rsa; + const BIGNUM *bn_n = NULL, *bn_e = NULL, *bn_d = NULL; + const BIGNUM *bn_p = NULL, *bn_q = NULL; + const BIGNUM *bn_dmp1 = NULL, *bn_dmq1 = NULL, *bn_iqmp = NULL; +#endif + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { + warnx("PEM file '%s' does not contain an %s %s key.", opt_file, + keytype->name, private ? "private" : "public"); + return CKR_FUNCTION_FAILED; + } + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e) || + (private && + (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &bn_d) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &bn_p) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &bn_q) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, + &bn_dmp1) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, + &bn_dmq1) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, + &bn_iqmp)))) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + rsa = EVP_PKEY_get0_RSA(pkey); + if (rsa == NULL) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + RSA_get0_key(rsa, &bn_n, &bn_e, private ? &bn_d : NULL); + if (private) { + RSA_get0_factors(rsa, &bn_p, &bn_q); + RSA_get0_crt_params(rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp); + } + if (bn_n == NULL || bn_e == NULL || + (private && (bn_d == NULL || bn_p == NULL || bn_q == NULL || + bn_dmp1 == NULL || bn_dmq1 == NULL || bn_iqmp == NULL))) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#endif + + rc = add_bignum_attr(CKA_MODULUS, bn_n, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_PUBLIC_EXPONENT, bn_e, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + if (private) { + rc = add_bignum_attr(CKA_PRIVATE_EXPONENT, bn_d, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_PRIME_1, bn_p, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_PRIME_2, bn_q, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_EXPONENT_1, bn_dmp1, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_EXPONENT_2, bn_dmq1, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_COEFFICIENT, bn_iqmp, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + } + +done: +#if OPENSSL_VERSION_PREREQ(3, 0) + if (bn_n != NULL) + BN_free(bn_n); + if (bn_e != NULL) + BN_free(bn_e); + if (bn_d != NULL) + BN_free(bn_d); + if (bn_p != NULL) + BN_free(bn_p); + if (bn_q != NULL) + BN_free(bn_q); + if (bn_dmp1 != NULL) + BN_free(bn_dmp1); + if (bn_dmq1 != NULL) + BN_free(bn_dmq1); + if (bn_iqmp != NULL) + BN_free(bn_iqmp); +#endif + + return rc; } -/** - * Parse the list-key args. - */ -static CK_RV parse_list_key_args(char *argv[], int argc, p11sak_kt *kt, - CK_ULONG *keylength, CK_SLOT_ID *slot, - const char **pin, int *long_print, char **label, - int *full_uri, int *force_pin_prompt) + +static CK_RV p11sak_import_dh_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) { - CK_RV rc; - CK_BBOOL slotIDset = CK_FALSE; - int i; + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_p = NULL, *bn_g = NULL, *bn_pub = NULL, *bn_priv = NULL; +#else + const DH *dh; + const BIGNUM *bn_p = NULL, *bn_g = NULL, *bn_pub = NULL, *bn_priv = NULL; +#endif + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { + warnx("PEM file '%s' does not contain an %s %s key.", opt_file, + keytype->name, private ? "private" : "public"); + return CKR_FUNCTION_FAILED; + } + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g) || + (!private && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub)) || + (private && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + dh = EVP_PKEY_get0_DH(pkey); + if (dh == NULL) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } + DH_get0_pqg(dh, &bn_p, NULL, &bn_g); + DH_get0_key(dh, !private ? &bn_pub : NULL, private ? &bn_priv : NULL); + if (bn_p == NULL || bn_g == NULL || + (!private && bn_pub == NULL) || (private && bn_priv == NULL)) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#endif - int base = 0; - char *endptr, *str; + rc = add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); + if (rc != CKR_OK) + goto done; - if (last_parm_is_help(argv, argc)) { - print_listkeys_help(); - return CKR_ARGUMENTS_BAD; + rc = add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); + if (rc != CKR_OK) + goto done; + + rc = add_bignum_attr(CKA_VALUE, private ? bn_priv : bn_pub, + attrs, num_attrs); + if (rc != CKR_OK) + goto done; + +done: +#if OPENSSL_VERSION_PREREQ(3, 0) + if (bn_p != NULL) + BN_free(bn_p); + if (bn_g != NULL) + BN_free(bn_g); + if (bn_pub != NULL) + BN_free(bn_pub); + if (bn_priv != NULL) + BN_free(bn_priv); +#endif + + return rc; +} + +static CK_RV p11sak_import_dsa_pkey(const struct p11sak_keytype *keytype, + EVP_PKEY *pkey, bool private, + CK_ATTRIBUTE **attrs, CK_ULONG *num_attrs) +{ + CK_RV rc = CKR_OK; +#if OPENSSL_VERSION_PREREQ(3, 0) + BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; + BIGNUM *bn_pub = NULL, *bn_priv = NULL; +#else + const DSA *dsa; + const BIGNUM *bn_p = NULL, *bn_q = NULL, *bn_g = NULL; + const BIGNUM *bn_pub = NULL, *bn_priv = NULL; +#endif + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { + warnx("PEM file '%s' does not contain an %s %s key.", opt_file, + keytype->name, private ? "private" : "public"); + return CKR_FUNCTION_FAILED; + } + +#if OPENSSL_VERSION_PREREQ(3, 0) + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &bn_p) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_Q, &bn_q) || + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &bn_g) || + (!private && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub)) || + (private && + !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv))) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#else + dsa = EVP_PKEY_get0_DSA(pkey); + if (dsa == NULL) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; } + DSA_get0_pqg(dsa, &bn_p, &bn_q, &bn_g); + DSA_get0_key(dsa, !private ? &bn_pub : NULL, private ? &bn_priv : NULL); + if (bn_p == NULL || bn_q == NULL || bn_g == NULL || + (!private && bn_pub == NULL) || (private && bn_priv == NULL)) { + warnx("Failed to get the %s params.", keytype->name); + ERR_print_errors_cb(openssl_err_cb, NULL); + rc = CKR_FUNCTION_FAILED; + goto done; + } +#endif - for (i = 2; i < argc; i++) { - /* Get arguments */ - if (strcasecmp(argv[i], "des") == 0) { - *kt = kt_DES; - *keylength = 64; - } else if (strcasecmp(argv[i], "3des") == 0) { - *kt = kt_3DES; - } else if (strcasecmp(argv[i], "aes") == 0) { - *kt = kt_AES; - } else if (strcasecmp(argv[i], "aes-xts") == 0) { - *kt = kt_AES_XTS; - } else if (strcasecmp(argv[i], "rsa") == 0) { - *kt = kt_RSAPKCS; - } else if (strcasecmp(argv[i], "ec") == 0) { - *kt = kt_EC; - } else if (strcasecmp(argv[i], "ibm-dilithium") == 0) { - *kt = kt_IBM_DILITHIUM; - } else if (strcasecmp(argv[i], "ibm-kyber") == 0) { - *kt = kt_IBM_KYBER; - } else if (strcasecmp(argv[i], "generic") == 0) { - *kt = kt_GENERIC; - } else if (strcasecmp(argv[i], "secret") == 0) { - *kt = kt_SECRET; - } else if (strcasecmp(argv[i], "public") == 0) { - *kt = kt_PUBLIC; - } else if (strcasecmp(argv[i], "private") == 0) { - *kt = kt_PRIVATE; - } else if (strcasecmp(argv[i], "all") == 0) { - *kt = kt_ALL; - /* Get options */ - } else if (strcmp(argv[i], "--slot") == 0) { - if (i + 1 < argc) { - str = argv[i + 1]; - errno = 0; - *slot = strtol(str, &endptr, base); - - if (errno != 0) { - perror("strtol"); - fprintf(stderr, "--slot argument must be specified correctly.\n"); - return CKR_ARGUMENTS_BAD; - } + rc = add_bignum_attr(CKA_PRIME, bn_p, attrs, num_attrs); + if (rc != CKR_OK) + goto done; - if (endptr == str) { - fprintf(stderr, "--slot argument must be specified correctly.\n"); - return CKR_ARGUMENTS_BAD; - } + rc = add_bignum_attr(CKA_SUBPRIME, bn_q, attrs, num_attrs); + if (rc != CKR_OK) + goto done; - if (*endptr != '\0') { - fprintf(stderr, "--slot argument must be specified correctly.\n"); - return CKR_ARGUMENTS_BAD; - } + rc = add_bignum_attr(CKA_BASE, bn_g, attrs, num_attrs); + if (rc != CKR_OK) + goto done; - slotIDset = CK_TRUE; - } else { - fprintf(stderr, "--slot argument is missing.\n"); - return CKR_ARGUMENTS_BAD; - } - i++; - } else if (strcmp(argv[i], "--pin") == 0) { - if (i + 1 < argc) { - *pin = argv[i + 1]; - } else { - fprintf(stderr, "--pin argument is missing.\n"); - return CKR_ARGUMENTS_BAD; - } - i++; - } else if ((strcmp(argv[i], "-l") == 0) - || (strcmp(argv[i], "--long") == 0)) { - *long_print = 1; - } else if (strcmp(argv[i], "--label") == 0) { - if (i + 1 < argc) { - *label = argv[i + 1]; - } else { - fprintf(stderr, "--label